mgcp: Optionally send ptime in SDP

Currently the SDP 'ptime' media attribute is never set in generated
MGCP responses.

This patch optionally includes the 'ptime' attribute if
packet_duration_ms is != 0. This behaviour can be enabled/disabled
by using the VTY command "sdp audio-payload send-ptime" (enabled by
default).

Sponsored-by: On-Waves ehf
diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c
index b8d1920..7d3ad74 100644
--- a/openbsc/src/libmgcp/mgcp_protocol.c
+++ b/openbsc/src/libmgcp/mgcp_protocol.c
@@ -230,11 +230,12 @@
 	const char *addr = endp->cfg->local_ip;
 	const char *fmtp_extra = endp->bts_end.fmtp_extra;
 	char sdp_record[4096];
+	int len;
 
 	if (!addr)
 		addr = endp->cfg->source_addr;
 
-	snprintf(sdp_record, sizeof(sdp_record) - 1,
+	len = snprintf(sdp_record, sizeof(sdp_record) - 1,
 			"I: %u\n\n"
 			"v=0\r\n"
 			"o=- %u 23 IN IP4 %s\r\n"
@@ -247,7 +248,25 @@
 			endp->net_end.local_port, endp->bts_end.payload_type,
 			endp->bts_end.payload_type, endp->tcfg->audio_name,
 			fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : "");
+
+	if (len < 0 || len >= sizeof(sdp_record))
+		goto buffer_too_small;
+
+	if (endp->bts_end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
+		int nchars = snprintf(sdp_record + len, sizeof(sdp_record) - len,
+				      "a=ptime:%d\r\n",
+				      endp->bts_end.packet_duration_ms);
+		if (nchars < 0 || nchars >= sizeof(sdp_record) - len)
+			goto buffer_too_small;
+
+		len += nchars;
+	}
 	return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record);
+
+buffer_too_small:
+	LOGP(DMGCP, LOGL_ERROR, "SDP buffer too small: %d (needed %d)\n",
+	     sizeof(sdp_record), len);
+	return NULL;
 }
 
 /*
@@ -1109,6 +1128,7 @@
 	cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
 	cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
 	cfg->trunk.audio_payload = 126;
+	cfg->trunk.audio_send_ptime = 1;
 	cfg->trunk.omit_rtcp = 0;
 
 	INIT_LLIST_HEAD(&cfg->trunks);
@@ -1131,6 +1151,7 @@
 	trunk->trunk_nr = nr;
 	trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
 	trunk->audio_payload = 126;
+	trunk->audio_send_ptime = 1;
 	trunk->number_endpoints = 33;
 	trunk->omit_rtcp = 0;
 	llist_add_tail(&trunk->entry, &cfg->trunks);
diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c
index e48b050..235b8bd 100644
--- a/openbsc/src/libmgcp/mgcp_vty.c
+++ b/openbsc/src/libmgcp/mgcp_vty.c
@@ -105,6 +105,8 @@
 	if (g_cfg->trunk.audio_fmtp_extra)
 		vty_out(vty, "  sdp audio fmtp-extra %s%s",
 			g_cfg->trunk.audio_fmtp_extra, VTY_NEWLINE);
+	vty_out(vty, "  %ssdp audio-payload send-ptime%s",
+		g_cfg->trunk.audio_send_ptime ? "" : "no ", VTY_NEWLINE);
 	vty_out(vty, "  loop %u%s", !!g_cfg->trunk.audio_loop, VTY_NEWLINE);
 	vty_out(vty, "  number endpoints %u%s", g_cfg->trunk.number_endpoints - 1, VTY_NEWLINE);
 	if (g_cfg->call_agent_addr)
@@ -391,6 +393,26 @@
       "sdp audio payload name NAME",
       SDP_STR AUDIO_STR AUDIO_STR "Name\n" "Payload name\n")
 
+DEFUN(cfg_mgcp_sdp_payload_send_ptime,
+      cfg_mgcp_sdp_payload_send_ptime_cmd,
+      "sdp audio-payload send-ptime",
+      SDP_STR AUDIO_STR
+      "Send SDP ptime (packet duration) attribute\n")
+{
+	g_cfg->trunk.audio_send_ptime = 1;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_no_sdp_payload_send_ptime,
+      cfg_mgcp_no_sdp_payload_send_ptime_cmd,
+      "no sdp audio-payload send-ptime",
+      NO_STR SDP_STR AUDIO_STR
+      "Send SDP ptime (packet duration) attribute\n")
+{
+	g_cfg->trunk.audio_send_ptime = 0;
+	return CMD_SUCCESS;
+}
+
 DEFUN(cfg_mgcp_loop,
       cfg_mgcp_loop_cmd,
       "loop (0|1)",
@@ -568,6 +590,8 @@
 			trunk->audio_payload, VTY_NEWLINE);
 		vty_out(vty, "  sdp audio-payload name %s%s",
 			trunk->audio_name, VTY_NEWLINE);
+		vty_out(vty, "  %ssdp audio-payload send-ptime%s",
+			trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
 		vty_out(vty, "  loop %d%s",
 			trunk->audio_loop, VTY_NEWLINE);
 		if (trunk->omit_rtcp)
@@ -649,6 +673,28 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_trunk_sdp_payload_send_ptime,
+      cfg_trunk_sdp_payload_send_ptime_cmd,
+      "sdp audio-payload send-ptime",
+      SDP_STR AUDIO_STR
+      "Send SDP ptime (packet duration) attribute\n")
+{
+	struct mgcp_trunk_config *trunk = vty->index;
+	trunk->audio_send_ptime = 1;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_trunk_no_sdp_payload_send_ptime,
+      cfg_trunk_no_sdp_payload_send_ptime_cmd,
+      "no sdp audio-payload send-ptime",
+      NO_STR SDP_STR AUDIO_STR
+      "Send SDP ptime (packet duration) attribute\n")
+{
+	struct mgcp_trunk_config *trunk = vty->index;
+	trunk->audio_send_ptime = 0;
+	return CMD_SUCCESS;
+}
+
 DEFUN(cfg_trunk_omit_rtcp,
       cfg_trunk_omit_rtcp_cmd,
       "rtcp-omit",
@@ -966,6 +1012,8 @@
 	install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_ts_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_sdp_fmtp_extra_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_send_ptime_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_ptime_cmd);
 
 	install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
 	install_node(&trunk_node, config_write_trunk);
@@ -983,6 +1031,8 @@
 	install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ts_cmd);
 	install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_cmd);
 	install_element(TRUNK_NODE, &cfg_trunk_sdp_fmtp_extra_cmd);
+	install_element(TRUNK_NODE, &cfg_trunk_sdp_payload_send_ptime_cmd);
+	install_element(TRUNK_NODE, &cfg_trunk_no_sdp_payload_send_ptime_cmd);
 
 	return 0;
 }