1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-12-27 04:03:24 +01:00

Implement simplistic VAD

This commit is contained in:
zugz (tox) 2020-05-07 00:00:00 +00:00
parent ddcf224db2
commit 7dead5ec96
No known key found for this signature in database
GPG Key ID: 6F2BDA289D04F249
18 changed files with 316 additions and 159 deletions

View File

@ -11,6 +11,7 @@ endif
CHECK_AUDIO_LIBS := $(shell $(PKG_CONFIG) --exists $(AUDIO_LIBS) || echo -n "error")
ifneq ($(CHECK_AUDIO_LIBS), error)
LIBS += $(AUDIO_LIBS)
LDFLAGS += -lm
CFLAGS += $(AUDIO_CFLAGS)
OBJ += $(AUDIO_OBJ)
else ifneq ($(MAKECMDGOALS), clean)

View File

@ -217,9 +217,9 @@ Audio output device\&. Integer value\&. Number corresponds to
/lsdev out
.RE
.PP
\fBVAD_treshold\fR
\fBVAD_threshold\fR
.RS 4
Voice Activity Detection treshold\&. Float value\&. Recommended values are around 40\&.0
Voice Activity Detection threshold\&. Float value\&. Recommended values are 1\&.0-40\&.0
.RE
.RE
.PP

View File

@ -135,9 +135,9 @@ OPTIONS
*output_device*;;
Audio output device. Integer value. Number corresponds to `/lsdev out`
*VAD_treshold*;;
Voice Activity Detection treshold. Float value. Recommended values are
around 40.0
*VAD_threshold*;;
Voice Activity Detection threshold. Float value. Recommended values are
1.0-40.0
*tox*::
Configuration related to paths.

View File

