client: collapse codecs[] and ptmap[]; allow codec variants

codecs[] is an array of enum osmo_mgcp_codecs.
ptmap[] is an array of { enum osmo_mgcp_codecs, unsigned int ptmap }.

MGCP lists first a bunch of payload type numbers and then specifies them
again for details, like the numbers 112, 96, 3 in this example:

 m=audio <port> RTP/AVP 112 96 3
 a=rtpmap:112 AMR/8000
 a=rtpmap:96 VND.3GPP.IUFP/16000
 a=rtpmap:3 GSM-FR/8000

So far we keep these lists in two separate arrays:
- codecs[], codecs_len stores the 'm=audio' list
- ptmap[], ptmap_len stores the 'a=rtpmap' list (and may omit some
  elements present in codecs[])
This applies to both struct mgcp_response and struct mgcp_msg.

These are semantically identical, and the separation leads to checks,
conversions and dear hopes of correct ordering.

So let's keep only one list with both codec and payload type number in
it. The 'm=audio' list establishes the order of the pt numbers, and the
'a=rtpmap' list adds codec information to the established entries.

In the internal API structs mgcp_msg and mgcp_response, just drop the
codecs[] entirely.

In public API struct mgcp_conn_peer, keep the codecs[] array, mark it
deprecated, and provide a backwards compat conversion: if any caller
invokes mgcp_conn_create() or mgcp_conn_modify() with codecs[] still
present in the verb_info arg, then move codecs[] entries over to the
ptmap[] array in a sensible way.
(BTW, even mgcp_conn_create() and mgcp_conn_modify() are never called
from outside of libosmo-mgcp-client in any of our osmo-cni programs;
users call osmo_mgcpc_ep_ci_add() and osmo_mgcpc_ep_ci_request(), which
in turn may pass user-provided codecs[] lists on to mgcp_conn_create() or
mgcp_conn_modify().)

Tests for parsing the MGCP response are mostly missing. They will be
added in upcoming patch I842ce65a9a70f313570857b7df53727cc572b9e6,
because they will be using only the new ptmap API.

Related: OS#6171
Change-Id: I798e02c6663376d3d52f4a74fc4b32411ce95bed
This commit is contained in:
Neels Hofmeyr 2023-12-07 03:46:46 +01:00
parent 960c031a67
commit cc2f7937ed
7 changed files with 175 additions and 74 deletions

View File

@ -35,3 +35,6 @@ libosmo-mgcp-client remove public API These public API items have not been calle
mgcp_client_cancel()
mgcp_msg_gen()
mgcp_msg_trans_id()
libosmo-mgcp-client deprecate public API New code should no longer use codecs[], instead use ptmap[].codec. There
is backwards compat code that moves codecs[] entries, if any, over to
ptmap[], so callers may migrate at own leisure.

View File

