1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-22 15:13:03 +01:00

Implement push-to-talk for conference audio

This commit is contained in:
jfreegman 2020-11-18 16:57:26 -05:00
parent 31f36318a2
commit 41be04a142
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
11 changed files with 135 additions and 19 deletions

View File

@ -222,6 +222,11 @@ Audio output device\&. Integer value\&. Number corresponds to
Voice Activity Detection threshold\&. Float value\&. Recommended values are 1\&.0\-40\&.0 Voice Activity Detection threshold\&. Float value\&. Recommended values are 1\&.0\-40\&.0
.RE .RE
.PP .PP
\fBpush_to_talk\fR
.RS 4
Enable/Disable Push\-To\-Talk for conference audio chats (active key is F2)\&. true or false
.RE
.PP
\fBconference_audio_channels\fR \fBconference_audio_channels\fR
.RS 4 .RS 4
Number of channels for conference audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo) Number of channels for conference audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)

View File

@ -145,6 +145,9 @@ OPTIONS
*chat_audio_channels*;; *chat_audio_channels*;;
Number of channels for 1-on-1 audio broadcast. Integer value. 1 (mono) or 2 (stereo) Number of channels for 1-on-1 audio broadcast. Integer value. 1 (mono) or 2 (stereo)
*push_to_talk*;;
Enable/Disable Push-To-Talk for conference audio chats (active key is F2). true or false
*tox*:: *tox*::
Configuration related to paths. Configuration related to paths.

View File

