add sdp_msg API: SDP parsing/composition

Rationale: in order to add full SDP to the MNCC protocol (upcoming patch
I8c3b2de53ffae4ec3a66b9dabf308c290a2c999f), we need to parse and compose SDP
messages. Obviously, libosmo-mgcp-client already contains similar code, but
that is unfortunately heavily glued to the actual MGCP implementation. The
simplest solution is to create this separate implementation, copy-pasting from
the existing libosmo-mgcp-client code as is convenient.

This API is added here to probe whether it works well. When it does, the
intention is to "move it up" to osmo-mgw and overhaul the SDP parsing in our
MGCP client and MGCP server APIs using this same API.

Change-Id: If3ce23cd5bab15e2ab4c52ef3e4c75979dffe931
diff --git a/include/osmocom/msc/Makefile.am b/include/osmocom/msc/Makefile.am
index 0d7d45c..faf1048 100644
--- a/include/osmocom/msc/Makefile.am
+++ b/include/osmocom/msc/Makefile.am
@@ -39,6 +39,7 @@
 	rrlp.h \
 	rtp_stream.h \
 	sccp_ran.h \
+	sdp_msg.h \
 	sgs_iface.h \
 	sgs_server.h \
 	sgs_vty.h \
diff --git a/include/osmocom/msc/sdp_msg.h b/include/osmocom/msc/sdp_msg.h
new file mode 100644
index 0000000..7ac6036
--- /dev/null
+++ b/include/osmocom/msc/sdp_msg.h
@@ -0,0 +1,68 @@
+/* Minimalistic SDP parse/compose API, focused on GSM audio codecs */
+#pragma once
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/sockaddr_str.h>
+
+extern const struct value_string sdp_msg_payload_type_names[];
+static inline const char *sdp_msg_payload_type_name(unsigned int payload_type)
+{ return get_value_string(sdp_msg_payload_type_names, payload_type); }
+int sdp_subtype_name_to_payload_type(const char *subtype_name);
+
+struct sdp_audio_codec {
+	unsigned int payload_type;
+	/* Like "GSM", "AMR", "EFR", ... */
+	char subtype_name[16];
+	unsigned int rate;
+	char fmtp[64];
+};
+
+struct sdp_audio_codecs {
+	unsigned int count;
+	struct sdp_audio_codec codec[16];
+};
+
+struct sdp_msg {
+	struct osmo_sockaddr_str rtp;
+	unsigned int ptime;
+	struct sdp_audio_codecs audio_codecs;
+};
+
+#define foreach_sdp_audio_codec(/* struct sdp_audio_codec* */ CODEC, \
+				/* struct sdp_audio_codecs* */ AC) \
+	for (CODEC = (AC)->codec; \
+	     (CODEC - (AC)->codec) < OSMO_MIN((AC)->count, ARRAY_SIZE((AC)->codec)); \
+	     CODEC++)
+
+const char *sdp_msg_line_end(const char *src);
+
+int sdp_audio_codec_cmp(const struct sdp_audio_codec *a, const struct sdp_audio_codec *b);
+
+struct sdp_audio_codec *sdp_audio_codec_add(struct sdp_audio_codecs *ac, unsigned int payload_type,
+					    const char *subtype_name, unsigned int rate, const char *fmtp);
+struct sdp_audio_codec *sdp_audio_codec_add_copy(struct sdp_audio_codecs *ac,
+						 const struct sdp_audio_codec *codec);
+int sdp_audio_codec_remove(struct sdp_audio_codecs *ac, const struct sdp_audio_codec *codec);
+struct sdp_audio_codec *sdp_audio_codec_by_payload_type(struct sdp_audio_codecs *ac,
+							unsigned int payload_type, bool create);
+struct sdp_audio_codec *sdp_audio_codec_by_descr(struct sdp_audio_codecs *ac,
+						 const struct sdp_audio_codec *codec);
+
+void sdp_audio_codecs_intersection(struct sdp_audio_codecs *ac_dest, const struct sdp_audio_codecs *ac_other,
+				   bool translate_payload_type_numbers);
+void sdp_audio_codecs_select(struct sdp_audio_codecs *ac, struct sdp_audio_codec *codec);
+
+int sdp_msg_to_str(char *dst, size_t dst_size, const struct sdp_msg *sdp);
+int sdp_msg_from_str(struct sdp_msg *sdp, const char *src);
+
+int sdp_audio_codec_name_buf(char *buf, size_t buflen, const struct sdp_audio_codec *codec);
+char *sdp_audio_codec_name_c(void *ctx, const struct sdp_audio_codec *codec);
+const char *sdp_audio_codec_name(const struct sdp_audio_codec *codec);
+
+int sdp_audio_codecs_name_buf(char *buf, size_t buflen, const struct sdp_audio_codecs *ac);
+char *sdp_audio_codecs_name_c(void *ctx, const struct sdp_audio_codecs *ac);
+const char *sdp_audio_codecs_name(const struct sdp_audio_codecs *ac);
+
+int sdp_msg_name_buf(char *buf, size_t buflen, const struct sdp_msg *sdp);
+char *sdp_msg_name_c(void *ctx, const struct sdp_msg *sdp);
+const char *sdp_msg_name(const struct sdp_msg *sdp);