mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-25 17:23:03 +01:00
Implement simplistic VAD
This commit is contained in:
parent
ddcf224db2
commit
7dead5ec96
@ -11,6 +11,7 @@ endif
|
|||||||
CHECK_AUDIO_LIBS := $(shell $(PKG_CONFIG) --exists $(AUDIO_LIBS) || echo -n "error")
|
CHECK_AUDIO_LIBS := $(shell $(PKG_CONFIG) --exists $(AUDIO_LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_AUDIO_LIBS), error)
|
ifneq ($(CHECK_AUDIO_LIBS), error)
|
||||||
LIBS += $(AUDIO_LIBS)
|
LIBS += $(AUDIO_LIBS)
|
||||||
|
LDFLAGS += -lm
|
||||||
CFLAGS += $(AUDIO_CFLAGS)
|
CFLAGS += $(AUDIO_CFLAGS)
|
||||||
OBJ += $(AUDIO_OBJ)
|
OBJ += $(AUDIO_OBJ)
|
||||||
else ifneq ($(MAKECMDGOALS), clean)
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
|
@ -217,9 +217,9 @@ Audio output device\&. Integer value\&. Number corresponds to
|
|||||||
/lsdev out
|
/lsdev out
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\fBVAD_treshold\fR
|
\fBVAD_threshold\fR
|
||||||
.RS 4
|
.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
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
@ -135,9 +135,9 @@ OPTIONS
|
|||||||
*output_device*;;
|
*output_device*;;
|
||||||
Audio output device. Integer value. Number corresponds to `/lsdev out`
|
Audio output device. Integer value. Number corresponds to `/lsdev out`
|
||||||
|
|
||||||
*VAD_treshold*;;
|
*VAD_threshold*;;
|
||||||
Voice Activity Detection treshold. Float value. Recommended values are
|
Voice Activity Detection threshold. Float value. Recommended values are
|
||||||
around 40.0
|
1.0-40.0
|
||||||
|
|
||||||
*tox*::
|
*tox*::
|
||||||
Configuration related to paths.
|
Configuration related to paths.
|
||||||
|
@ -82,8 +82,8 @@ audio = {
|
|||||||
// preferred audio output device; numbers correspond to /lsdev out
|
// preferred audio output device; numbers correspond to /lsdev out
|
||||||
output_device=0;
|
output_device=0;
|
||||||
|
|
||||||
// default VAD treshold; float (recommended values are around 40)
|
// default VAD threshold; float (recommended values are 1.0-40.0)
|
||||||
VAD_treshold=40.0;
|
VAD_threshold=5.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
tox = {
|
tox = {
|
||||||
|
@ -213,9 +213,8 @@ int start_transmission(ToxWindow *self, Call *call)
|
|||||||
return -1;
|
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);
|
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_None) {
|
||||||
if (error == de_FailedStart) {
|
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 */
|
/* Call must be active */
|
||||||
if (self->is_call) {
|
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;
|
self->chatwin->infobox.vad_lvl = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +22,6 @@
|
|||||||
|
|
||||||
#include "audio_device.h"
|
#include "audio_device.h"
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
#include "audio_call.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
@ -43,6 +39,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
extern struct Winthread Winthread;
|
extern struct Winthread Winthread;
|
||||||
@ -70,11 +67,8 @@ typedef struct Device {
|
|||||||
// used only by input devices:
|
// used only by input devices:
|
||||||
DataHandleCallback cb;
|
DataHandleCallback cb;
|
||||||
void *cb_data;
|
void *cb_data;
|
||||||
// TODO: implement VAD, and fix the typo, or remove these.
|
float VAD_threshold;
|
||||||
bool enable_VAD;
|
uint32_t VAD_samples_remaining;
|
||||||
#ifdef AUDIO
|
|
||||||
float VAD_treshold; /* 40 is usually recommended value */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// used only by output devices:
|
// used only by output devices:
|
||||||
uint32_t source;
|
uint32_t source;
|
||||||
@ -89,9 +83,11 @@ typedef struct AudioState {
|
|||||||
uint32_t num_devices[2];
|
uint32_t num_devices[2];
|
||||||
|
|
||||||
FrameInfo capture_frame_info;
|
FrameInfo capture_frame_info;
|
||||||
|
float input_volume;
|
||||||
|
|
||||||
// mutexes to prevent changes to input resp. output devices and al_devices
|
// 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];
|
pthread_mutex_t mutex[2];
|
||||||
|
|
||||||
// TODO: unused
|
// TODO: unused
|
||||||
@ -118,7 +114,9 @@ static void unlock(DeviceType type)
|
|||||||
static bool thread_running = true,
|
static bool thread_running = true,
|
||||||
thread_paused = true; /* Thread control */
|
thread_paused = true; /* Thread control */
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
static void *poll_input(void *);
|
static void *poll_input(void *);
|
||||||
|
#endif
|
||||||
|
|
||||||
static uint32_t sound_mode(bool stereo)
|
static uint32_t sound_mode(bool stereo)
|
||||||
{
|
{
|
||||||
@ -148,6 +146,7 @@ DeviceError init_devices(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
// Start poll thread
|
// Start poll thread
|
||||||
pthread_t thread_id;
|
pthread_t thread_id;
|
||||||
|
|
||||||
@ -156,6 +155,8 @@ DeviceError init_devices(void)
|
|||||||
return de_InternalError;
|
return de_InternalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
return de_None;
|
return de_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,8 +248,7 @@ bool device_is_muted(DeviceType type, uint32_t device_idx)
|
|||||||
return device->muted;
|
return device->muted;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
DeviceError device_set_VAD_threshold(uint32_t device_idx, float value)
|
||||||
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
|
|
||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) {
|
if (device_idx >= MAX_DEVICES) {
|
||||||
return de_InvalidSelection;
|
return de_InvalidSelection;
|
||||||
@ -260,14 +260,32 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
|
|||||||
return de_DeviceNotActive;
|
return de_DeviceNotActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value <= 0.0f) {
|
||||||
|
value = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
lock(input);
|
lock(input);
|
||||||
|
|
||||||
device->VAD_treshold = value;
|
device->VAD_threshold = value;
|
||||||
|
|
||||||
unlock(input);
|
unlock(input);
|
||||||
return de_None;
|
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)
|
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) {
|
if (type == input) {
|
||||||
device->cb = cb;
|
device->cb = cb;
|
||||||
device->cb_data = cb_data;
|
device->cb_data = cb_data;
|
||||||
device->enable_VAD = enable_VAD;
|
|
||||||
#ifdef AUDIO
|
#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
|
#endif
|
||||||
} else {
|
} else {
|
||||||
if (open_source(device) != de_None) {
|
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));
|
ALuint *bufids = malloc(processed * sizeof(ALuint));
|
||||||
|
|
||||||
if (bufids == NULL) {
|
if (bufids == NULL) {
|
||||||
pthread_mutex_unlock(device->mutex);
|
unlock(output);
|
||||||
return de_InternalError;
|
return de_InternalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,6 +658,33 @@ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t sample_
|
|||||||
return de_None;
|
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
|
#define FRAME_BUF_SIZE 16000
|
||||||
|
|
||||||
static void *poll_input(void *arg)
|
static void *poll_input(void *arg)
|
||||||
@ -679,9 +725,23 @@ static void *poll_input(void *arg)
|
|||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
lock(input);
|
lock(input);
|
||||||
|
|
||||||
|
float frame_volume = volume(frame_buf, f_size);
|
||||||
|
|
||||||
|
audio_state->input_volume = frame_volume;
|
||||||
|
|
||||||
for (int i = 0; i < MAX_DEVICES; i++) {
|
for (int i = 0; i < MAX_DEVICES; i++) {
|
||||||
Device *device = &audio_state->devices[input][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) {
|
if (device->active && !device->muted && device->cb) {
|
||||||
device->cb(frame_buf, f_size, device->cb_data);
|
device->cb(frame_buf, f_size, device->cb_data);
|
||||||
}
|
}
|
||||||
@ -697,6 +757,20 @@ static void *poll_input(void *arg)
|
|||||||
|
|
||||||
pthread_exit(NULL);
|
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)
|
void print_al_devices(ToxWindow *self, DeviceType type)
|
||||||
{
|
{
|
||||||
|
@ -66,9 +66,9 @@ DeviceError device_mute(DeviceType type, uint32_t device_idx);
|
|||||||
|
|
||||||
bool device_is_muted(DeviceType type, uint32_t device_idx);
|
bool device_is_muted(DeviceType type, uint32_t device_idx);
|
||||||
|
|
||||||
#ifdef AUDIO
|
DeviceError device_set_VAD_threshold(uint32_t device_idx, float value);
|
||||||
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
|
|
||||||
#endif
|
float device_get_VAD_threshold(uint32_t device_idx);
|
||||||
|
|
||||||
DeviceError set_source_position(uint32_t device_idx, float x, float y, float z);
|
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,
|
DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t length, uint8_t channels,
|
||||||
uint32_t sample_rate);
|
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);
|
void print_al_devices(ToxWindow *self, DeviceType type);
|
||||||
|
|
||||||
DeviceError selection_valid(DeviceType type, int32_t selection);
|
DeviceError selection_valid(DeviceType type, int32_t selection);
|
||||||
|
@ -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.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
|
||||||
ctx->infobox.starttime = get_unix_time();
|
ctx->infobox.starttime = get_unix_time();
|
||||||
ctx->infobox.vad_lvl = user_settings->VAD_treshold;
|
ctx->infobox.vad_lvl = 0.0f;
|
||||||
ctx->infobox.active = true;
|
ctx->infobox.active = true;
|
||||||
strcpy(ctx->infobox.timestr, "00");
|
strcpy(ctx->infobox.timestr, "00");
|
||||||
}
|
}
|
||||||
|
183
src/conference.c
183
src/conference.c
@ -353,12 +353,14 @@ uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *pre
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int len = strlen(prefix);
|
const size_t len = strlen(prefix);
|
||||||
|
|
||||||
if (len == 2 * TOX_PUBLIC_KEY_SIZE) {
|
if (len == 2 * TOX_PUBLIC_KEY_SIZE) {
|
||||||
for (uint32_t i = 0; i < chat->num_peers; ++i) {
|
for (uint32_t i = 0; i < chat->num_peers; ++i) {
|
||||||
if (strcasecmp(prefix, chat->name_list[i].pubkey_str) == 0) {
|
NameListEntry *entry = &chat->name_list[i];
|
||||||
entries[0] = &chat->name_list[i];
|
|
||||||
|
if (strcasecmp(prefix, entry->pubkey_str) == 0) {
|
||||||
|
entries[0] = entry;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,9 +369,11 @@ uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *pre
|
|||||||
uint32_t n = 0;
|
uint32_t n = 0;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < chat->num_peers; ++i) {
|
for (uint32_t i = 0; i < chat->num_peers; ++i) {
|
||||||
if (strncmp(prefix, chat->name_list[i].name, len) == 0
|
NameListEntry *entry = &chat->name_list[i];
|
||||||
|| strncasecmp(prefix, chat->name_list[i].pubkey_str, len) == 0) {
|
|
||||||
entries[n] = &chat->name_list[i];
|
if (strncmp(prefix, entry->name, len) == 0
|
||||||
|
|| strncasecmp(prefix, entry->pubkey_str, len) == 0) {
|
||||||
|
entries[n] = entry;
|
||||||
++n;
|
++n;
|
||||||
|
|
||||||
if (n == maxpeers) {
|
if (n == maxpeers) {
|
||||||
@ -418,11 +422,14 @@ static void conference_update_name_list(uint32_t conferencenum)
|
|||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < chat->max_idx; ++i) {
|
for (uint32_t i = 0; i < chat->max_idx; ++i) {
|
||||||
if (chat->peer_list[i].active) {
|
const ConferencePeer *peer = &chat->peer_list[i];
|
||||||
memcpy(chat->name_list[count].name, chat->peer_list[i].name, chat->peer_list[i].name_length + 1);
|
NameListEntry *entry = &chat->name_list[count];
|
||||||
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));
|
if (peer->active) {
|
||||||
chat->name_list[count].peernum = i;
|
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;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,7 +458,7 @@ static int realloc_peer_list(ConferenceChat *chat, uint32_t num_peers)
|
|||||||
return 0;
|
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) {
|
if (!tmp_list) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -462,13 +469,35 @@ static int realloc_peer_list(ConferenceChat *chat, uint32_t num_peers)
|
|||||||
return 0;
|
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
|
#ifdef AUDIO
|
||||||
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];
|
||||||
ConferencePeer *peer = &chat->peer_list[peernum];
|
ConferencePeer *peer = &chat->peer_list[peernum];
|
||||||
|
|
||||||
if (!peer->sending_audio) {
|
if (peer == NULL || !peer->sending_audio) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,10 +526,10 @@ static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t pee
|
|||||||
#endif
|
#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) {
|
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) {
|
if (peer->active && memcmp(peer->pubkey, pubkey, TOX_PUBLIC_KEY_SIZE) == 0) {
|
||||||
*idx = i;
|
*idx = i;
|
||||||
@ -567,7 +596,7 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
|
|||||||
|
|
||||||
peer->active = true;
|
peer->active = true;
|
||||||
peer->name_length = length;
|
peer->name_length = length;
|
||||||
peer->peernumber = i;
|
peer->peernum = i;
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
set_peer_audio_position(m, conferencenum, i);
|
set_peer_audio_position(m, conferencenum, i);
|
||||||
@ -628,16 +657,9 @@ static void conference_onConferencePeerNameChange(ToxWindow *self, Tox *m, uint3
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConferenceChat *chat = &conferences[conferencenum];
|
const ConferencePeer *peer = peer_in_conference(conferencenum, peernum);
|
||||||
|
|
||||||
if (!chat->active) {
|
if (peer != NULL && peer->name_length > 0) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < chat->max_idx; ++i) {
|
|
||||||
ConferencePeer *peer = &chat->peer_list[i];
|
|
||||||
|
|
||||||
if (peer->active && peer->peernumber == peernum && peer->name_length > 0) {
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
@ -648,8 +670,6 @@ static void conference_onConferencePeerNameChange(ToxWindow *self, Tox *m, uint3
|
|||||||
write_to_log(tmp_event, peer->name, ctx->log, true);
|
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 ");
|
line_info_add(self, timefrmt, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as ");
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
conference_onConferenceNameListChange(self, m, conferencenum);
|
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;
|
bool input_ret = false;
|
||||||
|
ConferenceChat *chat = &conferences[self->num];
|
||||||
|
|
||||||
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;
|
||||||
@ -725,14 +746,14 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
/* TODO: make this not suck */
|
/* TODO: make this not suck */
|
||||||
if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) {
|
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) {
|
if (complete_strs) {
|
||||||
for (uint32_t i = 0; i < conferences[self->num].num_peers; ++i) {
|
for (uint32_t i = 0; i < chat->num_peers; ++i) {
|
||||||
complete_strs[i] = (const char *) conferences[self->num].name_list[i].name;
|
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);
|
free(complete_strs);
|
||||||
}
|
}
|
||||||
} else if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) {
|
} 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
|
#endif
|
||||||
else if (wcsncmp(ctx->line, L"/mute ", wcslen(L"/mute ")) == 0) {
|
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) {
|
if (complete_strs) {
|
||||||
for (uint32_t i = 0; i < conferences[self->num].num_peers; ++i) {
|
for (uint32_t i = 0; i < chat->num_peers; ++i) {
|
||||||
complete_strs[i] = (const char *) conferences[self->num].name_list[i].name;
|
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) {
|
if (diff == -1) {
|
||||||
for (uint32_t i = 0; i < conferences[self->num].num_peers; ++i) {
|
for (uint32_t i = 0; i < chat->num_peers; ++i) {
|
||||||
complete_strs[i] = (const char *) conferences[self->num].name_list[i].pubkey_str;
|
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);
|
free(complete_strs);
|
||||||
@ -784,14 +805,14 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
input_ret = true;
|
input_ret = true;
|
||||||
const int L = y2 - CHATBOX_HEIGHT - sidebar_offset(self->num);
|
const int L = y2 - CHATBOX_HEIGHT - sidebar_offset(self->num);
|
||||||
|
|
||||||
if (conferences[self->num].side_pos < (int64_t) conferences[self->num].num_peers - L) {
|
if (chat->side_pos < (int64_t) chat->num_peers - L) {
|
||||||
++conferences[self->num].side_pos;
|
++chat->side_pos;
|
||||||
}
|
}
|
||||||
} else if (key == T_KEY_C_UP) {
|
} else if (key == T_KEY_C_UP) {
|
||||||
input_ret = true;
|
input_ret = true;
|
||||||
|
|
||||||
if (conferences[self->num].side_pos > 0) {
|
if (chat->side_pos > 0) {
|
||||||
--conferences[self->num].side_pos;
|
--chat->side_pos;
|
||||||
}
|
}
|
||||||
} else if (key == L'\r') {
|
} else if (key == L'\r') {
|
||||||
input_ret = true;
|
input_ret = true;
|
||||||
@ -850,14 +871,14 @@ static void draw_peer(ToxWindow *self, Tox *m, ChatContext *ctx, uint32_t i)
|
|||||||
if (audio) {
|
if (audio) {
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
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
|
const bool audio_active = is_self
|
||||||
? !timed_out(conferences[self->num].last_sent_audio, 2)
|
? !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 &&
|
const bool mute = audio_active &&
|
||||||
(is_self
|
(is_self
|
||||||
? device_is_muted(input, conferences[self->num].audio_in_idx)
|
? 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);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
const int aud_attr = A_BOLD | COLOR_PAIR(audio_active && !mute ? GREEN : RED);
|
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
|
#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 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);
|
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 ? GREEN : RED;
|
const int color = mic_on && volume > threshold ? GREEN : RED;
|
||||||
wattron(ctx->sidebar, COLOR_PAIR(color));
|
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, COLOR_PAIR(color));
|
||||||
wattroff(ctx->sidebar, A_BOLD);
|
wattroff(ctx->sidebar, A_BOLD);
|
||||||
++line;
|
++line;
|
||||||
@ -953,10 +987,9 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
|
|||||||
mvwhline(ctx->sidebar, line, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
|
mvwhline(ctx->sidebar, line, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
|
||||||
++line;
|
++line;
|
||||||
|
|
||||||
int maxlines = y2 - header_lines - CHATBOX_HEIGHT;
|
for (uint32_t i = 0;
|
||||||
uint32_t i;
|
i < num_peers && i < y2 - header_lines - CHATBOX_HEIGHT;
|
||||||
|
++i) {
|
||||||
for (i = 0; i < num_peers && i < maxlines; ++i) {
|
|
||||||
wmove(ctx->sidebar, i + header_lines, 1);
|
wmove(ctx->sidebar, i + header_lines, 1);
|
||||||
draw_peer(self, m, ctx, i);
|
draw_peer(self, m, ctx, i);
|
||||||
}
|
}
|
||||||
@ -1060,22 +1093,15 @@ static ToxWindow *new_conference_chat(uint32_t conferencenum)
|
|||||||
#define CONFAV_AUDIO_CHANNELS 1
|
#define CONFAV_AUDIO_CHANNELS 1
|
||||||
#define CONFAV_SAMPLES_PER_FRAME (CONFAV_SAMPLE_RATE * CONFAV_FRAME_DURATION / 1000)
|
#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)
|
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;
|
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 (!peer->sending_audio) {
|
||||||
if (open_output_device(&peer->audio_out_idx,
|
if (open_output_device(&peer->audio_out_idx,
|
||||||
sample_rate, CONFAV_FRAME_DURATION, channels) != de_None) {
|
sample_rate, CONFAV_FRAME_DURATION, channels) != de_None) {
|
||||||
@ -1085,7 +1111,7 @@ void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peern
|
|||||||
|
|
||||||
peer->sending_audio = true;
|
peer->sending_audio = true;
|
||||||
|
|
||||||
set_peer_audio_position(tox, conferencenum, i);
|
set_peer_audio_position(tox, conferencenum, peernum);
|
||||||
}
|
}
|
||||||
|
|
||||||
write_out(peer->audio_out_idx, pcm, samples, channels, sample_rate);
|
write_out(peer->audio_out_idx, pcm, samples, channels, sample_rate);
|
||||||
@ -1093,7 +1119,6 @@ void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peern
|
|||||||
peer->last_audio_time = get_unix_time();
|
peer->last_audio_time = get_unix_time();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void conference_read_device_callback(const int16_t *captured, uint32_t size, void *data)
|
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;
|
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)
|
bool conference_mute_self(uint32_t conferencenum)
|
||||||
{
|
{
|
||||||
ConferenceChat *chat = &conferences[conferencenum];
|
const ConferenceChat *chat = &conferences[conferencenum];
|
||||||
|
|
||||||
if (!chat->active || !chat->audio_enabled) {
|
if (!chat->active || !chat->audio_enabled) {
|
||||||
return false;
|
return false;
|
||||||
@ -1177,20 +1202,42 @@ bool conference_mute_peer(const Tox *m, uint32_t conferencenum, uint32_t peernum
|
|||||||
return conference_mute_self(conferencenum);
|
return conference_mute_self(conferencenum);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConferenceChat *chat = &conferences[conferencenum];
|
const ConferenceChat *chat = &conferences[conferencenum];
|
||||||
|
|
||||||
if (!chat->active || !chat->audio_enabled
|
if (!chat->active || !chat->audio_enabled
|
||||||
|| peernum > chat->max_idx) {
|
|| peernum > chat->max_idx) {
|
||||||
return false;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
device_mute(output, peer->audio_out_idx);
|
device_mute(output, peer->audio_out_idx);
|
||||||
return true;
|
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
|
#endif
|
||||||
|
@ -34,7 +34,7 @@ typedef struct ConferencePeer {
|
|||||||
bool active;
|
bool active;
|
||||||
|
|
||||||
uint8_t pubkey[TOX_PUBLIC_KEY_SIZE];
|
uint8_t pubkey[TOX_PUBLIC_KEY_SIZE];
|
||||||
uint32_t peernumber;
|
uint32_t peernum; /* index in chat->peer_list */
|
||||||
|
|
||||||
char name[TOX_MAX_NAME_LENGTH];
|
char name[TOX_MAX_NAME_LENGTH];
|
||||||
size_t 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 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);
|
||||||
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
|
const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
|
||||||
sample_rate, void *userdata);
|
sample_rate, void *userdata);
|
||||||
|
|
||||||
bool conference_mute_self(uint32_t conferencenum);
|
bool conference_mute_self(uint32_t conferencenum);
|
||||||
bool conference_mute_peer(const Tox *m, uint32_t conferencenum, uint32_t peernum);
|
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 */
|
#endif /* CONFERENCE_H */
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
@ -29,6 +30,11 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "conference.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])
|
void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
UNUSED_VAR(window);
|
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);
|
size_t tlen = tox_conference_get_title_size(m, self->num, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_CONFERENCE_TITLE_OK || tlen >= sizeof(title)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tox_conference_get_title(m, self->num, (uint8_t *) title, &err)) {
|
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;
|
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);
|
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])
|
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
UNUSED_VAR(window);
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
bool enable;
|
bool enable;
|
||||||
|
|
||||||
if (argc == 1 && !strcasecmp(argv[1], "on")) {
|
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")) {
|
} else if (argc == 1 && !strcasecmp(argv[1], "off")) {
|
||||||
enable = false;
|
enable = false;
|
||||||
} else {
|
} else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please specify: on | off");
|
print_err(self, "Please specify: on | off");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((enable ? enable_conference_audio : disable_conference_audio)(m, self->num)) {
|
if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, enable ? "Enabled conference audio" : "Disabled conference audio");
|
print_err(self, enable ? "Enabled conference audio" : "Disabled conference audio");
|
||||||
} else {
|
} 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])
|
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
UNUSED_VAR(window);
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
if (conference_mute_self(self->num)) {
|
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 {
|
} 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 {
|
} else {
|
||||||
NameListEntry *entries[16];
|
NameListEntry *entries[16];
|
||||||
uint32_t n = get_name_list_entries_by_prefix(self->num, argv[1], entries, 16);
|
uint32_t n = get_name_list_entries_by_prefix(self->num, argv[1], entries, 16);
|
||||||
|
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No such peer");
|
print_err(self, "No such peer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n > 1) {
|
if (n > 1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
|
print_err(self, "Multiple matching peers (use /mute [public key] to disambiguate):");
|
||||||
"Multiple matching peers (use /mute [public key] to disambiguate):");
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < n; ++i) {
|
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);
|
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)) {
|
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 {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No such audio peer");
|
print_err(self, "No such audio peer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
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 */
|
||||||
|
@ -29,5 +29,6 @@
|
|||||||
void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
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_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]);
|
||||||
|
|
||||||
#endif /* CONFERENCE_COMMANDS_H */
|
#endif /* CONFERENCE_COMMANDS_H */
|
||||||
|
@ -103,7 +103,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 },
|
||||||
{ "/sense", cmd_sense },
|
{ "/sense", cmd_conference_sense },
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
@ -311,7 +311,8 @@ static void help_draw_conference(ToxWindow *self)
|
|||||||
wattroff(win, A_BOLD);
|
wattroff(win, A_BOLD);
|
||||||
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\n");
|
wprintw(win, " /mute <nick> or <pubkey> : Toggle peer audio mute status\n");
|
||||||
|
wprintw(win, " /sense <n> : VAD sensitivity threshold\n\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
|
@ -197,9 +197,7 @@ int bin_pubkey_to_string(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t i;
|
for (size_t i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
|
|
||||||
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_pubkey[i] & 0xff);
|
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_pubkey[i] & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,19 +204,19 @@ static const struct audio_strings {
|
|||||||
const char *self;
|
const char *self;
|
||||||
const char *input_device;
|
const char *input_device;
|
||||||
const char *output_device;
|
const char *output_device;
|
||||||
const char *VAD_treshold;
|
const char *VAD_threshold;
|
||||||
} audio_strings = {
|
} audio_strings = {
|
||||||
"audio",
|
"audio",
|
||||||
"input_device",
|
"input_device",
|
||||||
"output_device",
|
"output_device",
|
||||||
"VAD_treshold",
|
"VAD_threshold",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void audio_defaults(struct user_settings *settings)
|
static void audio_defaults(struct user_settings *settings)
|
||||||
{
|
{
|
||||||
settings->audio_in_dev = 0;
|
settings->audio_in_dev = 0;
|
||||||
settings->audio_out_dev = 0;
|
settings->audio_out_dev = 0;
|
||||||
settings->VAD_treshold = 40.0;
|
settings->VAD_threshold = 5.0;
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
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;
|
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
|
#endif
|
||||||
|
@ -84,7 +84,7 @@ struct user_settings {
|
|||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
int audio_in_dev;
|
int audio_in_dev;
|
||||||
int audio_out_dev;
|
int audio_out_dev;
|
||||||
double VAD_treshold;
|
double VAD_threshold;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
20
src/toxic.c
20
src/toxic.c
@ -1440,20 +1440,10 @@ int main(int argc, char **argv)
|
|||||||
prompt_init_statusbar(prompt, m, !datafile_exists);
|
prompt_init_statusbar(prompt, m, !datafile_exists);
|
||||||
load_conferences(m);
|
load_conferences(m);
|
||||||
|
|
||||||
/* thread for ncurses stuff */
|
|
||||||
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
|
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
|
||||||
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
|
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
|
#ifdef AUDIO
|
||||||
|
|
||||||
av = init_audio(prompt, m);
|
av = init_audio(prompt, m);
|
||||||
@ -1479,6 +1469,16 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
#endif /* AUDIO */
|
#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
|
#ifdef PYTHON
|
||||||
|
|
||||||
init_python(m);
|
init_python(m);
|
||||||
|
Loading…
Reference in New Issue
Block a user