@ -90,6 +90,9 @@ audio = {
// Number of channels to use for 1-on-1 audio broadcasts; 1 for mono, 2 for stereo. // Number of channels to use for 1-on-1 audio broadcasts; 1 for mono, 2 for stereo.
chat_audio_channels=2; chat_audio_channels=2;
// toggle conference push-to-talk
push_to_talk=false;
}; };
tox = { tox = {

View File

@ -100,6 +100,7 @@ static const char *conference_cmd_list[] = {
"/quit", "/quit",
"/requests", "/requests",
#ifdef AUDIO #ifdef AUDIO
"/ptt",
"/sense", "/sense",
#endif #endif
"/status", "/status",
@ -200,6 +201,10 @@ int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char
conferences[i].audio_enabled = false; conferences[i].audio_enabled = false;
conferences[i].last_sent_audio = 0; conferences[i].last_sent_audio = 0;
#ifdef AUDIO
conferences[i].push_to_talk_enabled = user_settings->push_to_talk;
#endif
set_active_window_index(conferences[i].chatwin); set_active_window_index(conferences[i].chatwin);
conference_set_title(self, conferencenum, title, length); conference_set_title(self, conferencenum, title, length);
@ -568,6 +573,22 @@ static ConferencePeer *peer_in_conference(uint32_t conferencenum, uint32_t peern
} }
#ifdef AUDIO #ifdef AUDIO
/* Return true if ptt is disabled or enabled and active. */
static bool conference_check_push_to_talk(ConferenceChat *chat)
{
if (!chat->push_to_talk_enabled) {
return true;
}
return !timed_out(chat->ptt_last_pushed, 1);
}
static void conference_enable_push_to_talk(ConferenceChat *chat)
{
chat->ptt_last_pushed = get_unix_time();
}
static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t peernum) static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t peernum)
{ {
ConferenceChat *chat = &conferences[conferencenum]; ConferenceChat *chat = &conferences[conferencenum];
@ -599,7 +620,7 @@ static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t pee
const float angle = asinf(peer_posn - (float)(num_posns - 1) / 2); const float angle = asinf(peer_posn - (float)(num_posns - 1) / 2);
set_source_position(peer->audio_out_idx, sinf(angle), cosf(angle), 0); set_source_position(peer->audio_out_idx, sinf(angle), cosf(angle), 0);
} }
#endif #endif // AUDIO
static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers, uint8_t *pubkey, uint32_t *idx) static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers, uint8_t *pubkey, uint32_t *idx)
@ -774,7 +795,6 @@ static int sidebar_offset(uint32_t conferencenum)
return 2 + conferences[conferencenum].audio_enabled; return 2 + conferences[conferencenum].audio_enabled;
} }
/* /*
* Return true if input is recognized by handler * Return true if input is recognized by handler
*/ */
@ -817,6 +837,15 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
bool input_ret = false; bool input_ret = false;
ConferenceChat *chat = &conferences[self->num]; ConferenceChat *chat = &conferences[self->num];
#ifdef AUDIO
if (chat->audio_enabled && chat->push_to_talk_enabled && key == KEY_F(2)) {
input_ret = true;
conference_enable_push_to_talk(chat);
}
#endif // AUDIO
if (key == L'\t') { /* TAB key: auto-completes peer name or command */ if (key == L'\t') { /* TAB key: auto-completes peer name or command */
input_ret = true; input_ret = true;
@ -997,6 +1026,12 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
return; return;
} }
ConferenceChat *chat = &conferences[self->num];
if (!chat->active) {
return;
}
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
@ -1019,8 +1054,8 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE); mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
const uint32_t num_peers = conferences[self->num].num_peers; const uint32_t num_peers = chat->num_peers;
const bool audio = conferences[self->num].audio_enabled; const bool audio = chat->audio_enabled;
const int header_lines = sidebar_offset(self->num); const int header_lines = sidebar_offset(self->num);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
@ -1029,32 +1064,45 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
if (audio) { if (audio) {
#ifdef AUDIO #ifdef AUDIO
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
const bool mic_on = !device_is_muted(input, conferences[self->num].audio_in_idx); const bool ptt_idle = !conference_check_push_to_talk(chat) && chat->push_to_talk_enabled;
const bool mic_on = !device_is_muted(input, chat->audio_in_idx);
const float volume = get_input_volume(); const float volume = get_input_volume();
const float threshold = device_get_VAD_threshold(conferences[self->num].audio_in_idx); const float threshold = device_get_VAD_threshold(chat->audio_in_idx);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
wmove(ctx->sidebar, line, 1); wmove(ctx->sidebar, line, 1);
wattron(ctx->sidebar, A_BOLD); wattron(ctx->sidebar, A_BOLD);
wprintw(ctx->sidebar, "Mic: "); wprintw(ctx->sidebar, "Mic: ");
const int color = mic_on && volume > threshold ? GREEN : RED;
wattron(ctx->sidebar, COLOR_PAIR(color));
if (mic_on) { if (!mic_on) {
wattron(ctx->sidebar, COLOR_PAIR(RED));
wprintw(ctx->sidebar, "MUTED");
wattroff(ctx->sidebar, COLOR_PAIR(RED));
} else if (ptt_idle) {
wattron(ctx->sidebar, COLOR_PAIR(GREEN));
wprintw(ctx->sidebar, "PTT");
wattroff(ctx->sidebar, COLOR_PAIR(GREEN));
} else {
const int color = volume > threshold ? GREEN : RED;
wattron(ctx->sidebar, COLOR_PAIR(color));
float v = volume; float v = volume;
if (v <= 0.0f) {
wprintw(ctx->sidebar, ".");
}
while (v > 0.0f) { while (v > 0.0f) {
wprintw(ctx->sidebar, v > 10.0f ? (v > 15.0f ? "*" : "+") : (v > 5.0f ? "-" : ".")); wprintw(ctx->sidebar, v > 10.0f ? (v > 15.0f ? "*" : "+") : (v > 5.0f ? "-" : "."));
v -= 20.0f; v -= 20.0f;
} }
} else {
wprintw(ctx->sidebar, "OFF"); wattroff(ctx->sidebar, COLOR_PAIR(color));
} }
wattroff(ctx->sidebar, COLOR_PAIR(color));
wattroff(ctx->sidebar, A_BOLD); wattroff(ctx->sidebar, A_BOLD);
++line; ++line;
#endif #endif // AUDIO
} }
wmove(ctx->sidebar, line, 1); wmove(ctx->sidebar, line, 1);
@ -1195,7 +1243,13 @@ static void conference_read_device_callback(const int16_t *captured, uint32_t si
AudioInputCallbackData *audio_input_callback_data = (AudioInputCallbackData *)data; AudioInputCallbackData *audio_input_callback_data = (AudioInputCallbackData *)data;
conferences[audio_input_callback_data->conferencenum].last_sent_audio = get_unix_time(); ConferenceChat *chat = &conferences[audio_input_callback_data->conferencenum];
if (!conference_check_push_to_talk(chat)) {
return;
}
chat->last_sent_audio = get_unix_time();
int channels = user_settings->conference_audio_channels; int channels = user_settings->conference_audio_channels;
@ -1228,6 +1282,19 @@ bool init_conference_audio_input(Tox *tox, uint32_t conferencenum)
return success; return success;
} }
bool toggle_conference_push_to_talk(uint32_t conferencenum, bool enabled)
{
ConferenceChat *chat = &conferences[conferencenum];
if (!chat->active) {
return false;
}
chat->push_to_talk_enabled = enabled;
return true;
}
bool enable_conference_audio(Tox *tox, uint32_t conferencenum) bool enable_conference_audio(Tox *tox, uint32_t conferencenum)
{ {
if (!toxav_groupchat_av_enabled(tox, conferencenum)) { if (!toxav_groupchat_av_enabled(tox, conferencenum)) {
@ -1312,4 +1379,4 @@ float conference_get_VAD_threshold(uint32_t conferencenum)
return device_get_VAD_threshold(chat->audio_in_idx); return device_get_VAD_threshold(chat->audio_in_idx);
} }
#endif #endif // AUDIO

View File

@ -74,6 +74,9 @@ typedef struct {
NameListEntry *name_list; NameListEntry *name_list;
uint32_t num_peers; uint32_t num_peers;
bool push_to_talk_enabled;
time_t ptt_last_pushed;
bool audio_enabled; bool audio_enabled;
time_t last_sent_audio; time_t last_sent_audio;
uint32_t audio_in_idx; uint32_t audio_in_idx;
@ -104,6 +107,7 @@ uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *pre
bool init_conference_audio_input(Tox *tox, uint32_t conferencenum); bool init_conference_audio_input(Tox *tox, uint32_t conferencenum);
bool enable_conference_audio(Tox *tox, uint32_t conferencenum); bool enable_conference_audio(Tox *tox, uint32_t conferencenum);
bool disable_conference_audio(Tox *tox, uint32_t conferencenum); bool disable_conference_audio(Tox *tox, uint32_t conferencenum);
bool toggle_conference_push_to_talk(uint32_t conferencenum, bool enabled);
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum, void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum,
const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
sample_rate, void *userdata); sample_rate, void *userdata);

View File

@ -112,7 +112,8 @@ void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
} }
if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) { if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) {
print_err(self, enable ? "Enabled conference audio" : "Disabled conference audio"); print_err(self, enable ? "Enabled conference audio. Use the '/ptt' command to toggle Push-To-Talk."
: "Disabled conference audio");
} else { } else {
print_err(self, enable ? "Failed to enable audio" : "Failed to disable audio"); print_err(self, enable ? "Failed to enable audio" : "Failed to disable audio");
} }
@ -150,7 +151,7 @@ void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
if (conference_mute_peer(m, self->num, entries[0]->peernum)) { if (conference_mute_peer(m, self->num, entries[0]->peernum)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toggled audio mute status of %s", entries[0]->name); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toggled audio mute status of %s", entries[0]->name);
} else { } else {
print_err(self, "No such audio peer"); print_err(self, "Peer is not on the call");
} }
} }
} }
@ -185,4 +186,28 @@ void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, cha
print_err(self, "Failed to set conference audio input sensitivity."); print_err(self, "Failed to set conference audio input sensitivity.");
} }
} }
void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
bool enable;
if (argc == 1 && !strcasecmp(argv[1], "on")) {
enable = true;
} else if (argc == 1 && !strcasecmp(argv[1], "off")) {
enable = false;
} else {
print_err(self, "Please specify: on | off");
return;
}
if (!toggle_conference_push_to_talk(self->num, enable)) {
print_err(self, "Failed to toggle push to talk.");
return;
}
print_err(self, enable ? "Push-To-Talk is enabled. Push F2 to activate" : "Push-To-Talk is disabled");
}
#endif /* AUDIO */ #endif /* AUDIO */

