Compare commits

...

2 Commits

Author SHA1 Message Date
Andreas Eversberg
05e69d52b9 ASCI: Support conference briding with 1..n connections
For each RTP packet that is received from a connection, the mode is
checked whether receiving is allowed or not. If not it is discarded.

In case of "confecho" mode, the RTP is also sent by the receiving
connection.

Then a loop is used to send RTP to all sending endpoints except the one
that received the packet.

Because we have a loop that allows to have 1..n connections, we have no
maximum number of allowed connections anymore.

Change-Id: Ic99a55ab5a3a6170e940403fadd52697e99f2f3a
2023-07-10 10:04:48 +02:00
Andreas Eversberg
62d97f4463 ASCI: Add new mode for voice group/broadcast call
The new mode "confecho" is similar to "sendrecv", except that it also
echoes back RTP towards the sender. This is required for voice group or
broadcast calls. Talker and listeners use the same timeslot, so that
audio must be echoed from the talker to the listeners.

It is different from "loopback", because a loopback only echoes back RTP
towards the sender, but does not forward audio through the endpoint to
the other connections. Also it does not forward RTP from senders of
other connections.

The current implementation of MGW does not support transcoding and
mixing. This means that a sending connection must not send RTP that has
been received by multiple receiving connections. The application that
uses the MGW has to set the connection modes, so that only one
connection receives RTP in case of a conference.

Change-Id: I0639c663e119d85bef1010c7aa45e2f133a9daf0
2023-07-05 12:36:49 +02:00
7 changed files with 27 additions and 32 deletions

View File

@@ -47,6 +47,7 @@ enum mgcp_connection_mode {
MGCP_CONN_SEND_ONLY = 2, MGCP_CONN_SEND_ONLY = 2,
MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY, MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
MGCP_CONN_LOOPBACK = 4 | MGCP_CONN_RECV_SEND, MGCP_CONN_LOOPBACK = 4 | MGCP_CONN_RECV_SEND,
MGCP_CONN_CONFECHO = 8 | MGCP_CONN_RECV_SEND,
}; };
#define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:" #define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:"

View File

@@ -1548,6 +1548,7 @@ const struct value_string mgcp_client_connection_mode_strs[] = {
{ MGCP_CONN_RECV_SEND, "sendrecv" }, { MGCP_CONN_RECV_SEND, "sendrecv" },
{ MGCP_CONN_SEND_ONLY, "sendonly" }, { MGCP_CONN_SEND_ONLY, "sendonly" },
{ MGCP_CONN_RECV_ONLY, "recvonly" }, { MGCP_CONN_RECV_ONLY, "recvonly" },
{ MGCP_CONN_CONFECHO, "confecho" },
{ MGCP_CONN_LOOPBACK, "loopback" }, { MGCP_CONN_LOOPBACK, "loopback" },
{ 0, NULL } { 0, NULL }
}; };

View File

@@ -173,8 +173,8 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
struct mgcp_conn *conn; struct mgcp_conn *conn;
int rc; int rc;
/* Do not allow more then two connections */ /* Do not allow more then the maximum number of connections */
if (llist_count(&endp->conns) >= endp->type->max_conns) if (endp->type->max_conns && llist_count(&endp->conns) >= endp->type->max_conns)
return NULL; return NULL;
/* Create new connection and add it to the list */ /* Create new connection and add it to the list */

View File

