forward full SDP between MNCC and SIP

Populate the new 'sdp' field added in MNCC v6, to enable full SDP codec
negotiation between osmo-msc and SIP.

Change-Id: I3df5d06f38ee2d122706a9ebffde7db4f2bd6bae
This commit is contained in:
Neels Hofmeyr 2019-08-15 06:12:54 +02:00 committed by rhizomatica
parent f678caa819
commit c6db2ac7c7
4 changed files with 61 additions and 15 deletions

View File

@ -172,3 +172,13 @@ const char *call_leg_state(struct call_leg *leg)
return "Unknown call type";
}
}
void call_leg_update_sdp(struct call_leg *leg, const char *sdp)
{
/* If no SDP was received, keep whatever SDP was previously seen. */
if (!sdp || !*sdp)
return;
OSMO_STRLCPY_ARRAY(leg->sdp, sdp);
LOGP(DAPP, LOGL_NOTICE, "call(%u) leg(0x%p) received SDP: %s\n",
leg->call->id, leg, leg->sdp);
}

View File

@ -162,6 +162,8 @@ void calls_init(void);
struct call_leg *call_leg_other(struct call_leg *leg);
void call_leg_update_sdp(struct call_leg *cl, const char *sdp);
void call_leg_release(struct call_leg *leg);

View File