View File

@ -30,5 +30,6 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* CONFERENCE_COMMANDS_H */ #endif /* CONFERENCE_COMMANDS_H */

View File

@ -105,6 +105,7 @@ static struct cmd_func conference_commands[] = {
#ifdef AUDIO #ifdef AUDIO
{ "/audio", cmd_enable_audio }, { "/audio", cmd_enable_audio },
{ "/mute", cmd_conference_mute }, { "/mute", cmd_conference_mute },
{ "/ptt", cmd_conference_push_to_talk },
{ "/sense", cmd_conference_sense }, { "/sense", cmd_conference_sense },
#endif /* AUDIO */ #endif /* AUDIO */
{ NULL, NULL }, { NULL, NULL },

View File

@ -306,7 +306,7 @@ static void help_draw_conference(ToxWindow *self)
wprintw(win, "Conference commands:\n"); wprintw(win, "Conference commands:\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED)); wattroff(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, " /title <msg> : Set conference title (show current title if no msg)\n"); wprintw(win, " /title <msg> : Show/set conference title\n");
#ifdef AUDIO #ifdef AUDIO
wattron(win, A_BOLD); wattron(win, A_BOLD);
wprintw(win, "\n Audio:\n"); wprintw(win, "\n Audio:\n");
@ -314,6 +314,7 @@ static void help_draw_conference(ToxWindow *self)
wprintw(win, " /audio <on> or <off> : Enable/disable audio in an audio conference\n"); wprintw(win, " /audio <on> or <off> : Enable/disable audio in an audio conference\n");
wprintw(win, " /mute : Toggle self audio mute status\n"); wprintw(win, " /mute : Toggle self audio mute status\n");
wprintw(win, " /mute <nick> or <pubkey> : Toggle peer audio mute status\n"); wprintw(win, " /mute <nick> or <pubkey> : Toggle peer audio mute status\n");
wprintw(win, " /ptt <on> or <off> : Toggle audio input Push-To-Talk (F2 to activate)\n");
wprintw(win, " /sense <n> : VAD sensitivity threshold\n\n"); wprintw(win, " /sense <n> : VAD sensitivity threshold\n\n");
#endif #endif
@ -403,7 +404,7 @@ void help_onKey(ToxWindow *self, wint_t key)
case L'o': case L'o':
height = 6; height = 6;
#ifdef AUDIO #ifdef AUDIO
height += 5; height += 7;
#endif #endif
help_init_window(self, height, 80); help_init_window(self, height, 80);
self->help->type = HELP_CONFERENCE; self->help->type = HELP_CONFERENCE;

View File

@ -207,6 +207,7 @@ static const struct audio_strings {
const char *VAD_threshold; const char *VAD_threshold;
const char *conference_audio_channels; const char *conference_audio_channels;
const char *chat_audio_channels; const char *chat_audio_channels;
const char *push_to_talk;
} audio_strings = { } audio_strings = {
"audio", "audio",
"input_device", "input_device",
@ -214,6 +215,7 @@ static const struct audio_strings {
"VAD_threshold", "VAD_threshold",
"conference_audio_channels", "conference_audio_channels",
"chat_audio_channels", "chat_audio_channels",
"push_to_talk",
}; };
static void audio_defaults(struct user_settings *settings) static void audio_defaults(struct user_settings *settings)
@ -223,6 +225,7 @@ static void audio_defaults(struct user_settings *settings)
settings->VAD_threshold = 5.0; settings->VAD_threshold = 5.0;
settings->conference_audio_channels = 1; settings->conference_audio_channels = 1;
settings->chat_audio_channels = 2; settings->chat_audio_channels = 2;
settings->push_to_talk = 0;
} }
#endif #endif
@ -519,6 +522,8 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_int(setting, audio_strings.chat_audio_channels, &s->chat_audio_channels); config_setting_lookup_int(setting, audio_strings.chat_audio_channels, &s->chat_audio_channels);
s->chat_audio_channels = s->chat_audio_channels <= 0 || s->chat_audio_channels > 2 ? 2 : s->chat_audio_channels; s->chat_audio_channels = s->chat_audio_channels <= 0 || s->chat_audio_channels > 2 ? 2 : s->chat_audio_channels;
config_setting_lookup_bool(setting, audio_strings.push_to_talk, &s->push_to_talk);
} }
#endif #endif

View File

@ -87,6 +87,7 @@ struct user_settings {
double VAD_threshold; double VAD_threshold;
int conference_audio_channels; int conference_audio_channels;
int chat_audio_channels; int chat_audio_channels;
int push_to_talk; /* boolean */
#endif #endif
}; };