Added echo suppressor option

This commit is contained in:
Andreas Eversberg 2023-02-25 17:20:57 +01:00
parent c2bf2598b1
commit 5268c0fc9b
5 changed files with 77 additions and 23 deletions

View File

@ -118,7 +118,7 @@ static void echo_tx(struct v5x_echo_proc *ep, uint8_t *data, int len)
int in;
int16_t tx;
if (!ep->ec || !ep->enabled)
if (!ep->enabled)
return;
while (len--) {
@ -144,7 +144,7 @@ static void echo_rx(struct v5x_echo_proc *ep, uint8_t *data, int len)
int i;
int rc;
if (!ep->ec || !ep->enabled)
if (!ep->enabled)
return;
for (i = 0; i < len; i++) {
@ -157,19 +157,26 @@ static void echo_rx(struct v5x_echo_proc *ep, uint8_t *data, int len)
}
if (ulaw) {
rx = g711_ulaw_flipped_to_linear[*data];
rx_can = echo_can_update(ep->ec, tx, rx);
if (ep->port->use_line_echo == USE_ECHO_CANCELER)
rx_can = echo_can_update(ep->ec, tx, rx);
else
rx_can = echo_sup_update(ep->es, tx, rx);
*data++ = g711_linear_to_ulaw_flipped[(uint16_t)rx_can];
} else {
rx = g711_alaw_flipped_to_linear[*data];
rx_can = echo_can_update(ep->ec, tx, rx);
if (ep->port->use_line_echo == USE_ECHO_CANCELER)
rx_can = echo_can_update(ep->ec, tx, rx);
else
rx_can = echo_sup_update(ep->es, tx, rx);
*data++ = g711_linear_to_alaw_flipped[(uint16_t)rx_can];
}
answer_buffer[i] = rx + tx; /* yes, may overflow, but then it is no valid tone anyway */
}
rc = answertone_process(&ep->at, answer_buffer, len);
rc = answertone_process(&ep->at, answer_buffer, len, (ep->port->use_line_echo == USE_ECHO_CANCELER));
if (rc > 0) {
LOGP(DV5, LOGL_NOTICE, "Detected answer tone, disable echo chanceler of %s port %d.\n",
LOGP(DV5, LOGL_NOTICE, "Detected answer tone, disable echo %s of %s port %d.\n",
(ep->port->use_line_echo == USE_ECHO_CANCELER) ? "canceler" : "suppressor",
(v5up->type == V5X_USER_TYPE_PSTN) ? "PSTN" : "ISDN", v5up->nr);
ep->enabled = 0;
}

View File

@ -986,31 +986,59 @@ DEFUN(cfg_no_port_isdn, cfg_no_port_isdn_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_echo, cfg_echo_cmd,
DEFUN(cfg_echo_can, cfg_echo_can_cmd,
"line-echo-canceler",
"Enable line echo canceler for all calls")
{
struct v5x_user_port *v5up = vty->index;
v5up->echo_configured = 1;
v5up->use_line_echo = USE_ECHO_CANCELER;
if (v5up->ts[0] && v5up->ts[0]->b_activated)
v5x_echo_reset(&v5up->ep[0], v5up->echo_configured);
v5x_echo_reset(&v5up->ep[0], v5up->use_line_echo);
if (v5up->ts[1] && v5up->ts[1]->b_activated)
v5x_echo_reset(&v5up->ep[1], v5up->echo_configured);
v5x_echo_reset(&v5up->ep[1], v5up->use_line_echo);
return CMD_SUCCESS;
}
DEFUN(cfg_no_echo, cfg_no_echo_cmd,
DEFUN(cfg_no_echo_can, cfg_no_echo_can_cmd,
"no line-echo-canceler",
NO_STR "Disable line echo canceler for all calls")
{
struct v5x_user_port *v5up = vty->index;
v5up->echo_configured = 0;
v5up->use_line_echo = 0;
if (v5up->ts[0] && v5up->ts[0]->b_activated)
v5x_echo_reset(&v5up->ep[0], v5up->echo_configured);
v5x_echo_reset(&v5up->ep[0], v5up->use_line_echo);
if (v5up->ts[1] && v5up->ts[1]->b_activated)
v5x_echo_reset(&v5up->ep[1], v5up->echo_configured);
v5x_echo_reset(&v5up->ep[1], v5up->use_line_echo);
return CMD_SUCCESS;
}
DEFUN(cfg_echo_sup, cfg_echo_sup_cmd,
"line-echo-suppressor",
"Enable line echo suppressor for all calls")
{
struct v5x_user_port *v5up = vty->index;
v5up->use_line_echo = USE_ECHO_SUPPRESSOR;
if (v5up->ts[0] && v5up->ts[0]->b_activated)
v5x_echo_reset(&v5up->ep[0], v5up->use_line_echo);
if (v5up->ts[1] && v5up->ts[1]->b_activated)
v5x_echo_reset(&v5up->ep[1], v5up->use_line_echo);
return CMD_SUCCESS;
}
DEFUN(cfg_no_echo_sup, cfg_no_echo_sup_cmd,
"no line-echo-suppressor",
NO_STR "Disable line echo suppressor for all calls")
{
struct v5x_user_port *v5up = vty->index;
v5up->use_line_echo = 0;
if (v5up->ts[0] && v5up->ts[0]->b_activated)
v5x_echo_reset(&v5up->ep[0], v5up->use_line_echo);
if (v5up->ts[1] && v5up->ts[1]->b_activated)
v5x_echo_reset(&v5up->ep[1], v5up->use_line_echo);
return CMD_SUCCESS;
}
@ -1038,8 +1066,10 @@ static void config_write_user_port(struct vty *vty, struct v5x_interface *v5if)
vty_out(vty, " port isdn %d%s", v5up->nr, VTY_NEWLINE);
break;
}
if (v5up->echo_configured)
if (v5up->use_line_echo == USE_ECHO_CANCELER)
vty_out(vty, " line-echo-canceler%s", VTY_NEWLINE);
if (v5up->use_line_echo == USE_ECHO_SUPPRESSOR)
vty_out(vty, " line-echo-suppressor%s", VTY_NEWLINE);
}
}
@ -1173,8 +1203,10 @@ int v5le_vty_init(void)
install_element(LINK_NODE, &cfg_e1_line_cmd);
install_element(LINK_NODE, &cfg_no_e1_line_cmd);
install_node(&port_node, NULL);
install_element(PORT_NODE, &cfg_echo_cmd);
install_element(PORT_NODE, &cfg_no_echo_cmd);
install_element(PORT_NODE, &cfg_echo_can_cmd);
install_element(PORT_NODE, &cfg_no_echo_can_cmd);
install_element(PORT_NODE, &cfg_echo_sup_cmd);
install_element(PORT_NODE, &cfg_no_echo_sup_cmd);
return 0;
}

