mgcp: Store one more codec/payload type if it is present

In case of some RTP proxy from time to time we are offered both
G729 and G711 but only one of them will work. I intend to adjust
the codec at runtime in case we receive the wrong codec.
diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
index 2458909..34c3d97 100644
--- a/openbsc/include/openbsc/mgcp_internal.h
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -90,6 +90,7 @@
 
 	/* audio codec information */
 	struct mgcp_rtp_codec codec;
+	struct mgcp_rtp_codec alt_codec; /* TODO/XXX: make it generic */
 
 	/* per endpoint data */
 	int  frames_per_packet;
diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c
index fff2ece..a728b67 100644
--- a/openbsc/src/libmgcp/mgcp_protocol.c
+++ b/openbsc/src/libmgcp/mgcp_protocol.c
@@ -738,7 +738,9 @@
 {
 	char *line;
 	int found_media = 0;
+	/* TODO/XXX make it more generic */
 	int audio_payload = -1;
+	int audio_payload_alt = -1;
 
 	for_each_line(line, p->save) {
 		switch (line[0]) {
@@ -758,10 +760,12 @@
 
 			if (sscanf(line, "a=rtpmap:%d %63s",
 				   &payload, audio_name) == 2) {
-				if (payload != audio_payload)
-					break;
-
-				set_audio_info(p->cfg, &rtp->codec, payload, audio_name);
+				if (payload == audio_payload)
+					set_audio_info(p->cfg, &rtp->codec,
+							payload, audio_name);
+				else if (payload == audio_payload_alt)
+					set_audio_info(p->cfg, &rtp->alt_codec,
+							payload, audio_name);
 			} else if (sscanf(line, "a=ptime:%d-%d",
 					  &ptime, &ptime2) >= 1) {
 				if (ptime2 > 0 && ptime2 != ptime)
@@ -769,6 +773,7 @@
 				else
 					rtp->packet_duration_ms = ptime;
 			} else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
+				/* TODO/XXX: Store this per codec and derive it on use */
 				if (ptime2 * rtp->codec.frame_duration_den >
 				    rtp->codec.frame_duration_num * 1500)
 					/* more than 1 frame */
@@ -777,15 +782,20 @@
 			break;
 		}
 		case 'm': {
-			int port;
+			int port, rc;
 			audio_payload = -1;
+			audio_payload_alt = -1;
 
-			if (sscanf(line, "m=audio %d RTP/AVP %d",
-				   &port, &audio_payload) == 2) {
+			rc = sscanf(line, "m=audio %d RTP/AVP %d %d",
+				   &port, &audio_payload, &audio_payload_alt);
+			if (rc >= 2) {
 				rtp->rtp_port = htons(port);
 				rtp->rtcp_port = htons(port + 1);
 				found_media = 1;
 				set_audio_info(p->cfg, &rtp->codec, audio_payload, NULL);
+				if (rc == 3)
+					set_audio_info(p->cfg, &rtp->alt_codec,
+							audio_payload_alt, NULL);
 			}
 			break;
 		}
@@ -1486,6 +1496,7 @@
 	end->output_enabled	= 0;
 
 	mgcp_rtp_codec_reset(&end->codec);
+	mgcp_rtp_codec_reset(&end->alt_codec);
 }
 
 static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c
index 06981dd..a057503 100644
--- a/openbsc/tests/mgcp/mgcp_test.c
+++ b/openbsc/tests/mgcp/mgcp_test.c
@@ -1,6 +1,6 @@
 /*
- * (C) 2011-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2011-2012 by On-Waves
+ * (C) 2011-2012,2014 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2011-2012,2014 by On-Waves
  * All Rights Reserved
  *
  * This program is free software; you can redistribute it and/or modify
@@ -268,6 +268,61 @@
 #define PTYPE_NONE 128
 #define PTYPE_NYI  PTYPE_NONE
 
+#define CRCX_MULT_1 "CRCX 2 1@mgw MGCP 1.0\r\n"	\
+		 "M: recvonly\r\n"		\
+		 "C: 2\r\n"			\
+		 "X\r\n"			\
+		 "L: p:20\r\n"		\
+		 "\r\n"				\
+		 "v=0\r\n"			\
+		 "c=IN IP4 123.12.12.123\r\n"	\
+		 "m=audio 5904 RTP/AVP 18 97\r\n"\
+		 "a=rtpmap:18 G729/8000\r\n"	\
+		 "a=rtpmap:97 GSM-EFR/8000\r\n"	\
+		 "a=ptime:40\r\n"
+
+#define CRCX_MULT_2 "CRCX 2 2@mgw MGCP 1.0\r\n"	\
+		 "M: recvonly\r\n"		\
+		 "C: 2\r\n"			\
+		 "X\r\n"			\
+		 "L: p:20\r\n"		\
+		 "\r\n"				\
+		 "v=0\r\n"			\
+		 "c=IN IP4 123.12.12.123\r\n"	\
+		 "m=audio 5904 RTP/AVP 18 97 101\r\n"\
+		 "a=rtpmap:18 G729/8000\r\n"	\
+		 "a=rtpmap:97 GSM-EFR/8000\r\n"	\
+		 "a=rtpmap:101 FOO/8000\r\n"	\
+		 "a=ptime:40\r\n"
+
+#define CRCX_MULT_3 "CRCX 2 3@mgw MGCP 1.0\r\n"	\
+		 "M: recvonly\r\n"		\
+		 "C: 2\r\n"			\
+		 "X\r\n"			\
+		 "L: p:20\r\n"		\
+		 "\r\n"				\
+		 "v=0\r\n"			\
+		 "c=IN IP4 123.12.12.123\r\n"	\
+		 "m=audio 5904 RTP/AVP\r\n"	\
+		 "a=rtpmap:18 G729/8000\r\n"	\
+		 "a=rtpmap:97 GSM-EFR/8000\r\n"	\
+		 "a=rtpmap:101 FOO/8000\r\n"	\
+		 "a=ptime:40\r\n"
+
+#define CRCX_MULT_4 "CRCX 2 4@mgw MGCP 1.0\r\n"	\
+		 "M: recvonly\r\n"		\
+		 "C: 2\r\n"			\
+		 "X\r\n"			\
+		 "L: p:20\r\n"		\
+		 "\r\n"				\
+		 "v=0\r\n"			\
+		 "c=IN IP4 123.12.12.123\r\n"	\
+		 "m=audio 5904 RTP/AVP 18\r\n"	\
+		 "a=rtpmap:18 G729/8000\r\n"	\
+		 "a=rtpmap:97 GSM-EFR/8000\r\n"	\
+		 "a=rtpmap:101 FOO/8000\r\n"	\
+		 "a=ptime:40\r\n"
+
 struct mgcp_test {
 	const char *name;
 	const char *req;
@@ -877,6 +932,72 @@
 	force_monotonic_time_us = -1;
 }
 
+static void test_multilple_codec(void)
+{
+	struct mgcp_config *cfg;
+	struct mgcp_endpoint *endp;
+	struct msgb *inp, *resp;
+
+	printf("Testing multiple payload types\n");
+
+	cfg = mgcp_config_alloc();
+	cfg->trunk.number_endpoints = 64;
+	mgcp_endpoints_allocate(&cfg->trunk);
+	cfg->policy_cb = mgcp_test_policy_cb;
+	mgcp_endpoints_allocate(mgcp_trunk_alloc(cfg, 1));
+
+	/* Allocate endpoint 1@mgw with two codecs */
+	last_endpoint = -1;
+	inp = create_msg(CRCX_MULT_1);
+	resp = mgcp_handle_message(cfg, inp);
+	msgb_free(inp);
+	msgb_free(resp);
+
+	OSMO_ASSERT(last_endpoint == 1);
+	endp = &cfg->trunk.endpoints[last_endpoint];
+	OSMO_ASSERT(endp->net_end.codec.payload_type == 18);
+	OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 97);
+
+	/* Allocate 2@mgw with three codecs, last one ignored */
+	last_endpoint = -1;
+	inp = create_msg(CRCX_MULT_2);
+	resp = mgcp_handle_message(cfg, inp);
+	msgb_free(inp);
+	msgb_free(resp);
+
+	OSMO_ASSERT(last_endpoint == 2);
+	endp = &cfg->trunk.endpoints[last_endpoint];
+	OSMO_ASSERT(endp->net_end.codec.payload_type == 18);
+	OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 97);
+
+	/* Allocate 3@mgw with no codecs, check for PT == -1 */
+	last_endpoint = -1;
+	inp = create_msg(CRCX_MULT_3);
+	resp = mgcp_handle_message(cfg, inp);
+	msgb_free(inp);
+	msgb_free(resp);
+
+	OSMO_ASSERT(last_endpoint == 3);
+	endp = &cfg->trunk.endpoints[last_endpoint];
+	OSMO_ASSERT(endp->net_end.codec.payload_type == -1);
+	OSMO_ASSERT(endp->net_end.alt_codec.payload_type == -1);
+
+	/* Allocate 4@mgw with a single codec */
+	last_endpoint = -1;
+	inp = create_msg(CRCX_MULT_4);
+	resp = mgcp_handle_message(cfg, inp);
+	msgb_free(inp);
+	msgb_free(resp);
+
+	OSMO_ASSERT(last_endpoint == 4);
+	endp = &cfg->trunk.endpoints[last_endpoint];
+	OSMO_ASSERT(endp->net_end.codec.payload_type == 18);
+	OSMO_ASSERT(endp->net_end.alt_codec.payload_type == -1);
+
+
+	talloc_free(cfg);
+}
+
 int main(int argc, char **argv)
 {
 	osmo_init_logging(&log_info);
@@ -892,6 +1013,7 @@
 	test_packet_error_detection(0, 0);
 	test_packet_error_detection(0, 1);
 	test_packet_error_detection(1, 1);
+	test_multilple_codec();
 
 	printf("Done\n");
 	return EXIT_SUCCESS;
diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok
index 033f783..a56a3fd 100644
--- a/openbsc/tests/mgcp/mgcp_test.ok
+++ b/openbsc/tests/mgcp/mgcp_test.ok
@@ -474,4 +474,5 @@
 In TS: 160320, dTS: 160, Seq: 1002
 Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 Stats: Jitter = 0, Transit = -144000
+Testing multiple payload types
 Done