@@ -38,7 +38,6 @@
const struct mgcp_endpoint_typeset ep_typeset = { const struct mgcp_endpoint_typeset ep_typeset = {
/* Specify endpoint properties for RTP endpoint */ /* Specify endpoint properties for RTP endpoint */
.rtp = { .rtp = {
.max_conns = 2,
.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb, .dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
.cleanup_cb = mgcp_cleanup_rtp_bridge_cb, .cleanup_cb = mgcp_cleanup_rtp_bridge_cb,
}, },

View File

@@ -75,7 +75,7 @@ void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble)
} }
/*! Parse connection mode. /*! Parse connection mode.
* \param[in] mode as string (recvonly, sendrecv, sendonly or loopback) * \param[in] mode as string (recvonly, sendrecv, sendonly confecho or loopback)
* \param[in] endp pointer to endpoint (only used for log output) * \param[in] endp pointer to endpoint (only used for log output)
* \param[out] associated connection to be modified accordingly * \param[out] associated connection to be modified accordingly
* \returns 0 on success, -1 on error */ * \returns 0 on success, -1 on error */
@@ -100,6 +100,8 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
conn->mode = MGCP_CONN_RECV_SEND; conn->mode = MGCP_CONN_RECV_SEND;
else if (strcasecmp(mode, "sendonly") == 0) else if (strcasecmp(mode, "sendonly") == 0)
conn->mode = MGCP_CONN_SEND_ONLY; conn->mode = MGCP_CONN_SEND_ONLY;
else if (strcasecmp(mode, "confecho") == 0)
conn->mode = MGCP_CONN_CONFECHO;
else if (strcasecmp(mode, "loopback") == 0) else if (strcasecmp(mode, "loopback") == 0)
conn->mode = MGCP_CONN_LOOPBACK; conn->mode = MGCP_CONN_LOOPBACK;
else { else {

View File

@@ -1290,8 +1290,10 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
struct mgcp_conn_rtp *conn_src = mc->conn_src; struct mgcp_conn_rtp *conn_src = mc->conn_src;
struct mgcp_conn *conn = conn_src->conn; struct mgcp_conn *conn = conn_src->conn;
struct mgcp_conn *conn_dst; struct mgcp_conn *conn_dst;
struct mgcp_endpoint *endp = conn->endp;
struct osmo_sockaddr *from_addr = mc->from_addr; struct osmo_sockaddr *from_addr = mc->from_addr;
char ipbuf[INET6_ADDRSTRLEN]; char ipbuf[INET6_ADDRSTRLEN];
int rc = 0;
/*! NOTE: This callback function implements the endpoint specific /*! NOTE: This callback function implements the endpoint specific
* dispatch behaviour of an rtp bridge/proxy endpoint. It is assumed * dispatch behaviour of an rtp bridge/proxy endpoint. It is assumed
@@ -1323,36 +1325,26 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
return mgcp_conn_rtp_dispatch_rtp(conn_src, msg); return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
} }
/* Find a destination connection. */ /* If the mode does not allow receiving RTP, we are done. */
/* NOTE: This code path runs every time an RTP packet is received. The if (conn->mode != MGCP_CONN_RECV_ONLY &&
* function mgcp_find_dst_conn() we use to determine the detination conn->mode != MGCP_CONN_RECV_SEND &&
* connection will iterate the connection list inside the endpoint. conn->mode != MGCP_CONN_CONFECHO)
* Since list iterations are quite costly, we will figure out the return rc;
* destination only once and use the optional private data pointer of
* the connection to cache the destination connection pointer. */
if (!conn->priv) {
conn_dst = mgcp_find_dst_conn(conn);
conn->priv = conn_dst;
} else {
conn_dst = (struct mgcp_conn *)conn->priv;
}
/* There is no destination conn, stop here */ /* If the mode is "confecho", send RTP back to the sender. */
if (!conn_dst) { if (conn->mode == MGCP_CONN_CONFECHO)
LOGPCONN(conn, DRTP, LOGL_DEBUG, rc = mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
"no connection to forward an incoming RTP packet to\n");
return -1;
}
/* The destination conn is not an RTP connection */ /* Dispatch RTP packet to all other connection(s) that send audio. */
if (conn_dst->type != MGCP_CONN_TYPE_RTP) { llist_for_each_entry(conn_dst, &endp->conns, entry) {
LOGPCONN(conn, DRTP, LOGL_ERROR, if (conn_dst == conn)
"unable to find suitable destination conn\n"); continue;
return -1; if (conn_dst->mode == MGCP_CONN_SEND_ONLY ||
conn_dst->mode == MGCP_CONN_RECV_SEND ||
conn_dst->mode == MGCP_CONN_CONFECHO)
rc = mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
} }
return rc;
/* Dispatch RTP packet to destination RTP connection */
return mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
} }
/*! dispatch incoming RTP packet to E1 subslot, handle RTCP packets locally. /*! dispatch incoming RTP packet to E1 subslot, handle RTCP packets locally.

View File

@@ -967,7 +967,7 @@ mgcp_header_done:
} }
/* Check if we are able to accept the creation of another connection */ /* Check if we are able to accept the creation of another connection */
if (llist_count(&endp->conns) >= endp->type->max_conns) { if (endp->type->max_conns && llist_count(&endp->conns) >= endp->type->max_conns) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR, LOGPENDP(endp, DLMGCP, LOGL_ERROR,
"CRCX: endpoint full, max. %i connections allowed!\n", "CRCX: endpoint full, max. %i connections allowed!\n",
endp->type->max_conns); endp->type->max_conns);