View File

@ -429,6 +429,11 @@ struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t
LOGP(DV5, LOGL_ERROR, "Failed to create line echo canceler\n");
goto error;
}
v5up->ep[i].es = echo_sup_create(v5up, 8000);
if (!v5up->ep[i].es) {
LOGP(DV5, LOGL_ERROR, "Failed to create line echo suppressor\n");
goto error;
}
rc = answertone_init(&v5up->ep[i].at, 8000);
if (rc < 0) {
LOGP(DV5, LOGL_ERROR, "Failed to create answer tone detector\n");
@ -468,9 +473,14 @@ void v5x_user_port_destroy(struct v5x_user_port *v5up)
/* destory line echo canceler */
if (v5up->ep[i].ec) {
echo_can_free(v5up->ep[i].ec);
answertone_exit(&v5up->ep[i].at);
v5up->ep[i].ec = NULL;
}
/* destory line echo suppressor */
if (v5up->ep[i].es) {
echo_sup_free(v5up->ep[i].es);
v5up->ep[i].es = NULL;
}
answertone_exit(&v5up->ep[i].at);
/* unassign ports */
if (v5up->ts[i]) {
@ -499,8 +509,8 @@ void v5x_echo_reset(struct v5x_echo_proc *ep, int enable)
answertone_reset(&ep->at);
ep->tx_buffer_in = 0;
ep->tx_buffer_out = 0;
if (ep->ec)
echo_can_flush(ep->ec);
echo_can_flush(ep->ec);
echo_sup_flush(ep->es);
}
struct v5x_user_port *v5x_user_port_find(struct v5x_interface *v5if, uint16_t nr, bool is_isdn)

View File

@ -32,7 +32,8 @@
#include <osmocom/gsm/lapd_core.h>
#include <osmocom/abis/e1_input.h>
#include "libecho/echo.h"
#include "libecho/echo_cancel.h"
#include "libecho/echo_suppress.h"
#include "libecho/answertone.h"
#include "ph_socket.h"
@ -301,10 +302,14 @@ struct v5x_mgmt_proto {
#define EC_BUFFER 1024
#define EC_TAPS 256
#define USE_ECHO_CANCELER 1
#define USE_ECHO_SUPPRESSOR 2
struct v5x_echo_proc {
struct v5x_user_port *port; /* back pointer to user port */
int enabled; /* line echo canceler enabled (configured and not disabled by ANS) */
echo_can_state_t *ec; /* echo canceler state */
echo_sup_state_t *es; /* echo suppressor state */
int16_t tx_buffer[EC_BUFFER]; /* buffer to store TX audio */
int tx_buffer_in; /* next pos to write to buffer */
int tx_buffer_out; /* next pos to read from buffer */
@ -331,7 +336,7 @@ struct v5x_user_port {
ph_socket_t ph_socket; /* unix socket to connect port to */
bool le_unblocked; /* if port is not blocked by LE */
bool an_unblocked; /* if port is not blocked by AN */
int echo_configured; /* line echo canceler is configured */
int use_line_echo; /* line echo canceler/suppressor is configured */
struct v5x_echo_proc ep[2]; /* echo canceler process */
};

View File

@ -2265,7 +2265,7 @@ void v5x_le_channel_assign(struct v5x_user_port *v5up, int channel)
OSMO_ASSERT(channel >= 1 && channel <= 2);
/* reset echo canceler state */
v5x_echo_reset(&v5up->ep[channel - 1], v5up->echo_configured);
v5x_echo_reset(&v5up->ep[channel - 1], v5up->use_line_echo);
/* the channels are pre-assigned with V5.1, so only activation state is set */
if (v5if->dialect == V5X_DIALECT_V51) {