client: allow passing and receiving full SDP to/from MGW

Clients can continue to use the current way of providing the information
contained in the SDP part.

A client may also decide to directly provide an SDP string. That may be
useful to send a list of payload types with mixed fmtp (e.g. two
entries, one for AMR OA and one for AMR BE) or any other custom SDP that
is not possible to be represented with the previous structure of struct
mgcp_conn_peer:

 struct sdp_msg sdp = {};
 sdp_audio_codecs_add(&sdp.audio_codecs, 96, "AMR", 8000, "octet-align=1");
 sdp_audio_codecs_add(&sdp.audio_codecs, 97, "AMR", 8000, "octet-align=0");

 struct mgcp_conn_peer verb_info = { ... };
 sdp_msg_to_sdp_str_buf(verb_info.sdp, sizeof(verb_info.sdp), &sdp);

 osmo_mgcpc_ep_ci_request(my_ci, MGCP_VERB_MDCX, &verb_info,...);

(TODO: sdp_msg, sdp_audio_codecs_add() and sdp_msg_to_sdp_str_buf() so
far only exists in osmo-msc.git)

If no SDP is present in the passed verb_info, the SDP part is composed
as before from the mgcp_conn_peer members addr, port, ptime, ptmap,
param. If an SDP string is present in the passed verb_info, ignore the
data in the individual members, and directly pass the given SDP string
instead -- the caller does not need to pass both the individual members
and SDP, either one suffices.

A client can read the full SDP response from the MGW, again for example
to accurately parse a list with mixed fmtp for AMR like above, like
this:

 /* Handling successful event after osmo_mgcpc_ep_ci_request(my_fi, my_notify_event): */
 const struct mgcp_conn_peer *response_info = osmo_mgcpc_ep_ci_get_rtp_info(ci);
 struct sdp_msg sdp;
 sdp_msg_from_sdp_str(&sdp, response_info->sdp);

 for (int i = 0; i < sdp.audio_codecs.count; i++)
 	printf("PT %u = %s %s",
	       sdp.audio_codecs.codec[i].payload_type,
	       sdp.audio_codecs.codec[i].subtype_name,
	       sdp.audio_codecs.codec[i].fmtp);

Related: OS#5723
Change-Id: Ib26b4d24546a9a9af65d4313fdf87cdeff9cbc22
This commit is contained in:
Neels Hofmeyr 2023-03-30 16:51:09 +02:00
parent 9f70f78ae3
commit 1b46b3405a
4 changed files with 30 additions and 2 deletions

View File

@ -83,6 +83,7 @@ struct mgcp_response_head {
};
struct mgcp_response {
/* The complete MGCP + SDP response. See also 'sdp' below. */
char *body;
struct mgcp_response_head head;
uint16_t audio_port;
@ -92,6 +93,8 @@ struct mgcp_response {
unsigned int codecs_len;
struct ptmap ptmap[MGCP_MAX_CODECS];
unsigned int ptmap_len;
/* Start of the SDP part of 'body'. */
char *sdp;
};
enum mgcp_verb {
@ -131,6 +134,8 @@ struct mgcp_msg {
int x_osmo_osmux_cid; /* -1 is wildcard */
bool param_present;
struct mgcp_codec_param param;
char sdp[1024];
};
void mgcp_client_conf_init(struct mgcp_client_conf *conf);

View File

@ -61,6 +61,8 @@ struct mgcp_conn_peer {
* mgcp_common.h */
bool param_present;
struct mgcp_codec_param param;
char sdp[1024];
};
struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,

View File

@ -493,6 +493,7 @@ int mgcp_response_parse_params(struct mgcp_response *r)
rc = 0;
goto exit;
}
r->sdp = data_ptr;
/* data_ptr now points to the beginning of the section-end-marker; for_each_non_empty_line()
* skips any \r and \n characters for free, so we don't need to skip the marker. */
@ -1194,6 +1195,13 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
/* Add separator to mark the beginning of the SDP block */
MSGB_PRINTF_OR_RET("\r\n");
if (mgcp_msg->sdp[0] != '\0') {
/* The caller provided a full SDP string, no need to compose SDP. */
MSGB_PRINTF_OR_RET("%s", mgcp_msg->sdp);
return 0;
}
/* The caller did not provide a full SDP section, compose SDP string from the mgcp_msg members. */
/* Add SDP protocol version */
MSGB_PRINTF_OR_RET("v=0\r\n");
@ -1376,8 +1384,9 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
/* Using SDP makes sense when a valid IP/Port combination is specifiec,
* if we do not know this information yet, we fall back to LCO */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_IP
&& mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT)
if (((mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_IP)
&& (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT))
|| mgcp_msg->sdp[0] != '\0')
use_sdp = true;
/* Add local connection options (LCO) */

View File

@ -140,6 +140,9 @@ static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
mgcp_msg->audio_ip = info->addr;
mgcp_msg->audio_port = info->port;
mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
if (info->sdp[0] != '\0')
OSMO_STRLCPY_ARRAY(mgcp_msg->sdp, info->sdp);
}
static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer)
@ -179,6 +182,9 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
mgcp_msg.presence |= MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID;
}
if (mgcp_ctx->conn_peer_local.sdp[0] != '\0')
OSMO_STRLCPY_ARRAY(mgcp_msg.sdp, mgcp_ctx->conn_peer_local.sdp);
/* Note: We take the endpoint and the call_id from the remote
* connection info, because we can be confident that the
* information there is valid. For the local info, we explicitly
@ -319,6 +325,9 @@ static void mgw_crcx_resp_cb(struct mgcp_response *r, void *priv)
return;
}
if (r->sdp && r->sdp[0] != '\0')
OSMO_STRLCPY_ARRAY(mgcp_ctx->conn_peer_remote.sdp, r->sdp);
mgcp_ctx->conn_peer_remote.call_id = mgcp_ctx->conn_peer_local.call_id;
osmo_fsm_inst_dispatch(fi, EV_CRCX_RESP, mgcp_ctx);
@ -426,6 +435,9 @@ static void mgw_mdcx_resp_cb(struct mgcp_response *r, void *priv)
osmo_strlcpy(mgcp_ctx->conn_peer_remote.addr, r->audio_ip, sizeof(mgcp_ctx->conn_peer_remote.addr));
mgcp_ctx->conn_peer_remote.port = r->audio_port;
if (r->sdp && r->sdp[0] != '\0')
OSMO_STRLCPY_ARRAY(mgcp_ctx->conn_peer_remote.sdp, r->sdp);
osmo_fsm_inst_dispatch(fi, EV_MDCX_RESP, mgcp_ctx);
}