@ -82,8 +82,8 @@ audio = {
// preferred audio output device; numbers correspond to /lsdev out
output_device=0;
// default VAD treshold; float (recommended values are around 40)
VAD_treshold=40.0;
// default VAD threshold; float (recommended values are 1.0-40.0)
VAD_threshold=5.0;
};
tox = {

View File

@ -213,9 +213,8 @@ int start_transmission(ToxWindow *self, Call *call)
return -1;
}
DeviceError error = open_input_device(&call->in_idx, read_device_callback, &self->num, true,
DeviceError error = open_input_device(&call->in_idx, read_device_callback, &self->num, false,
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels);
/* Set VAD as true for all; TODO: Make it more dynamic */
if (error != de_None) {
if (error == de_FailedStart) {
@ -819,7 +818,7 @@ void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
/* Call must be active */
if (self->is_call) {
device_set_VAD_treshold(CallControl.calls[self->num].in_idx, value);
device_set_VAD_threshold(CallControl.calls[self->num].in_idx, value);
self->chatwin->infobox.vad_lvl = value;
}

View File

@ -22,10 +22,6 @@
#include "audio_device.h"
#ifdef AUDIO
#include "audio_call.h"
#endif
#include "line_info.h"
#include "settings.h"
#include "misc_tools.h"
@ -43,6 +39,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
extern struct user_settings *user_settings;
extern struct Winthread Winthread;
@ -70,11 +67,8 @@ typedef struct Device {
// used only by input devices:
DataHandleCallback cb;
void *cb_data;
// TODO: implement VAD, and fix the typo, or remove these.
bool enable_VAD;
#ifdef AUDIO
float VAD_treshold; /* 40 is usually recommended value */
#endif
float VAD_threshold;
uint32_t VAD_samples_remaining;
// used only by output devices:
uint32_t source;
@ -89,9 +83,11 @@ typedef struct AudioState {
uint32_t num_devices[2];
FrameInfo capture_frame_info;
float input_volume;
// mutexes to prevent changes to input resp. output devices and al_devices
// during poll_input iterations resp. calls to write_out
// during poll_input iterations resp. calls to write_out;
// mutex[input] also used to lock input_volume which poll_input writes to.
pthread_mutex_t mutex[2];
// TODO: unused
@ -118,7 +114,9 @@ static void unlock(DeviceType type)
static bool thread_running = true,
thread_paused = true; /* Thread control */
#ifdef AUDIO
static void *poll_input(void *);
#endif
static uint32_t sound_mode(bool stereo)
{
@ -148,6 +146,7 @@ DeviceError init_devices(void)
}
}
#ifdef AUDIO
// Start poll thread
pthread_t thread_id;
@ -156,6 +155,8 @@ DeviceError init_devices(void)
return de_InternalError;
}
#endif
return de_None;
}
@ -247,8 +248,7 @@ bool device_is_muted(DeviceType type, uint32_t device_idx)
return device->muted;
}
#ifdef AUDIO
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
DeviceError device_set_VAD_threshold(uint32_t device_idx, float value)
{
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
@ -260,14 +260,32 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
return de_DeviceNotActive;
}
if (value <= 0.0f) {
value = 0.0f;
}
lock(input);
device->VAD_treshold = value;
device->VAD_threshold = value;
unlock(input);
return de_None;
}
#endif
float device_get_VAD_threshold(uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) {
return 0.0;
}
Device *device = &audio_state->devices[input][device_idx];
if (!device->active) {
return 0.0;
}
return device->VAD_threshold;
}
DeviceError set_source_position(uint32_t device_idx, float x, float y, float z)
{
@ -511,9 +529,10 @@ static DeviceError open_device(DeviceType type, uint32_t *device_idx,
if (type == input) {
device->cb = cb;
device->cb_data = cb_data;
device->enable_VAD = enable_VAD;
#ifdef AUDIO
device->VAD_treshold = user_settings->VAD_treshold;
device->VAD_threshold = enable_VAD ? user_settings->VAD_threshold : 0.0f;
#else
device->VAD_threshold = 0.0f;
#endif
} else {
if (open_source(device) != de_None) {
@ -606,7 +625,7 @@ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t sample_
ALuint *bufids = malloc(processed * sizeof(ALuint));
if (bufids == NULL) {
pthread_mutex_unlock(device->mutex);
unlock(output);
return de_InternalError;
}
@ -639,6 +658,33 @@ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t sample_
return de_None;
}
#ifdef AUDIO
/* Adapted from qtox,
* Copyright © 2014-2019 by The qTox Project Contributors
*
* return normalized volume of buffer in range 0.0-100.0
*/
float volume(int16_t *frame, uint32_t samples)
{
float sum_of_squares = 0;
for (uint32_t i = 0; i < samples; i++) {
const float sample = (float)(frame[i]) / INT16_MAX;
sum_of_squares += powf(sample, 2);
}
const float root_mean_square = sqrtf(sum_of_squares / samples);
const float root_two = 1.414213562;
// normalizedVolume == 1.0 corresponds to a sine wave of maximal amplitude
const float normalized_volume = root_mean_square * root_two;
return 100.0f * fminf(1.0f, normalized_volume);
}
// Time in ms for which we continue to capture audio after VAD is triggered:
#define VAD_TIME 250
#define FRAME_BUF_SIZE 16000
static void *poll_input(void *arg)
@ -679,9 +725,23 @@ static void *poll_input(void *arg)
pthread_mutex_lock(&Winthread.lock);
lock(input);
float frame_volume = volume(frame_buf, f_size);
audio_state->input_volume = frame_volume;
for (int i = 0; i < MAX_DEVICES; i++) {
Device *device = &audio_state->devices[input][i];
if (device->VAD_threshold != 0.0f) {
if (frame_volume >= device->VAD_threshold) {
device->VAD_samples_remaining = VAD_TIME * (audio_state->capture_frame_info.sample_rate / 1000);
} else if (device->VAD_samples_remaining < f_size) {
continue;
} else {
device->VAD_samples_remaining -= f_size;
}
}
if (device->active && !device->muted && device->cb) {
device->cb(frame_buf, f_size, device->cb_data);
}
@ -697,6 +757,20 @@ static void *poll_input(void *arg)
pthread_exit(NULL);
}
#endif
float get_input_volume(void)
{
float ret = 0.0f;
if (audio_state->al_device[input] != NULL) {
lock(input);
ret = audio_state->input_volume;
unlock(input);
}
return ret;
}
void print_al_devices(ToxWindow *self, DeviceType type)
{

View File

@ -66,9 +66,9 @@ DeviceError device_mute(DeviceType type, uint32_t device_idx);
bool device_is_muted(DeviceType type, uint32_t device_idx);
#ifdef AUDIO
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
#endif
DeviceError device_set_VAD_threshold(uint32_t device_idx, float value);
float device_get_VAD_threshold(uint32_t device_idx);
DeviceError set_source_position(uint32_t device_idx, float x, float y, float z);
@ -88,6 +88,9 @@ DeviceError close_device(DeviceType type, uint32_t device_idx);
DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t length, uint8_t channels,
uint32_t sample_rate);
/* return current input volume as float in range 0.0-100.0 */
float get_input_volume(void);
void print_al_devices(ToxWindow *self, DeviceType type);
DeviceError selection_valid(DeviceType type, int32_t selection);

View File

@ -950,7 +950,7 @@ static void init_infobox(ToxWindow *self)
ctx->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
ctx->infobox.starttime = get_unix_time();
ctx->infobox.vad_lvl = user_settings->VAD_treshold;
ctx->infobox.vad_lvl = 0.0f;
ctx->infobox.active = true;
strcpy(ctx->infobox.timestr, "00");
}

View File

@ -353,12 +353,14 @@ uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *pre
return 0;
}
const int len = strlen(prefix);
const size_t len = strlen(prefix);
if (len == 2 * TOX_PUBLIC_KEY_SIZE) {
for (uint32_t i = 0; i < chat->num_peers; ++i) {
if (strcasecmp(prefix, chat->name_list[i].pubkey_str) == 0) {
entries[0] = &chat->name_list[i];
NameListEntry *entry = &chat->name_list[i];
if (strcasecmp(prefix, entry->pubkey_str) == 0) {
entries[0] = entry;
return 1;
}
}
@ -367,9 +369,11 @@ uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *pre
uint32_t n = 0;
for (uint32_t i = 0; i < chat->num_peers; ++i) {
if (strncmp(prefix, chat->name_list[i].name, len) == 0
|| strncasecmp(prefix, chat->name_list[i].pubkey_str, len) == 0) {
entries[n] = &chat->name_list[i];
NameListEntry *entry = &chat->name_list[i];
if (strncmp(prefix, entry->name, len) == 0
|| strncasecmp(prefix, entry->pubkey_str, len) == 0) {
entries[n] = entry;
++n;
if (n == maxpeers) {
@ -418,11 +422,14 @@ static void conference_update_name_list(uint32_t conferencenum)
uint32_t count = 0;
for (uint32_t i = 0; i < chat->max_idx; ++i) {
if (chat->peer_list[i].active) {
memcpy(chat->name_list[count].name, chat->peer_list[i].name, chat->peer_list[i].name_length + 1);
bin_pubkey_to_string(chat->peer_list[i].pubkey, sizeof(chat->peer_list[i].pubkey),
chat->name_list[count].pubkey_str, sizeof(chat->name_list[count].pubkey_str));
chat->name_list[count].peernum = i;
const ConferencePeer *peer = &chat->peer_list[i];
NameListEntry *entry = &chat->name_list[count];
if (peer->active) {
memcpy(entry->name, peer->name, peer->name_length + 1);
bin_pubkey_to_string(peer->pubkey, sizeof(peer->pubkey),
entry->pubkey_str, sizeof(entry->pubkey_str));
entry->peernum = i;
++count;
}
}
@ -451,7 +458,7 @@ static int realloc_peer_list(ConferenceChat *chat, uint32_t num_peers)
return 0;
}
struct ConferencePeer *tmp_list = realloc(chat->peer_list, num_peers * sizeof(struct ConferencePeer));
ConferencePeer *tmp_list = realloc(chat->peer_list, num_peers * sizeof(ConferencePeer));
if (!tmp_list) {
return -1;
@ -462,13 +469,35 @@ static int realloc_peer_list(ConferenceChat *chat, uint32_t num_peers)
return 0;
}
/* return NULL if peer or conference doesn't exist */
static ConferencePeer *peer_in_conference(uint32_t conferencenum, uint32_t peernum)
{
if (conferencenum >= MAX_CONFERENCE_NUM) {
return NULL;
}
const ConferenceChat *chat = &conferences[conferencenum];
if (!chat->active || peernum > chat->max_idx) {
return NULL;
}
ConferencePeer *peer = &chat->peer_list[peernum];
if (!peer->active) {
return NULL;
}
return peer;
}
#ifdef AUDIO
static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t peernum)
{
ConferenceChat *chat = &conferences[conferencenum];
ConferencePeer *peer = &chat->peer_list[peernum];
if (!peer->sending_audio) {
if (peer == NULL || !peer->sending_audio) {
return;
}
@ -497,10 +526,10 @@ static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t pee
#endif
static bool find_peer_by_pubkey(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)
{
for (uint32_t i = 0; i < num_peers; ++i) {
ConferencePeer *peer = &list[i];
const ConferencePeer *peer = &list[i];
if (peer->active && memcmp(peer->pubkey, pubkey, TOX_PUBLIC_KEY_SIZE) == 0) {
*idx = i;
@ -567,7 +596,7 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
peer->active = true;
peer->name_length = length;
peer->peernumber = i;
peer->peernum = i;
#ifdef AUDIO
set_peer_audio_position(m, conferencenum, i);
@ -628,28 +657,19 @@ static void conference_onConferencePeerNameChange(ToxWindow *self, Tox *m, uint3
return;
}
ConferenceChat *chat = &conferences[conferencenum];
const ConferencePeer *peer = peer_in_conference(conferencenum, peernum);
if (!chat->active) {
return;
}
if (peer != NULL && peer->name_length > 0) {
ChatContext *ctx = self->chatwin;
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
for (uint32_t i = 0; i < chat->max_idx; ++i) {
ConferencePeer *peer = &chat->peer_list[i];
char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (const char *) name);
if (peer->active && peer->peernumber == peernum && peer->name_length > 0) {
ChatContext *ctx = self->chatwin;
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
write_to_log(tmp_event, peer->name, ctx->log, true);
line_info_add(self, timefrmt, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as ");
char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (const char *) name);
write_to_log(tmp_event, peer->name, ctx->log, true);
line_info_add(self, timefrmt, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as ");
break;
}
}
conference_onConferenceNameListChange(self, m, conferencenum);
@ -716,6 +736,7 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
bool input_ret = false;
ConferenceChat *chat = &conferences[self->num];
if (key == L'\t') { /* TAB key: auto-completes peer name or command */
input_ret = true;
@ -725,14 +746,14 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
/* TODO: make this not suck */
if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) {
const char **complete_strs = calloc(conferences[self->num].num_peers, sizeof(const char *));
const char **complete_strs = calloc(chat->num_peers, sizeof(const char *));
if (complete_strs) {
for (uint32_t i = 0; i < conferences[self->num].num_peers; ++i) {
complete_strs[i] = (const char *) conferences[self->num].name_list[i].name;
for (uint32_t i = 0; i < chat->num_peers; ++i) {
complete_strs[i] = (const char *) chat->name_list[i].name;
}
diff = complete_line(self, complete_strs, conferences[self->num].num_peers);
diff = complete_line(self, complete_strs, chat->num_peers);
free(complete_strs);
}
} else if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) {
@ -746,20 +767,20 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
#endif
else if (wcsncmp(ctx->line, L"/mute ", wcslen(L"/mute ")) == 0) {
const char **complete_strs = calloc(conferences[self->num].num_peers, sizeof(const char *));
const char **complete_strs = calloc(chat->num_peers, sizeof(const char *));
if (complete_strs) {
for (uint32_t i = 0; i < conferences[self->num].num_peers; ++i) {
complete_strs[i] = (const char *) conferences[self->num].name_list[i].name;
for (uint32_t i = 0; i < chat->num_peers; ++i) {
complete_strs[i] = (const char *) chat->name_list[i].name;
}
diff = complete_line(self, complete_strs, conferences[self->num].num_peers);
diff = complete_line(self, complete_strs, chat->num_peers);
if (diff == -1) {
for (uint32_t i = 0; i < conferences[self->num].num_peers; ++i) {
complete_strs[i] = (const char *) conferences[self->num].name_list[i].pubkey_str;
for (uint32_t i = 0; i < chat->num_peers; ++i) {
complete_strs[i] = (const char *) chat->name_list[i].pubkey_str;
}
diff = complete_line(self, complete_strs, conferences[self->num].num_peers);
diff = complete_line(self, complete_strs, chat->num_peers);
}
free(complete_strs);
@ -784,14 +805,14 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
input_ret = true;
const int L = y2 - CHATBOX_HEIGHT - sidebar_offset(self->num);
if (conferences[self->num].side_pos < (int64_t) conferences[self->num].num_peers - L) {
++conferences[self->num].side_pos;
if (chat->side_pos < (int64_t) chat->num_peers - L) {
++chat->side_pos;
}
} else if (key == T_KEY_C_UP) {
input_ret = true;
if (conferences[self->num].side_pos > 0) {
--conferences[self->num].side_pos;
if (chat->side_pos > 0) {
--chat->side_pos;
}
} else if (key == L'\r') {
input_ret = true;
@ -850,14 +871,14 @@ static void draw_peer(ToxWindow *self, Tox *m, ChatContext *ctx, uint32_t i)
if (audio) {
#ifdef AUDIO
pthread_mutex_lock(&Winthread.lock);
const ConferencePeer *peer = &conferences[self->num].peer_list[peernum];
const ConferencePeer *peer = peer_in_conference(self->num, peernum);
const bool audio_active = is_self
? !timed_out(conferences[self->num].last_sent_audio, 2)
: peer->active && peer->sending_audio && !timed_out(peer->last_audio_time, 2);
: peer != NULL && peer->sending_audio && !timed_out(peer->last_audio_time, 2);
const bool mute = audio_active &&
(is_self
? device_is_muted(input, conferences[self->num].audio_in_idx)
: device_is_muted(output, peer->audio_out_idx));
: peer != NULL && device_is_muted(output, peer->audio_out_idx));
pthread_mutex_unlock(&Winthread.lock);
const int aud_attr = A_BOLD | COLOR_PAIR(audio_active && !mute ? GREEN : RED);
@ -929,14 +950,27 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
#ifdef AUDIO
pthread_mutex_lock(&Winthread.lock);
const bool mic_on = !device_is_muted(input, conferences[self->num].audio_in_idx);
const float volume = get_input_volume();
const float threshold = device_get_VAD_threshold(conferences[self->num].audio_in_idx);
pthread_mutex_unlock(&Winthread.lock);
wmove(ctx->sidebar, line, 1);
wattron(ctx->sidebar, A_BOLD);
wprintw(ctx->sidebar, "Mic: ");
const int color = mic_on ? GREEN : RED;
const int color = mic_on && volume > threshold ? GREEN : RED;
wattron(ctx->sidebar, COLOR_PAIR(color));
wprintw(ctx->sidebar, mic_on ? "ON" : "OFF");
if (mic_on) {
float v = volume;
while (v > 0.0f) {
wprintw(ctx->sidebar, v > 10.0f ? (v > 15.0f ? "*" : "+") : (v > 5.0f ? "-" : "."));
v -= 20.0f;
}
} else {
wprintw(ctx->sidebar, "OFF");
}
wattroff(ctx->sidebar, COLOR_PAIR(color));
wattroff(ctx->sidebar, A_BOLD);
++line;
@ -953,10 +987,9 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
mvwhline(ctx->sidebar, line, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
++line;
int maxlines = y2 - header_lines - CHATBOX_HEIGHT;
uint32_t i;
for (i = 0; i < num_peers && i < maxlines; ++i) {
for (uint32_t i = 0;
i < num_peers && i < y2 - header_lines - CHATBOX_HEIGHT;
++i) {
wmove(ctx->sidebar, i + header_lines, 1);
draw_peer(self, m, ctx, i);
}
@ -1060,40 +1093,32 @@ static ToxWindow *new_conference_chat(uint32_t conferencenum)
#define CONFAV_AUDIO_CHANNELS 1
#define CONFAV_SAMPLES_PER_FRAME (CONFAV_SAMPLE_RATE * CONFAV_FRAME_DURATION / 1000)
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernumber, const int16_t *pcm,
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum, const int16_t *pcm,
unsigned int samples, uint8_t channels, uint32_t sample_rate, void *userdata)
{
ConferenceChat *chat = &conferences[conferencenum];
ConferencePeer *peer = peer_in_conference(conferencenum, peernum);
if (!chat->active) {
if (peer == NULL) {
return;
}
for (uint32_t i = 0; i < chat->max_idx; ++i) {
ConferencePeer *peer = &chat->peer_list[i];
if (!peer->active || peer->peernumber != peernumber) {
continue;
if (!peer->sending_audio) {
if (open_output_device(&peer->audio_out_idx,
sample_rate, CONFAV_FRAME_DURATION, channels) != de_None) {
// TODO: error message?
return;
}
if (!peer->sending_audio) {
if (open_output_device(&peer->audio_out_idx,
sample_rate, CONFAV_FRAME_DURATION, channels) != de_None) {
// TODO: error message?
return;
}
peer->sending_audio = true;
peer->sending_audio = true;
set_peer_audio_position(tox, conferencenum, i);
}
write_out(peer->audio_out_idx, pcm, samples, channels, sample_rate);
peer->last_audio_time = get_unix_time();
return;
set_peer_audio_position(tox, conferencenum, peernum);
}
write_out(peer->audio_out_idx, pcm, samples, channels, sample_rate);
peer->last_audio_time = get_unix_time();
return;
}
static void conference_read_device_callback(const int16_t *captured, uint32_t size, void *data)
@ -1155,12 +1180,12 @@ bool disable_conference_audio(Tox *tox, uint32_t conferencenum)
chat->audio_enabled = false;
}
return (toxav_groupchat_disable_av(tox, conferencenum) == 0);
return toxav_groupchat_disable_av(tox, conferencenum) == 0;
}
bool conference_mute_self(uint32_t conferencenum)
{
ConferenceChat *chat = &conferences[conferencenum];
const ConferenceChat *chat = &conferences[conferencenum];
if (!chat->active || !chat->audio_enabled) {
return false;
@ -1177,20 +1202,42 @@ bool conference_mute_peer(const Tox *m, uint32_t conferencenum, uint32_t peernum
return conference_mute_self(conferencenum);
}
ConferenceChat *chat = &conferences[conferencenum];
const ConferenceChat *chat = &conferences[conferencenum];
if (!chat->active || !chat->audio_enabled
|| peernum > chat->max_idx) {
return false;
}
const ConferencePeer *peer = &chat->peer_list[peernum];
const ConferencePeer *peer = peer_in_conference(conferencenum, peernum);
if (!peer->active || !peer->sending_audio) {
if (peer == NULL || !peer->sending_audio) {
return false;
}
device_mute(output, peer->audio_out_idx);
return true;
}
bool conference_set_VAD_threshold(uint32_t conferencenum, float threshold)
{
const ConferenceChat *chat = &conferences[conferencenum];
if (!chat->active || !chat->audio_enabled) {
return false;
}
return (device_set_VAD_threshold(chat->audio_in_idx, threshold) == de_None);
}
float conference_get_VAD_threshold(uint32_t conferencenum)
{
const ConferenceChat *chat = &conferences[conferencenum];
if (!chat->active || !chat->audio_enabled) {
return 0.0f;
}
return device_get_VAD_threshold(chat->audio_in_idx);
}
#endif

View File

@ -34,7 +34,7 @@ typedef struct ConferencePeer {
bool active;
uint8_t pubkey[TOX_PUBLIC_KEY_SIZE];
uint32_t peernumber;
uint32_t peernum; /* index in chat->peer_list */
char name[TOX_MAX_NAME_LENGTH];
size_t name_length;
@ -96,11 +96,13 @@ 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 enable_conference_audio(Tox *tox, uint32_t conferencenum);
bool disable_conference_audio(Tox *tox, uint32_t conferencenum);
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernumber,
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum,
const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
sample_rate, void *userdata);
bool conference_mute_self(uint32_t conferencenum);
bool conference_mute_peer(const Tox *m, uint32_t conferencenum, uint32_t peernum);
bool conference_set_VAD_threshold(uint32_t conferencenum, float threshold);
float conference_get_VAD_threshold(uint32_t conferencenum);
#endif /* CONFERENCE_H */

View File

@ -21,6 +21,7 @@
*/
#include <string.h>
#include <stdlib.h>
#include "toxic.h"
#include "windows.h"
@ -29,6 +30,11 @@
#include "log.h"
#include "conference.h"
static void print_err(ToxWindow *self, const char *error_str)
{
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
}
void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
@ -40,12 +46,12 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
size_t tlen = tox_conference_get_title_size(m, self->num, &err);
if (err != TOX_ERR_CONFERENCE_TITLE_OK || tlen >= sizeof(title)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set");
print_err(self, "Title is not set");
return;
}
if (!tox_conference_get_title(m, self->num, (uint8_t *) title, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set");
print_err(self, "Title is not set");
return;
}
@ -81,11 +87,11 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
write_to_log(tmp_event, selfnick, self->chatwin->log, true);
}
#ifdef AUDIO
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
#ifdef AUDIO
bool enable;
if (argc == 1 && !strcasecmp(argv[1], "on")) {
@ -93,43 +99,38 @@ void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
} else if (argc == 1 && !strcasecmp(argv[1], "off")) {
enable = false;
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please specify: on | off");
print_err(self, "Please specify: on | off");
return;
}
if ((enable ? enable_conference_audio : disable_conference_audio)(m, self->num)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, enable ? "Enabled conference audio" : "Disabled conference audio");
if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) {
print_err(self, enable ? "Enabled conference audio" : "Disabled conference audio");
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, enable ? "Failed to enable audio" : "Failed to disable audio");
print_err(self, enable ? "Failed to enable audio" : "Failed to disable audio");
}
#endif
}
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
#ifdef AUDIO
if (argc < 1) {
if (conference_mute_self(self->num)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toggled self audio mute status");
print_err(self, "Toggled self audio mute status");
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No audio input to mute");
print_err(self, "No audio input to mute");
}
} else {
NameListEntry *entries[16];
uint32_t n = get_name_list_entries_by_prefix(self->num, argv[1], entries, 16);
if (n == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No such peer");
print_err(self, "No such peer");
return;
}
if (n > 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
"Multiple matching peers (use /mute [public key] to disambiguate):");
print_err(self, "Multiple matching peers (use /mute [public key] to disambiguate):");
for (uint32_t i = 0; i < n; ++i) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s: %s", entries[i]->pubkey_str, entries[i]->name);
@ -141,9 +142,39 @@ void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
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);
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No such audio peer");
print_err(self, "No such audio peer");
}
}
#endif
}
void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
if (argc == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Current VAD threshold: %.1f",
(double) conference_get_VAD_threshold(self->num));
return;
}
if (argc > 1) {
print_err(self, "Only one argument allowed.");
return;
}
char *end;
float value = strtof(argv[1], &end);
if (*end) {
print_err(self, "Invalid input");
return;
}
if (conference_set_VAD_threshold(self->num, value)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Set VAD threshold to %.1f", (double) value);
} else {
print_err(self, "Failed to set conference audio input sensitivity.");
}
}
#endif /* AUDIO */

View File

@ -29,5 +29,6 @@
void cmd_conference_set_title(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_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* CONFERENCE_COMMANDS_H */

View File

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

View File

@ -311,7 +311,8 @@ static void help_draw_conference(ToxWindow *self)
wattroff(win, A_BOLD);
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 <nick> or <pubkey> : Toggle peer audio mute status\n\n");
wprintw(win, " /mute <nick> or <pubkey> : Toggle peer audio mute status\n");
wprintw(win, " /sense <n> : VAD sensitivity threshold\n\n");
#endif
help_draw_bottom_menu(win);

View File

@ -197,9 +197,7 @@ int bin_pubkey_to_string(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char
return -1;
}
size_t i;
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
for (size_t i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_pubkey[i] & 0xff);
}

View File

@ -204,19 +204,19 @@ static const struct audio_strings {
const char *self;
const char *input_device;
const char *output_device;
const char *VAD_treshold;
const char *VAD_threshold;
} audio_strings = {
"audio",
"input_device",
"output_device",
"VAD_treshold",
"VAD_threshold",
};
static void audio_defaults(struct user_settings *settings)
{
settings->audio_in_dev = 0;
settings->audio_out_dev = 0;
settings->VAD_treshold = 40.0;
settings->VAD_threshold = 5.0;
}
#endif
@ -505,7 +505,7 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_int(setting, audio_strings.output_device, &s->audio_out_dev);
s->audio_out_dev = s->audio_out_dev < 0 || s->audio_out_dev > MAX_DEVICES ? 0 : s->audio_out_dev;
config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold);
config_setting_lookup_float(setting, audio_strings.VAD_threshold, &s->VAD_threshold);
}
#endif

View File

@ -84,7 +84,7 @@ struct user_settings {
#ifdef AUDIO
int audio_in_dev;
int audio_out_dev;
double VAD_treshold;
double VAD_threshold;
#endif
};

View File

@ -1440,20 +1440,10 @@ int main(int argc, char **argv)
prompt_init_statusbar(prompt, m, !datafile_exists);
load_conferences(m);
/* thread for ncurses stuff */
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
}
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0) {
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
}
/* thread for message queue */
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0) {
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
}
#ifdef AUDIO
av = init_audio(prompt, m);
@ -1479,6 +1469,16 @@ int main(int argc, char **argv)
#endif /* AUDIO */
/* thread for ncurses stuff */
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0) {
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
}
/* thread for message queue */
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0) {
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
}
#ifdef PYTHON
init_python(m);