summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2019-08-15 06:12:54 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2019-09-17 15:34:38 +0200
commit5dc054375e8bf54221aefa1b6cbb6e5a75b5f112 (patch)
tree75f6841fb76cc972ec31de6669f1dc2429c3410f
parent5e3c9d7224758e0fd530f7718e1bb97bc5c9ae62 (diff)
add sdp to mnccneels/codecs
-rw-r--r--src/call.c10
-rw-r--r--src/call.h7
-rw-r--r--src/mncc.c37
-rw-r--r--src/mncc_protocol.h6
-rw-r--r--src/sdp.c16
-rw-r--r--src/sip.c46
6 files changed, 98 insertions, 24 deletions
diff --git a/src/call.c b/src/call.c
index 9f593ea..487be56 100644
--- a/src/call.c
+++ b/src/call.c
@@ -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);
+}
diff --git a/src/call.h b/src/call.h
index bc772a4..9bf68eb 100644
--- a/src/call.h
+++ b/src/call.h
@@ -54,6 +54,11 @@ struct call_leg {
uint32_t payload_type;
uint32_t payload_msg_type;
+ /* SDP as received for this call leg. If this is an MNCC call leg, contains the SDP most recently received in an
+ * MNCC message; if this is a SIP call leg, contains the SDP most recently received in a SIP message. If no SDP
+ * was received yet, this string is empty. Otherwise a nul terminated string. */
+ char sdp[1024];
+
/**
* Remote started to ring/alert
*/
@@ -157,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);
diff --git a/src/mncc.c b/src/mncc.c
index f2e2579..bd18cc4 100644
--- a/src/mncc.c
+++ b/src/mncc.c
@@ -185,6 +185,8 @@ static bool send_rtp_connect(struct mncc_call_leg *leg, struct call_leg *other)
mncc.ip = ntohl(other->ip);
mncc.port = other->port;
mncc.payload_type = other->payload_type;
+
+ OSMO_STRLCPY_ARRAY(mncc.sdp, other->sdp);
/*
* FIXME: mncc.payload_msg_type should already be compatible.. but
* payload_type should be different..
@@ -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));
@@ -502,6 +508,8 @@ static void check_setup(struct mncc_connection *conn, const char *buf, int rc)
}
/* TODO.. bearer caps and better audio handling */
+ printf("MNCC_SETUP_IND SDP: <<\n%s>>\n", data->sdp);
+
if (!continue_setup(conn, data)) {
LOGP(DMNCC, LOGL_ERROR,
"MNCC screening parameters failed leg(%u)\n", data->callref);
@@ -529,6 +537,8 @@ 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));
+ 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 +648,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 +684,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 +704,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 +784,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 +815,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 +839,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 +920,15 @@ 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);
+ printf("call->initial->sdp == %s\n", call->initial->sdp);
+ } else
+ printf("no call->initial\n");
+
rc = write(conn->fd.fd, &mncc, sizeof(mncc));
if (rc != sizeof(mncc)) {
LOGP(DMNCC, LOGL_ERROR, "Failed to send message leg(%u)\n",
diff --git a/src/mncc_protocol.h b/src/mncc_protocol.h
index 4950a77..b6f6635 100644
--- a/src/mncc_protocol.h
+++ b/src/mncc_protocol.h
@@ -158,6 +158,9 @@ struct gsm_mncc {
unsigned char lchan_type;
unsigned char lchan_mode;
+
+ /* A buffer to contain SDP ('\0' terminated) */
+ char sdp[1024];
};
struct gsm_data_frame {
@@ -166,7 +169,7 @@ struct gsm_data_frame {
unsigned char data[0];
};
-#define MNCC_SOCK_VERSION 5
+#define MNCC_SOCK_VERSION 6
struct gsm_mncc_hello {
uint32_t msg_type;
uint32_t version;
@@ -189,6 +192,7 @@ struct gsm_mncc_rtp {
uint16_t port;
uint32_t payload_type;
uint32_t payload_msg_type;
+ char sdp[1024];
};
struct gsm_mncc_bridge {
diff --git a/src/sdp.c b/src/sdp.c
index 46330cd..4a3067d 100644
--- a/src/sdp.c
+++ b/src/sdp.c
@@ -178,7 +178,9 @@ bool sdp_extract_sdp(struct sip_call_leg *leg, const sip_t *sip, bool any_codec)
continue;
for (map = media->m_rtpmaps; map; map = map->rm_next) {
- if (!any_codec && strcasecmp(map->rm_encoding, leg->wanted_codec) != 0)
+ if (!any_codec
+ && leg->wanted_codec
+ && strcasecmp(map->rm_encoding, leg->wanted_codec) != 0)
continue;
leg->base.port = media->m_port;
@@ -202,8 +204,19 @@ bool sdp_extract_sdp(struct sip_call_leg *leg, const sip_t *sip, bool any_codec)
return true;
}
+/* One leg has sent a SIP or MNCC message, which is now translated/forwarded to the counterpart MNCC or SIP.
+ * Take as much from the source's SDP as possible, but make sure the connection mode reflects the 'mode' arg (sendrecv,
+ * recvonly, sendonly, inactive).
+ * @param leg The target receiving the SDP.
+ * @param other The source of which we are to reflect the SDP.
+ * For example, if the MNCC sent an MNCC_SETUP_IND, the SDP from the MNCC is found in 'other', while 'leg' reflects the
+ * SIP side that should receive this SDP in the SIP Invite that is being composed by the caller.
+ */
char *sdp_create_file(struct sip_call_leg *leg, struct call_leg *other, sdp_mode_t mode)
{
+ /* TODO: make sure SDP reflects the requested mode */
+ return talloc_strdup(leg, other->sdp);
+#if 0
struct in_addr net = { .s_addr = other->ip };
char *fmtp_str = NULL, *sdp;
char *mode_attribute;
@@ -251,4 +264,5 @@ char *sdp_create_file(struct sip_call_leg *leg, struct call_leg *other, sdp_mode
mode_attribute);
talloc_free(fmtp_str);
return sdp;
+#endif
}
diff --git a/src/sip.c b/src/sip.c
index 2b28b4e..2aa0ded 100644
--- a/src/sip.c
+++ b/src/sip.c
@@ -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)
@@ -73,8 +79,10 @@ static void call_progress(struct sip_call_leg *leg, const sip_t *sip, int status
return;
/* Extract SDP for session in progress with matching codec */
+ /*
if (status == 183)
sdp_extract_sdp(leg, sip, false);
+ */
LOGP(DSIP, LOGL_INFO, "leg(%p) is now progressing.\n", leg);
other->ring_call(other);
@@ -91,12 +99,14 @@ static void call_connect(struct sip_call_leg *leg, const sip_t *sip)
return;
}
+ /*
if (!sdp_extract_sdp(leg, sip, false)) {
LOGP(DSIP, LOGL_ERROR, "leg(%p) incompatible audio, releasing\n", leg);
nua_cancel(leg->nua_handle, TAG_END());
other->release_call(other);
return;
}
+ */
LOGP(DSIP, LOGL_INFO, "leg(%p) is now connected(%s).\n", leg, sip->sip_call_id->i_id);
leg->state = SIP_CC_CONNECTED;
@@ -114,20 +124,8 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh,
LOGP(DSIP, LOGL_INFO, "Incoming call(%s) handle(%p)\n", sip->sip_call_id->i_id, nh);
- if (!sdp_screen_sdp(sip)) {
- LOGP(DSIP, LOGL_ERROR, "No supported codec.\n");
- nua_respond(nh, SIP_406_NOT_ACCEPTABLE, TAG_END());
- nua_handle_destroy(nh);
- return;
- }
-
call = call_sip_create();
- if (!call) {
- LOGP(DSIP, LOGL_ERROR, "No supported codec.\n");
- nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
- nua_handle_destroy(nh);
- return;
- }
+ OSMO_ASSERT(call);
if (sip->sip_to)
to = sip->sip_to->a_url->url_user;
@@ -145,6 +143,8 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh,
leg->state = SIP_CC_DLG_CNFD;
leg->dir = SIP_DIR_MO;
+
+
/*
* FIXME/TODO.. we need to select the codec at some point. But it is
* not this place. It starts with the TCH/F vs. TCH/H selection based
@@ -152,6 +152,7 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh,
* are GSM related... and do not belong here. Just pick the first codec
* so the IP address, port and payload type is set.
*/
+ /*
if (!sdp_extract_sdp(leg, sip, true)) {
LOGP(DSIP, LOGL_ERROR, "leg(%p) no audio, releasing\n", leg);
nua_respond(nh, SIP_406_NOT_ACCEPTABLE, TAG_END());
@@ -159,6 +160,7 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh,
call_leg_release(&leg->base);
return;
}
+ */
struct in_addr net = { .s_addr = leg->base.ip };
inet_ntop(AF_INET, &net, ip_addr, sizeof(ip_addr));
LOGP(DSIP, LOGL_INFO, "SDP Extracted: IP=(%s) PORT=(%u) PAYLOAD=(%u).\n",
@@ -177,6 +179,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 +222,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 +336,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 +374,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 +403,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) {
@@ -599,6 +610,9 @@ static int send_invite(struct sip_agent *agent, struct sip_call_leg *leg,
agent->app->sip.remote_port);
char *sdp = sdp_create_file(leg, other, sdp_sendrecv);
+ LOGP(DSIP, LOGL_DEBUG, "Will send INVITE with SDP: %s\n",
+ sdp);
+
leg->state = SIP_CC_INITIAL;
leg->dir = SIP_DIR_MT;
nua_invite(leg->nua_handle,