mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-24 05:02:10 +00:00
[core] eavesdrop: init L16 codec at right ptime in certain conditions.
[core] eavesdrop: avoid eavesdropping on itself and return error. [core] eavesdrop: adjust buffer operations for ptime mismatch and for when ptimes are the same. [core] eavesdrop: add buffering based on LCM (Least Common Multiple) when ptime mismatch, and have audio write thread enabled when ptime eavesdropee < ptime eavesdropper. [unit-tests] add unit-tests for eavesdrop.
This commit is contained in:
committed by
Andrey Volk
parent
3509ae537e
commit
5aabb54f68
+94
-19
@@ -2184,6 +2184,25 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_update_display(switch_core_
|
||||
return status;
|
||||
}
|
||||
|
||||
/*Greatest Common Divisor*/
|
||||
static uint32_t switch_gcd(uint32_t x, uint32_t y)
|
||||
{
|
||||
if (y == 0) {
|
||||
return x;
|
||||
}
|
||||
|
||||
return switch_gcd(y, x % y);
|
||||
}
|
||||
|
||||
/*Least Common Multiple*/
|
||||
static uint32_t switch_lcm(uint32_t x, uint32_t y)
|
||||
{
|
||||
uint32_t gcd = switch_gcd(x, y);
|
||||
|
||||
if (gcd) return (x * y) / gcd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session_t *session,
|
||||
const char *uuid, const char *require_group, switch_eavesdrop_flag_t flags)
|
||||
@@ -2213,11 +2232,17 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
|
||||
const char *vval;
|
||||
int buf_size = 0;
|
||||
int channels;
|
||||
int lcm, buff_min_len, buffered = 1;
|
||||
|
||||
if (!switch_channel_media_up(channel)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (tsession == session) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Eavesdrop target invalid.\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
while(switch_channel_state_change_pending(tchannel) || !switch_channel_media_up(tchannel)) {
|
||||
switch_yield(10000);
|
||||
if (!--sanity) break;
|
||||
@@ -2286,8 +2311,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
if (switch_core_codec_init(&codec,
|
||||
if (tread_impl.decoded_bytes_per_packet < read_impl.decoded_bytes_per_packet) {
|
||||
if (switch_core_codec_init(&codec,
|
||||
"L16",
|
||||
NULL,
|
||||
NULL,
|
||||
read_impl.actual_samples_per_second,
|
||||
read_impl.microseconds_per_packet / 1000,
|
||||
read_impl.number_of_channels,
|
||||
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
|
||||
NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if (switch_core_codec_init(&codec,
|
||||
"L16",
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -2298,10 +2336,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
|
||||
NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
|
||||
goto end;
|
||||
}
|
||||
buffered = 0;
|
||||
}
|
||||
|
||||
switch_core_session_get_read_impl(session, &read_impl);
|
||||
|
||||
ep->read_impl = read_impl;
|
||||
ep->tread_impl = tread_impl;
|
||||
|
||||
@@ -2440,6 +2478,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
|
||||
switch_core_session_receive_message(tsession, &msg);
|
||||
}
|
||||
|
||||
lcm = switch_lcm(tread_impl.decoded_bytes_per_packet, read_impl.decoded_bytes_per_packet);
|
||||
|
||||
while (switch_channel_up_nosig(tchannel) && switch_channel_ready(channel)) {
|
||||
uint32_t len = sizeof(buf);
|
||||
switch_event_t *event = NULL;
|
||||
@@ -2569,15 +2609,24 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
|
||||
channels = 1;
|
||||
}
|
||||
|
||||
tlen = tread_impl.decoded_bytes_per_packet * channels;
|
||||
tlen = ep->read_impl.decoded_bytes_per_packet * channels;
|
||||
|
||||
if (len > tlen) {
|
||||
len = tlen;
|
||||
}
|
||||
|
||||
if (buffered) {
|
||||
buff_min_len = lcm * 2;
|
||||
if (switch_buffer_inuse(ep->buffer) < buff_min_len) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
buff_min_len = len;
|
||||
}
|
||||
|
||||
if (ep->buffer) {
|
||||
switch_buffer_lock(ep->buffer);
|
||||
while (switch_buffer_inuse(ep->buffer) >= len) {
|
||||
while (switch_buffer_inuse(ep->buffer) >= buff_min_len) {
|
||||
int tchanged = 0, changed = 0;
|
||||
|
||||
write_frame.datalen = (uint32_t) switch_buffer_read(ep->buffer, buf, len);
|
||||
@@ -2592,7 +2641,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
|
||||
tchanged = 1;
|
||||
}
|
||||
|
||||
if (read_impl.number_of_channels != ep->tread_impl.number_of_channels ||
|
||||
if (read_impl.number_of_channels != ep->read_impl.number_of_channels ||
|
||||
read_impl.actual_samples_per_second != ep->read_impl.actual_samples_per_second) {
|
||||
changed = 1;
|
||||
}
|
||||
@@ -2606,6 +2655,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
|
||||
ep->read_impl.number_of_channels,
|
||||
read_impl.actual_samples_per_second,
|
||||
read_impl.number_of_channels);
|
||||
|
||||
tlen = read_impl.decoded_bytes_per_packet * channels;
|
||||
|
||||
if (len > tlen) {
|
||||
len = tlen;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (tchanged) {
|
||||
@@ -2615,28 +2671,44 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
|
||||
ep->tread_impl.number_of_channels,
|
||||
tread_impl.actual_samples_per_second,
|
||||
tread_impl.number_of_channels);
|
||||
}
|
||||
|
||||
|
||||
tlen = tread_impl.decoded_bytes_per_packet * channels;
|
||||
|
||||
if (len > tlen) {
|
||||
len = tlen;
|
||||
}
|
||||
|
||||
switch_core_codec_destroy(&codec);
|
||||
switch_core_codec_destroy(&codec);
|
||||
|
||||
if (tread_impl.decoded_bytes_per_packet < read_impl.decoded_bytes_per_packet) {
|
||||
if (switch_core_codec_init(&codec,
|
||||
"L16",
|
||||
NULL,
|
||||
NULL,
|
||||
tread_impl.actual_samples_per_second,
|
||||
tread_impl.microseconds_per_packet / 1000,
|
||||
tread_impl.number_of_channels,
|
||||
read_impl.actual_samples_per_second,
|
||||
read_impl.microseconds_per_packet / 1000,
|
||||
read_impl.number_of_channels,
|
||||
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
|
||||
NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
|
||||
switch_buffer_unlock(ep->buffer);
|
||||
goto end;
|
||||
}
|
||||
buffered = 1;
|
||||
lcm = switch_lcm(tread_impl.decoded_bytes_per_packet, read_impl.decoded_bytes_per_packet);
|
||||
} else {
|
||||
if (switch_core_codec_init(&codec,
|
||||
"L16",
|
||||
NULL,
|
||||
NULL,
|
||||
tread_impl.actual_samples_per_second,
|
||||
tread_impl.microseconds_per_packet / 1000,
|
||||
tread_impl.number_of_channels,
|
||||
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
|
||||
NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
|
||||
switch_buffer_unlock(ep->buffer);
|
||||
goto end;
|
||||
}
|
||||
if (buffered == 1) {
|
||||
buffered = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ep->read_impl = read_impl;
|
||||
@@ -2658,11 +2730,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
|
||||
|
||||
switch_buffer_unlock(ep->buffer);
|
||||
switch_buffer_lock(ep->buffer);
|
||||
}
|
||||
|
||||
if (ep->tread_impl.decoded_bytes_per_packet == ep->read_impl.decoded_bytes_per_packet) {
|
||||
/* push just the number of samples worth of a packet. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch_buffer_unlock(ep->buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end_loop:
|
||||
|
||||
Reference in New Issue
Block a user