void toxav_thread(void *args) { ToxAV *av = args; toxav_thread_init = 1; debug("Toxav thread init\n"); while (1) { if(toxav_thread_msg) { TOX_MSG *msg = &toxav_msg; if(msg->msg == UTOXAV_KILL) { break; } switch(msg->msg) { case UTOXAV_START_CALL: { FRIEND *f = &friend[msg->param1]; toxaudio_postmessage(AUDIO_STOP_RINGTONE, msg->param1, 0, NULL); toxaudio_postmessage(AUDIO_START, msg->param1, 0, NULL); f->call_state_self = ( TOXAV_FRIEND_CALL_STATE_SENDING_A | TOXAV_FRIEND_CALL_STATE_ACCEPTING_A ); if (msg->param2) { toxvideo_postmessage(VIDEO_RECORD_START, msg->param1, 0, NULL); f->call_state_self |= (TOXAV_FRIEND_CALL_STATE_SENDING_V | TOXAV_FRIEND_CALL_STATE_ACCEPTING_V); } break; } case UTOXAV_END_CALL: { FRIEND *f = &friend[msg->param1]; toxaudio_postmessage(AUDIO_STOP_RINGTONE, msg->param1, 0, NULL); toxaudio_postmessage(AUDIO_END, msg->param1, 0, NULL); if ((f->call_state_self | TOXAV_FRIEND_CALL_STATE_SENDING_V | TOXAV_FRIEND_CALL_STATE_ACCEPTING_V)){ toxvideo_postmessage(VIDEO_RECORD_STOP, msg->param1, 0, NULL); } break; } case UTOXAV_START_PREVIEW: { toxvideo_postmessage(VIDEO_PREVIEW_START, 0, 0, NULL); break; } case UTOXAV_END_PREVIEW: { toxvideo_postmessage(VIDEO_PREVIEW_STOP, 0, 0, NULL); break; } } } toxav_thread_msg = 0; toxav_iterate(av); yieldcpu(toxav_iteration_interval(av)); } toxav_thread_msg = 0; toxav_thread_init = 0; debug("UTOXAV:\tClean thread exit!\n"); return; }
_Bool doevent(void) { XEvent event; XNextEvent(display, &event); if(event.xany.window && event.xany.window != window) { if(event.type == ClientMessage) { XClientMessageEvent *ev = &event.xclient; if((Atom)event.xclient.data.l[0] == wm_delete_window) { if(ev->window == video_win[0]) { video_end(0); video_preview = 0; toxvideo_postmessage(VIDEO_PREVIEW_END, 0, 0, NULL); return 1; } int i; for(i = 0; i != countof(friend); i++) { if(video_win[i + 1] == ev->window) { FRIEND *f = &friend[i]; tox_postmessage(TOX_HANGUP, f->callid, 0, NULL); break; } } if(i == countof(friend)) { debug("this should not happen\n"); } } }
void friend_free(FRIEND *f) { uint16_t j = 0; while(j != f->edit_history_length) { free(f->edit_history[j]); j++; } free(f->edit_history); free(f->name); free(f->status_message); free(f->typed); MSG_IDX i = 0; while(i < f->msg.n) { MESSAGE *msg = f->msg.data[i]; if((msg->flags & (~1)) == 4) { //MSG_IMG *img = (void*)msg; //todo: free image } if((msg->flags & (~1)) == 6) { MSG_FILE *file = (void*)msg; free(file->path); FILE_T *ft = &f->incoming[file->filenumber]; if(ft->data) { if(ft->inline_png) { free(ft->data); } else { fclose(ft->data); free(ft->path); } } if(msg->flags & 1) { ft->status = FT_NONE; } } message_free(msg); i++; } free(f->msg.data); if(f->calling) { toxaudio_postmessage(AUDIO_CALL_END, f->callid, 0, NULL); if(f->calling == CALL_OK_VIDEO) { toxvideo_postmessage(VIDEO_CALL_END, f->callid, 0, NULL); } } memset(f, 0, sizeof(FRIEND));// }
void utox_av_local_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL control) { TOXAV_ERR_CALL_CONTROL err = 0; toxav_call_control(av, friend_number, control, &err); if (err) { debug("uToxAV:\tLocal call control error!\n"); } else { TOXAV_ERR_BIT_RATE_SET bitrate_err = 0; switch (control) { case TOXAV_CALL_CONTROL_HIDE_VIDEO: { toxav_bit_rate_set(av, friend_number, -1, 0, &bitrate_err); toxvideo_postmessage(VIDEO_RECORD_STOP, friend_number, 0, NULL); friend[friend_number].call_state_self &= (0xFF ^ TOXAV_FRIEND_CALL_STATE_SENDING_V); break; } case TOXAV_CALL_CONTROL_SHOW_VIDEO: { toxav_bit_rate_set(av, friend_number, -1, UTOX_DEFAULT_BITRATE_V, &bitrate_err); toxvideo_postmessage(VIDEO_RECORD_START, friend_number, 0, NULL); friend[friend_number].call_state_self |= TOXAV_FRIEND_CALL_STATE_SENDING_V; break; } default: { debug("uToxAV:\tUnhandled local call control\n"); } // TODO // TOXAV_CALL_CONTROL_RESUME, // TOXAV_CALL_CONTROL_PAUSE, // TOXAV_CALL_CONTROL_CANCEL, // TOXAV_CALL_CONTROL_MUTE_AUDIO, // TOXAV_CALL_CONTROL_UNMUTE_AUDIO, } if (bitrate_err) { debug("uToxAV:\tError setting/changing video bitrate\n"); } } return; }
static void dropdown_video_onselect(uint16_t i, const DROPDOWN* dm) { DROP_ELEMENT *e = &((DROP_ELEMENT*) dm->userdata)[i]; void *handle = e->handle; uint16_t b = 0; if(!handle && video_preview) { video_end(0); video_preview = 0; b = 1; //tell video thread to stop preview too } else if((size_t)handle == 1) { desktopgrab(1); return; } toxvideo_postmessage(VIDEO_SET, b, 0, handle); }
void friend_free(FRIEND *f) { uint16_t j = 0; while(j != f->edit_history_length) { free(f->edit_history[j]); j++; } free(f->edit_history); free(f->name); free(f->status_message); free(f->typed); MSG_IDX i = 0; while(i < f->msg.n) { MESSAGE *msg = f->msg.data[i]; switch(msg->msg_type) { case MSG_TYPE_IMAGE: { //MSG_IMG *img = (void*)msg; //todo: free image break; } case MSG_TYPE_FILE: { // TODO KILL THIS SECTION MSG_FILE *file = (void*)msg; free(file->path); break; } } message_free(msg); i++; } free(f->msg.data); if(f->calling) { toxaudio_postmessage(AUDIO_CALL_END, f->callid, 0, NULL); if(f->calling == CALL_OK_VIDEO) { toxvideo_postmessage(VIDEO_CALL_END, f->callid, 0, NULL); } } memset(f, 0, sizeof(FRIEND));// }
void tox_settingschanged(void) { //free everything tox_connected = 0; list_freeall(); list_dropdown_clear(&dropdown_audio_in); list_dropdown_clear(&dropdown_audio_out); list_dropdown_clear(&dropdown_video); tox_thread_init = 0; toxaudio_postmessage(AUDIO_KILL, 0, 0, NULL); toxvideo_postmessage(VIDEO_KILL, 0, 0, NULL); toxav_postmessage(TOXAV_KILL, 0, 0, NULL); tox_postmessage(0, 1, 0, NULL); while(!tox_thread_init) { yieldcpu(1); } list_start(); }
void tox_message(uint8_t tox_message_id, uint16_t param1, uint16_t param2, void *data) { switch(tox_message_id) { case DHT_CONNECTED: { /* param1: connection status (1 = connected, 0 = disconnected) */ tox_connected = param1; redraw(); break; } case DNS_RESULT: { /* param1: result (0 = failure, 1 = success) * data: resolved tox id (if successful) */ if(param1) { friend_addid(data, edit_addmsg.data, edit_addmsg.length); } else { addfriend_status = ADDF_BADNAME; } free(data); redraw(); break; } case OPEN_FILES: { tox_postmessage(TOX_SENDFILES, param1, param2, data); break; } case SAVE_FILE: { tox_postmessage(TOX_ACCEPTFILE, param1, param2, data); break; } case NEW_AUDIO_IN_DEVICE: { if(UI_STRING_ID_INVALID == param1) { list_dropdown_add_hardcoded(&dropdown_audio_in, data, data); } else { list_dropdown_add_localized(&dropdown_audio_in, param1, data); } if (loaded_audio_in_device != 0 && (dropdown_audio_in.dropcount - 1) == loaded_audio_in_device) { toxaudio_postmessage(AUDIO_SET_INPUT, 0, 0, data); dropdown_audio_in.selected = loaded_audio_in_device; loaded_audio_in_device = 0; } break; } case NEW_AUDIO_OUT_DEVICE: { list_dropdown_add_hardcoded(&dropdown_audio_out, data, data); if (loaded_audio_out_device != 0 && (dropdown_audio_out.dropcount - 1) == loaded_audio_out_device) { toxaudio_postmessage(AUDIO_SET_OUTPUT, 0, 0, data); dropdown_audio_out.selected = loaded_audio_out_device; loaded_audio_out_device = 0; } break; } case NEW_VIDEO_DEVICE: { if(UI_STRING_ID_INVALID == param1) { // Device name is a hardcoded string. // data is a pointer to a buffer, that contains device handle pointer, // followed by device name string. list_dropdown_add_hardcoded(&dropdown_video, data + sizeof(void*), *(void**)data); } else { // Device name is localized with param1 containing UI_STRING_ID. // data is device handle pointer. list_dropdown_add_localized(&dropdown_video, param1, data); } //param2 == true, if this device will be chosen by video detecting code. if(param2) { dropdown_video.selected = dropdown_video.over = (dropdown_video.dropcount - 1); } break; } case FRIEND_REQUEST: { /* data: pointer to FRIENDREQ structure */ list_addfriendreq(data); break; } case FRIEND_ADD: { /* confirmation that friend has been added to friend list (add) */ if(param1) { /* friend was not added */ addfriend_status = param2; } else { /* friend was added */ edit_addid.length = 0; edit_addmsg.length = 0; FRIEND *f = &friend[param2]; friends++; f->msg.scroll = 1.0; memcpy(f->cid, data, sizeof(f->cid)); friend_setname(f, NULL, 0); list_addfriend(f); addfriend_status = ADDF_SENT; } free(data); redraw(); break; } case FRIEND_ACCEPT: { /* confirmation that friend has been added to friend list (accept) */ if(!param1) { FRIEND *f = &friend[param2]; FRIENDREQ *req = data; friends++; memcpy(f->cid, req->id, sizeof(f->cid)); friend_setname(f, NULL, 0); list_addfriend2(f, req); redraw(); } free(data); break; } case FRIEND_DEL: { friend_free(data); friends--; break; } case FRIEND_MESSAGE: { friend_addmessage(&friend[param1], data); redraw(); break; } #define updatefriend(fp) redraw();//list_draw(); if(sitem && fp == sitem->data) {ui_drawmain();} #define updategroup(gp) redraw();//list_draw(); if(sitem && gp == sitem->data) {ui_drawmain();} case FRIEND_NAME: { FRIEND *f = &friend[param1]; friend_setname(f, data, param2); updatefriend(f); break; } case FRIEND_STATUS_MESSAGE: { FRIEND *f = &friend[param1]; free(f->status_message); f->status_length = param2; f->status_message = data; updatefriend(f); break; } case FRIEND_STATUS: { FRIEND *f = &friend[param1]; f->status = param2; updatefriend(f); break; } case FRIEND_TYPING: { FRIEND *f = &friend[param1]; friend_set_typing(f, param2); updatefriend(f); break; } case FRIEND_ONLINE: { FRIEND *f = &friend[param1]; f->online = param2; if(!f->online) { friend_set_typing(f, 0); } updatefriend(f); break; } case FRIEND_CALL_STATUS: { /* param1: friend id param2: call id data: integer call status */ FRIEND *f = &friend[param1]; uint8_t status = (size_t)data; if(status == CALL_NONE && (f->calling == CALL_OK || f->calling == CALL_OK_VIDEO)) { toxaudio_postmessage(AUDIO_CALL_END, param2, 0, NULL); if(f->calling == CALL_OK_VIDEO) { toxvideo_postmessage(VIDEO_CALL_END, param2, 0, NULL); } video_end(param1 + 1); } f->calling = status; f->callid = param2; if(status == CALL_OK) { toxaudio_postmessage(AUDIO_CALL_START, param2, 0, NULL); } call_notify(f, status); updatefriend(f); break; } case FRIEND_CALL_VIDEO: { /* param1: friend id param2: call id */ FRIEND *f = &friend[param1]; f->calling = CALL_OK_VIDEO; f->callid = param2; updatefriend(f); toxvideo_postmessage(VIDEO_CALL_START, param2, 0, NULL); toxaudio_postmessage(AUDIO_CALL_START, param2, 0, NULL); f->call_width = 640; f->call_height = 480; video_begin(param1 + 1, f->name, f->name_length, 640, 480); call_notify(f, CALL_OK_VIDEO); break; } case FRIEND_CALL_MEDIACHANGE: { /* param1: friend id param2: call id data: zero = audio, nonzero = audio/video */ FRIEND *f = &friend[param1]; if(!data) { video_end(param1 + 1); } else { f->call_width = 640; f->call_height = 480; video_begin(param1 + 1, f->name, f->name_length, 640, 480); } break; } case FRIEND_CALL_START_VIDEO: { /* param1: friend id param2: call id */ FRIEND *f = &friend[param1]; if(f->calling == CALL_OK) { f->calling = CALL_OK_VIDEO; toxvideo_postmessage(VIDEO_CALL_START, param2, 0, NULL); updatefriend(f); } break; } case FRIEND_CALL_STOP_VIDEO: { /* param1: friend id param2: call id */ FRIEND *f = &friend[param1]; if(f->calling == CALL_OK_VIDEO) { f->calling = CALL_OK; toxvideo_postmessage(VIDEO_CALL_END, param2, 0, NULL); updatefriend(f); } break; } case FRIEND_VIDEO_FRAME: { /* param1: friend id param2: call id data: frame data */ uint16_t *image = data; FRIEND *f = &friend[param1]; _Bool b = (image[0] != f->call_width || image[1] != f->call_height); if(b) { f->call_width = image[0]; f->call_height = image[1]; } video_frame(param1 + 1, (void*)&image[2], image[0], image[1], b); free(image); break; } case PREVIEW_FRAME_NEW: case PREVIEW_FRAME: { if(video_preview) { video_frame(0, data, param1, param2, tox_message_id == PREVIEW_FRAME_NEW); } free(data); break; } case FRIEND_FILE_IN_NEW: case FRIEND_FILE_IN_NEW_INLINE: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->incoming[param2]; _Bool inline_png = (tox_message_id == FRIEND_FILE_IN_NEW_INLINE); MSG_FILE *msg = malloc(sizeof(MSG_FILE)); msg->author = 0; msg->msg_type = MSG_TYPE_FILE; msg->filenumber = param2; msg->status = (inline_png ? FILE_OK : FILE_PENDING); msg->name_length = (ft->name_length > sizeof(msg->name)) ? sizeof(msg->name) : ft->name_length; msg->size = ft->total; msg->progress = 0; msg->speed = 0; msg->inline_png = inline_png; msg->path = NULL; memcpy(msg->name, ft->name, msg->name_length); friend_addmessage(f, msg); ft->chatdata = msg; file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_OUT_NEW: case FRIEND_FILE_OUT_NEW_INLINE: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->outgoing[param2]; _Bool inline_png = (tox_message_id == FRIEND_FILE_OUT_NEW_INLINE); MSG_FILE *msg = malloc(sizeof(MSG_FILE)); msg->author = 1; msg->msg_type = MSG_TYPE_FILE; msg->filenumber = param2; msg->status = FILE_PENDING; msg->name_length = (ft->name_length >= sizeof(msg->name)) ? sizeof(msg->name) - 1 : ft->name_length; msg->size = ft->total; msg->progress = 0; msg->speed = 0; msg->inline_png = inline_png; msg->path = NULL; memcpy(msg->name, ft->name, msg->name_length); msg->name[msg->name_length] = 0; friend_addmessage(f, msg); ft->chatdata = msg; updatefriend(f); break; } case FRIEND_FILE_IN_STATUS: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->incoming[param2]; MSG_FILE *msg = ft->chatdata; msg->status = (size_t)data; file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_OUT_STATUS: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->outgoing[param2]; MSG_FILE *msg = ft->chatdata; msg->status = (size_t)data; file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_IN_DONE: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->incoming[param2]; MSG_FILE *msg = ft->chatdata; msg->status = FILE_DONE; msg->path = data; file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_IN_DONE_INLINE: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->incoming[param2]; MSG_FILE *msg = ft->chatdata; msg->status = FILE_DONE; msg->path = data; friend_recvimage(f, data, msg->size); file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_OUT_DONE: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->outgoing[param2]; MSG_FILE *msg = ft->chatdata; msg->status = FILE_DONE; msg->path = data; file_notify(f, msg); updatefriend(f); break; } case FRIEND_FILE_IN_PROGRESS: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->incoming[param2]; FILE_PROGRESS *p = data; MSG_FILE *msg = ft->chatdata; msg->progress = p->bytes; msg->speed = p->speed; free(p); updatefriend(f); break; } case FRIEND_FILE_OUT_PROGRESS: { FRIEND *f = &friend[param1]; FILE_T *ft = &f->outgoing[param2]; FILE_PROGRESS *p = data; MSG_FILE *msg = ft->chatdata; msg->progress = p->bytes; msg->speed = p->speed; free(p); updatefriend(f); break; } case GROUP_ADD: { GROUPCHAT *g = &group[param1]; g->name_length = snprintf((char*)g->name, sizeof(g->name), "Groupchat #%u", param1); g->topic_length = sizeof("Drag friends to invite them") - 1; memcpy(g->topic, "Drag friends to invite them", sizeof("Drag friends to invite them") - 1); g->msg.scroll = 1.0; g->type = tox_group_get_type(data, param1); list_addgroup(g); redraw(); break; } case GROUP_MESSAGE: { GROUPCHAT *g = &group[param1]; message_add(&messages_group, data, &g->msg); if(sitem && g == sitem->data) { redraw();//ui_drawmain(); } break; } case GROUP_PEER_DEL: { GROUPCHAT *g = &group[param1]; if (param2 > MAX_GROUP_PEERS) //TODO: dynamic arrays. break; if(g->peername[param2]) { free(g->peername[param2]); g->peername[param2] = NULL; } g->peers--; g->peername[param2] = g->peername[g->peers]; g->peername[g->peers] = NULL; if (g->type == TOX_GROUPCHAT_TYPE_AV) { g->last_recv_audio[param2] = g->last_recv_audio[g->peers]; g->last_recv_audio[g->peers] = 0; group_av_peer_remove(g, param2); g->source[param2] = g->source[g->peers]; } if (g->peers == g->our_peer_number) { g->our_peer_number = param2; } g->topic_length = snprintf((char*)g->topic, sizeof(g->topic), "%u users in chat", g->peers); updategroup(g); break; } case GROUP_PEER_ADD: case GROUP_PEER_NAME: { GROUPCHAT *g = &group[param1]; if (param2 > MAX_GROUP_PEERS) //TODO: dynamic arrays. break; if(g->peername[param2]) { free(g->peername[param2]); } if(tox_message_id == GROUP_PEER_ADD) { if (g->type == TOX_GROUPCHAT_TYPE_AV) { group_av_peer_add(g, param2); } if (tox_group_peernumber_is_ours(data, param1, param2)) { g->our_peer_number = param2; } uint8_t *n = malloc(10); n[0] = 9; memcpy(n + 1, "<unknown>", 9); data = n; g->peers++; } g->peername[param2] = data; g->topic_length = snprintf((char*)g->topic, sizeof(g->topic), "%u users in chat", g->peers); updategroup(g); break; } case GROUP_TITLE: { GROUPCHAT *g = &group[param1]; if (param2 > sizeof(g->name)) { memcpy(g->name, data, sizeof(g->name)); g->name_length = sizeof(g->name); } else { memcpy(g->name, data, param2); g->name_length = param2; } free(data); updategroup(g); break; } case GROUP_AUDIO_START: { GROUPCHAT *g = &group[param1]; if (g->type == TOX_GROUPCHAT_TYPE_AV) { g->audio_calling = 1; toxaudio_postmessage(GROUP_AUDIO_CALL_START, param1, 0, NULL); updategroup(g); } break; } case GROUP_AUDIO_END: { GROUPCHAT *g = &group[param1]; if (g->type == TOX_GROUPCHAT_TYPE_AV) { g->audio_calling = 0; toxaudio_postmessage(GROUP_AUDIO_CALL_END, param1, 0, NULL); updategroup(g); } break; } case GROUP_UPDATE: { GROUPCHAT *g = &group[param1]; updategroup(g); break; } }