From ad04fa4dcd4a01d4aa2a1ac7c0bcf220b02caf19 Mon Sep 17 00:00:00 2001 From: cnhenry Date: Mon, 10 Aug 2015 06:14:38 -0500 Subject: [PATCH] Major refactoring and fixes towards AV --- src/audio_call.c | 500 ++++++++++++++++++--------------------------- src/audio_call.h | 8 +- src/chat.c | 35 ++-- src/friendlist.c | 1 + src/prompt.c | 8 +- src/toxic.c | 16 +- src/video_call.c | 185 +++++++++-------- src/video_call.h | 6 +- src/video_device.c | 176 ++++++++-------- src/windows.h | 2 +- 10 files changed, 437 insertions(+), 500 deletions(-) diff --git a/src/audio_call.c b/src/audio_call.c index 9b7a15c..e06e398 100644 --- a/src/audio_call.c +++ b/src/audio_call.c @@ -29,9 +29,9 @@ #include "line_info.h" #include "notify.h" - #ifdef VIDEO - #include "video_call.h" - #endif /* VIDEO */ +#ifdef VIDEO +#include "video_call.h" +#endif /* VIDEO */ #include #include @@ -55,7 +55,7 @@ #define cbend pthread_exit(NULL) -#define frame_size (CallContrl.audio_sample_rate * CallContrl.audio_frame_duration / 1000) +#define frame_size (CallControl.audio_sample_rate * CallControl.audio_frame_duration / 1000) static int set_call(Call* call, bool start) { @@ -92,19 +92,19 @@ void receive_video_frame_cb( ToxAV *av, uint32_t friend_number, void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, bool stable, uint32_t bit_rate, void *user_data); -void callback_recv_invite ( void* av, uint32_t friend_number, void *arg ); -void callback_recv_ringing ( void* av, uint32_t friend_number, void *arg ); -void callback_recv_starting ( void* av, uint32_t friend_number, void *arg ); -void callback_recv_ending ( void* av, uint32_t friend_number, void *arg ); -void callback_call_started ( void* av, uint32_t friend_number, void *arg ); -void callback_call_canceled ( void* av, uint32_t friend_number, void *arg ); -void callback_call_rejected ( void* av, uint32_t friend_number, void *arg ); -void callback_call_ended ( void* av, uint32_t friend_number, void *arg ); -void callback_requ_timeout ( void* av, uint32_t friend_number, void *arg ); -void callback_peer_timeout ( void* av, uint32_t friend_number, void *arg ); -void callback_media_change ( void* av, uint32_t friend_number, void *arg ); +void callback_recv_invite ( uint32_t friend_number ); +void callback_recv_ringing ( uint32_t friend_number ); +void callback_recv_starting ( uint32_t friend_number ); +void callback_recv_ending ( uint32_t friend_number ); +void callback_call_started ( uint32_t friend_number ); +void callback_call_canceled ( uint32_t friend_number ); +void callback_call_rejected ( uint32_t friend_number ); +void callback_call_ended ( uint32_t friend_number ); +void callback_requ_timeout ( uint32_t friend_number ); +void callback_peer_timeout ( uint32_t friend_number ); +void callback_media_change ( uint32_t friend_number ); -void write_device_callback( void* agent, int32_t friend_number, const int16_t* PCM, uint16_t size, void* arg ); +void write_device_callback( uint32_t friend_number, const int16_t* PCM, uint16_t size ); static void print_err (ToxWindow *self, const char *error_str) { @@ -114,64 +114,54 @@ static void print_err (ToxWindow *self, const char *error_str) ToxAV *init_audio(ToxWindow *self, Tox *tox) { TOXAV_ERR_NEW error; - CallContrl.errors = ae_None; - CallContrl.window = self; + CallControl.errors = ae_None; + CallControl.prompt = self; + CallControl.pending_call = false; - CallContrl.av = toxav_new(tox, &error); + CallControl.av = toxav_new(tox, &error); - CallContrl.audio_enabled = true; - CallContrl.audio_bit_rate = 48; - CallContrl.audio_sample_rate = 48000; - CallContrl.audio_frame_duration = 10; - CallContrl.audio_channels = 1; + CallControl.audio_enabled = true; + CallControl.audio_bit_rate = 48; + CallControl.audio_sample_rate = 48000; + CallControl.audio_frame_duration = 10; + CallControl.audio_channels = 1; -#ifdef VIDEO + CallControl.video_enabled = false; + CallControl.video_bit_rate = 0; + CallControl.video_frame_duration = 0; - if ( !init_video(self, tox, CallContrl.av, &CallContrl) ) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init video"); - return NULL; - } + memset(CallControl.calls, 0, sizeof(CallControl.calls)); -#else - - CallContrl.video_enabled = false; - CallContrl.video_bit_rate = 0; - CallContrl.video_frame_duration = 0; - -#endif /* VIDEO */ - - memset(CallContrl.calls, 0, sizeof(CallContrl.calls)); - - if ( !CallContrl.av ) { - CallContrl.errors |= ae_StartingCoreAudio; + if ( !CallControl.av ) { + CallControl.errors |= ae_StartingCoreAudio; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init ToxAV"); + return NULL; } - if ( init_devices(CallContrl.av) == de_InternalError ) { + if ( init_devices(CallControl.av) == de_InternalError ) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices"); - toxav_kill(CallContrl.av); - return CallContrl.av = NULL; + toxav_kill(CallControl.av); + + return CallControl.av = NULL; } - toxav_callback_call(CallContrl.av, call_cb, &CallContrl); - toxav_callback_call_state(CallContrl.av, callstate_cb, &CallContrl); - toxav_callback_audio_receive_frame(CallContrl.av, receive_audio_frame_cb, &CallContrl); - toxav_callback_audio_bit_rate_status(CallContrl.av, audio_bit_rate_status_cb, &CallContrl); - toxav_callback_video_receive_frame(CallContrl.av, receive_video_frame_cb, &CallContrl); - toxav_callback_video_bit_rate_status(CallContrl.av, video_bit_rate_status_cb, &CallContrl); + toxav_callback_call(CallControl.av, call_cb, &CallControl); + toxav_callback_call_state(CallControl.av, callstate_cb, &CallControl); + toxav_callback_audio_receive_frame(CallControl.av, receive_audio_frame_cb, &CallControl); + toxav_callback_audio_bit_rate_status(CallControl.av, audio_bit_rate_status_cb, &CallControl); - return CallContrl.av; + return CallControl.av; } void terminate_audio() { int i; for (i = 0; i < MAX_CALLS; ++i) - stop_transmission(&CallContrl.calls[i], i); + stop_transmission(&CallControl.calls[i], i); - if ( CallContrl.av ) - toxav_kill(CallContrl.av); + if ( CallControl.av ) + toxav_kill(CallControl.av); terminate_devices(); } @@ -179,53 +169,50 @@ void terminate_audio() void read_device_callback(const int16_t* captured, uint32_t size, void* data) { TOXAV_ERR_SEND_FRAME error; - int32_t friend_number = *((int32_t*)data); /* TODO: Or pass an array of call_idx's */ - int64_t sample_count = CallContrl.audio_sample_rate * CallContrl.audio_frame_duration / 1000; + uint32_t friend_number = *((uint32_t*)data); /* TODO: Or pass an array of call_idx's */ + int64_t sample_count = CallControl.audio_sample_rate * CallControl.audio_frame_duration / 1000; - if ( sample_count <= 0 || toxav_audio_send_frame(CallContrl.av, friend_number, + if ( sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number, captured, sample_count, - CallContrl.audio_channels, - CallContrl.audio_sample_rate, &error) == false ) + CallControl.audio_channels, + CallControl.audio_sample_rate, &error) == false ) {} } -void write_device_callback(void *agent, int32_t friend_number, const int16_t* PCM, uint16_t size, void* arg) +void write_device_callback(uint32_t friend_number, const int16_t* PCM, uint16_t size) { - (void)arg; - (void)agent; - - if (friend_number >= 0 && CallContrl.calls[friend_number].ttas) - write_out(CallContrl.calls[friend_number].out_idx, PCM, size, CallContrl.audio_channels); + if (friend_number >= 0 && CallControl.calls[friend_number].ttas) + write_out(CallControl.calls[friend_number].out_idx, PCM, size, CallControl.audio_channels); } int start_transmission(ToxWindow *self, Call *call) { - if ( !self || !CallContrl.av) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Could not prepare transmission"); + if ( !self || !CallControl.av ) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare transmission"); return -1; } if (set_call(call, true) == -1) return -1; - DeviceError error = open_primary_device(input, &call->in_idx, CallContrl.audio_sample_rate, CallContrl.audio_frame_duration, CallContrl.audio_channels); + DeviceError error = open_primary_device(input, &call->in_idx, + CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels); - if ( error == de_FailedStart) - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to start input device"); + if ( error != de_None ) { + if ( error == de_FailedStart) + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to start input device"); - if ( error == de_InternalError ) - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Internal error with opening input device"); - - if ( error != de_None ) - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input device!"); + if ( error == de_InternalError ) + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Internal error with opening input device"); + } if ( register_device_callback(self->num, call->in_idx, - read_device_callback, &self->num, true) != de_None) + read_device_callback, &self->num, true) != de_None) /* Set VAD as true for all; TODO: Make it more dynamic */ line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!"); if ( open_primary_device(output, &call->out_idx, - CallContrl.audio_sample_rate, CallContrl.audio_frame_duration, CallContrl.audio_channels) != de_None ) { + CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None ) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!"); call->has_output = 0; } @@ -233,12 +220,13 @@ int start_transmission(ToxWindow *self, Call *call) return 0; } -int stop_transmission(Call *call, int32_t friend_number) +int stop_transmission(Call *call, uint32_t friend_number) { if ( call->ttas ) { TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK; - if ( CallContrl.call_state != TOXAV_FRIEND_CALL_STATE_FINISHED ) - toxav_call_control(CallContrl.av, friend_number, TOXAV_CALL_CONTROL_CANCEL, &error); + + if ( CallControl.call_state != TOXAV_FRIEND_CALL_STATE_FINISHED ) + toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_CANCEL, &error); if ( error == TOXAV_ERR_CALL_CONTROL_OK ) { call->ttas = false; @@ -249,7 +237,7 @@ int stop_transmission(Call *call, int32_t friend_number) if ( call->out_idx != -1 ) close_device(output, call->out_idx); - if (set_call(call, false) == -1) + if ( set_call(call, false) == -1 ) return -1; return 0; @@ -272,222 +260,146 @@ int stop_transmission(Call *call, int32_t friend_number) /* * Callbacks */ - void call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data) { - TOXAV_ERR_ANSWER error; - CallControl* cc = user_data; - ToxWindow* window = cc->window; - //cc->audio_enabled = audio_enabled; - //cc->video_enabled = video_enabled; - cc->pending_call = true; - - callback_recv_invite(av, friend_number, user_data); + CallControl.pending_call = true; + callback_recv_invite(friend_number); } void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data) { - CallControl* cc = user_data; - ToxWindow* window = cc->window; - cc->call_state = state; + ToxWindow* windows = CallControl.prompt; + CallControl.call_state = state; - if ( state == TOXAV_FRIEND_CALL_STATE_FINISHED ) { - if ( CallContrl.pending_call ) { - CallContrl.pending_call = false; - callback_call_rejected(av, friend_number, &CallContrl); - } else { - callback_call_ended(av, friend_number, &CallContrl); - } - } else { - if ( state == TOXAV_FRIEND_CALL_STATE_ERROR ) { - line_info_add(window, NULL, NULL, NULL, SYS_MSG, 0, 0, "ToxAV callstate error!"); - CallContrl.pending_call = false; - callback_call_ended(av, friend_number, &CallContrl); - } else { - CallContrl.pending_call = false; - callback_call_started(av, friend_number, &CallContrl); - } + switch ( state ) { + case ( TOXAV_FRIEND_CALL_STATE_ERROR ): + line_info_add(windows, NULL, NULL, NULL, SYS_MSG, 0, 0, "ToxAV callstate error!"); + stop_transmission(&CallControl.calls[friend_number], friend_number); + callback_call_ended(friend_number); + CallControl.pending_call = false; + + break; + case ( TOXAV_FRIEND_CALL_STATE_FINISHED ): + if ( CallControl.pending_call ) + callback_call_rejected(friend_number); + else + callback_call_ended(friend_number); + + stop_transmission(&CallControl.calls[friend_number], friend_number); + + /* Reset call state after finishing */ + CallControl.call_state = 0; + CallControl.pending_call = false; + + break; + default: /* Start answered call */ + callback_call_started(friend_number); + CallControl.pending_call = false; + + break; } + +#ifdef VIDEO + + /* Handle receiving client video call states */ + //if (state & ~TOXAV_FRIEND_CALL_STATE_SENDING_V) { + // callback_recv_video_end(CallControl.av, friend_number, &CallControl); + //} + + //if (state & ~(TOXAV_FRIEND_CALL_STATE_ACCEPTING_V & TOXAV_FRIEND_CALL_STATE_SENDING_V)) { + // CallControl.video_call = false; + //} + +#endif /* VIDEO */ } void receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, void *user_data) { - CallControl* cc = user_data; - - write_device_callback(CallContrl.calls[friend_number].out_idx, friend_number, pcm, frame_size, cc); + write_device_callback(friend_number, pcm, frame_size); } void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, bool stable, uint32_t bit_rate, void *user_data) { - CallControl* cc = user_data; - if ( stable ) - cc->audio_bit_rate = bit_rate; + CallControl.audio_bit_rate = bit_rate; } -#define CB_BODY(friend_number, Arg, onFunc) do { ToxWindow* windows = (Arg); int i;\ -for (i = 0; i < MAX_WINDOWS_NUM; ++i) if (windows[i].onFunc != NULL) windows[i].onFunc(&windows[i], CallContrl.av, friend_number); } while (0) +#define CB_BODY(friend_number, onFunc) do { ToxWindow* windows = CallControl.prompt; int i;\ +for (i = 0; i < MAX_WINDOWS_NUM; ++i) if ( windows[i].onFunc != NULL ) windows[i].onFunc(&windows[i], CallControl.av, friend_number, CallControl.call_state); } while (0) - -void callback_recv_invite ( void* av, uint32_t friend_number, void* arg ) +void callback_recv_invite ( uint32_t friend_number ) { - //CB_BODY(friend_number, arg, onInvite); - CallControl* cc = (CallControl*)arg; - ToxWindow* windows = cc->window; - - int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onInvite != NULL && windows[i].num == friend_number) { - windows[i].onInvite(&windows[i], av, friend_number, cc->call_state); - } + CB_BODY(friend_number, onInvite); } -void callback_recv_ringing ( void* av, uint32_t friend_number, void* arg ) +void callback_recv_ringing ( uint32_t friend_number ) { - //CB_BODY(friend_number, arg, onRinging); - CallControl* cc = arg; - ToxWindow* windows = cc->window; - - int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onRinging != NULL && windows[i].is_call && windows[i].num == friend_number) { - windows[i].onRinging(&windows[i], av, friend_number, cc->call_state); - } + CB_BODY(friend_number, onRinging); } -void callback_recv_starting ( void* av, uint32_t friend_number, void* arg ) +void callback_recv_starting ( uint32_t friend_number ) { - CallControl* cc = arg; - ToxWindow* windows = cc->window; - + ToxWindow* windows = CallControl.prompt; + int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onStarting != NULL && windows[i].is_call && windows[i].num == friend_number) { - windows[i].onStarting(&windows[i], av, friend_number, cc->call_state); - if ( 0 != start_transmission(&windows[i], &CallContrl.calls[friend_number])) {/* YEAH! */ + for (i = 0; i < MAX_WINDOWS_NUM; ++i) { + if ( windows[i].onStarting != NULL && windows[i].num == friend_number ) { + windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state); + if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) /* YEAH! */ line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!"); - } + return; } + } } -void callback_recv_ending ( void* av, uint32_t friend_number, void* arg ) +void callback_recv_ending ( uint32_t friend_number ) { - //CB_BODY(friend_number, arg, onEnding); - CallControl* cc = arg; - ToxWindow* windows = cc->window; + CB_BODY(friend_number, onEnding); +} +void callback_call_started ( uint32_t friend_number ) +{ + ToxWindow* windows = CallControl.prompt; int i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onEnding != NULL && windows[i].is_call && windows[i].num == friend_number) { - windows[i].onEnding(&windows[i], av, friend_number, cc->call_state); - } - - stop_transmission(&CallContrl.calls[friend_number], friend_number); - -#ifdef VIDEO - callback_video_ending(av, friend_number, &CallContrl); -#endif /* VIDEO */ -} -void callback_call_started ( void* av, uint32_t friend_number, void* arg ) -{ - CallControl* cc = arg; - ToxWindow* windows = cc->window; - - int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onStart != NULL && windows[i].is_call && windows[i].num == friend_number) { - windows[i].onStart(&windows[i], av, friend_number, cc->call_state); - if ( 0 != start_transmission(&windows[i], &CallContrl.calls[friend_number]) ) {/* YEAH! */ + if ( windows[i].onStart != NULL && windows[i].num == friend_number ) { + windows[i].onStart(&windows[i], CallControl.av, friend_number, CallControl.call_state); + if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) {/* YEAH! */ line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!"); return; } } } -void callback_call_canceled ( void* av, uint32_t friend_number, void* arg ) +void callback_call_canceled ( uint32_t friend_number ) { - //CB_BODY(friend_number, arg, onCancel); - CallControl* cc = arg; - ToxWindow* windows = cc->window; - - int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onCancel != NULL && windows[i].is_call && windows[i].num == friend_number) { - windows[i].onCancel(&windows[i], av, friend_number, cc->call_state); - } - - /* In case call is active */ - stop_transmission(&CallContrl.calls[friend_number], friend_number); -#ifdef VIDEO - callback_video_ending(av, friend_number, &CallContrl); -#endif /* VIDEO */ + CB_BODY(friend_number, onCancel); } -void callback_call_rejected ( void* av, uint32_t friend_number, void* arg ) +void callback_call_rejected ( uint32_t friend_number ) { - //CB_BODY(friend_number, arg, onReject); - - CallControl* cc = arg; - ToxWindow* windows = cc->window; - - int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onReject != NULL && windows[i].is_call && windows[i].num == friend_number) { - windows[i].onReject(&windows[i], av, friend_number, cc->call_state); - } - + CB_BODY(friend_number, onReject); } -void callback_call_ended ( void* av, uint32_t friend_number, void* arg ) +void callback_call_ended ( uint32_t friend_number ) { - //CB_BODY(friend_number, arg, onEnd); - CallControl* cc = arg; - ToxWindow* windows = cc->window; - - int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onEnd != NULL && windows[i].is_call && windows[i].num == friend_number) { - windows[i].onEnd(&windows[i], av, friend_number, cc->call_state); - } - - stop_transmission(&CallContrl.calls[friend_number], friend_number); -#ifdef VIDEO - callback_video_ending(av, friend_number, &CallContrl); -#endif /* VIDEO */ + CB_BODY(friend_number, onEnd); } - -void callback_requ_timeout ( void* av, uint32_t friend_number, void* arg ) +void callback_requ_timeout ( uint32_t friend_number ) { - //CB_BODY(friend_number, arg, onRequestTimeout); - CallControl* cc = arg; - ToxWindow* windows = cc->window; - - int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onRequestTimeout != NULL && windows[i].is_call && windows[i].num == friend_number) { - windows[i].onRequestTimeout(&windows[i], av, friend_number, cc->call_state); - } + CB_BODY(friend_number, onRequestTimeout); } -void callback_peer_timeout ( void* av, uint32_t friend_number, void* arg ) +void callback_peer_timeout ( uint32_t friend_number ) { - //CB_BODY(friend_number, arg, onPeerTimeout); - CallControl* cc = arg; - ToxWindow* windows = cc->window; + CB_BODY(friend_number, onPeerTimeout); - int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onPeerTimeout != NULL && windows[i].is_call && windows[i].num == friend_number) { - windows[i].onPeerTimeout(&windows[i], av, friend_number, cc->call_state); - } - - stop_transmission(&CallContrl.calls[friend_number], friend_number); + stop_transmission(&CallControl.calls[friend_number], friend_number); /* Call is stopped manually since there might be some other * actions that one can possibly take on timeout */ - TOXAV_ERR_CALL_CONTROL error; - bool call_running = toxav_call_control(av, friend_number, TOXAV_CALL_CONTROL_CANCEL, &error); + toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_CANCEL, NULL); } -// void callback_media_change(void* av, int32_t friend_number, void* arg) +// void callback_media_change(void* av, uint32_t friend_number, void* arg) // { /*... TODO cancel all media change requests */ // } @@ -510,7 +422,7 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA goto on_error; } - if ( !CallContrl.av ) { + if ( !CallControl.av ) { error_str = "ToxAV not supported!"; goto on_error; } @@ -520,20 +432,24 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA goto on_error; } - bool call_running; - call_running = toxav_call(CallContrl.av, self->num, CallContrl.audio_bit_rate, CallContrl.video_bit_rate, &error); + if ( CallControl.pending_call ) { + error_str = "Already a pending call!"; + goto on_error; + } - if ( !call_running ) { + toxav_call(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error); + if ( error != TOXAV_ERR_CALL_OK ) { if ( error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL ) error_str = "Already in a call!"; else if ( error == TOXAV_ERR_CALL_MALLOC ) error_str = "Memory allocation issue"; - else if ( error == TOXAV_ERR_CALL_FRIEND_NOT_FOUND) error_str = "Friend number invalid"; - else if ( error == TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED) error_str = "Friend is valid but not currently connected"; + else if ( error == TOXAV_ERR_CALL_FRIEND_NOT_FOUND ) error_str = "Friend number invalid"; + else if ( error == TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED ) error_str = "Friend is valid but not currently connected"; else error_str = "Internal error!"; goto on_error; } - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Calling... idx: %d", self->call_idx); + CallControl.pending_call = true; + callback_recv_ringing(self->num); return; on_error: @@ -550,14 +466,18 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ goto on_error; } - if ( !CallContrl.av ) { + if ( !CallControl.av ) { error_str = "Audio not supported!"; goto on_error; } - bool call_running = toxav_answer(CallContrl.av, self->num, CallContrl.audio_bit_rate, CallContrl.video_bit_rate, &error); + if ( !CallControl.pending_call ) { + error_str = "No incoming call!"; + goto on_error; + } - if ( !call_running ) { + toxav_answer(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error); + if ( error != TOXAV_ERR_ANSWER_OK ) { if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING ) error_str = "No incoming call!"; else if ( error == TOXAV_ERR_ANSWER_CODEC_INITIALIZATION ) error_str = "Failed to initialize codecs!"; else if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND ) error_str = "Friend not found!"; @@ -568,10 +488,8 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ } /* Callback will print status... */ - - self->is_call = call_running; - CallContrl.pending_call = false; - callback_recv_starting(CallContrl.av, self->num, &CallContrl); + callback_recv_starting(self->num); + CallControl.pending_call = false; return; on_error: @@ -580,7 +498,6 @@ on_error: void cmd_reject(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { - TOXAV_ERR_CALL_CONTROL error; const char *error_str; if ( argc != 0 ) { @@ -588,27 +505,22 @@ void cmd_reject(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ goto on_error; } - if ( !CallContrl.av ) { + if ( !CallControl.av ) { error_str = "Audio not supported!"; goto on_error; } - bool call_running; - call_running = toxav_call_control(CallContrl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, &error); - - if ( error != TOXAV_ERR_CALL_CONTROL_OK ) { - if ( error == TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION ) error_str = "Cannot reject in invalid state!"; - else if ( CallContrl.pending_call == false ) error_str = "No incoming call!"; - else error_str = "Internal error!"; - + if ( !CallControl.pending_call ) { + error_str = "No incoming call!"; goto on_error; } - /* Callback will print status... */ + /* Manually send a cancel call control because call hasn't started */ + toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL); + CallControl.pending_call = false; - self->is_call = call_running; - CallContrl.pending_call = false; - callback_call_rejected(CallContrl.av, self->num, &CallContrl); + /* Callback will print status... */ + callback_call_rejected(self->num); return; on_error: @@ -617,7 +529,6 @@ on_error: void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { - TOXAV_ERR_CALL_CONTROL error; const char *error_str; if ( argc != 0 ) { @@ -625,32 +536,24 @@ void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ goto on_error; } - if ( !CallContrl.av ) { + if ( !CallControl.av ) { error_str = "Audio not supported!"; goto on_error; } - bool call_running; - if( CallContrl.pending_call && CallContrl.call_state != TOXAV_FRIEND_CALL_STATE_FINISHED ) { - call_running = toxav_call_control(CallContrl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, &error); -#ifdef SOUND_NOTIFY - stop_sound(self->ringing_sound); -#endif - CallContrl.pending_call = false; - callback_call_ended(CallContrl.av, self->num, &CallContrl); - } else { - call_running = toxav_call_control(CallContrl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, &error); - callback_call_ended(CallContrl.av, self->num, &CallContrl); - } +#ifdef VIDEO + callback_video_end(CallControl.av, self->num, &CallControl); - if ( error != TOXAV_ERR_CALL_CONTROL_OK ) { - if ( error == TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION ) error_str = "Cannot hangup in invalid state!"; - else if ( error == TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL ) error_str = "No call!"; - else if ( error == TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND ) error_str = "Invalid friend!"; - else error_str = "Internal error!"; +#endif /* VIDEO */ - goto on_error; - } + stop_transmission(&CallControl.calls[self->num], self->num); + + if ( CallControl.pending_call ) + callback_call_ended(self->num); + else + callback_call_canceled(self->num); + + CallControl.pending_call = false; return; on_error: @@ -774,23 +677,23 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a /* If call is active, change device */ if ( self->is_call ) { - Call* this_call = &CallContrl.calls[self->num]; - if (this_call->ttas) { + Call* this_call = &CallControl.calls[self->num]; + if ( this_call->ttas ) { - if (type == output) { + if ( type == output ) { pthread_mutex_lock(&this_call->mutex); close_device(output, this_call->out_idx); this_call->has_output = open_device(output, selection, &this_call->out_idx, - CallContrl.audio_sample_rate, CallContrl.audio_frame_duration, CallContrl.audio_channels) + CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) == de_None ? 1 : 0; pthread_mutex_unlock(&this_call->mutex); } else { /* TODO: check for failure */ close_device(input, this_call->in_idx); - open_device(input, selection, &this_call->in_idx, CallContrl.audio_sample_rate, - CallContrl.audio_frame_duration, CallContrl.audio_channels); + open_device(input, selection, &this_call->in_idx, CallControl.audio_sample_rate, + CallControl.audio_frame_duration, CallControl.audio_channels); /* Set VAD as true for all; TODO: Make it more dynamic */ register_device_callback(self->num, this_call->in_idx, read_device_callback, &self->num, true); } @@ -831,10 +734,10 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA /* If call is active, use this_call values */ if ( self->is_call ) { - Call* this_call = &CallContrl.calls[self->num]; + Call* this_call = &CallControl.calls[self->num]; pthread_mutex_lock(&this_call->mutex); - if (type == input) { + if ( type == input ) { device_mute(type, this_call->in_idx); self->chatwin->infobox.in_is_muted ^= 1; } else { @@ -871,7 +774,7 @@ void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M /* Call must be active */ if ( self->is_call ) { - device_set_VAD_treshold(CallContrl.calls[self->num].in_idx, value); + device_set_VAD_treshold(CallControl.calls[self->num].in_idx, value); self->chatwin->infobox.vad_lvl = value; } @@ -885,6 +788,5 @@ on_error: void stop_current_call(ToxWindow* self) { TOXAV_ERR_CALL_CONTROL error; - bool call_running = toxav_call_control(CallContrl.av, &self->num, TOXAV_CALL_CONTROL_CANCEL, &error); - self->is_call = call_running; + toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, &error); } diff --git a/src/audio_call.h b/src/audio_call.h index 83032e3..8203423 100644 --- a/src/audio_call.h +++ b/src/audio_call.h @@ -43,11 +43,11 @@ typedef struct Call { pthread_mutex_t mutex; } Call; -typedef struct CallControl { +struct CallControl { AudioError errors; ToxAV *av; - ToxWindow *window; + ToxWindow *prompt; Call calls[MAX_CALLS]; bool pending_call; @@ -65,13 +65,13 @@ typedef struct CallControl { } CallControl; -CallControl CallContrl; +struct CallControl CallControl; /* You will have to pass pointer to first member of 'windows' declared in windows.c */ ToxAV *init_audio(ToxWindow *self, Tox *tox); void terminate_audio(); int start_transmission(ToxWindow *self, Call *call); -int stop_transmission(Call *call, int friend_number); +int stop_transmission(Call *call, uint32_t friend_number); void stop_current_call(ToxWindow *self); #endif /* AUDIO_CALL_H */ diff --git a/src/chat.c b/src/chat.c index 8199f77..880f5bd 100644 --- a/src/chat.c +++ b/src/chat.c @@ -627,7 +627,7 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, ui void chat_onInvite (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) { - if (!self || self->is_call || self->num != friend_number) + if (!self || self->num != friend_number) return; /* call is flagged active here */ @@ -646,7 +646,7 @@ void chat_onInvite (ToxWindow *self, ToxAV *av, uint32_t friend_number, int stat void chat_onRinging (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) { - if (!self || !self->is_call || self->num != friend_number) + if (!self || self->num != friend_number) return; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it."); @@ -659,16 +659,16 @@ void chat_onRinging (ToxWindow *self, ToxAV *av, uint32_t friend_number, int sta void chat_onStarting (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) { - if (!self || !self->is_call || self->num != friend_number) + if (!self || self->num != friend_number) return; - /* call is flagged active here */ - self->is_call = true; - init_infobox(self); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it."); + /* call is flagged active here */ + self->is_call = true; + #ifdef SOUND_NOTIFY stop_sound(self->ringing_sound); #endif /* SOUND_NOTIFY */ @@ -676,13 +676,14 @@ void chat_onStarting (ToxWindow *self, ToxAV *av, uint32_t friend_number, int st void chat_onEnding (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) { - if (!self || !self->is_call || self->num != friend_number) + if (!self || self->num != friend_number) return; - self->is_call = false; kill_infobox(self); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!"); + self->is_call = false; + #ifdef SOUND_NOTIFY stop_sound(self->ringing_sound); #endif /* SOUND_NOTIFY */ @@ -690,7 +691,7 @@ void chat_onEnding (ToxWindow *self, ToxAV *av, uint32_t friend_number, int stat void chat_onError (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) { - if (!self || !self->is_call || self->num != friend_number) + if (!self || self->num != friend_number) return; self->is_call = false; @@ -703,7 +704,7 @@ void chat_onError (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state void chat_onStart (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) { - if (!self || !self->is_call || self->num != friend_number) + if (!self || self->num != friend_number) return; /* call is flagged active here */ @@ -720,7 +721,7 @@ void chat_onStart (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state void chat_onCancel (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) { - if (!self || !self->is_call || self->num != friend_number) + if (!self || self->num != friend_number) return; self->is_call = false; @@ -734,11 +735,11 @@ void chat_onCancel (ToxWindow *self, ToxAV *av, uint32_t friend_number, int stat void chat_onReject (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) { - if (!self || !self->is_call || self->num != friend_number) + if (!self || self->num != friend_number) return; - self->is_call = false; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Rejected!"); + self->is_call = false; #ifdef SOUND_NOTIFY stop_sound(self->ringing_sound); @@ -747,12 +748,12 @@ void chat_onReject (ToxWindow *self, ToxAV *av, uint32_t friend_number, int stat void chat_onEnd (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) { - if (!self || !self->is_call || self->num != friend_number) + if (!self || self->num != friend_number) return; - self->is_call = false; kill_infobox(self); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!"); + self->is_call = false; #ifdef SOUND_NOTIFY stop_sound(self->ringing_sound); @@ -761,7 +762,7 @@ void chat_onEnd (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) void chat_onRequestTimeout (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) { - if (!self || !self->is_call || self->num != friend_number) + if (!self || self->num != friend_number) return; self->is_call = false; @@ -774,7 +775,7 @@ void chat_onRequestTimeout (ToxWindow *self, ToxAV *av, uint32_t friend_number, void chat_onPeerTimeout (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state) { - if (!self || !self->is_call || self->num != friend_number) + if (!self || self->num != friend_number) return; self->is_call = false; diff --git a/src/friendlist.c b/src/friendlist.c index 11d0022..0cd557f 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -1111,6 +1111,7 @@ ToxWindow new_friendlist(void) ret.device_selection[0] = ret.device_selection[1] = -1; #endif /* AUDIO */ + ret.num = -1; ret.active_box = -1; Help *help = calloc(1, sizeof(Help)); diff --git a/src/prompt.c b/src/prompt.c index 5f95f36..d7d64c6 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -49,12 +49,13 @@ extern struct Winthread Winthread; extern FriendsList Friends; FriendRequests FrndRequests; - -#ifdef AUDIO +#ifdef VIDEO +#define AC_NUM_GLOB_COMMANDS 20 +#elif AUDIO #define AC_NUM_GLOB_COMMANDS 18 #else #define AC_NUM_GLOB_COMMANDS 16 -#endif /* AUDIO */ +#endif /* Array of global command names used for tab completion. */ static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = { @@ -500,6 +501,7 @@ ToxWindow new_prompt(void) ToxWindow ret; memset(&ret, 0, sizeof(ret)); + ret.num = -1; ret.active = true; ret.is_prompt = true; diff --git a/src/toxic.c b/src/toxic.c index a9731f5..c333266 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -65,6 +65,9 @@ #ifdef AUDIO #include "audio_call.h" +#ifdef VIDEO +#include "video_call.h" +#endif /* VIDEO */ ToxAV *av; #endif /* AUDIO */ @@ -83,7 +86,7 @@ ToxWindow *prompt = NULL; struct Winthread Winthread; struct cqueue_thread cqueue_thread; -struct audio_thread audio_thread; +struct av_thread av_thread; struct arg_opts arg_opts; struct user_settings *user_settings = NULL; @@ -835,7 +838,7 @@ void *thread_cqueue(void *data) } #ifdef AUDIO -void *thread_audio(void *data) +void *thread_av(void *data) { ToxAV *av = (ToxAV *) data; @@ -1141,9 +1144,14 @@ int main(int argc, char *argv[]) #ifdef AUDIO av = init_audio(prompt, m); + +#ifdef VIDEO + init_video(prompt, m, av); - /* audio thread */ - if (pthread_create(&audio_thread.tid, NULL, thread_audio, (void *) av) != 0) +#endif /* VIDEO */ + + /* AV thread */ + if (pthread_create(&av_thread.tid, NULL, thread_av, (void *) av) != 0) exit_toxic_err("failed in main", FATALERR_THREAD_CREATE); set_primary_device(input, user_settings->audio_in_dev); diff --git a/src/video_call.c b/src/video_call.c index 5280517..d5ead8f 100644 --- a/src/video_call.c +++ b/src/video_call.c @@ -7,7 +7,13 @@ #include "line_info.h" #include "notify.h" -#include "assert.h" +#include +#include +#include +#include +#include +#include +#include void receive_video_frame_cb( ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, @@ -17,34 +23,31 @@ void receive_video_frame_cb( ToxAV *av, uint32_t friend_number, void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, bool stable, uint32_t bit_rate, void *user_data); -void callback_recv_video_starting(void* av, uint32_t friend_number, void *arg); -void callback_video_starting ( void* av, uint32_t friend_number, void *arg ); -void callback_video_ending ( void* av, uint32_t friend_number, void *arg ); - static void print_err (ToxWindow *self, const char *error_str) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str); } -ToxAV *init_video(ToxWindow *self, Tox *tox, ToxAV *av, CallControl *user_data) +ToxAV *init_video(ToxWindow *self, Tox *tox, ToxAV *av) { - - user_data->video_enabled = true; - user_data->video_bit_rate = 5000; - user_data->video_frame_duration = 10; + CallControl.video_enabled = true; + CallControl.video_bit_rate = 5000; + CallControl.video_frame_duration = 10; if ( !av ) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video failed to init ToxAV"); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video failed to init with ToxAV instance"); + return NULL; } - if ( init_video_devices(user_data->av) == vde_InternalError ) { + if ( init_video_devices(av) == vde_InternalError ) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init video devices"); + return NULL; } - toxav_callback_video_receive_frame(user_data->av, receive_video_frame_cb, &user_data); - toxav_callback_video_bit_rate_status(user_data->av, video_bit_rate_status_cb, &user_data); + toxav_callback_video_receive_frame(av, receive_video_frame_cb, &CallControl); + toxav_callback_video_bit_rate_status(av, video_bit_rate_status_cb, &CallControl); return av; } @@ -53,25 +56,25 @@ void terminate_video() { int i; for (i = 0; i < MAX_CALLS; ++i) - stop_video_transmission(&CallContrl.calls[i], i); + stop_video_transmission(&CallControl.calls[i], i); terminate_video_devices(); } void read_video_device_callback(int16_t width, int16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, void* data) { + uint32_t friend_number = *((uint32_t*)data); /* TODO: Or pass an array of call_idx's */ TOXAV_ERR_SEND_FRAME error; - int32_t friend_number = *((int32_t*)data); /* TODO: Or pass an array of call_idx's */ - if ( toxav_video_send_frame(CallContrl.av, friend_number, width, height, y, u, v, &error ) == false ) { - line_info_add(CallContrl.window, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to send video frame"); - if ( error == TOXAV_ERR_SEND_FRAME_NULL ) { - line_info_add(CallContrl.window, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error NULL video frame"); - } else if ( error == TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND ) { - line_info_add(CallContrl.window, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error friend not found"); - } else if ( error = TOXAV_ERR_SEND_FRAME_INVALID ) { - line_info_add(CallContrl.window, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error invalid video frame"); - } + if ( toxav_video_send_frame(CallControl.av, friend_number, width, height, y, u, v, &error ) == false ) { + line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to send video frame"); + + if ( error == TOXAV_ERR_SEND_FRAME_NULL ) + line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error NULL video frame"); + else if ( error == TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND ) + line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error friend not found"); + else if ( error == TOXAV_ERR_SEND_FRAME_INVALID ) + line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error invalid video frame"); } } @@ -80,17 +83,19 @@ void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_ int32_t ystride, int32_t ustride, int32_t vstride, void *user_data) { - Call* this_call = &CallContrl.calls[friend_number]; - - if(write_video_out(width, height, y, u, v, ystride, ustride, vstride, user_data) == vde_DeviceNotActive) { - callback_recv_video_starting(CallContrl.av, friend_number, &CallContrl); - } + if (write_video_out(width, height, y, u, v, ystride, ustride, vstride, user_data) == vde_DeviceNotActive) + callback_recv_video_starting(CallControl.av, friend_number, &CallControl); } int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call) { if ( !self || !av) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Could not prepare transmission"); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare transmission"); + return -1; + } + + if (toxav_video_bit_rate_set(CallControl.av, self->num, CallControl.video_bit_rate, false, NULL)) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate"); return -1; } @@ -99,8 +104,7 @@ int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call) return -1; } - if ( register_video_device_callback(self->num, call->in_idx, - read_video_device_callback, &self->num) != vde_None) + if ( register_video_device_callback(self->num, call->in_idx, read_video_device_callback, &self->num) != vde_None) line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input video handler!"); return 0; @@ -108,13 +112,18 @@ int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call) int stop_video_transmission(Call *call, int friend_number) { + if (toxav_video_bit_rate_set(CallControl.av, friend_number, 0, true, NULL)) { + return -1; + } + if ( call->in_idx != -1 ) close_video_device(vdt_input, call->in_idx); + if ( call->out_idx != -1 ) close_video_device(vdt_output, call->out_idx); + return 0; } - /* * End of transmission */ @@ -132,72 +141,72 @@ void receive_video_frame_cb(ToxAV *av, uint32_t friend_number, int32_t ystride, int32_t ustride, int32_t vstride, void *user_data) { - CallControl* cc = (CallControl*)user_data; - write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data); } void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, bool stable, uint32_t bit_rate, void *user_data) { - CallControl* cc = (CallControl*)user_data; - if ( stable ) { - cc->video_bit_rate = bit_rate; - toxav_video_bit_rate_set(CallContrl.av, friend_number, CallContrl.video_bit_rate, false, NULL); + CallControl.video_bit_rate = bit_rate; + toxav_video_bit_rate_set(CallControl.av, friend_number, CallControl.video_bit_rate, false, NULL); } } void callback_recv_video_starting(void* av, uint32_t friend_number, void *arg) { - CallControl *cc = (CallControl*)arg; - ToxWindow* windows = cc->window; - Call* this_call = &cc->calls[friend_number]; + Call* this_call = &CallControl.calls[friend_number]; open_primary_video_device(vdt_output, &this_call->out_idx); - cc->video_call = true; + CallControl.video_call = true; } +void callback_recv_video_end(void* av, uint32_t friend_number, void *arg) +{ + Call* this_call = &CallControl.calls[friend_number]; + if(this_call->out_idx != -1) + close_video_device(vdt_output, this_call->out_idx); +} void callback_video_starting(void* av, uint32_t friend_number, void *arg) { - CallControl *cc = (CallControl*)arg; - ToxWindow* windows = cc->window; - Call* this_call = &cc->calls[friend_number]; + ToxWindow* windows = CallControl.prompt; + Call* this_call = &CallControl.calls[friend_number]; - int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) { - if (windows[i].is_call && windows[i].num == friend_number) { - cc->video_call = true; - if(0 != start_video_transmission(&windows[i], av, this_call)) { - line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!"); - cc->video_call = false; - return; + TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK; + toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error); + + if (error == TOXAV_ERR_CALL_CONTROL_OK) { + int i; + for (i = 0; i < MAX_WINDOWS_NUM; ++i) { + if (windows[i].is_call && windows[i].num == friend_number) { + if(0 != start_video_transmission(&windows[i], CallControl.av, this_call)) { + line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!"); + return; + } + + CallControl.video_call = true; + line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Video capture starting."); } - - line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Video capture starting."); } } } - -void callback_video_ending(void* av, uint32_t friend_number, void *arg) +void callback_video_end(void* av, uint32_t friend_number, void *arg) { - CallControl *cc = (CallControl*)arg; - ToxWindow* windows = cc->window; - Call* this_call = &cc->calls[friend_number]; + ToxWindow* windows = CallControl.prompt; - int i; - for (i = 0; i < MAX_WINDOWS_NUM; ++i) { - if (windows[i].is_call && windows[i].num == friend_number) { - line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Video operations ending."); + if ( CallControl.video_call ) { + toxav_video_bit_rate_set(CallControl.av, friend_number, 0, true, NULL); - } + int i; + for (i = 0; i < MAX_WINDOWS_NUM; ++i) + if (windows[i].is_call && windows[i].num == friend_number) + line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Video call ending."); + + for (i = 0; i < MAX_CALLS; ++i) + stop_video_transmission(&CallControl.calls[i], i); + + CallControl.video_call = false; } - - for (i = 0; i < MAX_CALLS; ++i) - stop_video_transmission(&CallContrl.calls[i], i); - - cc->video_call = false; - } /* * End of Callbacks @@ -217,7 +226,7 @@ void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M goto on_error; } - if ( !CallContrl.av ) { + if ( !CallControl.av ) { error_str = "ToxAV not supported!"; goto on_error; } @@ -232,17 +241,17 @@ void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M goto on_error; } - if ( CallContrl.video_call ) { + if ( CallControl.video_call ) { error_str = "Video is already sending in this call."; goto on_error; } - if ( toxav_video_bit_rate_set(CallContrl.av, self->num, CallContrl.video_bit_rate, false, NULL) == false ) { + if ( toxav_video_bit_rate_set(CallControl.av, self->num, CallControl.video_bit_rate, false, NULL) == false ) { error_str = "ToxAV video bit rate uninitialized."; goto on_error; } - callback_video_starting(CallContrl.av, self->num, &CallContrl); + callback_video_starting(CallControl.av, self->num, &CallControl); return; on_error: @@ -258,17 +267,17 @@ void cmd_end_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg goto on_error; } - if ( !CallContrl.av ) { + if ( !CallControl.av ) { error_str = "ToxAV not supported!"; goto on_error; } - if ( !CallContrl.video_call ) { + if ( !CallControl.video_call ) { error_str = "Video is not running in this call."; goto on_error; } - callback_video_ending(CallContrl.av, self->num, &CallContrl); + callback_video_end(CallControl.av, self->num, &CallControl); return; on_error: @@ -277,7 +286,6 @@ on_error: void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "List video devices"); const char *error_str; if ( argc != 1 ) { @@ -310,7 +318,6 @@ on_error: /* This changes primary video device only */ void cmd_change_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Change video device"); const char *error_str; if ( argc != 2 ) { @@ -344,7 +351,7 @@ void cmd_change_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, } if ( set_primary_video_device(type, selection) == vde_InvalidSelection ) { - error_str="Invalid selection!"; + error_str = "Invalid selection!"; goto on_error; } @@ -355,7 +362,6 @@ on_error: void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Change current video device"); const char *error_str; if ( argc != 2 ) { @@ -388,22 +394,21 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch goto on_error; } - if ( selection_valid(type, selection) == vde_InvalidSelection ) { + if ( video_selection_valid(type, selection) == vde_InvalidSelection ) { error_str="Invalid selection!"; goto on_error; } /* If call is active, change device */ if ( self->is_call ) { - Call* this_call = &CallContrl.calls[self->num]; - if (this_call->ttas) { + Call* this_call = &CallControl.calls[self->num]; + if ( this_call->ttas ) { - - if (type == output) { + if ( type == vdt_output ) { } else { /* TODO: check for failure */ - close_video_device(input, &this_call->in_idx); + close_video_device(input, this_call->in_idx); open_video_device(input, selection, &this_call->in_idx); register_video_device_callback(self->num, this_call->in_idx, read_video_device_callback, &self->num); } diff --git a/src/video_call.h b/src/video_call.h index 0c3fc98..4333227 100644 --- a/src/video_call.h +++ b/src/video_call.h @@ -37,9 +37,13 @@ typedef enum _VideoError { } VideoError; /* You will have to pass pointer to first member of 'windows' declared in windows.c */ -ToxAV *init_video(ToxWindow *self, Tox *tox, ToxAV *av, CallControl *user_data); +ToxAV *init_video(ToxWindow *self, Tox *tox, ToxAV *av); void terminate_video(); int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call); int stop_video_transmission(Call *call, int friend_number); +void callback_recv_video_starting(void* av, uint32_t friend_number, void *arg); +void callback_video_starting( void* av, uint32_t friend_number, void *arg ); +void callback_video_end( void* av, uint32_t friend_number, void *arg ); + #endif /* VIDEO_CALL_H */ \ No newline at end of file diff --git a/src/video_device.c b/src/video_device.c index 06798c7..15ed17b 100644 --- a/src/video_device.c +++ b/src/video_device.c @@ -23,6 +23,7 @@ #include "video_device.h" #include "video_call.h" +#include #include #include #include @@ -142,9 +143,9 @@ static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *input, uint16_t width, uint16_t height) { uint8_t *end = input + width * height * 2; - while(input != end) { + while (input != end) { uint8_t *line_end = input + width * 2; - while(input != line_end) { + while (input != line_end) { *plane_y++ = *input++; *plane_u++ = *input++; *plane_y++ = *input++; @@ -152,7 +153,7 @@ static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, } line_end = input + width * 2; - while(input != line_end) { + while (input != line_end) { *plane_y++ = *input++; input++;//u *plane_y++ = *input++; @@ -171,20 +172,20 @@ VideoDeviceError init_video_devices() size[vdt_input] = 0; #ifdef __linux__ - for(; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) { + for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) { int fd; char device_address[] = "/dev/videoXX"; snprintf(device_address + 10, sizeof(char) * strlen(device_address) - 10, "%i", size[vdt_input]); fd = open(device_address, O_RDWR | O_NONBLOCK, 0); - if (fd == -1) { + if ( fd == -1 ) { break; } else { struct v4l2_capability cap; char* video_input_name; /* Query V4L for capture capabilities */ - if(ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) { + if ( ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1 ) { video_input_name = cap.card; } else { video_input_name = device_address; @@ -202,11 +203,11 @@ VideoDeviceError init_video_devices() video_devices_names[vdt_output][0] = video_output_name; // Start poll thread - if (pthread_mutex_init(&video_mutex, NULL) != 0) + if ( pthread_mutex_init(&video_mutex, NULL) != 0 ) return vde_InternalError; pthread_t thread_id; - if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0) + if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0 ) return vde_InternalError; #ifdef VIDEO @@ -222,7 +223,7 @@ VideoDeviceError terminate_video_devices() video_thread_running = false; usleep(20000); - if (pthread_mutex_destroy(&video_mutex) != 0) + if ( pthread_mutex_destroy(&video_mutex) != 0 ) return (VideoDeviceError) vde_InternalError; return (VideoDeviceError) vde_None; @@ -231,7 +232,7 @@ VideoDeviceError terminate_video_devices() VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t device_idx, VideoDataHandleCallback callback, void* data) { - if (size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] || video_devices_running[vdt_input][device_idx]->fd == NULL) + if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] || !video_devices_running[vdt_input][device_idx]->fd ) return vde_InvalidSelection; lock; @@ -245,7 +246,7 @@ VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection) { - if (size[type] <= selection || selection < 0) return vde_InvalidSelection; + if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection; primary_video_device[type] = selection; @@ -264,19 +265,19 @@ void get_primary_video_device_name(VideoDeviceType type, char *buf, int size) VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t* device_idx) { - if (size[type] <= selection || selection < 0) return vde_InvalidSelection; + if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection; lock; uint32_t i; - for (i = 0; i < MAX_DEVICES && video_devices_running[type][i] != NULL; ++i); + for (i = 0; i < MAX_DEVICES && video_devices_running[type][i]; ++i); if (i == MAX_DEVICES) { unlock; return vde_AllDevicesBusy; } else *device_idx = i; for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */ if ( video_devices_running[type][i] && video_devices_running[type][i]->selection == selection ) { - + video_devices_running[type][*device_idx] = video_devices_running[type][i]; video_devices_running[type][i]->ref_count ++; @@ -288,16 +289,17 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint VideoDevice* device = video_devices_running[type][*device_idx] = calloc(1, sizeof(VideoDevice)); device->selection = selection; - if (pthread_mutex_init(device->mutex, NULL) != 0) { + if ( pthread_mutex_init(device->mutex, NULL) != 0 ) { free(device); unlock; return vde_InternalError; } - if (type == vdt_input) { + if ( type == vdt_input ) { video_thread_paused = true; #ifdef __linux__ + /* Open selected device */ char device_address[] = "/dev/videoXX"; snprintf(device_address + 10 , sizeof(device_address) - 10, "%i", selection); @@ -308,7 +310,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint /* Obtain video device capabilities */ struct v4l2_capability cap; - if (-1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap)) { + if ( -1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap) ) { return vde_FailedStart; } @@ -318,32 +320,30 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - if(-1 == xioctl(device->fd, VIDIOC_G_FMT, &fmt)) { + if( -1 == xioctl(device->fd, VIDIOC_G_FMT, &fmt) ) { return vde_FailedStart; } device->video_width = fmt.fmt.pix.width; device->video_height = fmt.fmt.pix.height; - - /* Request buffers */ struct v4l2_requestbuffers req; memset(&(req), 0, sizeof(req)); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; - if (-1 == xioctl(device->fd, VIDIOC_REQBUFS, &req)) { + if ( -1 == xioctl(device->fd, VIDIOC_REQBUFS, &req) ) { return vde_FailedStart; } - if(req.count < 2) { + if ( req.count < 2 ) { return vde_FailedStart; } device->buffers = calloc(req.count, sizeof(struct VideoBuffer)); - for(i = 0; i < req.count; ++i) { + for (i = 0; i < req.count; ++i) { struct v4l2_buffer buf; memset(&(buf), 0, sizeof(buf)); @@ -351,7 +351,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint buf.memory = V4L2_MEMORY_MMAP; buf.index = i; - if (-1 == xioctl(device->fd, VIDIOC_QUERYBUF, &buf)) { + if ( -1 == xioctl(device->fd, VIDIOC_QUERYBUF, &buf) ) { return vde_FailedStart; } @@ -362,7 +362,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint MAP_SHARED /* recommended */, device->fd, buf.m.offset); - if(MAP_FAILED == device->buffers[i].start) { + if ( MAP_FAILED == device->buffers[i].start ) { return vde_FailedStart; } } @@ -378,39 +378,40 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint buf.memory = V4L2_MEMORY_MMAP; buf.index = i; - if (-1 == xioctl(device->fd, VIDIOC_QBUF, &buf)) { + if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) { return vde_FailedStart; } } + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (-1 == xioctl(device->fd, VIDIOC_STREAMON, &type)) { + + /* Turn on video stream */ + if ( -1 == xioctl(device->fd, VIDIOC_STREAMON, &type) ) { return vde_FailedStart; } -#endif /* __linux__ */ +#else /* __OSX__ */ /*TODO: Add OSX implementation of opening video devices */ -#ifdef __OSX__ -#endif /*__OSX__*/ +#endif - /* Initialize X11 window associated to device */ - if ((device->x_display = XOpenDisplay(NULL)) == NULL) { + /* Create X11 window associated to device */ + if ( (device->x_display = XOpenDisplay(NULL)) == NULL ) { return vde_FailedStart; } int screen = DefaultScreen(device->x_display); - if ((device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), - 0, 0, device->video_width, device->video_height, 0, - BlackPixel(device->x_display, screen), - BlackPixel(device->x_display, screen))) == NULL) { + if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0, + device->video_width, device->video_height, 0, BlackPixel(device->x_display, screen), + BlackPixel(device->x_display, screen))) ) { return vde_FailedStart; } XStoreName(device->x_display, device->x_window, "Video Preview"); XSelectInput(device->x_display, device->x_window, ExposureMask|ButtonPressMask|KeyPressMask); - if ((device->x_gc = DefaultGC(device->x_display, screen)) == NULL) { + if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) { return vde_FailedStart; } @@ -422,36 +423,33 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint vpx_img_alloc(&device->input, VPX_IMG_FMT_I420, device->video_width, device->video_height, 1); video_thread_paused = false; - } else { - /* Initialize X11 window associated to device */ - if ((device->x_display = XOpenDisplay(NULL)) == NULL) { + } else { /* vdt_output */ + + /* Create X11 window associated to device */ + if ( (device->x_display = XOpenDisplay(NULL)) == NULL ) { return vde_FailedStart; } int screen = DefaultScreen(device->x_display); - if ((device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), - 0, 0, 100, 100, 0, - BlackPixel(device->x_display, screen), - BlackPixel(device->x_display, screen))) == NULL) { + if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0, + 100, 100, 0, BlackPixel(device->x_display, screen), BlackPixel(device->x_display, screen))) ) { return vde_FailedStart; } XStoreName(device->x_display, device->x_window, "Video Receive"); XSelectInput(device->x_display, device->x_window, ExposureMask|ButtonPressMask|KeyPressMask); - if ((device->x_gc = DefaultGC(device->x_display, screen)) == NULL) { + if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) { return vde_FailedStart; } - XMapWindow(device->x_display, device->x_window); XClearWindow(device->x_display, device->x_window); XMapRaised(device->x_display, device->x_window); XFlush(device->x_display); vpx_img_alloc(&device->input, VPX_IMG_FMT_I420, device->video_width, device->video_height, 1); - } unlock; @@ -465,41 +463,42 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height, { VideoDevice* device = video_devices_running[vdt_output][0]; - if (!device) return vde_DeviceNotActive; + if ( !device ) return vde_DeviceNotActive; pthread_mutex_lock(device->mutex); int screen = DefaultScreen(device->x_display); - /* Recreate missing window */ - if(!device->x_window) { - device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), - 0, 0, device->video_width, device->video_height, 0, - BlackPixel(device->x_display, screen), - BlackPixel(device->x_display, screen)); + /* Recreate missing X11 window */ + if ( !device->x_window ) { + device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0, + device->video_width, device->video_height, 0, BlackPixel(device->x_display, screen), + BlackPixel(device->x_display, screen)); XMapWindow(device->x_display, device->x_window); XClearWindow(device->x_display, device->x_window); XMapRaised(device->x_display, device->x_window); + XFlush(device->x_display); } /* Resize X11 window to correct size */ - if(device->video_width != width || device->video_height != height) { + if ( device->video_width != width || device->video_height != height ) { device->video_width = width; device->video_height = height; XResizeWindow(device->x_display, device->x_window, width, height); + vpx_img_free(&device->input); vpx_img_alloc(&device->input, VPX_IMG_FMT_I420, width, height, 1); } - /* Display video image */ + /* Convert YUV420 data to BGR */ ystride = abs(ystride); ustride = abs(ustride); vstride = abs(vstride); - uint8_t *img_data = malloc(width * height * 4); yuv420tobgr(width, height, y, u, v, ystride, ustride, vstride, img_data); + /* Allocate image data in X11 */ XImage image = { .width = width, .height = height, @@ -516,6 +515,7 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height, .data = (char*)img_data }; + /* Render image data */ Pixmap pixmap = XCreatePixmap(device->x_display, device->x_window, width, height, 24); XPutImage(device->x_display, pixmap, device->x_gc, &image, 0, 0, 0, 0, width, height); XCopyArea(device->x_display, pixmap, device->x_window, device->x_gc, 0, 0, width, height, 0, 0); @@ -535,17 +535,22 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so (void)arg; uint32_t i; - while (video_thread_running) { - if (video_thread_paused) usleep(10000); /* Wait for unpause. */ + if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */ else { for (i = 0; i < size[vdt_input]; ++i) { lock; - if (video_devices_running[vdt_input][i] != NULL) + if ( video_devices_running[vdt_input][i] != NULL ) { + /* Obtain frame image data from device buffers */ + void *data; + uint16_t video_width; + uint16_t video_height; + uint8_t *y, *u, *v; +#ifdef __linux__ VideoDevice* device = video_devices_running[vdt_input][i]; struct v4l2_buffer buf; memset(&(buf), 0, sizeof(buf)); @@ -553,30 +558,33 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; - if (-1 == ioctl(device->fd, VIDIOC_DQBUF, &buf)) { + if ( -1 == ioctl(device->fd, VIDIOC_DQBUF, &buf) ) { unlock; continue; } - void *data = (void*)device->buffers[buf.index].start; - uint16_t video_width = device->video_width; - uint16_t video_height = device->video_height; - uint8_t *y = device->input.planes[0]; - uint8_t *u = device->input.planes[1]; - uint8_t *v = device->input.planes[2]; - int screen = DefaultScreen(device->x_display); + data = (void*)device->buffers[buf.index].start; + video_width = device->video_width; + video_height = device->video_height; + y = device->input.planes[0]; + u = device->input.planes[1]; + v = device->input.planes[2]; +#else /* __OSX__*/ +#endif - /* Convert to YUV420 for ToxAV */ + /* Convert frame image data to YUV420 for ToxAV */ yuv422to420(y, u, v, data, video_width, video_height); - /* Send data to friend through ToxAV */ + /* Send frame data to friend through ToxAV */ if ( device->cb ) device->cb(video_width, video_height, y, u, v, device->cb_data); - /* Display image for video preview */ + /* Convert YUV420 data to BGR */ uint8_t *img_data = malloc(video_width * video_height * 4); yuv420tobgr(video_width, video_height, y, u, v, video_width, video_width/2, video_width/2, img_data); + + /* Allocate image data in X11 */ XImage image = { .width = video_width, .height = video_height, @@ -593,6 +601,7 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so .data = (char*)img_data }; + /* Render image data */ Pixmap pixmap = XCreatePixmap(device->x_display, device->x_window, video_width, video_height, 24); XPutImage(device->x_display, pixmap, device->x_gc, &image, 0, 0, 0, 0, video_width, video_height); XCopyArea(device->x_display, pixmap, device->x_window, device->x_gc, 0, 0, video_width, video_height, 0, 0); @@ -600,12 +609,11 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so XFlush(device->x_display); free(img_data); - - if (-1 == xioctl(device->fd, VIDIOC_QBUF, &buf)) { + if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) { unlock; continue; } - } + } unlock; } usleep(1000 * 1000 / 24); @@ -617,13 +625,13 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx) { - if (device_idx >= MAX_DEVICES) return vde_InvalidSelection; + if ( device_idx >= MAX_DEVICES ) return vde_InvalidSelection; lock; VideoDevice *device = video_devices_running[type][device_idx]; VideoDeviceError rc = vde_None; - if (!device) { + if ( !device ) { unlock; return vde_DeviceNotActive; } @@ -632,17 +640,18 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx) if ( !device->ref_count ) { - if (type == vdt_input) { + if ( type == vdt_input ) { + enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if(-1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type)) {} + if( -1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type) ) {} int i; - for(i = 0; i < device->n_buffers; ++i) { - if (-1 == munmap(device->buffers[i].start, device->buffers[i].length)) { + for (i = 0; i < device->n_buffers; ++i) { + if ( -1 == munmap(device->buffers[i].start, device->buffers[i].length) ) { } } close(device->fd); - //vpx_img_free(&device->input); + vpx_img_free(&device->input); XDestroyWindow(device->x_display, device->x_window); XFlush(device->x_display); XCloseDisplay(device->x_display); @@ -673,4 +682,9 @@ void print_video_devices(ToxWindow* self, VideoDeviceType type) line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, video_devices_names[type][i]); return; +} + +VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection) +{ + return (size[type] <= selection || selection < 0) ? vde_InvalidSelection : vde_None; } \ No newline at end of file diff --git a/src/windows.h b/src/windows.h index fc0172c..c27b433 100644 --- a/src/windows.h +++ b/src/windows.h @@ -76,7 +76,7 @@ struct cqueue_thread { pthread_t tid; }; -struct audio_thread { +struct av_thread { pthread_t tid; };