@ -184,11 +184,13 @@ static bool send_rtp_connect(struct mncc_call_leg *leg, struct call_leg *other)
mncc.callref = leg->callref;
mncc.ip = ntohl(other->ip);
mncc.port = other->port;
/* Send payload_type as legacy compatibility, in addition full SDP. */
mncc.payload_type = other->payload_type;
/*
* FIXME: mncc.payload_msg_type should already be compatible.. but
* payload_type should be different..
*/
/* Send full SDP info forwarded from SIP, since MNCC protocol version 6: */
OSMO_STRLCPY_ARRAY(mncc.sdp, other->sdp);
struct in_addr net = { .s_addr = other->ip };
inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr));
LOGP(DMNCC, LOGL_DEBUG, "SEND rtp_connect: IP=(%s) PORT=(%u)\n", ip_addr, mncc.port);
@ -396,6 +398,8 @@ static void check_rtp_connect(struct mncc_connection *conn, const char *buf, int
return mncc_send(conn, MNCC_REJ_REQ, rtp->callref);
}
call_leg_update_sdp(&leg->base, rtp->sdp);
/* extract information about where the RTP is */
if (rtp->ip != 0 || rtp->port != 0 || rtp->payload_type != 0)
return;
@ -433,6 +437,8 @@ static void check_rtp_create(struct mncc_connection *conn, const char *buf, int
leg->base.payload_type = rtp->payload_type;
leg->base.payload_msg_type = rtp->payload_msg_type;
call_leg_update_sdp(&leg->base, rtp->sdp);
/* TODO.. now we can continue with the call */
struct in_addr net = { .s_addr = leg->base.ip };
inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr));
@ -501,7 +507,6 @@ static void check_setup(struct mncc_connection *conn, const char *buf, int rc)
return mncc_send(conn, MNCC_REJ_REQ, data->callref);
}
/* TODO.. bearer caps and better audio handling */
if (!continue_setup(conn, data)) {
LOGP(DMNCC, LOGL_ERROR,
"MNCC screening parameters failed leg(%u)\n", data->callref);
@ -529,6 +534,9 @@ static void check_setup(struct mncc_connection *conn, const char *buf, int rc)
memcpy(&leg->calling, &data->calling, sizeof(leg->calling));
memcpy(&leg->imsi, data->imsi, sizeof(leg->imsi));
/* forward full SDP description of audio codecs */
call_leg_update_sdp(&leg->base, data->sdp);
LOGP(DMNCC, LOGL_INFO,
"Created call(%u) with MNCC leg(%u) IMSI(%.16s)\n",
call->id, leg->callref, data->imsi);
@ -638,6 +646,8 @@ static void check_stp_cmpl_ind(struct mncc_connection *conn, const char *buf, in
if (!leg)
return;
call_leg_update_sdp(&leg->base, data->sdp);
LOGP(DMNCC, LOGL_INFO, "leg(%u) is now connected.\n", leg->callref);
stop_cmd_timer(leg, MNCC_SETUP_COMPL_IND);
leg->state = MNCC_CC_CONNECTED;
@ -672,6 +682,8 @@ static void check_cnf_ind(struct mncc_connection *conn, const char *buf, int rc)
if (!leg)
return;
call_leg_update_sdp(&leg->base, data->sdp);
LOGP(DMNCC, LOGL_DEBUG,
"leg(%u) confirmed. creating RTP socket.\n",
leg->callref);
@ -690,6 +702,8 @@ static void check_alrt_ind(struct mncc_connection *conn, const char *buf, int rc
if (!leg)
return;
call_leg_update_sdp(&leg->base, data->sdp);
LOGP(DMNCC, LOGL_DEBUG,
"leg(%u) is alerting.\n", leg->callref);
@ -768,6 +782,8 @@ static void check_stp_cnf(struct mncc_connection *conn, const char *buf, int rc)
if (!leg)
return;
call_leg_update_sdp(&leg->base, data->sdp);
LOGP(DMNCC, LOGL_DEBUG, "leg(%u) setup completed\n", leg->callref);
other_leg = call_leg_other(&leg->base);
@ -797,6 +813,8 @@ static void check_dtmf_start(struct mncc_connection *conn, const char *buf, int
if (!leg)
return;
call_leg_update_sdp(&leg->base, data->sdp);
LOGP(DMNCC, LOGL_DEBUG, "leg(%u) DTMF key=%c\n", leg->callref, data->keypad);
other_leg = call_leg_other(&leg->base);
@ -819,6 +837,8 @@ static void check_dtmf_stop(struct mncc_connection *conn, const char *buf, int r
if (!leg)
return;
call_leg_update_sdp(&leg->base, data->sdp);
LOGP(DMNCC, LOGL_DEBUG, "leg(%u) DTMF key=%c\n", leg->callref, data->keypad);
mncc_fill_header(&out_mncc, MNCC_STOP_DTMF_RSP, leg->callref);
@ -898,12 +918,12 @@ int mncc_create_remote_leg(struct mncc_connection *conn, struct call *call)
OSMO_STRLCPY_ARRAY(mncc.called.number, call->dest);
}
/*
* TODO/FIXME:
* - Determine/request channel based on offered audio codecs
* - Screening, redirect?
* - Synth. the bearer caps based on codecs?
*/
/* The call->initial leg is a SIP call leg that starts an MT call. There was SDP received in the SIP INVITE that
* started this call. This here will be the call->remote, always forwarding the SDP that came in on
* call->initial. */
if (call->initial)
OSMO_STRLCPY_ARRAY(mncc.sdp, call->initial->sdp);
rc = write(conn->fd.fd, &mncc, sizeof(mncc));
if (rc != sizeof(mncc)) {
LOGP(DMNCC, LOGL_ERROR, "Failed to send message leg(%u)\n",

View File

@ -43,6 +43,12 @@ static void sip_dtmf_call(struct call_leg *_leg, int keypad);
static void sip_hold_call(struct call_leg *_leg);
static void sip_retrieve_call(struct call_leg *_leg);
static const char *sip_get_sdp(const sip_t *sip)
{
if (!sip || !sip->sip_payload)
return NULL;
return sip->sip_payload->pl_data;
}
/* Find a SIP Call leg by given nua_handle */
static struct sip_call_leg *sip_find_leg(nua_handle_t *nh)
@ -82,7 +88,6 @@ static void call_progress(struct sip_call_leg *leg, const sip_t *sip, int status
static void call_connect(struct sip_call_leg *leg, const sip_t *sip)
{
/* extract SDP file and if compatible continue */
struct call_leg *other = call_leg_other(&leg->base);
if (!other) {
@ -177,6 +182,8 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh,
nua_handle_bind(nh, leg);
leg->sdp_payload = talloc_strdup(leg, sip->sip_payload->pl_data);
call_leg_update_sdp(&leg->base, sip_get_sdp(sip));
app_route_call(call,
talloc_strdup(leg, from),
talloc_strdup(leg, to));
@ -218,6 +225,8 @@ static void sip_handle_reinvite(struct sip_call_leg *leg, nua_handle_t *nh, cons
inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr));
LOGP(DSIP, LOGL_DEBUG, "pre re-INVITE have IP:port (%s:%u)\n", ip_addr, leg->base.port);
call_leg_update_sdp(&leg->base, sip_get_sdp(sip));
if (mode == sdp_sendonly) {
/* SIP side places call on HOLD */
sdp = sdp_create_file(leg, other, sdp_recvonly);
@ -330,6 +339,8 @@ void nua_callback(nua_event_t event, int status, char const *phrase, nua_t *nua,
struct sip_call_leg *leg;
leg = (struct sip_call_leg *) hmagic;
call_leg_update_sdp(&leg->base, sip_get_sdp(sip));
/* MT call is moving forward */
/* The dialogue is now confirmed */
@ -366,8 +377,10 @@ void nua_callback(nua_event_t event, int status, char const *phrase, nua_t *nua,
* respond to the re-INVITE query. */
if (sip->sip_payload && sip->sip_payload->pl_data) {
struct sip_call_leg *leg = sip_find_leg(nh);
if (leg)
if (leg) {
call_leg_update_sdp(&leg->base, sip_get_sdp(sip));
sip_handle_reinvite(leg, nh, sip);
}
}
} else if (event == nua_r_bye || event == nua_r_cancel) {
/* our bye or hang up is answered */
@ -393,9 +406,10 @@ void nua_callback(nua_event_t event, int status, char const *phrase, nua_t *nua,
if (status == 100) {
struct sip_call_leg *leg = sip_find_leg(nh);
if (leg)
if (leg) {
call_leg_update_sdp(&leg->base, sip_get_sdp(sip));
sip_handle_reinvite(leg, nh, sip);
else
} else
new_call((struct sip_agent *) magic, nh, sip);
}
} else if (event == nua_i_cancel) {