|
|
|
|
@ -56,6 +56,14 @@ static unsigned int g_tx_reasons;
|
|
|
|
|
static int g_tx_encode_error; |
|
|
|
|
static uint32_t g_aec_reported_over, g_aec_reported_under, g_pcm_events; |
|
|
|
|
|
|
|
|
|
/* Секундные суммы под g_mtx; длительности локальные, без сравнения с удалёнными PTS. */ |
|
|
|
|
struct call_audio_duration { uint64_t count, total_us, max_us; }; |
|
|
|
|
static struct call_audio_duration g_feed_lock_time, g_process_time, g_post_time; |
|
|
|
|
static void call_audio_duration_add(struct call_audio_duration* d, uint64_t us) { |
|
|
|
|
++d->count; d->total_us += us; |
|
|
|
|
if (us > d->max_us) d->max_us = us; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Task и данные — одна аллокация; uasync освобождает task после callback и при destroy. */ |
|
|
|
|
struct call_audio_tx { |
|
|
|
|
struct posted_task task; |
|
|
|
|
@ -70,6 +78,7 @@ static void call_audio_send(void* arg) {
|
|
|
|
|
struct call_audio_tx* tx = arg; |
|
|
|
|
pthread_mutex_lock(&g_mtx); |
|
|
|
|
int current = tx->generation == g_tx_generation; |
|
|
|
|
if (current) call_audio_duration_add(&g_post_time, (get_time_tb() - tx->created_tb) * 100); |
|
|
|
|
if (g_tx_pending) --g_tx_pending; |
|
|
|
|
int send = current && g_active && !g_ending && g_inst == tx->inst && g_call_id == tx->call_id; |
|
|
|
|
if (get_time_tb() - tx->created_tb > 2000) { |
|
|
|
|
@ -231,6 +240,7 @@ static int call_audio_start_impl(uint64_t call_id, int prepared) {
|
|
|
|
|
++g_tx_generation; g_tx_dropped = g_tx_reported = 0; |
|
|
|
|
g_capture_epoch = 1; g_capture_end = INT64_MIN; g_codec_delay = codec_delay; |
|
|
|
|
g_tx_reasons = 0; g_tx_encode_error = 0; |
|
|
|
|
g_feed_lock_time = g_process_time = g_post_time = (struct call_audio_duration){0}; |
|
|
|
|
g_ending = 0; |
|
|
|
|
g_ended_started = 0; |
|
|
|
|
g_glitch_started = 0; |
|
|
|
|
@ -380,7 +390,9 @@ static int call_audio_feed_impl(uint64_t call_id, const int16_t* pcm, int count,
|
|
|
|
|
struct UTUN_INSTANCE* inst = NULL; |
|
|
|
|
int len = -1; |
|
|
|
|
|
|
|
|
|
uint64_t entered_us = get_time_us(); |
|
|
|
|
pthread_mutex_lock(&g_mtx); |
|
|
|
|
uint64_t locked_us = get_time_us(); |
|
|
|
|
if (!g_active || call_id != g_call_id || !g_encoder) { |
|
|
|
|
pthread_mutex_unlock(&g_mtx); |
|
|
|
|
return -1; |
|
|
|
|
@ -418,6 +430,8 @@ static int call_audio_feed_impl(uint64_t call_id, const int16_t* pcm, int count,
|
|
|
|
|
tx = amplified; |
|
|
|
|
} else if (muted) { memset(amplified, 0, sizeof(amplified)); tx = amplified; } |
|
|
|
|
len = opus_codec_encode(g_encoder, tx, count, opus, (int)sizeof(opus)); |
|
|
|
|
call_audio_duration_add(&g_feed_lock_time, locked_us - entered_us); |
|
|
|
|
call_audio_duration_add(&g_process_time, get_time_us() - locked_us); |
|
|
|
|
ua = g_inst ? g_inst->ua : NULL; |
|
|
|
|
inst = g_inst; |
|
|
|
|
if (len <= 0 || !ua || !inst || g_ending || g_tx_pending >= 8) { |
|
|
|
|
@ -578,6 +592,7 @@ int call_audio_get_stats(uint64_t call_id, int* buffer_ms, int* tempo_x100,
|
|
|
|
|
unsigned int reasons = 0; |
|
|
|
|
int encode_error = 0; |
|
|
|
|
int tx_changed = 0, aec_changed = 0; |
|
|
|
|
struct call_audio_duration lock_time = {0}, process_time = {0}, post_time = {0}; |
|
|
|
|
pthread_mutex_lock(&g_mtx); |
|
|
|
|
if (g_active && call_id == g_call_id && g_vj) { |
|
|
|
|
call_jitter_get_stats(g_vj, buffer_ms, tempo_x100, dropped, underruns, range); |
|
|
|
|
@ -589,9 +604,18 @@ int call_audio_get_stats(uint64_t call_id, int* buffer_ms, int* tempo_x100,
|
|
|
|
|
tx_changed = tx_dropped != g_tx_reported; g_tx_reported = tx_dropped; |
|
|
|
|
reasons = g_tx_reasons; g_tx_reasons = 0; encode_error = g_tx_encode_error; |
|
|
|
|
events = g_pcm_events; g_pcm_events = 0; |
|
|
|
|
lock_time = g_feed_lock_time; process_time = g_process_time; post_time = g_post_time; |
|
|
|
|
g_feed_lock_time = g_process_time = g_post_time = (struct call_audio_duration){0}; |
|
|
|
|
ok = 1; |
|
|
|
|
} |
|
|
|
|
pthread_mutex_unlock(&g_mtx); |
|
|
|
|
if (lock_time.count || post_time.count) |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "call audio TX timing call=%llu frames=%llu posts=%llu " |
|
|
|
|
"lock_avg_max_us=%llu/%llu process_avg_max_us=%llu/%llu post_avg_max_us=%llu/%llu pending=%u", |
|
|
|
|
(unsigned long long)call_id, (unsigned long long)lock_time.count, (unsigned long long)post_time.count, |
|
|
|
|
(unsigned long long)(lock_time.count ? lock_time.total_us / lock_time.count : 0), (unsigned long long)lock_time.max_us, |
|
|
|
|
(unsigned long long)(process_time.count ? process_time.total_us / process_time.count : 0), (unsigned long long)process_time.max_us, |
|
|
|
|
(unsigned long long)(post_time.count ? post_time.total_us / post_time.count : 0), (unsigned long long)post_time.max_us, tx_pending); |
|
|
|
|
if (tx_changed) DEBUG_WARN(DEBUG_CATEGORY_CALL, |
|
|
|
|
"%s: TX dropped=%u pending=%u limit=8 max_age=200ms reasons=queue:%d alloc:%d core:%d encode:%d age:%d ending:%d encode_result=%d", |
|
|
|
|
CALL_AUDIO_ID, tx_dropped, tx_pending, !!(reasons & 1), !!(reasons & 2), !!(reasons & 4), |
|
|
|
|
|