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:
parent
ddcf224db2
commit
7dead5ec96
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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 = {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
221
src/conference.c
221
src/conference.c
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 },
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -84,7 +84,7 @@ struct user_settings {
|
||||
#ifdef AUDIO
|
||||
int audio_in_dev;
|
||||
int audio_out_dev;
|
||||
double VAD_treshold;
|
||||
double VAD_threshold;
|
||||
#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);
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user