diff --git a/build/Makefile.am b/build/Makefile.am index 4bc008d..b821b36 100644 --- a/build/Makefile.am +++ b/build/Makefile.am @@ -56,7 +56,9 @@ toxic_LDADD = $(LIBTOXCORE_LDFLAGS) \ if BUILD_AV toxic_SOURCES += $(top_srcdir)/src/audio_call.c \ - $(top_srcdir)/src/audio_call.h + $(top_srcdir)/src/audio_call.h \ + $(top_srcdir)/src/device.c \ + $(top_srcdir)/src/device.h toxic_CFLAGS += $(LIBTOXAV_CFLAGS) \ $(OPENAL_CFLAGS) diff --git a/src/audio_call.c b/src/audio_call.c index 992255b..fd23838 100644 --- a/src/audio_call.c +++ b/src/audio_call.c @@ -8,6 +8,7 @@ #include "toxic_windows.h" #include "audio_call.h" +#include "device.h" #include "chat_commands.h" #include "global_commands.h" #include "toxic_windows.h" @@ -24,12 +25,9 @@ #define _cbend pthread_exit(NULL) -#define AUDIO_FRAME_SIZE (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000) - #define MAX_CALLS 10 -#define _True 1 -#define _False 0 +#define frame_size (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000) typedef struct _DeviceIx { @@ -44,11 +42,27 @@ typedef struct _DeviceIx { typedef struct _Call { pthread_t ttid; /* Transmission thread id */ _Bool ttas; /* Transmission thread active status (0 - stopped, 1- running) */ + int in_idx, out_idx; + pthread_mutex_t mutex; } Call; -struct _ASettings { - DeviceIx device[2]; +void set_call(Call* call, _Bool start) +{ + call->in_idx = -1; + call->out_idx = -1; + + if ( start ) { + call->ttas = _True; + pthread_mutex_init(&call->mutex, NULL); + } + else { + call->ttid = 0; + pthread_mutex_destroy(&call->mutex); + } +} + +struct _ASettings { AudioError errors; ToxAv *av; @@ -58,17 +72,17 @@ struct _ASettings { Call calls[MAX_CALLS]; } ASettins; -void callback_recv_invite ( int32_t call_index, void *arg ); -void callback_recv_ringing ( int32_t call_index, void *arg ); +void callback_recv_invite ( int32_t call_index, void *arg ); +void callback_recv_ringing ( int32_t call_index, void *arg ); void callback_recv_starting ( int32_t call_index, void *arg ); -void callback_recv_ending ( int32_t call_index, void *arg ); -void callback_recv_error ( int32_t call_index, void *arg ); -void callback_call_started ( int32_t call_index, void *arg ); +void callback_recv_ending ( int32_t call_index, void *arg ); +void callback_recv_error ( int32_t call_index, void *arg ); +void callback_call_started ( int32_t call_index, void *arg ); void callback_call_canceled ( int32_t call_index, void *arg ); void callback_call_rejected ( int32_t call_index, void *arg ); -void callback_call_ended ( int32_t call_index, void *arg ); -void callback_requ_timeout ( int32_t call_index, void *arg ); -void callback_peer_timeout ( int32_t call_index, void *arg ); +void callback_call_ended ( int32_t call_index, void *arg ); +void callback_requ_timeout ( int32_t call_index, void *arg ); +void callback_peer_timeout ( int32_t call_index, void *arg ); static void print_err (ToxWindow *self, uint8_t *error_str) @@ -76,228 +90,45 @@ static void print_err (ToxWindow *self, uint8_t *error_str) line_info_add(self, NULL, NULL, NULL, error_str, SYS_MSG, 0, 0); } -/* Opens device under current index - */ -int device_open (ToxWindow *self, _Devices type) -{ - WINDOW *window = self->chatwin->history; - - /* Do not error if no device */ - if ( !ASettins.device[type].size ) return 0; - - ALCdevice *prev_device = ASettins.device[type].dhndl; - - uint8_t msg[MAX_STR_SIZE]; - uint8_t *error = NULL; - - if ( type == input ) { - ASettins.device[type].dhndl = alcCaptureOpenDevice( - ASettins.device[type].devices[ASettins.device[type].index], - av_DefaultSettings.audio_sample_rate, - AL_FORMAT_MONO16, - AUDIO_FRAME_SIZE * 4); - - if (alcGetError(ASettins.device[type].dhndl) != AL_NO_ERROR) { - - /* Now check if we have previous device and act acording to it */ - if ( !prev_device ) { - error = "Error starting input device!"; - - ASettins.errors |= ErrorStartingCaptureDevice; - } else { - error = "Could not start input device, falling back to previous"; - - /* NOTE: What if device is opened? */ - ASettins.device[type].dhndl = prev_device; - } - } else { - /* Close previous */ - if ( prev_device ) - alcCaptureCloseDevice(prev_device); - - if ( window ) { - snprintf(msg, sizeof(msg), "Input device: %s", ASettins.device[type].devices[ASettins.device[type].index]); - line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); - } - } - - ASettins.device[type].ctx = NULL; - } else { - ASettins.device[type].dhndl = alcOpenDevice(ASettins.device[type].devices[ASettins.device[type].index]); - - if (alcGetError(ASettins.device[type].dhndl) != AL_NO_ERROR) { - - /* Now check if we have previous device and act acording to it */ - if ( !prev_device ) { - error = "Error starting output device!"; - - ASettins.errors |= ErrorStartingOutputDevice; - ASettins.device[type].ctx = NULL; - } else { - error = "Could not start output device, falling back to previous"; - - /* NOTE: What if device is opened? */ - ASettins.device[type].dhndl = prev_device; - } - } else { - - /* Close previous */ - if ( prev_device ) { - alcCaptureCloseDevice(prev_device); - alcMakeContextCurrent(NULL); - alcDestroyContext(ASettins.device[type].ctx); - } - - ASettins.device[type].ctx = alcCreateContext(ASettins.device[type].dhndl, NULL); - - if ( window ) { - snprintf(msg, sizeof(msg), "Output device: %s", ASettins.device[type].devices[ASettins.device[type].index]); - line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); - } - } - } - - if ( error ) { - if ( window ) { - snprintf(msg, sizeof(msg), "Error: %s", error); - line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); - } - - return -1; - } else return 0; -} - -int device_close (ToxWindow *self, _Devices type) -{ - /* Only close if device opened */ - if ( ASettins.device[type].dhndl ) { - uint8_t *device = NULL; - - if (type == input) { - alcCaptureCloseDevice(ASettins.device[type].dhndl); - device = "input"; - } else { - alcCloseDevice(ASettins.device[type].dhndl); - alcMakeContextCurrent(NULL); - - if ( ASettins.device[type].ctx ) - alcDestroyContext(ASettins.device[type].ctx); - - device = "output"; - } - - ASettins.device[type].index = ASettins.device[type].dix; - - if ( device == NULL ) { - return -1; - } - - if ( self ) { - uint8_t msg[MAX_STR_SIZE]; - snprintf(msg, sizeof(msg), "Closed %s device", device); - line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); - } - } - - return 0; -} - - -int device_set(ToxWindow *self, _Devices type, long int selection) -{ - uint8_t str[MAX_STR_SIZE]; - uint8_t *s_type = type == input ? "input" : "output"; - - if ( selection < 0 || selection >= ASettins.device[type].size ) { - snprintf(str, sizeof(str), "Cannot set audio %s device: Invalid index: %d", s_type); - line_info_add(self, NULL, NULL, NULL, str, SYS_MSG, 0, 0); - return -1; - } - - ASettins.device[type].index = selection; - - if ( device_open(self, type) != 0 ) { - snprintf(str, sizeof(str), "Cannot open audio %s device index: %d", s_type); - line_info_add(self, NULL, NULL, NULL, str, SYS_MSG, 0, 0); - return -1; - } - - return 0; -} - - ToxAv *init_audio(ToxWindow *self, Tox *tox) { ASettins.cs = av_DefaultSettings; ASettins.cs.video_height = ASettins.cs.video_width = 0; - ASettins.errors = NoError; + ASettins.errors = ae_None; memset(ASettins.calls, 0, sizeof(Call) * 10); - /* Capture devices */ - const char *stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); - ASettins.device[input].size = 0; + + /* Streaming stuff from core */ - if ( stringed_device_list ) { - const char *default_device = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); + ASettins.av = toxav_new(tox, MAX_CALLS); - for ( ; *stringed_device_list; ++ASettins.device[input].size ) { - ASettins.device[input].devices[ASettins.device[input].size] = stringed_device_list; - - if ( strcmp( default_device , ASettins.device[input].devices[ASettins.device[input].size] ) == 0 ) - ASettins.device[input].index = ASettins.device[input].dix = ASettins.device[input].size; - - stringed_device_list += strlen( stringed_device_list ) + 1; - } + if ( !ASettins.av ) { + ASettins.errors |= ae_StartingCoreAudio; + return NULL; + } + + if ( init_devices(ASettins.av) == de_InternalError ) { + line_info_add(self, NULL, NULL, NULL, "Failed to init devices", SYS_MSG, 0, 0); + toxav_kill(ASettins.av); + return ASettins.av = NULL; } + toxav_register_callstate_callback(callback_call_started, av_OnStart, self); + toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, self); + toxav_register_callstate_callback(callback_call_rejected, av_OnReject, self); + toxav_register_callstate_callback(callback_call_ended, av_OnEnd, self); + toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, self); - /* Output devices */ - stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER); - ASettins.device[output].size = 0; + toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, self); + toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, self); + toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, self); - if ( stringed_device_list ) { - const char *default_device = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); - - for ( ; *stringed_device_list; ++ASettins.device[output].size ) { - ASettins.device[output].devices[ASettins.device[output].size] = stringed_device_list; - - if ( strcmp( default_device , ASettins.device[output].devices[ASettins.device[output].size] ) == 0 ) - ASettins.device[output].index = ASettins.device[output].dix = ASettins.device[output].size; - - stringed_device_list += strlen( stringed_device_list ) + 1; - } - } - - if (!ASettins.device[input].size && !ASettins.device[output].size) { - uint8_t *msg = "No devices: disabling audio!"; - line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); - ASettins.av = NULL; - } else { - /* Streaming stuff from core */ - - ASettins.av = toxav_new(tox, MAX_CALLS); - - if ( !ASettins.av ) { - ASettins.errors |= ErrorStartingCoreAudio; - return NULL; - } - - toxav_register_callstate_callback(callback_call_started, av_OnStart, self); - toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, self); - toxav_register_callstate_callback(callback_call_rejected, av_OnReject, self); - toxav_register_callstate_callback(callback_call_ended, av_OnEnd, self); - toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, self); - - toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, self); - toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, self); - toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, self); - - toxav_register_callstate_callback(callback_recv_error, av_OnError, self); - toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, self); - toxav_register_callstate_callback(callback_peer_timeout, av_OnPeerTimeout, self); - } + toxav_register_callstate_callback(callback_recv_error, av_OnError, self); + toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, self); + toxav_register_callstate_callback(callback_peer_timeout, av_OnPeerTimeout, self); + return ASettins.av; } @@ -311,159 +142,112 @@ void terminate_audio() if ( ASettins.av ) toxav_kill(ASettins.av); - device_close(NULL, input); - device_close(NULL, output); + terminate_devices(); } -int errors() +void read_device_callback (const int16_t* captured, uint32_t size, void* data) { - return ASettins.errors; + int32_t call_index = *((int32_t*)data); /* TODO: Or pass an array of call_idx's */ + + uint8_t encoded_payload[RTP_PAYLOAD_SIZE]; + int32_t payload_size = toxav_prepare_audio_frame(ASettins.av, call_index, encoded_payload, RTP_PAYLOAD_SIZE, captured, size); + if ( payload_size <= 0 || toxav_send_audio(ASettins.av, call_index, encoded_payload, payload_size) < 0 ) { + /*fprintf(stderr, "Could not encode audio packet\n");*/ + } } - - /* * Transmission */ void *transmission(void *arg) -{ +{ +#define lock pthread_mutex_lock(&this_call->mutex) +#define unlock pthread_mutex_unlock(&this_call->mutex) + ToxWindow* self = arg; - int32_t call_index = self->call_index; + int32_t call_index = self->call_idx; /* Missing audio support */ if ( !ASettins.av ) _cbend; Call* this_call = &ASettins.calls[call_index]; - - this_call->ttas = _True; - /* Prepare devices */ - alcCaptureStart(ASettins.device[input].dhndl); - alcMakeContextCurrent(ASettins.device[output].ctx); - int32_t dec_frame_len; - int16_t frame[4096]; - int32_t sample = 0; - uint32_t buffer; - int32_t ready; - int32_t openal_buffers = 5; - uint32_t source, *buffers; - uint8_t encoded_payload[RTP_PAYLOAD_SIZE]; - const int32_t frame_size = AUDIO_FRAME_SIZE; - - /* Prepare buffers */ - buffers = calloc(sizeof(uint32_t), openal_buffers); - alGenBuffers(openal_buffers, buffers); - alGenSources((uint32_t)1, &source); - alSourcei(source, AL_LOOPING, AL_FALSE); - - uint16_t zeros[frame_size]; - memset(zeros, 0, frame_size); int16_t PCM[frame_size]; - - int32_t i = 0; - - for (; i < openal_buffers; ++i) { - alBufferData(buffers[i], AL_FORMAT_MONO16, zeros, frame_size, 48000); - } - - alSourceQueueBuffers(source, openal_buffers, buffers); - alSourcePlay(source); - if (alGetError() != AL_NO_ERROR) { - /* Print something? */ - /*fprintf(stderr, "Error starting audio\n");*/ + + if ( open_primary_device(input, &this_call->in_idx) != de_None ) goto cleanup; + if ( register_device_callback(this_call->in_idx, read_device_callback, &call_index, _True) != de_None) + /* Set VAD as true for all; TODO: Make it more dynamic */ + goto cleanup; + + if ( open_primary_device(output, &this_call->out_idx) != de_None ) goto cleanup; -// goto cleanup; - } - /* Start transmission */ while (this_call->ttas) { - - alcGetIntegerv(ASettins.device[input].dhndl, ALC_CAPTURE_SAMPLES, (int32_t) sizeof(int32_t), &sample); - - /* RECORD AND SEND */ - if (sample >= frame_size) { - alcCaptureSamples(ASettins.device[input].dhndl, frame, frame_size); - - int32_t payload_size = toxav_prepare_audio_frame(ASettins.av, call_index, encoded_payload, RTP_PAYLOAD_SIZE, frame, frame_size); - if ( payload_size <= 0 || toxav_send_audio(ASettins.av, call_index, encoded_payload, payload_size) < 0 ) { - /*fprintf(stderr, "Could not encode audio packet\n");*/ - } + + lock; + + if (playback_device_ready(this_call->out_idx) == de_Busy) { + unlock; + continue; } - - /* PLAYBACK */ - - alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready); - - if (ready <= 0) continue; - + dec_frame_len = toxav_recv_audio(ASettins.av, call_index, frame_size, PCM); /* Play the packet */ if (dec_frame_len > 0) { - alSourceUnqueueBuffers(source, 1, &buffer); - alBufferData(buffer, AL_FORMAT_MONO16, PCM, dec_frame_len * 2 * 1, 48000); - int32_t error = alGetError(); - - if (error != AL_NO_ERROR) { - fprintf(stderr, "Error setting buffer %d\n", error); - break; - } - - alSourceQueueBuffers(source, 1, &buffer); - - if (alGetError() != AL_NO_ERROR) { - fprintf(stderr, "Error: could not buffer audio\n"); - break; - } - - alGetSourcei(source, AL_SOURCE_STATE, &ready); - - if (ready != AL_PLAYING) alSourcePlay(source); + write_out(this_call->out_idx, PCM, dec_frame_len, av_DefaultSettings.audio_channels); } - else { - /* Error ignored */ + else if (dec_frame_len != 0) { + /* >implying it'll ever get an error */ } - + + unlock; + usleep(1000); } cleanup: - - alDeleteSources(1, &source); - alDeleteBuffers(openal_buffers, buffers); - /* - device_close(NULL, input); - device_close(NULL, output);*/ - + if ( this_call->in_idx != -1 ) if ( close_device(input, this_call->in_idx) != de_None ) + line_info_add(self, NULL, NULL, NULL, "Failed to close input device!", SYS_MSG, 0, 0); + + if ( this_call->out_idx != -1 ) if ( close_device(output, this_call->out_idx) != de_None ) + line_info_add(self, NULL, NULL, NULL, "Failed to close output device!", SYS_MSG, 0, 0); + + set_call(this_call, _False); + _cbend; } int start_transmission(ToxWindow *self) { - if ( !ASettins.av || self->call_index == -1 ) return -1; + if ( !ASettins.av || self->call_idx == -1 ) return -1; /* Don't provide support for video */ - if ( 0 != toxav_prepare_transmission(ASettins.av, self->call_index, &ASettins.cs, 0) ) { + if ( 0 != toxav_prepare_transmission(ASettins.av, self->call_idx, &ASettins.cs, 0) ) { line_info_add(self, NULL, NULL, NULL, "Could not prepare transmission", SYS_MSG, 0, 0); } - if ( !toxav_capability_supported(ASettins.av, self->call_index, AudioDecoding) || - !toxav_capability_supported(ASettins.av, self->call_index, AudioEncoding) ) + if ( !toxav_capability_supported(ASettins.av, self->call_idx, AudioDecoding) || + !toxav_capability_supported(ASettins.av, self->call_idx, AudioEncoding) ) return -1; - if ( 0 != pthread_create(&ASettins.calls[self->call_index].ttid, NULL, transmission, self ) && - 0 != pthread_detach(ASettins.calls[self->call_index].ttid) ) { + set_call(&ASettins.calls[self->call_idx], _True); + + if ( 0 != pthread_create(&ASettins.calls[self->call_idx].ttid, NULL, transmission, self ) && + 0 != pthread_detach(ASettins.calls[self->call_idx].ttid) ) { return -1; - } + } } int stop_transmission(int call_index) { - toxav_kill_transmission(ASettins.av, call_index); - ASettins.calls[call_index].ttas = _False; + if ( ASettins.calls[call_index].ttas ) { + toxav_kill_transmission(ASettins.av, call_index); + ASettins.calls[call_index].ttas = _False; + } } /* * End of transmission @@ -493,7 +277,7 @@ void callback_recv_starting ( int32_t call_index, void* arg ) ToxWindow* windows = arg; int i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onStarting != NULL && windows[i].call_index == call_index) { + if (windows[i].onStarting != NULL && windows[i].call_idx == call_index) { windows[i].onStarting(&windows[i], ASettins.av, call_index); if ( 0 != start_transmission(&windows[i]) ) {/* YEAH! */ line_info_add(&windows[i], NULL, NULL, NULL, "Error starting transmission!", SYS_MSG, 0, 0); @@ -516,7 +300,7 @@ void callback_call_started ( int32_t call_index, void* arg ) ToxWindow* windows = arg; int i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) - if (windows[i].onStart != NULL && windows[i].call_index == call_index) { + if (windows[i].onStart != NULL && windows[i].call_idx == call_index) { windows[i].onStart(&windows[i], ASettins.av, call_index); if ( 0 != start_transmission(&windows[i]) ) {/* YEAH! */ line_info_add(&windows[i], NULL, NULL, NULL, "Error starting transmission!", SYS_MSG, 0, 0); @@ -577,7 +361,7 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA goto on_error; } - ToxAvError error = toxav_call(ASettins.av, &self->call_index, self->num, TypeAudio, 30); + ToxAvError error = toxav_call(ASettins.av, &self->call_idx, self->num, TypeAudio, 30); if ( error != ErrorNone ) { if ( error == ErrorAlreadyInCall ) error_str = "Already in a call!"; @@ -586,7 +370,7 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA goto on_error; } - snprintf(msg, sizeof(msg), "Calling... idx: %d", self->call_index); + snprintf(msg, sizeof(msg), "Calling... idx: %d", self->call_idx); line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); return; @@ -609,7 +393,7 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ goto on_error; } - ToxAvError error = toxav_answer(ASettins.av, self->call_index, TypeAudio); + ToxAvError error = toxav_answer(ASettins.av, self->call_idx, TypeAudio); if ( error != ErrorNone ) { if ( error == ErrorInvalidState ) error_str = "Cannot answer in invalid state!"; @@ -640,7 +424,7 @@ void cmd_reject(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ goto on_error; } - ToxAvError error = toxav_reject(ASettins.av, self->call_index, "Why not?"); + ToxAvError error = toxav_reject(ASettins.av, self->call_idx, "Why not?"); if ( error != ErrorNone ) { if ( error == ErrorInvalidState ) error_str = "Cannot reject in invalid state!"; @@ -671,7 +455,7 @@ void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ goto on_error; } - ToxAvError error = toxav_hangup(ASettins.av, self->call_index); + ToxAvError error = toxav_hangup(ASettins.av, self->call_idx); if ( error != ErrorNone ) { if ( error == ErrorInvalidState ) error_str = "Cannot hangup in invalid state!"; @@ -700,7 +484,7 @@ void cmd_cancel(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[ goto on_error; } - ToxAvError error = toxav_cancel(ASettins.av, self->call_index, self->num, + ToxAvError error = toxav_cancel(ASettins.av, self->call_idx, self->num, "Only those who appreciate small things know the beauty that is life"); if ( error != ErrorNone ) { @@ -730,7 +514,7 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (* goto on_error; } - _Devices type; + DeviceType type; if ( strcmp(argv[1], "in") == 0 ) /* Input devices */ type = input; @@ -744,18 +528,14 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (* return; } - int i = 0; - - for ( ; i < ASettins.device[type].size; i ++) { - snprintf(msg, sizeof(msg), "%d: %s", i, ASettins.device[type].devices[i]); - line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); - } + print_devices(self, type); return; on_error: print_err (self, error_str); } +/* This changes primary device only */ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { uint8_t msg[MAX_STR_SIZE]; @@ -769,12 +549,7 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char ( goto on_error; } - if ( ASettins.calls[self->call_index].ttas ) { /* Transmission is active */ - error_str = "Cannot change device while active transmission"; - goto on_error; - } - - _Devices type; + DeviceType type; if ( strcmp(argv[1], "in") == 0 ) /* Input devices */ type = input; @@ -797,22 +572,80 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char ( goto on_error; } - if ( device_close(self, type) != 0 ) { - error_str = "Could not close device!"; + if ( set_primary_device(type, selection) == de_InvalidSelection ) { + error_str="Invalid selection!"; goto on_error; } - if ( device_set(self, type, selection ) == 0) { - /*snprintf(msg, sizeof(msg), "Selected: %s", ASettins.device[type].devices[selection]); - line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);*/ - } - - if ( device_open(self, type) == 0 ) { - snprintf(msg, sizeof(msg), "Now using: %s", ASettins.device[type].devices[selection]); - line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); - } - return; on_error: print_err (self, error_str); } + +void cmd_set_this_session_device(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) +{ + uint8_t msg[MAX_STR_SIZE]; + uint8_t *error_str; + + if ( argc != 2 ) { + if ( argc < 1 ) error_str = "Type must be specified!"; + else if ( argc < 2 ) error_str = "Must have id!"; + else error_str = "Only two arguments allowed!"; + + goto on_error; + } + + DeviceType type; + + if ( strcmp(argv[1], "in") == 0 ) /* Input devices */ + type = input; + + else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */ + type = output; + + else { + snprintf(msg, sizeof(msg), "Invalid type: %s", argv[1]); + line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); + return; + } + + + char *end; + long int selection = strtol(argv[2], &end, 10); + + if ( *end ) { + error_str = "Invalid input"; + goto on_error; + } + + if ( selection_valid(type, selection) == de_InvalidSelection ) { + error_str="Invalid selection!"; + goto on_error; + } + + /* If call is active, change device */ + if ( self->call_idx > -1) { + Call* this_call = &ASettins.calls[self->call_idx]; + if (this_call->ttas) { + if (type == output) { + pthread_mutex_lock(&this_call->mutex); + close_device(output, this_call->out_idx); + open_device(output, selection, &this_call->out_idx); + 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); + /* Set VAD as true for all; TODO: Make it more dynamic */ + register_device_callback(this_call->in_idx, read_device_callback, &self->call_idx, _True); + } + } + } + + self->device_selection[type] = selection; + + return; +on_error: + print_err (self, error_str); +} \ No newline at end of file diff --git a/src/audio_call.h b/src/audio_call.h index 264e94b..6b78e38 100644 --- a/src/audio_call.h +++ b/src/audio_call.h @@ -7,19 +7,15 @@ #include -#define MAX_DEVICES 32 +#include "device.h" typedef enum _AudioError { - NoError = 0, - ErrorStartingCaptureDevice = 1 << 0, - ErrorStartingOutputDevice = 1 << 1, - ErrorStartingCoreAudio = 1 << 2 + ae_None = 0, + ae_StartingCaptureDevice = 1 << 0, + ae_StartingOutputDevice = 1 << 1, + ae_StartingCoreAudio = 1 << 2 } AudioError; -typedef enum _Devices { - input, - output, -} _Devices; /* You will have to pass pointer to first member of 'windows' * declared in windows.c otherwise undefined behaviour will @@ -27,9 +23,11 @@ typedef enum _Devices { ToxAv *init_audio(ToxWindow *self, Tox *tox); void terminate_audio(); -int errors(); +int clear_call_settings_per_se(ToxWindow *self); int start_transmission(ToxWindow *self); -int device_set(ToxWindow *self, _Devices type, long int selection); +int stop_transmission(int call_index); +int device_set(ToxWindow* self, DeviceType type, long int selection); + #endif /* _audio_h */ diff --git a/src/chat.c b/src/chat.c index b4f877e..5b5693a 100644 --- a/src/chat.c +++ b/src/chat.c @@ -51,7 +51,7 @@ extern struct _Winthread Winthread; extern struct user_settings *user_settings; #ifdef _SUPPORT_AUDIO -#define AC_NUM_CHAT_COMMANDS 23 +#define AC_NUM_CHAT_COMMANDS 24 #else #define AC_NUM_CHAT_COMMANDS 18 #endif /* _SUPPORT_AUDIO */ @@ -84,6 +84,7 @@ static const uint8_t chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = { { "/answer" }, { "/reject" }, { "/hangup" }, + { "/sdev" }, #endif /* _SUPPORT_AUDIO */ }; @@ -382,7 +383,7 @@ void chat_onInvite (ToxWindow *self, ToxAv *av, int call_index) /* call_index is set here and reset on call end */ - self->call_index = call_index; + self->call_idx = call_index; line_info_add(self, NULL, NULL, NULL, "Incoming audio call!\nType: \"/answer\" or \"/reject\"", SYS_MSG, 0, 0); @@ -391,7 +392,7 @@ void chat_onInvite (ToxWindow *self, ToxAv *av, int call_index) void chat_onRinging (ToxWindow *self, ToxAv *av, int call_index) { - if ( self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) + if ( self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; line_info_add(self, NULL, NULL, NULL, "Ringing...\n\"cancel\" ?", SYS_MSG, 0, 0); @@ -399,7 +400,7 @@ void chat_onRinging (ToxWindow *self, ToxAv *av, int call_index) void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index) { - if ( self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) + if ( self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; line_info_add(self, NULL, NULL, NULL, "Call started!\nType: \"/hangup\" to end it.", SYS_MSG, 0, 0); @@ -407,23 +408,25 @@ void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index) void chat_onEnding (ToxWindow *self, ToxAv *av, int call_index) { - if (self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) + if (self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + self->call_idx = -1; line_info_add(self, NULL, NULL, NULL, "Call ended!", SYS_MSG, 0, 0); } void chat_onError (ToxWindow *self, ToxAv *av, int call_index) { - if (self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) + if (self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + self->call_idx = -1; line_info_add(self, NULL, NULL, NULL, "Error!", SYS_MSG, 0, 0); } void chat_onStart (ToxWindow *self, ToxAv *av, int call_index) { - if ( self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) + if ( self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; line_info_add(self, NULL, NULL, NULL, "Call started!\nType: \"/hangup\" to end it.", SYS_MSG, 0, 0); @@ -431,41 +434,46 @@ void chat_onStart (ToxWindow *self, ToxAv *av, int call_index) void chat_onCancel (ToxWindow *self, ToxAv *av, int call_index) { - if ( self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) + if ( self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + self->call_idx = -1; line_info_add(self, NULL, NULL, NULL, "Call canceled!", SYS_MSG, 0, 0); } void chat_onReject (ToxWindow *self, ToxAv *av, int call_index) { - if (self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) + if (self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + self->call_idx = -1; line_info_add(self, NULL, NULL, NULL, "Rejected!", SYS_MSG, 0, 0); } void chat_onEnd (ToxWindow *self, ToxAv *av, int call_index) { - if (self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) + if (self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + self->call_idx = -1; line_info_add(self, NULL, NULL, NULL, "Call ended!", SYS_MSG, 0, 0); } void chat_onRequestTimeout (ToxWindow *self, ToxAv *av, int call_index) { - if (self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) + if (self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + self->call_idx = -1; line_info_add(self, NULL, NULL, NULL, "No answer!", SYS_MSG, 0, 0); } void chat_onPeerTimeout (ToxWindow *self, ToxAv *av, int call_index) { - if (self->call_index != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) + if (self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0)) return; + self->call_idx = -1; line_info_add(self, NULL, NULL, NULL, "Peer disconnected; call ended!", SYS_MSG, 0, 0); } @@ -899,7 +907,8 @@ ToxWindow new_chat(Tox *m, int32_t friendnum) ret.onRequestTimeout = &chat_onRequestTimeout; ret.onPeerTimeout = &chat_onPeerTimeout; - ret.call_index = -1; + ret.call_idx = -1; + ret.device_selection[0] = ret.device_selection[1] = -1; #endif /* _SUPPORT_AUDIO */ uint8_t name[TOX_MAX_NAME_LENGTH] = {'\0'}; diff --git a/src/chat_commands.h b/src/chat_commands.h index 76ecd64..30ca9f1 100644 --- a/src/chat_commands.h +++ b/src/chat_commands.h @@ -33,4 +33,5 @@ void cmd_answer(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ void cmd_reject(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_hangup(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); +void cmd_set_this_session_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); #endif /* _SUPPORT_AUDIO */ diff --git a/src/execute.c b/src/execute.c index 34e8e31..7dc18cb 100644 --- a/src/execute.c +++ b/src/execute.c @@ -73,6 +73,7 @@ static struct cmd_func chat_commands[] = { { "/answer", cmd_answer }, { "/reject", cmd_reject }, { "/hangup", cmd_hangup }, + { "/sdev", cmd_set_this_session_device }, #endif /* _SUPPORT_AUDIO */ }; diff --git a/src/execute.h b/src/execute.h index df9072e..57b0b26 100644 --- a/src/execute.h +++ b/src/execute.h @@ -24,7 +24,7 @@ #ifdef _SUPPORT_AUDIO #define GLOBAL_NUM_COMMANDS 16 -#define CHAT_NUM_COMMANDS 10 +#define CHAT_NUM_COMMANDS 11 #else #define GLOBAL_NUM_COMMANDS 14 #define CHAT_NUM_COMMANDS 5 diff --git a/src/friendlist.c b/src/friendlist.c index d8ca16d..874b01f 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -623,7 +623,8 @@ ToxWindow new_friendlist(void) ret.onRequestTimeout = &friendlist_onAv; ret.onPeerTimeout = &friendlist_onAv; - ret.call_index = -1; + ret.call_idx = -1; + ret.device_selection[0] = ret.device_selection[1] = -1; #endif /* _SUPPORT_AUDIO */ strcpy(ret.name, "friends"); diff --git a/src/line_info.c b/src/line_info.c index 923613a..6fc96bb 100644 --- a/src/line_info.c +++ b/src/line_info.c @@ -121,7 +121,7 @@ void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *na memset(new_line, 0, sizeof(struct line_info)); - int len = 1; /* there will always be a newline */ + int len = 1; /* there will always be a newline */ /* for type-specific formatting in print function */ switch (type) { diff --git a/src/main.c b/src/main.c index f6d6a35..ccd2f14 100644 --- a/src/main.c +++ b/src/main.c @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef _WIN32 #include @@ -62,6 +63,7 @@ #include "file_senders.h" #include "line_info.h" #include "settings.h" +#include "global_commands.h" #ifdef _SUPPORT_AUDIO #include "audio_call.h" @@ -459,33 +461,66 @@ void *thread_winref(void *data) draw_active_window(m); } +int exit_print(char* exe_name, char* invalid_arg, char* error_str) +{ + const char* help_str = + "usage: \n" + " -f tox protocol data file path \n" + " -s custom settings path \n" + " -n don't load from data file (create new profile) \n" + " -h print this help \n" + " -4 force ipv4 \n"; + + if (!error_str && !invalid_arg) { + printf("%s %s", exe_name, help_str); + return 0; + } else if (invalid_arg) { + fprintf(stderr, "%s invalid arg: %s", exe_name, invalid_arg); + return 1; + } else if (error_str) { + fprintf(stderr, "%s error: %s", exe_name, error_str); + return 1; + } +} + int main(int argc, char *argv[]) { - char *user_config_dir = get_user_config_dir(); + char *user_config_dir = get_user_config_dir(), *settings_path = NULL; int config_err = 0; f_loadfromfile = 1; - int f_flag = 0; int i = 0; int f_use_ipv4 = 0; /* Make sure all written files are read/writeable only by the current user. */ umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - for (i = 0; i < argc; ++i) { - if (argv[i] == NULL) - break; - else if (argv[i][0] == '-') { + for (i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { if (argv[i][1] == 'f') { - if (argv[i + 1] != NULL) - DATA_FILE = strdup(argv[i + 1]); + ++i; + if (i < argc) + DATA_FILE = strdup(argv[i]); else - f_flag = -1; + return exit_print(argv[0], NULL, "argument 'f' requires value"); + } else if (argv[i][1] == 'n') { f_loadfromfile = 0; + } else if (argv[i][1] == 'h') { + return exit_print(argv[0], NULL, NULL); } else if (argv[i][1] == '4') { f_use_ipv4 = 1; + } else if (argv[i][1] == 's') { + ++i; + if (i < argc) + settings_path = argv[i]; + else + return exit_print(argv[0], NULL, "argument 's' requires value"); + } else { + return exit_print(argv[0], argv[i]+1, NULL); /* Invalid arg */ } + } else { + return exit_print(argv[0], argv[i], NULL); /* Invalid value/arg */ } } @@ -521,7 +556,7 @@ int main(int argc, char *argv[]) } memset(user_settings, 0, sizeof(struct user_settings)); - int settings_err = settings_load(user_settings, NULL); + int settings_err = settings_load(user_settings, settings_path); Tox *m = init_tox(f_use_ipv4); init_term(); @@ -556,23 +591,20 @@ int main(int argc, char *argv[]) av = init_audio(prompt, m); - device_set(prompt, input, user_settings->audio_in_dev); - device_set(prompt, output, user_settings->audio_out_dev); - - if ( errors() == NoError ) - msg = "Audio initiated with no problems."; - else /* Get error code and stuff */ - msg = "Error initiating audio!"; - - line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); +// device_set(prompt, input, user_settings->audio_in_dev); +// device_set(prompt, output, user_settings->audio_out_dev); + + set_primary_device(input, user_settings->audio_in_dev); + set_primary_device(output, user_settings->audio_out_dev); + + char* string = malloc(1000); + sprintf(string, "i:%d o:%d", user_settings->audio_in_dev, user_settings->audio_out_dev); + + line_info_add(prompt, NULL, NULL, NULL, string, SYS_MSG, 0, 0); + cmd_myid(NULL, prompt, m, 0, NULL); #endif /* _SUPPORT_AUDIO */ - if (f_flag == -1) { - msg = "You passed '-f' without giving an argument. Defaulting to 'data' for a keyfile..."; - line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); - } - if (config_err) { msg = "Unable to determine configuration directory. Defaulting to 'data' for a keyfile..."; line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); diff --git a/src/settings.c b/src/settings.c index 0faea09..81d5bc9 100644 --- a/src/settings.c +++ b/src/settings.c @@ -20,12 +20,17 @@ * */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include - +#include #ifdef _SUPPORT_AUDIO - #include "audio_call.h" + #include "device.h" #endif /* _SUPPORT_AUDIO */ #include "toxic_windows.h" @@ -84,17 +89,16 @@ static void uset_colours(struct user_settings *s, int val) static void uset_ain_dev(struct user_settings *s, int val) { if (val < 0 || val > MAX_DEVICES) - val = (long int) 0; - - s->audio_in_dev = (long int) val; + val = 0; + s->audio_in_dev = val; } static void uset_aout_dev(struct user_settings *s, int val) { if (val < 0 || val > MAX_DEVICES) - val = (long int) 0; + val = 0; - s->audio_out_dev = (long int) val; + s->audio_out_dev = val; } #endif /* _SUPPORT_AUDIO */ @@ -104,7 +108,7 @@ int settings_load(struct user_settings *s, char *path) char *user_config_dir = get_user_config_dir(); FILE *fp = NULL; char dflt_path[MAX_STR_SIZE]; - + if (path) { fp = fopen(path, "r"); } else { @@ -120,30 +124,28 @@ int settings_load(struct user_settings *s, char *path) } else if (fp == NULL && path) { return -1; } - + char line[MAX_STR_SIZE]; while (fgets(line, sizeof(line), fp)) { if (line[0] == '#' || !line[0]) continue; - - char *name = strtok(line, ":"); - char *val_s = strtok(NULL, ";"); - - if (name == NULL || val_s == NULL) + + const char *key = strtok(line, ":"); + const char *val = strtok(NULL, ";"); + + if (key == NULL || val == NULL) continue; - - int val = atoi(val_s); + int i; - for (i = 0; i < NUM_SETTINGS; ++i) { - if (!strcmp(user_settings_list[i].name, name)) { - (user_settings_list[i].func)(s, val); + if (strcmp(user_settings_list[i].name, key) == 0) { + (user_settings_list[i].func)(s, atoi(val)); break; } } - } - + } + fclose(fp); return 0; } diff --git a/src/settings.h b/src/settings.h index 1d997fc..68a0e18 100644 --- a/src/settings.h +++ b/src/settings.h @@ -34,8 +34,8 @@ struct user_settings { int colour_theme; /* boolean (0 for default toxic colours) */ #ifdef _SUPPORT_AUDIO - long int audio_in_dev; - long int audio_out_dev; + int audio_in_dev; + int audio_out_dev; #endif /* _SUPPORT_AUDIO */ }; diff --git a/src/toxic_windows.h b/src/toxic_windows.h index 03b80d5..29addf1 100644 --- a/src/toxic_windows.h +++ b/src/toxic_windows.h @@ -132,8 +132,9 @@ struct ToxWindow { void(*onRequestTimeout)(ToxWindow *, ToxAv *, int); void(*onPeerTimeout)(ToxWindow *, ToxAv *, int); - int call_index; /* If in a call will have this index set, otherwise it's -1. - * Don't modify outside av callbacks. */ + int call_idx; /* If in a call will have this index set, otherwise it's -1. + * Don't modify outside av callbacks. */ + int device_selection[2]; /* -1 if not set, if set uses these selections instead of primary device */ #endif /* _SUPPORT_AUDIO */ char name[TOX_MAX_NAME_LENGTH];