From e775c51a06ad076071e5aad2f43a6272f77a1d39 Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 22 Feb 2014 23:58:36 +0100 Subject: [PATCH 1/8] Merge upsteam/master --- build/Makefile.am | 9 +++++++ configure.ac | 65 ++++++++++++++++++++++++++++++++++++++++++++- src/chat.c | 13 +++++++-- src/friendlist.c | 7 ++++- src/friendlist.h | 1 + src/main.c | 47 +++++++++++++++++--------------- src/prompt.c | 13 +++++++-- src/toxic_windows.h | 2 +- 8 files changed, 128 insertions(+), 29 deletions(-) diff --git a/build/Makefile.am b/build/Makefile.am index a670d9b..83437e6 100644 --- a/build/Makefile.am +++ b/build/Makefile.am @@ -41,3 +41,12 @@ toxic_LDADD = $(LIBTOXCORE_LDFLAGS) \ $(LIBSODIUM_LIBS) \ $(WINSOCK2_LIBS) + +# For audio support +if BUILD_AV +toxic_SOURCES += $(top_srcdir)/src/audio_call.c \ + $(top_srcdir)/src/audio_call.h + +toxic_CFLAGS += $(LIBTOXAV_CFLAGS) +toxic_LDADD += $(LIBTOXAV_LIBS) +endif \ No newline at end of file diff --git a/configure.ac b/configure.ac index 4fcd5d1..28430e3 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.65]) -AC_INIT([toxic], [0.2.4], [http://tox.im/]) +AC_INIT([toxic], [0.2.5], [https://tox.im/]) AC_CONFIG_AUX_DIR(configure_aux) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADERS([config.h]) @@ -381,6 +381,69 @@ if test "x$LIBTOXCORE_FOUND" = "xno"; then AC_SUBST(LIBTOXCORE_LDFLAGS) fi + +#### +#### A/V Stuff + +AV_SEARCH_DIR= +BUILD_AV="yes" + +AC_ARG_WITH(libtoxav-prefix, + AC_HELP_STRING([--with-libtoxav-prefix=DIR], + [search for libtoxav in DIR, i.e. look for libraries in + DIR/lib and for headers in DIR/include]), + [ + AV_SEARCH_DIR="$withval" + ] +) + +if test -n "$AV_SEARCH_DIR"; then + CFLAGS="$CFLAGS -I$AV_SEARCH_DIR/include" + CPPFLAGS="$CPPFLAGS -I$AV_SEARCH_DIR/include" + LDFLAGS="$LDFLAGS -L$AV_SEARCH_DIR/lib" + export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$AV_SEARCH_DIR/lib/pkgconfig +fi + +# Check if specified enable +AC_ARG_ENABLE([av], + [AC_HELP_STRING([--disable-av], [build AV support libraries (default: auto)]) ], + [ + if test "x$enableval" = "xno"; then + BUILD_AV="no" + elif test "x$enableval" = "xyes"; then + BUILD_AV="yes" + fi + ] +) + +# Check for A/V library + +if test "x$BUILD_AV" = "xyes"; then + export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig + + PKG_CHECK_EXISTS([libtoxav], + [ + AC_CHECK_HEADER([tox/toxav.h], + [ + # Place define for audio support + AC_DEFINE([_SUPPORT_AUDIO], [], [If audio supported]) + AC_MSG_NOTICE([Building with audio support]) + ], + [ + AC_MSG_NOTICE([No A/V headers; disabling A/V support]) + BUILD_AV="no" + ],) + ], + [ + AC_MSG_NOTICE([No A/V library; disabling A/V support]) + ]) +fi + +AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes") + + + + TOXIC_VERSION="$PACKAGE_VERSION" AC_PATH_PROG([GIT], [git], [no]) if test "x$GIT" != "xno"; then diff --git a/src/chat.c b/src/chat.c index efec9fa..d89bfdd 100644 --- a/src/chat.c +++ b/src/chat.c @@ -547,7 +547,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m) self->x = x2; /* Truncate note if it doesn't fit in statusbar */ - uint16_t maxlen = x2 - getcurx(statusbar->topline) - 4; + uint16_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 7; if (statusbar->statusmsg_len > maxlen) { statusbar->statusmsg[maxlen] = '\0'; statusbar->statusmsg_len = maxlen; @@ -559,7 +559,16 @@ static void chat_onDraw(ToxWindow *self, Tox *m) wattroff(statusbar->topline, A_BOLD); } - wprintw(statusbar->topline, "\n"); + wclrtoeol(statusbar->topline); + wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3); + wprintw(statusbar->topline, "{"); + + int i; + + for (i = 0; i < KEY_IDENT_DIGITS; ++i) + wprintw(statusbar->topline, "%02X", friends[self->num].pub_key[i] & 0xff); + + wprintw(statusbar->topline, "}\n"); mvwhline(ctx->linewin, 0, 0, ACS_HLINE, x2); } diff --git a/src/friendlist.c b/src/friendlist.c index f569405..7e22091 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -130,6 +130,7 @@ static void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int num, bool sort friends[i].online = false; friends[i].status = TOX_USERSTATUS_NONE; friends[i].namelength = tox_get_name(m, num, friends[i].name); + tox_get_client_id(m, num, friends[i].pub_key); if (friends[i].namelength == -1 || friends[i].name[0] == '\0') { strcpy(friends[i].name, (uint8_t *) UNKNOWN_NAME); @@ -363,7 +364,11 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m) wprintw(self->window, " (%s)\n", friends[f].statusmsg); } else { - wprintw(self->window, "[O]"); + wprintw(self->window, "["); + wattron(self->window, A_BOLD); + wprintw(self->window, "O"); + wattroff(self->window, A_BOLD); + wprintw(self->window, "]"); if (f_selected) wattron(self->window, A_BOLD); diff --git a/src/friendlist.h b/src/friendlist.h index 3abc781..029c9a6 100644 --- a/src/friendlist.h +++ b/src/friendlist.h @@ -9,6 +9,7 @@ typedef struct { uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH]; uint16_t statusmsg_len; uint8_t pending_groupchat[TOX_CLIENT_ID_SIZE]; + uint8_t pub_key[TOX_CLIENT_ID_SIZE]; int num; int chatwin; bool active; diff --git a/src/main.c b/src/main.c index 3a68fbf..3b9bcc1 100644 --- a/src/main.c +++ b/src/main.c @@ -232,34 +232,34 @@ int init_connection(Tox *m) return 5; } -static void do_tox(Tox *m, ToxWindow *prompt) +static void do_connection(Tox *m, ToxWindow *prompt) { static int conn_try = 0; static int conn_err = 0; static bool dht_on = false; - if (!dht_on && !tox_isconnected(m) && !(conn_try++ % 100)) { + bool is_connected = tox_isconnected(m); + + if (!dht_on && !is_connected && !(conn_try++ % 100)) { prep_prompt_win(); if (!conn_err) { wprintw(prompt->window, "Establishing connection...\n"); if ((conn_err = init_connection(m))) wprintw(prompt->window, "\nAuto-connect failed with error code %d\n", conn_err); } - } else if (!dht_on && tox_isconnected(m)) { + } else if (!dht_on && is_connected) { dht_on = true; prompt_update_connectionstatus(prompt, dht_on); prep_prompt_win(); wprintw(prompt->window, "\nDHT connected.\n"); - } else if (dht_on && !tox_isconnected(m)) { + } else if (dht_on && !is_connected) { dht_on = false; prompt_update_connectionstatus(prompt, dht_on); prep_prompt_win(); wprintw(prompt->window, "\nDHT disconnected. Attempting to reconnect.\n"); } - - tox_do(m); } int f_loadfromfile; @@ -405,9 +405,7 @@ static void do_file_senders(Tox *m) continue; } - int pieces = 0; - - while (pieces++ < MAX_PIECES_SEND) { + while (true) { if (tox_file_send_data(m, friendnum, filenum, file_senders[i].nextpiece, file_senders[i].piecelen) == -1) break; @@ -432,21 +430,17 @@ static void do_file_senders(Tox *m) } } -/* This should only be called on exit */ -static void close_file_transfers(Tox *m) +void exit_toxic(Tox *m) { + store_data(m, DATA_FILE); + int i; for (i = 0; i < max_file_senders_index; ++i) { if (file_senders[i].active) fclose(file_senders[i].file); } -} -void exit_toxic(Tox *m) -{ - store_data(m, DATA_FILE); - close_file_transfers(m); free(DATA_FILE); free(SRVLIST_FILE); free(prompt->stb); @@ -456,6 +450,16 @@ void exit_toxic(Tox *m) exit(EXIT_SUCCESS); } +static void do_toxic(Tox *m, ToxWindow *prompt) +{ + do_connection(m, prompt); + draw_active_window(m); + do_file_senders(m); + + /* main tox-core loop */ + tox_do(m); +} + int main(int argc, char *argv[]) { char *user_config_dir = get_user_config_dir(); @@ -466,6 +470,9 @@ int main(int argc, char *argv[]) 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; @@ -549,12 +556,8 @@ int main(int argc, char *argv[]) prompt_init_statusbar(prompt, m); sort_friendlist_index(m); - while (true) { - do_tox(m, prompt); - do_file_senders(m); - draw_active_window(m); - } + while (true) + do_toxic(m, prompt); - exit_toxic(m); return 0; } diff --git a/src/prompt.c b/src/prompt.c index 741b9e0..6d0a238 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -162,7 +162,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key) else if (key == KEY_END) { /* END key: move cursor to end of line */ if (prt->pos != prt->len) prt->pos = prt->len; - } + } else if (key == KEY_LEFT) { if (prt->pos > 0) @@ -418,7 +418,16 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m) snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick); /* temporary until statusmessage saving works */ - uint8_t *statusmsg = "Toxing on Toxic v.0.2.4"; + uint8_t ver[strlen(TOXICVER) + 1]; + uint8_t statusmsg[MAX_STR_SIZE]; + strcpy(ver, TOXICVER); + uint8_t *toxic_ver = strtok(ver, "_"); + + if (toxic_ver != NULL) + snprintf(statusmsg, MAX_STR_SIZE, "Toxing on Toxic v.%s", toxic_ver); + else + snprintf(statusmsg, MAX_STR_SIZE, "Toxing on Toxic hacker edition"); + m_set_statusmessage(m, statusmsg, strlen(statusmsg) + 1); snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg); diff --git a/src/toxic_windows.h b/src/toxic_windows.h index 3a3d62e..774b790 100644 --- a/src/toxic_windows.h +++ b/src/toxic_windows.h @@ -26,6 +26,7 @@ #define N_DEFAULT_WINS 2 /* number of permanent default windows */ #define CURS_Y_OFFSET 3 /* y-axis cursor offset for chat contexts */ #define CHATBOX_HEIGHT 4 +#define KEY_IDENT_DIGITS 2 /* number of hex digits to display for the pub-key based identifier */ #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 @@ -149,7 +150,6 @@ struct PromptBuf { #define MAX_FILES 256 #define FILE_PIECE_SIZE 1024 #define TIMEOUT_FILESENDER 300 -#define MAX_PIECES_SEND 100 /* Max number of pieces to send per file per call to do_file_senders() */ typedef struct { FILE *file; From fd86f01fd0a0cf350d698e679cc93d2a0ff71861 Mon Sep 17 00:00:00 2001 From: mannol Date: Sun, 23 Feb 2014 00:00:34 +0100 Subject: [PATCH 2/8] Started with audio --- src/audio_call.c | 14 ++++++++++++++ src/audio_call.h | 8 ++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/audio_call.c create mode 100644 src/audio_call.h diff --git a/src/audio_call.c b/src/audio_call.c new file mode 100644 index 0000000..457d371 --- /dev/null +++ b/src/audio_call.c @@ -0,0 +1,14 @@ +/* + * Toxic -- Tox Curses Client + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef _SUPPORT_AUDIO +#include + +#error "Get me a kill" + +#endif /* _SUPPORT_AUDIO */ \ No newline at end of file diff --git a/src/audio_call.h b/src/audio_call.h new file mode 100644 index 0000000..6ace39d --- /dev/null +++ b/src/audio_call.h @@ -0,0 +1,8 @@ +/* + * Toxic -- Tox Curses Client + */ + +#ifndef _audio_h +#define _audio_h + +#endif /* _audio_h */ \ No newline at end of file From 416419a6e7416640b2ddfff57584d4915a413987 Mon Sep 17 00:00:00 2001 From: mannol Date: Fri, 7 Mar 2014 03:14:04 +0100 Subject: [PATCH 3/8] Toxic now supports audio calls --- build/Makefile.am | 8 +- configure.ac | 34 ++-- misc/DHTservers | 3 +- src/audio_call.c | 487 +++++++++++++++++++++++++++++++++++++++++++- src/audio_call.h | 26 +++ src/chat.c | 145 ++++++++++++- src/chat_commands.c | 10 + src/chat_commands.h | 8 + src/execute.c | 7 + src/execute.h | 5 + src/friendlist.c | 44 ++++ src/main.c | 30 ++- src/toxic_windows.h | 21 +- 13 files changed, 804 insertions(+), 24 deletions(-) diff --git a/build/Makefile.am b/build/Makefile.am index 83437e6..e8e8848 100644 --- a/build/Makefile.am +++ b/build/Makefile.am @@ -44,9 +44,13 @@ toxic_LDADD = $(LIBTOXCORE_LDFLAGS) \ # For audio support if BUILD_AV + toxic_SOURCES += $(top_srcdir)/src/audio_call.c \ $(top_srcdir)/src/audio_call.h -toxic_CFLAGS += $(LIBTOXAV_CFLAGS) -toxic_LDADD += $(LIBTOXAV_LIBS) +toxic_CFLAGS += $(LIBTOXAV_CFLAGS) \ + $(OPENAL_CFLAGS) + +toxic_LDADD += $(LIBTOXAV_LIBS) \ + $(OPENAL_LIBS) endif \ No newline at end of file diff --git a/configure.ac b/configure.ac index 28430e3..a58f474 100644 --- a/configure.ac +++ b/configure.ac @@ -419,23 +419,29 @@ AC_ARG_ENABLE([av], # Check for A/V library if test "x$BUILD_AV" = "xyes"; then - export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig + PKG_CHECK_MODULES([OPENAL], [openal], + [ + export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig - PKG_CHECK_EXISTS([libtoxav], - [ - AC_CHECK_HEADER([tox/toxav.h], + PKG_CHECK_MODULES([LIBTOXAV], [libtoxav], [ - # Place define for audio support - AC_DEFINE([_SUPPORT_AUDIO], [], [If audio supported]) - AC_MSG_NOTICE([Building with audio support]) - ], + AC_CHECK_HEADER([tox/toxav.h], + [ + # Place define for audio support + AC_DEFINE([_SUPPORT_AUDIO], [], [If audio supported]) + AC_MSG_NOTICE([Building with audio support]) + ], + [ + AC_MSG_NOTICE([No A/V headers; disabling A/V support]) + BUILD_AV="no" + ],) + ], [ - AC_MSG_NOTICE([No A/V headers; disabling A/V support]) - BUILD_AV="no" - ],) - ], + AC_MSG_NOTICE([No A/V library; disabling A/V support]) + ]) + ], [ - AC_MSG_NOTICE([No A/V library; disabling A/V support]) + AC_MSG_NOTICE([No openal library; disabling A/V support]) ]) fi @@ -443,6 +449,8 @@ AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes") +#debug mode +CFLAGS="-ggdb3 -O0 -pg" TOXIC_VERSION="$PACKAGE_VERSION" AC_PATH_PROG([GIT], [git], [no]) diff --git a/misc/DHTservers b/misc/DHTservers index 5e27942..d82237c 100644 --- a/misc/DHTservers +++ b/misc/DHTservers @@ -1,2 +1 @@ -192.254.75.98 33445 FE3914F4616E227F29B2103450D6B55A836AD4BD23F97144E2C4ABE8D504FE1B -2607:5600:284::2 33445 FE3914F4616E227F29B2103450D6B55A836AD4BD23F97144E2C4ABE8D504FE1B +127.0.0.1 33447 25530DE8BF0DACA3F2ECD1A2FF07C6E21E5BEE12993F36157A2846DF8E837E33 diff --git a/src/audio_call.c b/src/audio_call.c index 457d371..e14a343 100644 --- a/src/audio_call.c +++ b/src/audio_call.c @@ -7,8 +7,491 @@ #endif #ifdef _SUPPORT_AUDIO -#include -#error "Get me a kill" + +#include "audio_call.h" +#include "toxic_windows.h" +#include "chat_commands.h" +#include "toxic_windows.h" +#include +#include +#include +#include +#include +#include +#include + +#define MAX_DEVICES 32 +#define _cbend pthread_exit(NULL) + +typedef struct _DeviceIx { + + ALCdevice* dhndl; /* Handle of device selected/opened */ + ALCcontext* ctx; /* Device context */ + const char* devices[MAX_DEVICES]; /* Container */ + int size; + int dix; /* Index of default device */ +} DeviceIx; + +enum _devices +{ + input, + output, +}; + +struct _ASettings { + + DeviceIx device[2]; + + AudioError errors; + + ToxAv* av; + + pthread_t ttid; /* Transmission thread id */ + int ttas; /* Transmission thread active status (0 - stopped, 1- running) */ +} ASettins; + + +void *callback_recv_invite ( void *arg ); +void *callback_recv_ringing ( void *arg ); +void *callback_recv_starting ( void *arg ); +void *callback_recv_ending ( void *arg ); +void *callback_recv_error ( void *arg ); +void *callback_call_started ( void *arg ); +void *callback_call_canceled ( void *arg ); +void *callback_call_rejected ( void *arg ); +void *callback_call_ended ( void *arg ); +void *callback_requ_timeout ( void *arg ); + + + + + +ToxAv* init_audio(ToxWindow* window, Tox* tox) +{ + ASettins.errors = NoError; + ASettins.ttas = 0; /* Not running */ + + /* Capture device */ + const char* stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); + ASettins.device[input].size = 0; + + if ( stringed_device_list ) { + const char* default_device = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); + + 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].dix = ASettins.device[input].size; + + stringed_device_list += strlen( stringed_device_list ) + 1; + } + + ++ASettins.device[input].size; + } + + if ( ASettins.device[input].size ) { /* Have device */ + ASettins.device[input].dhndl = alcCaptureOpenDevice( + ASettins.device[input].devices[ASettins.device[input].dix], AUDIO_SAMPLE_RATE, AL_FORMAT_MONO16, AUDIO_FRAME_SIZE * 4); + + if (alcGetError(ASettins.device[input].dhndl) != AL_NO_ERROR) { + ASettins.errors |= ErrorStartingCaptureDevice; + } + + wprintw(window->window, "Input device: %s\n", ASettins.device[input].devices[ASettins.device[input].dix]); + } else { /* No device */ + wprintw(window->window, "No input device!\n"); + ASettins.device[input].dhndl = NULL; + } + + ASettins.device[input].ctx = NULL; + + + + + /* Output device */ + stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER); + ASettins.device[output].size = 0; + + 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].dix = ASettins.device[output].size; + + stringed_device_list += strlen( stringed_device_list ) + 1; + } + + ++ASettins.device[output].size; + } + + if ( ASettins.device[output].size ) { /* Have device */ + ASettins.device[output].dhndl = alcOpenDevice(ASettins.device[output].devices[ASettins.device[output].dix]); + + if (alcGetError(ASettins.device[output].dhndl) != AL_NO_ERROR) { + ASettins.errors |= ErrorStartingOutputDevice; + } + + wprintw(window->window, "Output device: %s\n", ASettins.device[output].devices[ASettins.device[output].dix]); + ASettins.device[output].ctx = alcCreateContext(ASettins.device[output].dhndl, NULL); + } else { /* No device */ + wprintw(window->window, "No output device!\n"); + ASettins.device[output].dhndl = NULL; + ASettins.device[output].ctx = NULL; + } + + + /* Streaming stuff from core */ + ASettins.av = toxav_new(tox, window, 0, 0); + + if ( !ASettins.av ) { + ASettins.errors |= ErrorStartingCoreAudio; + return NULL; + } + + toxav_register_callstate_callback(callback_call_started, av_OnStart); + toxav_register_callstate_callback(callback_call_canceled, av_OnCancel); + toxav_register_callstate_callback(callback_call_rejected, av_OnReject); + toxav_register_callstate_callback(callback_call_ended, av_OnEnd); + toxav_register_callstate_callback(callback_recv_invite, av_OnInvite); + + toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging); + toxav_register_callstate_callback(callback_recv_starting, av_OnStarting); + toxav_register_callstate_callback(callback_recv_ending, av_OnEnding); + + toxav_register_callstate_callback(callback_recv_error, av_OnError); + toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout); + + return ASettins.av; +} + +void terminate_audio() +{ + if ( ASettins.device[input].dhndl ) { + alcCaptureCloseDevice(ASettins.device[input].dhndl); + } + + if ( ASettins.device[output].dhndl ) { + alcCloseDevice(ASettins.device[output].dhndl); + alcMakeContextCurrent(NULL); + alcDestroyContext(ASettins.device[output].ctx); + } + + toxav_kill(ASettins.av); +} + + +int errors() +{ + return ASettins.errors; +} + + + +/* + * Transmission + */ + +void* transmission(void* arg) +{ + (void)arg; /* Avoid warning */ + + ASettins.ttas = 1; + + /* 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; + + /* 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[AUDIO_FRAME_SIZE]; + memset(zeros, 0, AUDIO_FRAME_SIZE); + int16_t PCM[AUDIO_FRAME_SIZE]; + + int32_t i = 0; + for (; i < openal_buffers; ++i) { + alBufferData(buffers[i], AL_FORMAT_MONO16, zeros, AUDIO_FRAME_SIZE, 48000); + } + + alSourceQueueBuffers(source, openal_buffers, buffers); + alSourcePlay(source); + + if (alGetError() != AL_NO_ERROR) { + /* Print something? */ + /*fprintf(stderr, "Error starting audio\n");*/ + goto cleanup; + } + + /* Start transmission */ + while (ASettins.ttas) { + + alcGetIntegerv(ASettins.device[input].dhndl, ALC_CAPTURE_SAMPLES, (int32_t) sizeof(int32_t), &sample); + + /* RECORD AND SEND */ + if (sample >= AUDIO_FRAME_SIZE) { + alcCaptureSamples(ASettins.device[input].dhndl, frame, AUDIO_FRAME_SIZE); + + if (toxav_send_audio(ASettins.av, frame, AUDIO_FRAME_SIZE) < 0) + /*fprintf(stderr, "Could not encode or send audio packet\n")*/; + + } else usleep(1000); + + + + /* PLAYBACK */ + + alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready); + + if (ready <= 0) + continue; + + dec_frame_len = toxav_recv_audio(ASettins.av, AUDIO_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); + } + + usleep(1000); + } + +cleanup: + + alDeleteSources(1, &source); + alDeleteBuffers(openal_buffers, buffers); + alcMakeContextCurrent(NULL); + + _cbend; +} + +int start_transmission() +{ + if ( !toxav_audio_decoding(ASettins.av) || + !toxav_audio_encoding(ASettins.av) ) + return -1; + + /* Don't provide support for video */ + toxav_prepare_transmission(ASettins.av, 0); + + if ( 0 != pthread_create(&ASettins.ttid, NULL, transmission, NULL ) && + 0 != pthread_detach(ASettins.ttid) ) { + return -1; + } +} + +int stop_transmission() +{ + ASettins.ttas = 0; +} +/* + * End of transmission + */ + + + + + +/* + * Callbacks + */ + +#define CB_BODY(Arg, onFunc) do { ToxWindow* windows = toxav_get_agent_handler(Arg); int i;\ +for (i = 0; i < MAX_WINDOWS_NUM; ++i) if (windows[i].onFunc != NULL) windows[i].onFunc(&windows[i], Arg); } while (0) + +void *callback_recv_invite ( void* arg ) +{ + CB_BODY(arg, onInvite); + _cbend; +} +void *callback_recv_ringing ( void* arg ) +{ + CB_BODY(arg, onRinging); + _cbend; +} +void *callback_recv_starting ( void* arg ) +{ + CB_BODY(arg, onStarting); + _cbend; +} +void *callback_recv_ending ( void* arg ) +{ + CB_BODY(arg, onEnding); + stop_transmission(); +} +void *callback_recv_error ( void* arg ) +{ + CB_BODY(arg, onError); + _cbend; +} +void *callback_call_started ( void* arg ) +{ + CB_BODY(arg, onStart); + _cbend; +} +void *callback_call_canceled ( void* arg ) +{ + CB_BODY(arg, onCancel); + _cbend; +} +void *callback_call_rejected ( void* arg ) +{ + CB_BODY(arg, onReject); + _cbend; +} +void *callback_call_ended ( void* arg ) +{ + CB_BODY(arg, onEnd); + stop_transmission(); + _cbend; +} + +void *callback_requ_timeout ( void* arg ) +{ + CB_BODY(arg, onTimeout); + _cbend; +} + +/* + * End of Callbacks + */ + + +/* + * Commands from chat_commands.h + */ +void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) +{ + const char* error_str; + + if (argc != 0) { error_str = "Invalid syntax!"; goto on_error; } + + if ( !ASettins.av ) { error_str = "No audio supported!"; goto on_error; } + + ToxAvError error = toxav_call(ASettins.av, self->num, TypeAudio, 30); + + if ( error != ErrorNone ) { + if ( error == ErrorAlreadyInCall ) error_str = "Already in a call!"; + else error_str = "Internal error!"; + + goto on_error; + } + + wprintw(window, "Calling...\n"); + + return; +on_error: + wprintw(window, "%s %d\n", error_str, argc); +} + +void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) +{ + const char* error_str; + + if (argc != 0) { error_str = "Invalid syntax!"; goto on_error; } + + if ( !ASettins.av ) { error_str = "No audio supported!"; goto on_error; } + + ToxAvError error = toxav_answer(ASettins.av, TypeAudio); + + if ( error != ErrorNone ) { + if ( error == ErrorInvalidState ) error_str = "Cannot answer in invalid state!"; + else if ( error == ErrorNoCall ) error_str = "No incomming call!"; + else error_str = "Internal error!"; + + goto on_error; + } + + /* Callback will print status... */ + + return; +on_error: + wprintw(window, "%s\n", error_str); +} + +void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) +{ + const char* error_str; + + if (argc != 0) { error_str = "Invalid syntax!"; goto on_error; } + + if ( !ASettins.av ) { error_str = "No audio supported!"; goto on_error; } + + ToxAvError error = toxav_hangup(ASettins.av); + + if ( error != ErrorNone ) { + if ( error == ErrorInvalidState ) error_str = "Cannot hangup in invalid state!"; + else if ( error == ErrorNoCall ) error_str = "No call!"; + else error_str = "Internal error!"; + + goto on_error; + } + + return; +on_error: + wprintw(window, "%s\n", error_str); +} + +void cmd_cancel(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) +{ + const char* error_str; + + if (argc != 0) { error_str = "Invalid syntax!"; goto on_error; } + + if ( !ASettins.av ) { error_str = "No audio supported!"; goto on_error; } + + ToxAvError error = toxav_hangup(ASettins.av); + + if ( error != ErrorNone ) { + if ( error == ErrorNoCall ) error_str = "No call!"; + else error_str = "Internal error!"; + + goto on_error; + } + + /* Callback will print status... */ + + return; +on_error: + wprintw(window, "%s\n", error_str); +} + + + + #endif /* _SUPPORT_AUDIO */ \ No newline at end of file diff --git a/src/audio_call.h b/src/audio_call.h index 6ace39d..3fb38b6 100644 --- a/src/audio_call.h +++ b/src/audio_call.h @@ -5,4 +5,30 @@ #ifndef _audio_h #define _audio_h +#ifdef _SUPPORT_AUDIO + + +#include + +typedef struct ToxWindow ToxWindow; + +typedef enum _AudioError +{ + NoError = 0, + ErrorStartingCaptureDevice = 1 << 0, + ErrorStartingOutputDevice = 1 << 1, + ErrorStartingCoreAudio = 1 << 2 +} AudioError; + +/* You will have to pass pointer to first member of 'windows' + * declared in windows.c otherwise undefined behaviour will + */ +ToxAv* init_audio(ToxWindow* window, Tox* tox); +void terminate_audio(); + +int errors(); + +int start_transmission(); + +#endif /* _SUPPORT_AUDIO */ #endif /* _audio_h */ \ No newline at end of file diff --git a/src/chat.c b/src/chat.c index d89bfdd..492ada1 100644 --- a/src/chat.c +++ b/src/chat.c @@ -16,13 +16,17 @@ #include "friendlist.h" #include "toxic_strings.h" +#ifdef _SUPPORT_AUDIO + #include "audio_call.h" +#endif /* _SUPPORT_AUDIO */ + extern char *DATA_FILE; extern int store_data(Tox *m, char *path); extern FileSender file_senders[MAX_FILES]; extern ToxicFriend friends[MAX_FRIENDS_NUM]; -#define AC_NUM_CHAT_COMMANDS 17 +#define AC_NUM_CHAT_COMMANDS 21 /* Array of chat command names used for tab completion. */ static const uint8_t chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = { @@ -43,6 +47,15 @@ static const uint8_t chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = { { "/savefile" }, { "/sendfile" }, { "/status" }, + +#ifdef _SUPPORT_AUDIO + + { "/call" }, + { "/cancel" }, + { "/answer" }, + { "/hangup" }, + +#endif /* _SUPPORT_AUDIO */ }; static void chat_onMessage(ToxWindow *self, Tox *m, int num, uint8_t *msg, uint16_t len) @@ -259,6 +272,123 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int friendnumber, uint8_ alert_window(self, WINDOW_ALERT_2, true); } +/* Av Stuff */ +#ifdef _SUPPORT_AUDIO + +void chat_onInvite (ToxWindow *self, ToxAv *av) +{ + if (self->num != toxav_get_peer_id(av, 0)) + return; + + ChatContext *ctx = self->chatwin; + + wprintw(ctx->history, "Incomming audio call!\n" + "Answer: \"/answer\" \"/cancel\"\n"); + + alert_window(self, WINDOW_ALERT_0, true); +} +void chat_onRinging (ToxWindow *self, ToxAv *av) +{ + if (self->num != toxav_get_peer_id(av, 0)) + return; + + ChatContext *ctx = self->chatwin; + + wprintw(ctx->history, "Ringing...\n" + "\"/cancel\" ?\n"); +} +void chat_onStarting (ToxWindow *self, ToxAv *av) +{ + if (self->num != toxav_get_peer_id(av, 0)) + return; + + ChatContext *ctx = self->chatwin; + + if ( 0 != start_transmission() ) {/* YEAH! */ + wprintw(ctx->history, "Error starting transmission!\n"); + return; + } + + wprintw(ctx->history, "Call started! \n" + "Type: \"/hangup\" to end it.\n"); + +} +void chat_onEnding (ToxWindow *self, ToxAv *av) +{ + if (self->num != toxav_get_peer_id(av, 0)) + return; + + ChatContext *ctx = self->chatwin; + + toxav_kill_transmission(av); + + wprintw(ctx->history, "Call ended! \n"); +} +void chat_onError (ToxWindow *self, ToxAv *av) +{ + if (self->num != toxav_get_peer_id(av, 0)) + return; + + ChatContext *ctx = self->chatwin; + + wprintw(ctx->history, "Error! \n"); +} +void chat_onStart (ToxWindow *self, ToxAv *av) +{ + if (self->num != toxav_get_peer_id(av, 0)) + return; + + ChatContext *ctx = self->chatwin; + + if ( 0 != start_transmission() ) {/* YEAH! */ + wprintw(ctx->history, "Error starting transmission!\n"); + return; + } + + wprintw(ctx->history, "Call started! \n" + "Type: \"/hangup\" to end it.\n"); +} +void chat_onCancel (ToxWindow *self, ToxAv *av) +{ + if (self->num != toxav_get_peer_id(av, 0)) + return; + + ChatContext *ctx = self->chatwin; + + wprintw(ctx->history, "Call canceled! \n"); +} +void chat_onReject (ToxWindow *self, ToxAv *av) +{ + if (self->num != toxav_get_peer_id(av, 0)) + return; + + ChatContext *ctx = self->chatwin; + + wprintw(ctx->history, "Rejected! \n"); +} +void chat_onEnd (ToxWindow *self, ToxAv *av) +{ + if (self->num != toxav_get_peer_id(av, 0)) + return; + + ChatContext *ctx = self->chatwin; + + toxav_kill_transmission(av); + + wprintw(ctx->history, "Call ended! \n"); +} +void chat_onTimeout (ToxWindow *self, ToxAv *av) +{ + if (self->num != toxav_get_peer_id(av, 0)) + return; + + ChatContext *ctx = self->chatwin; + + wprintw(ctx->history, "No answer! \n"); +} + +#endif /* _SUPPORT_AUDIO */ + static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, uint8_t *action) { if (action == NULL) { wprintw(ctx->history, "Invalid syntax.\n"); @@ -619,6 +749,19 @@ ToxWindow new_chat(Tox *m, int friendnum) ret.onFileSendRequest = &chat_onFileSendRequest; ret.onFileControl = &chat_onFileControl; ret.onFileData = &chat_onFileData; + +#ifdef _SUPPORT_AUDIO + ret.onInvite = &chat_onInvite; + ret.onRinging = &chat_onRinging; + ret.onStarting = &chat_onStarting; + ret.onEnding = &chat_onEnding; + ret.onError = &chat_onError; + ret.onStart = &chat_onStart; + ret.onCancel = &chat_onCancel; + ret.onReject = &chat_onReject; + ret.onEnd = &chat_onEnd; + ret.onTimeout = &chat_onTimeout; +#endif /* _SUPPORT_AUDIO */ uint8_t name[TOX_MAX_NAME_LENGTH] = {'\0'}; uint16_t len = tox_get_name(m, friendnum, name); diff --git a/src/chat_commands.c b/src/chat_commands.c index 8a9505a..600c07a 100644 --- a/src/chat_commands.c +++ b/src/chat_commands.c @@ -38,6 +38,16 @@ void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg wprintw(window, " /sendfile : Send a file\n"); wprintw(window, " /savefile : Receive a file\n"); wprintw(window, " /quit or /exit : Exit Toxic\n"); + +#ifdef _SUPPORT_AUDIO + + wprintw(window, " /call : Audio call\n"); + wprintw(window, " /cancel : Cancel call\n"); + wprintw(window, " /answer : Answer incomming call\n"); + wprintw(window, " /hangup : Hangup active call\n"); + +#endif /* _SUPPORT_AUDIO */ + wprintw(window, " /help : Print this message again\n"); wattron(window, COLOR_PAIR(CYAN) | A_BOLD); diff --git a/src/chat_commands.h b/src/chat_commands.h index fd8059a..d52357b 100644 --- a/src/chat_commands.h +++ b/src/chat_commands.h @@ -7,3 +7,11 @@ void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_ST void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); + + +#ifdef _SUPPORT_AUDIO +void cmd_call(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); +void cmd_answer(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]); +#endif /* _SUPPORT_AUDIO */ \ No newline at end of file diff --git a/src/execute.c b/src/execute.c index beac6bb..104af9a 100644 --- a/src/execute.c +++ b/src/execute.c @@ -37,6 +37,13 @@ static struct cmd_func chat_commands[] = { { "/join", cmd_join_group }, { "/savefile", cmd_savefile }, { "/sendfile", cmd_sendfile }, + +#ifdef _SUPPORT_AUDIO + { "/call", cmd_call }, + { "/cancel", cmd_cancel }, + { "/answer", cmd_answer }, + { "/hangup", cmd_hangup }, +#endif /* _SUPPORT_AUDIO */ }; /* Parses input command and puts args into arg array. diff --git a/src/execute.h b/src/execute.h index c720a33..9586410 100644 --- a/src/execute.h +++ b/src/execute.h @@ -4,7 +4,12 @@ #define MAX_NUM_ARGS 4 /* Includes command */ #define GLOBAL_NUM_COMMANDS 13 + +#ifdef _SUPPORT_AUDIO +#define CHAT_NUM_COMMANDS 9 +#else #define CHAT_NUM_COMMANDS 5 +#endif /* _SUPPORT_AUDIO */ enum { GLOBAL_COMMAND_MODE, diff --git a/src/friendlist.c b/src/friendlist.c index 7e22091..c6273b5 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -15,6 +15,7 @@ #include "chat.h" #include "friendlist.h" #include "misc_tools.h" +#include "audio_call.h" extern char *DATA_FILE; extern ToxWindow *prompt; @@ -395,6 +396,36 @@ static void friendlist_onInit(ToxWindow *self, Tox *m) } +#ifdef _SUPPORT_AUDIO +static void friendlist_onAv(ToxWindow *self, ToxAv *av) +{ + int id = toxav_get_peer_id(av, 0); + + if ( id >= max_friends_index) + return; + + Tox* m = toxav_get_tox(av); + + if (friends[id].chatwin == -1) { + if (num_active_windows() < MAX_WINDOWS_NUM) { + friends[id].chatwin = add_window(m, new_chat(m, friends[id].num)); + } else { + uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'}; + tox_get_name(m, id, nick); + nick[TOXIC_MAX_NAME_LENGTH] = '\0'; + wprintw(prompt->window, "Audio action from: %s!\n", nick); + + prep_prompt_win(); + wattron(prompt->window, COLOR_PAIR(RED)); + wprintw(prompt->window, "* Warning: Too many windows are open.\n"); + wattron(prompt->window, COLOR_PAIR(RED)); + + alert_window(prompt, WINDOW_ALERT_0, true); + } + } +} +#endif /* _SUPPORT_AUDIO */ + ToxWindow new_friendlist(void) { ToxWindow ret; @@ -414,6 +445,19 @@ ToxWindow new_friendlist(void) ret.onStatusMessageChange = &friendlist_onStatusMessageChange; ret.onFileSendRequest = &friendlist_onFileSendRequest; ret.onGroupInvite = &friendlist_onGroupInvite; + +#ifdef _SUPPORT_AUDIO + ret.onInvite = &friendlist_onAv; + ret.onRinging = &friendlist_onAv; + ret.onStarting = &friendlist_onAv; + ret.onEnding = &friendlist_onAv; + ret.onError = &friendlist_onAv; + ret.onStart = &friendlist_onAv; + ret.onCancel = &friendlist_onAv; + ret.onReject = &friendlist_onAv; + ret.onEnd = &friendlist_onAv; + ret.onTimeout = &friendlist_onAv; +#endif /* _SUPPORT_AUDIO */ strcpy(ret.name, "friends"); return ret; diff --git a/src/main.c b/src/main.c index 3b9bcc1..cefe2ed 100644 --- a/src/main.c +++ b/src/main.c @@ -30,6 +30,7 @@ #include #include #include +#include #endif #include @@ -40,6 +41,10 @@ #include "prompt.h" #include "misc_tools.h" +#ifdef _SUPPORT_AUDIO + #include "audio_call.h" +#endif /* _SUPPORT_AUDIO */ + #ifndef PACKAGE_DATADIR #define PACKAGE_DATADIR "." #endif @@ -536,6 +541,22 @@ int main(int argc, char *argv[]) prompt = init_windows(m); +#ifdef _SUPPORT_AUDIO + + attron(COLOR_PAIR(RED) | A_BOLD); + wprintw(prompt->window, "Starting audio...\n"); + attroff(COLOR_PAIR(RED) | A_BOLD); + + ToxAv* av = init_audio(prompt, m); + + if ( errors() == NoError ) + wprintw(prompt->window, "Audio started with no problems.\n"); + else /* Get error code and stuff */ + wprintw(prompt->window, "Error starting audio!\n"); + + +#endif /* _SUPPORT_AUDIO */ + if (f_loadfromfile) load_data(m, DATA_FILE); @@ -556,8 +577,11 @@ int main(int argc, char *argv[]) prompt_init_statusbar(prompt, m); sort_friendlist_index(m); - while (true) - do_toxic(m, prompt); - + while (true) do_toxic(m, prompt); + +#ifdef _SUPPORT_AUDIO + terminate_audio(prompt, av); +#endif /* _SUPPORT_AUDIO */ + return 0; } diff --git a/src/toxic_windows.h b/src/toxic_windows.h index 774b790..58fac0f 100644 --- a/src/toxic_windows.h +++ b/src/toxic_windows.h @@ -15,7 +15,11 @@ #include -#define UNKNOWN_NAME "Unknown" +#ifdef _SUPPORT_AUDIO + #include +#endif /* _SUPPORT_AUDIO */ + +#define UNKNOWN_NAME "John Doe" #define MAX_WINDOWS_NUM 32 #define MAX_FRIENDS_NUM 100 @@ -85,6 +89,21 @@ struct ToxWindow { void(*onFileControl)(ToxWindow *, Tox *, int, uint8_t, uint8_t, uint8_t, uint8_t *, uint16_t); void(*onFileData)(ToxWindow *, Tox *, int, uint8_t, uint8_t *, uint16_t); +#ifdef _SUPPORT_AUDIO + + void(*onInvite)(ToxWindow *, ToxAv *); + void(*onRinging)(ToxWindow *, ToxAv *); + void(*onStarting)(ToxWindow *, ToxAv *); + void(*onEnding)(ToxWindow *, ToxAv *); + void(*onError)(ToxWindow *, ToxAv *); + void(*onStart)(ToxWindow *, ToxAv *); + void(*onCancel)(ToxWindow *, ToxAv *); + void(*onReject)(ToxWindow *, ToxAv *); + void(*onEnd)(ToxWindow *, ToxAv *); + void(*onTimeout)(ToxWindow *, ToxAv *); + +#endif /* _SUPPORT_AUDIO */ + char name[TOX_MAX_NAME_LENGTH]; int num; bool active; From c678d41709c63d76879b56e34db831c4a4922d87 Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 8 Mar 2014 01:12:51 +0100 Subject: [PATCH 4/8] Now supporting device selection --- misc/DHTnodes | 3 +- src/audio_call.c | 130 ++++++++++++++++++++++++++++++++++++++---- src/audio_call.h | 4 -- src/chat.c | 4 +- src/chat_commands.c | 8 +-- src/execute.c | 32 ++++++----- src/execute.h | 7 ++- src/global_commands.c | 7 ++- src/global_commands.h | 5 ++ src/prompt.c | 7 +++ src/prompt.h | 7 ++- 11 files changed, 172 insertions(+), 42 deletions(-) diff --git a/misc/DHTnodes b/misc/DHTnodes index d82237c..5e27942 100644 --- a/misc/DHTnodes +++ b/misc/DHTnodes @@ -1 +1,2 @@ -127.0.0.1 33447 25530DE8BF0DACA3F2ECD1A2FF07C6E21E5BEE12993F36157A2846DF8E837E33 +192.254.75.98 33445 FE3914F4616E227F29B2103450D6B55A836AD4BD23F97144E2C4ABE8D504FE1B +2607:5600:284::2 33445 FE3914F4616E227F29B2103450D6B55A836AD4BD23F97144E2C4ABE8D504FE1B diff --git a/src/audio_call.c b/src/audio_call.c index e14a343..778eb9d 100644 --- a/src/audio_call.c +++ b/src/audio_call.c @@ -6,12 +6,10 @@ #include "config.h" #endif -#ifdef _SUPPORT_AUDIO - - #include "audio_call.h" #include "toxic_windows.h" #include "chat_commands.h" +#include "global_commands.h" #include "toxic_windows.h" #include #include @@ -33,11 +31,11 @@ typedef struct _DeviceIx { int dix; /* Index of default device */ } DeviceIx; -enum _devices +typedef enum _devices { input, output, -}; +} _devices; struct _ASettings { @@ -87,8 +85,6 @@ ToxAv* init_audio(ToxWindow* window, Tox* tox) stringed_device_list += strlen( stringed_device_list ) + 1; } - - ++ASettins.device[input].size; } if ( ASettins.device[input].size ) { /* Have device */ @@ -125,8 +121,6 @@ ToxAv* init_audio(ToxWindow* window, Tox* tox) stringed_device_list += strlen( stringed_device_list ) + 1; } - - ++ASettins.device[output].size; } if ( ASettins.device[output].size ) { /* Have device */ @@ -491,7 +485,119 @@ on_error: } +void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) +{ + const char* error_str; + + if ( argc != 1 ) { + if ( argc < 1 ) error_str = "Type must be specified!"; + else error_str = "Only one argument allowed!"; + + goto on_error; + } + + _devices type; + + if ( strcmp(argv[1], "in") == 0 ) /* Input devices */ + type = input; + + else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */ + type = output; + + else { + wprintw(window, "Invalid type: %s\n", argv[1]); + return; + } + + int i = 0; + for ( ; i < ASettins.device[type].size; i ++) + wprintw(window, "%d: %s\n", i, ASettins.device[type].devices[i]); + + return; +on_error: + wprintw(window, "%s\n", error_str); +} - - -#endif /* _SUPPORT_AUDIO */ \ No newline at end of file +void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) +{ + const char* 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; + } + + _devices type; + + if ( strcmp(argv[1], "in") == 0 ) /* Input devices */ + type = input; + + else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */ + type = output; + + else { + wprintw(window, "Invalid type: %s\n", argv[1]); + return; + } + + + char *end; + long int selection = strtol(argv[2], &end, 10); + + if ( *end ) { + error_str = "Invalid input"; + goto on_error; + } + + if ( selection < 0 || selection >= ASettins.device[type].size ) { + error_str = "No device with such index"; + goto on_error; + } + + /* Close default device */ + if ( ASettins.device[type].dhndl ) { + alcCloseDevice(ASettins.device[type].dhndl); + + if ( ASettins.device[type].ctx) { /* Output device has context with it */ + alcMakeContextCurrent(NULL); + alcDestroyContext(ASettins.device[type].ctx); + } + } + + /* Open new device */ + + if ( type == input ) { + ASettins.device[input].dhndl = alcCaptureOpenDevice( + ASettins.device[input].devices[selection], AUDIO_SAMPLE_RATE, AL_FORMAT_MONO16, AUDIO_FRAME_SIZE * 4); + + if (alcGetError(ASettins.device[input].dhndl) != AL_NO_ERROR) { + error_str = "Error starting input device!"; + ASettins.errors |= ErrorStartingCaptureDevice; + } + + ASettins.device[input].ctx = NULL; + + wprintw(window, "Input device: %s\n", ASettins.device[type].devices[selection]); + } + else { + ASettins.device[output].dhndl = alcOpenDevice(ASettins.device[output].devices[selection]); + + if (alcGetError(ASettins.device[output].dhndl) != AL_NO_ERROR) { + error_str = "Error starting output device!"; + ASettins.errors |= ErrorStartingOutputDevice; + } + + ASettins.device[output].ctx = alcCreateContext(ASettins.device[output].dhndl, NULL); + + wprintw(window, "Output device: %s\n", ASettins.device[type].devices[selection]); + } + + + + return; +on_error: + wprintw(window, "%s\n", error_str); +} \ No newline at end of file diff --git a/src/audio_call.h b/src/audio_call.h index 3fb38b6..1b8801d 100644 --- a/src/audio_call.h +++ b/src/audio_call.h @@ -5,9 +5,6 @@ #ifndef _audio_h #define _audio_h -#ifdef _SUPPORT_AUDIO - - #include typedef struct ToxWindow ToxWindow; @@ -30,5 +27,4 @@ int errors(); int start_transmission(); -#endif /* _SUPPORT_AUDIO */ #endif /* _audio_h */ \ No newline at end of file diff --git a/src/chat.c b/src/chat.c index 7e0b29f..cd4aa18 100644 --- a/src/chat.c +++ b/src/chat.c @@ -47,9 +47,9 @@ extern ToxicFriend friends[MAX_FRIENDS_NUM]; #ifdef _SUPPORT_AUDIO -#define AC_NUM_CHAT_COMMANDS 22 + #define AC_NUM_CHAT_COMMANDS 22 #else -#define AC_NUM_CHAT_COMMANDS 18 + #define AC_NUM_CHAT_COMMANDS 18 #endif /* _SUPPORT_AUDIO */ /* Array of chat command names used for tab completion. */ diff --git a/src/chat_commands.c b/src/chat_commands.c index 9bac9a3..6ca7945 100644 --- a/src/chat_commands.c +++ b/src/chat_commands.c @@ -54,10 +54,10 @@ void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg #ifdef _SUPPORT_AUDIO - wprintw(window, " /call : Audio call\n"); - wprintw(window, " /cancel : Cancel call\n"); - wprintw(window, " /answer : Answer incomming call\n"); - wprintw(window, " /hangup : Hangup active call\n"); + wprintw(window, " /call : Audio call\n"); + wprintw(window, " /cancel : Cancel call\n"); + wprintw(window, " /answer : Answer incomming call\n"); + wprintw(window, " /hangup : Hangup active call\n"); #endif /* _SUPPORT_AUDIO */ diff --git a/src/execute.c b/src/execute.c index 462749d..3be7619 100644 --- a/src/execute.c +++ b/src/execute.c @@ -34,20 +34,24 @@ struct cmd_func { }; static struct cmd_func global_commands[] = { - { "/accept", cmd_accept }, - { "/add", cmd_add }, - { "/clear", cmd_clear }, - { "/connect", cmd_connect }, - { "/exit", cmd_quit }, - { "/groupchat", cmd_groupchat }, - { "/help", cmd_prompt_help }, - { "/log", cmd_log }, - { "/myid", cmd_myid }, - { "/nick", cmd_nick }, - { "/note", cmd_note }, - { "/q", cmd_quit }, - { "/quit", cmd_quit }, - { "/status", cmd_status }, + { "/accept", cmd_accept }, + { "/add", cmd_add }, + { "/clear", cmd_clear }, + { "/connect", cmd_connect }, + { "/exit", cmd_quit }, + { "/groupchat", cmd_groupchat }, + { "/help", cmd_prompt_help }, + { "/log", cmd_log }, + { "/myid", cmd_myid }, + { "/nick", cmd_nick }, + { "/note", cmd_note }, + { "/q", cmd_quit }, + { "/quit", cmd_quit }, + { "/status", cmd_status }, +#ifdef _SUPPORT_AUDIO + { "/lsdev", cmd_list_devices }, + { "/sdev", cmd_change_device }, +#endif /* _SUPPORT_AUDIO */ }; static struct cmd_func chat_commands[] = { diff --git a/src/execute.h b/src/execute.h index 42b90b9..cf84cb9 100644 --- a/src/execute.h +++ b/src/execute.h @@ -21,12 +21,13 @@ */ #define MAX_NUM_ARGS 4 /* Includes command */ -#define GLOBAL_NUM_COMMANDS 14 #ifdef _SUPPORT_AUDIO -#define CHAT_NUM_COMMANDS 9 + #define GLOBAL_NUM_COMMANDS 16 + #define CHAT_NUM_COMMANDS 9 #else -#define CHAT_NUM_COMMANDS 5 + #define GLOBAL_NUM_COMMANDS 14 + #define CHAT_NUM_COMMANDS 5 #endif /* _SUPPORT_AUDIO */ enum { diff --git a/src/global_commands.c b/src/global_commands.c index 80a2978..e0a7c78 100644 --- a/src/global_commands.c +++ b/src/global_commands.c @@ -377,7 +377,12 @@ void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a wprintw(window, " /help : Print this message again\n"); wprintw(window, " /clear : Clear the window\n"); wprintw(window, " /quit or /exit : Exit Toxic\n"); - + + #ifdef _SUPPORT_AUDIO + wprintw(window, " /lsdev : List devices where type: in|out\n"); + wprintw(window, " /sdev : Set active device\n"); + #endif /* _SUPPORT_AUDIO */ + wattron(window, COLOR_PAIR(CYAN) | A_BOLD); wprintw(window, " * Argument messages must be enclosed in quotation marks.\n"); wprintw(window, " * Use ctrl-o and ctrl-p to navigate through the tabs.\n\n"); diff --git a/src/global_commands.h b/src/global_commands.h index 5b0a66b..f8aec5b 100644 --- a/src/global_commands.h +++ b/src/global_commands.h @@ -32,3 +32,8 @@ void cmd_note(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE] void cmd_prompt_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_quit(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); + +#ifdef _SUPPORT_AUDIO +void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); +void cmd_change_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); +#endif /* _SUPPORT_AUDIO */ \ No newline at end of file diff --git a/src/prompt.c b/src/prompt.c index bda06e0..1539f6a 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -54,6 +54,13 @@ const uint8_t glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = { { "/note" }, { "/quit" }, { "/status" }, + +#ifdef _SUPPORT_AUDIO + + { "/lsdev" }, + { "/sdev" }, + +#endif /* _SUPPORT_AUDIO */ }; /* prevents input string from eating system messages: call this prior to printing a prompt message diff --git a/src/prompt.h b/src/prompt.h index 51acd59..aca8844 100644 --- a/src/prompt.h +++ b/src/prompt.h @@ -25,7 +25,12 @@ #define X_OFST 2 /* offset to account for prompt char */ -#define AC_NUM_GLOB_COMMANDS 15 + +#ifdef _SUPPORT_AUDIO + #define AC_NUM_GLOB_COMMANDS 17 +#else + #define AC_NUM_GLOB_COMMANDS 15 +#endif /* _SUPPORT_AUDIO */ ToxWindow new_prompt(void); void prep_prompt_win(void); From 6c2ae4ad24aa1db10bc88442c7a5e839b97383a4 Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 8 Mar 2014 02:09:11 +0100 Subject: [PATCH 5/8] Don't allow changing device while transmission is active --- src/audio_call.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/audio_call.c b/src/audio_call.c index 778eb9d..1aaa035 100644 --- a/src/audio_call.c +++ b/src/audio_call.c @@ -530,6 +530,11 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char ( goto on_error; } + if ( ASettins.ttas ) { /* Transmission is active */ + error_str = "Cannot change device while active transmission"; + goto on_error; + } + _devices type; if ( strcmp(argv[1], "in") == 0 ) /* Input devices */ From 1fd07837ea35de570aa2ec2c20fa23b0fdc2ed2e Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 8 Mar 2014 16:36:42 +0100 Subject: [PATCH 6/8] Fixed build problems --- configure.ac | 6 +----- src/execute.c | 5 +++++ src/global_commands.c | 4 ++-- src/groupchat.c | 2 +- src/main.c | 15 +++++++++------ 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index e17e4b4..68a99e8 100644 --- a/configure.ac +++ b/configure.ac @@ -428,7 +428,7 @@ if test "x$BUILD_AV" = "xyes"; then AC_CHECK_HEADER([tox/toxav.h], [ # Place define for audio support - AC_DEFINE([_SUPPORT_AUDIO], [], [If audio supported]) + AC_DEFINE([_SUPPORT_AUDIO], [], [Is audio supported]) AC_MSG_NOTICE([Building with audio support]) ], [ @@ -448,10 +448,6 @@ fi AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes") - -#debug mode -CFLAGS="-ggdb3 -O0 -pg" - TOXIC_VERSION="$PACKAGE_VERSION" AC_PATH_PROG([GIT], [git], [no]) if test "x$GIT" != "xno"; then diff --git a/src/execute.c b/src/execute.c index 3be7619..62581ad 100644 --- a/src/execute.c +++ b/src/execute.c @@ -20,8 +20,13 @@ * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include +#include #include "toxic_windows.h" #include "execute.h" diff --git a/src/global_commands.c b/src/global_commands.c index e0a7c78..cb2a993 100644 --- a/src/global_commands.c +++ b/src/global_commands.c @@ -378,10 +378,10 @@ void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a wprintw(window, " /clear : Clear the window\n"); wprintw(window, " /quit or /exit : Exit Toxic\n"); - #ifdef _SUPPORT_AUDIO +#ifdef _SUPPORT_AUDIO wprintw(window, " /lsdev : List devices where type: in|out\n"); wprintw(window, " /sdev : Set active device\n"); - #endif /* _SUPPORT_AUDIO */ +#endif /* _SUPPORT_AUDIO */ wattron(window, COLOR_PAIR(CYAN) | A_BOLD); wprintw(window, " * Argument messages must be enclosed in quotation marks.\n"); diff --git a/src/groupchat.c b/src/groupchat.c index 2f30ff9..86cbd11 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -43,7 +43,7 @@ static GroupChat groupchats[MAX_WINDOWS_NUM]; static int max_groupchat_index = 0; /* temporary until group chats have unique commands */ -extern glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE]; +extern const uint8_t glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE]; int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum) { diff --git a/src/main.c b/src/main.c index 57ae644..2b57c08 100644 --- a/src/main.c +++ b/src/main.c @@ -68,6 +68,10 @@ #define PACKAGE_DATADIR "." #endif +#ifdef _SUPPORT_AUDIO + ToxAv* av; +#endif /* _SUPPORT_AUDIO */ + /* Export for use in Callbacks */ char *DATA_FILE = NULL; ToxWindow *prompt = NULL; @@ -405,6 +409,9 @@ void exit_toxic(Tox *m) free(prompt->promptbuf->log); free(prompt->promptbuf); tox_kill(m); + #ifdef _SUPPORT_AUDIO + terminate_audio(prompt, av); + #endif /* _SUPPORT_AUDIO */ endwin(); exit(EXIT_SUCCESS); } @@ -486,7 +493,7 @@ int main(int argc, char *argv[]) wprintw(prompt->window, "Starting audio...\n"); attroff(COLOR_PAIR(RED) | A_BOLD); - ToxAv* av = init_audio(prompt, m); + av = init_audio(prompt, m); if ( errors() == NoError ) wprintw(prompt->window, "Audio started with no problems.\n"); @@ -518,10 +525,6 @@ int main(int argc, char *argv[]) while (true) do_toxic(m, prompt); - -#ifdef _SUPPORT_AUDIO - terminate_audio(prompt, av); -#endif /* _SUPPORT_AUDIO */ - + return 0; } From da924f07a987223fc98bed5075927a4f2f044a9c Mon Sep 17 00:00:00 2001 From: mannol Date: Tue, 11 Mar 2014 00:34:18 +0100 Subject: [PATCH 7/8] Updated to latest core --- src/audio_call.c | 30 +++++++++++++++--------------- src/file_senders.c | 4 ++++ src/log.c | 4 ++++ src/misc_tools.c | 4 ++++ src/toxic_strings.c | 4 ++++ 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/audio_call.c b/src/audio_call.c index 1aaa035..74aee64 100644 --- a/src/audio_call.c +++ b/src/audio_call.c @@ -140,25 +140,25 @@ ToxAv* init_audio(ToxWindow* window, Tox* tox) /* Streaming stuff from core */ - ASettins.av = toxav_new(tox, window, 0, 0); + ASettins.av = toxav_new(tox, 0, 0); if ( !ASettins.av ) { ASettins.errors |= ErrorStartingCoreAudio; return NULL; } - toxav_register_callstate_callback(callback_call_started, av_OnStart); - toxav_register_callstate_callback(callback_call_canceled, av_OnCancel); - toxav_register_callstate_callback(callback_call_rejected, av_OnReject); - toxav_register_callstate_callback(callback_call_ended, av_OnEnd); - toxav_register_callstate_callback(callback_recv_invite, av_OnInvite); + toxav_register_callstate_callback(callback_call_started, av_OnStart, window); + toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, window); + toxav_register_callstate_callback(callback_call_rejected, av_OnReject, window); + toxav_register_callstate_callback(callback_call_ended, av_OnEnd, window); + toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, window); - toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging); - toxav_register_callstate_callback(callback_recv_starting, av_OnStarting); - toxav_register_callstate_callback(callback_recv_ending, av_OnEnding); + toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, window); + toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, window); + toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, window); - toxav_register_callstate_callback(callback_recv_error, av_OnError); - toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout); + toxav_register_callstate_callback(callback_recv_error, av_OnError, window); + toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, window); return ASettins.av; } @@ -295,8 +295,8 @@ cleanup: int start_transmission() { - if ( !toxav_audio_decoding(ASettins.av) || - !toxav_audio_encoding(ASettins.av) ) + if ( !toxav_capability_supported(ASettins.av, AudioDecoding) || + !toxav_capability_supported(ASettins.av, AudioEncoding) ) return -1; /* Don't provide support for video */ @@ -324,8 +324,8 @@ int stop_transmission() * Callbacks */ -#define CB_BODY(Arg, onFunc) do { ToxWindow* windows = toxav_get_agent_handler(Arg); int i;\ -for (i = 0; i < MAX_WINDOWS_NUM; ++i) if (windows[i].onFunc != NULL) windows[i].onFunc(&windows[i], Arg); } while (0) +#define CB_BODY(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], ASettins.av); } while (0) void *callback_recv_invite ( void* arg ) { diff --git a/src/file_senders.c b/src/file_senders.c index d643bf4..b9d81fe 100644 --- a/src/file_senders.c +++ b/src/file_senders.c @@ -20,6 +20,10 @@ * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include diff --git a/src/log.c b/src/log.c index 0b41b43..5f8b132 100644 --- a/src/log.c +++ b/src/log.c @@ -20,6 +20,10 @@ * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include diff --git a/src/misc_tools.c b/src/misc_tools.c index be41bc1..d078e37 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -20,6 +20,10 @@ * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include diff --git a/src/toxic_strings.c b/src/toxic_strings.c index efebc03..8935954 100644 --- a/src/toxic_strings.c +++ b/src/toxic_strings.c @@ -20,6 +20,10 @@ * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include From e6f285adc7f99fafb7f56f655f81f37971c656a2 Mon Sep 17 00:00:00 2001 From: mannol Date: Tue, 11 Mar 2014 01:04:53 +0100 Subject: [PATCH 8/8] Update with latest core --- src/friendlist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/friendlist.c b/src/friendlist.c index ebfcb3c..f4df519 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -479,7 +479,7 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av) Tox* m = toxav_get_tox(av); if (friends[id].chatwin == -1) { - if (num_active_windows() < MAX_WINDOWS_NUM) { + if (get_num_active_windows() < MAX_WINDOWS_NUM) { friends[id].chatwin = add_window(m, new_chat(m, friends[id].num)); } else { uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};