@ -79,6 +79,8 @@ struct ptmap {
unsigned int pt;
};
int ptmap_cmp(const struct ptmap *a, const struct ptmap *b);
enum mgcp_verb {
MGCP_VERB_CRCX,
MGCP_VERB_MDCX,

View File

@ -29,11 +29,11 @@ struct mgcp_conn_peer {
/*! RTP packetization interval (optional) */
unsigned int ptime;
/*! RTP codec list (optional) */
enum mgcp_codecs codecs[MGCP_MAX_CODECS];
/*! Number of codecs in RTP codec list (optional) */
unsigned int codecs_len;
/*! Deprecated. Use only ptmap[].codec in new code. */
enum mgcp_codecs codecs[MGCP_MAX_CODECS]
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[i].codec instead");
unsigned int codecs_len
OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[] and ptmap_len instead");
/*! RTP payload type map (optional, only needed when payload types are
* used that differ from what IANA/3GPP defines) */

View File

@ -38,8 +38,6 @@ struct mgcp_response {
uint16_t audio_port;
char audio_ip[INET6_ADDRSTRLEN];
unsigned int ptime;
enum mgcp_codecs codecs[MGCP_MAX_CODECS];
unsigned int codecs_len;
struct ptmap ptmap[MGCP_MAX_CODECS];
unsigned int ptmap_len;
};
@ -84,8 +82,6 @@ struct mgcp_msg {
char *audio_ip;
enum mgcp_connection_mode conn_mode;
unsigned int ptime;
enum mgcp_codecs codecs[MGCP_MAX_CODECS];
unsigned int codecs_len;
struct ptmap ptmap[MGCP_MAX_CODECS];
unsigned int ptmap_len;
uint32_t x_osmo_ign;

View File

@ -302,7 +302,7 @@ static int mgcp_parse_audio_port_pt(struct mgcp_response *r, char *line)
char *pt_str;
char *pt_end;
unsigned long int pt;
unsigned int count = 0;
unsigned int ptmap_len;
unsigned int i;
/* Extract port information */
@ -316,10 +316,15 @@ static int mgcp_parse_audio_port_pt(struct mgcp_response *r, char *line)
if (!line)
goto exit;
/* Clear any previous entries before writing over r->ptmap */
r->ptmap_len = 0;
/* Keep a local ptmap_len to show only the full list after parsing succeeded in whole. */
ptmap_len = 0;
pt_str = strtok(line, " ");
while (1) {
/* Do not allow excessive payload types */
if (count >= ARRAY_SIZE(r->codecs))
if (ptmap_len >= ARRAY_SIZE(r->ptmap))
goto response_parse_failure_pt;
pt_str = strtok(NULL, " ");
@ -335,21 +340,23 @@ static int mgcp_parse_audio_port_pt(struct mgcp_response *r, char *line)
goto response_parse_failure_pt;
/* Do not allow duplicate payload types */
for (i = 0; i < count; i++)
if (r->codecs[i] == pt)
for (i = 0; i < ptmap_len; i++)
if (r->ptmap[i].pt == pt)
goto response_parse_failure_pt;
/* Note: The payload type we store may not necessarly match
* the codec types we have defined in enum mgcp_codecs. To
* ensure that the end result only contains codec types which
* match enum mgcp_codecs, we will go through afterwards and
* remap the affected entries with the inrofmation we learn
* from rtpmap */
r->codecs[count] = pt;
count++;
/* Some payload type numbers imply a specific codec. For those, using the PT number as enum mgcp_codecs
* yields the correct result. If no more specific information on the codec follows in "a=rtpmap:N"
* lines, then this default number takes over. This only applies for PT below the dynamic range (<96). */
if (pt < 96)
r->ptmap[ptmap_len].codec = pt;
else
r->ptmap[ptmap_len].codec = -1;
r->ptmap[ptmap_len].pt = pt;
ptmap_len++;
}
r->codecs_len = count;
/* Parsing succeeded, publish all entries. */
r->ptmap_len = ptmap_len;
exit:
return 0;
@ -365,10 +372,11 @@ response_parse_failure_pt:
return -EINVAL;
}
/* Parse a line like "m=audio 16002 RTP/AVP 98", extract port and payload types */
/* Parse an 'a=...' parameter */
static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *line)
{
unsigned int pt;
unsigned int i;
char codec_resp[64];
int rc;
@ -387,18 +395,39 @@ static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *li
"Failed to parse SDP parameter, invalid rtpmap: %s\n", osmo_quote_str(line, -1));
return -EINVAL;
}
if (r->ptmap_len >= ARRAY_SIZE(r->ptmap)) {
LOGP(DLMGCP, LOGL_ERROR, "No more space in ptmap array (len=%u)\n", r->ptmap_len);
return -ENOSPC;
}
rc = map_str_to_codec(codec_resp);
if (rc < 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Failed to parse SDP parameter, can't parse codec in rtpmap: %s\n", osmo_quote_str(line, -1));
return -EINVAL;
}
r->ptmap[r->ptmap_len].pt = pt;
r->ptmap[r->ptmap_len].codec = rc;
/* Earlier, a line like "m=audio 16002 RTP/AVP 98 112 3" established the desired order of payloads, now
* enrich it with actual codec information provided by "a=rtpmap:..." entries.
* For each, find the entry with the right pt number and add the info there. */
for (i = 0; i < r->ptmap_len; i++) {
if (r->ptmap[i].pt != pt)
continue;
r->ptmap[i].codec = rc;
return 0;
}
/* No entry was found. This is an error in the MGCP protocol, but let's just add another entry
* anyway, to not make it look like it was never there. */
LOGP(DLMGCP, LOGL_ERROR,
"error in MGCP message: 'a=rtpmap:%u' has no matching entry in 'm=audio ... %u'\n",
pt, pt);
if (r->ptmap_len >= ARRAY_SIZE(r->ptmap)) {
LOGP(DLMGCP, LOGL_ERROR,
"cannot parse all codecs: can only store up to %zu rtpmap entries.\n",
ARRAY_SIZE(r->ptmap));
return -ENOSPC;
}
r->ptmap[r->ptmap_len] = (struct ptmap){
.pt = pt,
.codec = rc,
};
r->ptmap_len++;
}
@ -508,7 +537,6 @@ int mgcp_response_parse_params(struct mgcp_response *r)
int rc;
char *data;
char *data_ptr;
int i;
/* Since this functions performs a destructive parsing, we create a
* local copy of the body data */
@ -553,10 +581,6 @@ int mgcp_response_parse_params(struct mgcp_response *r)
}
}
/* See also note in mgcp_parse_audio_port_pt() */
for (i = 0; i < r->codecs_len; i++)
r->codecs[i] = map_pt_to_codec(r->ptmap, r->ptmap_len, r->codecs[i]);
rc = 0;
exit:
talloc_free(data);
@ -1234,7 +1258,6 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
{
unsigned int i;
const char *codec;
unsigned int pt;
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
@ -1248,11 +1271,10 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
if (mgcp_msg->ptime)
MSGB_PRINTF_OR_RET(" p:%u,", mgcp_msg->ptime);
if (mgcp_msg->codecs_len) {
if (mgcp_msg->ptmap_len) {
MSGB_PRINTF_OR_RET(" a:");
for (i = 0; i < mgcp_msg->codecs_len; i++) {
pt = mgcp_msg->codecs[i];
codec = get_value_string_or_null(osmo_mgcpc_codec_names, pt);
for (i = 0; i < mgcp_msg->ptmap_len; i++) {
codec = get_value_string_or_null(osmo_mgcpc_codec_names, mgcp_msg->ptmap[i].codec);
/* Note: Use codec descriptors from enum mgcp_codecs
* in mgcp_client only! */
@ -1260,7 +1282,7 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
return -EINVAL;
MSGB_PRINTF_OR_RET("%s", extract_codec_name(codec));
if (i < mgcp_msg->codecs_len - 1)
if (i < mgcp_msg->ptmap_len - 1)
MSGB_PRINTF_OR_RET(";");
}
MSGB_PRINTF_OR_RET(",");
@ -1338,21 +1360,19 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
return -EINVAL;
}
MSGB_PRINTF_OR_RET("m=audio %u RTP/AVP", mgcp_msg->audio_port);
for (i = 0; i < mgcp_msg->codecs_len; i++) {
pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
MSGB_PRINTF_OR_RET(" %u", pt);
}
for (i = 0; i < mgcp_msg->ptmap_len; i++)
MSGB_PRINTF_OR_RET(" %u", mgcp_msg->ptmap[i].pt);
MSGB_PRINTF_OR_RET("\r\n");
}
/* Add optional codec parameters (fmtp) */
if (mgcp_msg->param_present) {
for (i = 0; i < mgcp_msg->codecs_len; i++) {
for (i = 0; i < mgcp_msg->ptmap_len; i++) {
/* The following is only applicable for AMR */
if (mgcp_msg->codecs[i] != CODEC_AMR_8000_1 && mgcp_msg->codecs[i] != CODEC_AMRWB_16000_1)
if (mgcp_msg->ptmap[i].codec != CODEC_AMR_8000_1
&& mgcp_msg->ptmap[i].codec != CODEC_AMRWB_16000_1)
continue;
pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
pt = mgcp_msg->ptmap[i].pt;
if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)
MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=1\r\n", pt);
else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)
@ -1360,14 +1380,14 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
}
}
for (i = 0; i < mgcp_msg->codecs_len; i++) {
pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
for (i = 0; i < mgcp_msg->ptmap_len; i++) {
pt = mgcp_msg->ptmap[i].pt;
/* Note: Only dynamic payload type from the range 96-127
* require to be explained further via rtpmap. All others
* are implcitly definedby the number in m=audio */
if (pt >= 96 && pt <= 127) {
codec = get_value_string_or_null(osmo_mgcpc_codec_names, mgcp_msg->codecs[i]);
codec = get_value_string_or_null(osmo_mgcpc_codec_names, mgcp_msg->ptmap[i].codec);
/* Note: Use codec descriptors from enum mgcp_codecs
* in mgcp_client only! */
@ -1575,3 +1595,20 @@ const char *mgcp_client_name(const struct mgcp_client *mgcp)
else
return mgcp_client_endpoint_domain(mgcp);
}
/*! Return typical cmp result, comparing a to b.
* Return 0 if a == b, -1 if a < b, 1 if a > b; comparing all members of ptmap in turn. */
int ptmap_cmp(const struct ptmap *a, const struct ptmap *b)
{
int rc;
if (a == b)
return 0;
if (!a)
return -1;
if (!b)
return 1;
rc = OSMO_CMP(a->codec, b->codec);
if (rc)
return rc;
return OSMO_CMP(a->pt, b->pt);
}

View File

@ -115,12 +115,10 @@ static void make_crcx_msg(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info
.call_id = info->call_id,
.conn_mode = MGCP_CONN_RECV_ONLY,
.ptime = info->ptime,
.codecs_len = info->codecs_len,
.ptmap_len = info->ptmap_len,
.param_present = info->param_present
};
osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);
memcpy(mgcp_msg->codecs, info->codecs, sizeof(mgcp_msg->codecs));
memcpy(mgcp_msg->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));
memcpy(&mgcp_msg->param, &info->param, sizeof(mgcp_msg->param));
@ -173,12 +171,10 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
.audio_ip = mgcp_ctx->conn_peer_local.addr,
.audio_port = mgcp_ctx->conn_peer_local.port,
.ptime = mgcp_ctx->conn_peer_local.ptime,
.codecs_len = mgcp_ctx->conn_peer_local.codecs_len,
.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len,
.param_present = mgcp_ctx->conn_peer_local.param_present
};
osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
memcpy(mgcp_msg.codecs, mgcp_ctx->conn_peer_local.codecs, sizeof(mgcp_msg.codecs));
memcpy(mgcp_msg.ptmap, mgcp_ctx->conn_peer_local.ptmap, sizeof(mgcp_msg.ptmap));
memcpy(&mgcp_msg.param, &mgcp_ctx->conn_peer_local.param, sizeof(mgcp_ctx->conn_peer_local.param));
@ -628,6 +624,72 @@ static struct osmo_fsm fsm_mgcp_client = {
.log_subsys = DLMGCP,
};
/* Provide backwards compat for deprecated conn_peer->codecs[]: when the caller passes in an mgcp_conn_peer instance
* that has codecs[] set, apply it to ptmap[] instead. */
static void mgcp_conn_peer_compat(struct mgcp_conn_peer *conn_peer)
{
struct ptmap ptmap[MGCP_MAX_CODECS];
unsigned int ptmap_len;
if (!conn_peer->codecs_len)
return;
/* Before dropping codecs[], codecs[] would indicate the order in which the codecs should appear in SDP. ptmap[]
* would indicate payload type numbers when not using a default payload type number (may omit entries).
* Now, ptmap[] just indicates both at the same time; codecs[] should be empty, and ptmap[] lists all codecs.
* So if any codecs[] are present, recreate ptmap[] in the order of codecs[]. */
ptmap_len = 0;
for (int i = 0; i < conn_peer->codecs_len; i++) {
enum mgcp_codecs codec = conn_peer->codecs[i];
struct ptmap *found = NULL;
/* Look up whether a specific pt was indicated for this codec */
for (int p = 0; p < conn_peer->ptmap_len; p++) {
if (conn_peer->ptmap[p].codec != codec)
continue;
found = &conn_peer->ptmap[p];
break;
}
if (found) {
ptmap[ptmap_len] = *found;
} else {
ptmap[ptmap_len] = (struct ptmap){
.codec = codec,
/* some enum mgcp_codecs correspond to their standard PT nr, so for compat: */
.pt = codec,
};
}
ptmap_len++;
}
/* Are there any entries in the old ptmap that were omitted by codecs[]? */
for (int p = 0; p < conn_peer->ptmap_len; p++) {
bool exists = false;
for (int i = 0; i < ptmap_len; i++) {
if (ptmap_cmp(&ptmap[i], &conn_peer->ptmap[p]))
continue;
exists = true;
break;
}
if (exists)
continue;
if (ptmap_len >= ARRAY_SIZE(ptmap))
break;
/* Not present yet, add it to the end */
ptmap[ptmap_len] = conn_peer->ptmap[p];
ptmap_len++;
}
/* Use the new ptmap[], and clear out legacy codecs[]. */
memcpy(conn_peer->ptmap, ptmap, sizeof(conn_peer->ptmap));
conn_peer->ptmap_len = ptmap_len;
conn_peer->codecs_len = 0;
}
/*! allocate FSM, and create a new connection on the MGW.
* \param[in] mgcp MGCP client descriptor.
* \param[in] parent_fi Parent FSM instance.
@ -642,6 +704,7 @@ struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm
struct osmo_fsm_inst *fi;
struct in6_addr ip_test;
mgcp_conn_peer_compat(conn_peer);
OSMO_ASSERT(parent_fi);
OSMO_ASSERT(mgcp);
@ -681,6 +744,8 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
struct mgcp_ctx *mgcp_ctx = fi->priv;
struct in6_addr ip_test;
mgcp_conn_peer_compat(conn_peer);
OSMO_ASSERT(mgcp_ctx);
OSMO_ASSERT(conn_peer);

View File

@ -107,9 +107,6 @@ void test_response_cb(struct mgcp_response *response, void *priv)
printf(" audio_port = %u\n", response->audio_port);
printf(" audio_ip = %s\n", response->audio_ip);
printf(" ptime = %u\n", response->ptime);
printf(" codecs_len = %u\n", response->codecs_len);
for(i=0;i<response->codecs_len;i++)
printf(" codecs[%u] = %u\n", i, response->codecs[i]);
printf(" ptmap_len = %u\n", response->ptmap_len);
for(i=0;i<response->ptmap_len;i++) {
printf(" ptmap[%u].codec = %u\n", i, response->ptmap[i].codec);
@ -149,12 +146,11 @@ void test_mgcp_msg(void)
.conn_id = "11",
.conn_mode = MGCP_CONN_RECV_SEND,
.ptime = 20,
.codecs[0] = CODEC_GSM_8000_1,
.codecs[1] = CODEC_AMR_8000_1,
.codecs[2] = CODEC_GSMEFR_8000_1,
.codecs_len = 1,
.ptmap[0].codec = CODEC_GSMEFR_8000_1,
.ptmap[0].pt = 96,
.ptmap = {
{ .codec = CODEC_GSM_8000_1, .pt = CODEC_GSM_8000_1 },
{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
{ .codec = CODEC_GSMEFR_8000_1, .pt = 96 },
},
.ptmap_len = 1,
.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
.x_osmo_osmux_cid = -1, /* wildcard */
@ -179,9 +175,9 @@ void test_mgcp_msg(void)
mgcp_msg.presence =
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
mgcp_msg.codecs_len = 2;
mgcp_msg.ptmap_len = 2;
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
mgcp_msg.codecs_len = 1;
mgcp_msg.ptmap_len = 1;
printf("%s\n", (char *)msg->data);
printf("Generated CRCX message (three codecs, one with custom pt):\n");
@ -189,9 +185,9 @@ void test_mgcp_msg(void)
mgcp_msg.presence =
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
mgcp_msg.codecs_len = 3;
mgcp_msg.ptmap_len = 3;
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
mgcp_msg.codecs_len = 1;
mgcp_msg.ptmap_len = 1;
printf("%s\n", (char *)msg->data);
printf("Generated MDCX message:\n");
@ -209,9 +205,9 @@ void test_mgcp_msg(void)
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
mgcp_msg.codecs_len = 2;
mgcp_msg.ptmap_len = 2;
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
mgcp_msg.codecs_len = 1;
mgcp_msg.ptmap_len = 1;
printf("%s\n", (char *)msg->data);
printf("Generated MDCX message (three codecs, one with custom pt):\n");
@ -220,9 +216,9 @@ void test_mgcp_msg(void)
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
mgcp_msg.codecs_len = 3;
mgcp_msg.ptmap_len = 3;
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
mgcp_msg.codecs_len = 1;
mgcp_msg.ptmap_len = 1;
printf("%s\n", (char *)msg->data);
printf("Generated DLCX message:\n");
@ -330,8 +326,10 @@ void test_mgcp_client_cancel(void)
.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID
| MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
.ptime = 20,
.codecs[0] = CODEC_AMR_8000_1,
.codecs_len = 1
.ptmap = {
{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
},
.ptmap_len = 1
};
printf("\n%s():\n", __func__);