SDP: Make process possible multiple fmtp attributes per rtpmap.
authorRichard Mudgett <rmudgett@digium.com>
Fri, 28 Apr 2017 00:37:53 +0000 (19:37 -0500)
committerRichard Mudgett <rmudgett@digium.com>
Tue, 9 May 2017 17:57:57 +0000 (12:57 -0500)
Change-Id: Ie7511008d82b59590e0eb520a21b5e1da4bd7349

include/asterisk/sdp.h
main/sdp.c
tests/test_sdp.c

index 8aa9e3b..224a0e5 100644 (file)
@@ -561,7 +561,40 @@ struct ast_sdp *ast_sdp_alloc(struct ast_sdp_o_line *o_line,
        struct ast_sdp_t_line *t_line);
 
 /*!
- * \brief Find an attribute on the top-level SDP
+ * \brief Find the first attribute match index in the top-level SDP
+ *
+ * \note This will not search within streams for the given attribute.
+ *
+ * \param sdp The SDP in which to search
+ * \param attr_name The name of the attribute to search for
+ * \param payload Optional payload number to search for. If irrelevant, set to -1
+ *
+ * \retval index of attribute line on success.
+ * \retval -1 on failure or not found.
+ *
+ * \since 15.0.0
+ */
+int ast_sdp_find_a_first(const struct ast_sdp *sdp, const char *attr_name, int payload);
+
+/*!
+ * \brief Find the next attribute match index in the top-level SDP
+ *
+ * \note This will not search within streams for the given attribute.
+ *
+ * \param sdp The SDP in which to search
+ * \param last The last matching index found
+ * \param attr_name The name of the attribute to search for
+ * \param payload Optional payload number to search for. If irrelevant, set to -1
+ *
+ * \retval index of attribute line on success.
+ * \retval -1 on failure or not found.
+ *
+ * \since 15.0.0
+ */
+int ast_sdp_find_a_next(const struct ast_sdp *sdp, int last, const char *attr_name, int payload);
+
+/*!
+ * \brief Find an attribute in the top-level SDP
  *
  * \note This will not search within streams for the given attribute.
  *
@@ -578,9 +611,40 @@ struct ast_sdp_a_line *ast_sdp_find_attribute(const struct ast_sdp *sdp,
        const char *attr_name, int payload);
 
 /*!
- * \brief Find an attribute on an SDP stream (m-line)
+ * \brief Find the first attribute match index in an SDP stream (m-line)
  *
- * \param sdp The SDP in which to search
+ * \param m_line The SDP m-line in which to search
+ * \param attr_name The name of the attribute to search for
+ * \param payload Optional payload number to search for. If irrelevant, set to -1
+ *
+ * \retval index of attribute line on success.
+ * \retval -1 on failure or not found.
+ *
+ * \since 15.0.0
+ */
+int ast_sdp_m_find_a_first(const struct ast_sdp_m_line *m_line, const char *attr_name,
+       int payload);
+
+/*!
+ * \brief Find the next attribute match index in an SDP stream (m-line)
+ *
+ * \param m_line The SDP m-line in which to search
+ * \param last The last matching index found
+ * \param attr_name The name of the attribute to search for
+ * \param payload Optional payload number to search for. If irrelevant, set to -1
+ *
+ * \retval index of attribute line on success.
+ * \retval -1 on failure or not found.
+ *
+ * \since 15.0.0
+ */
+int ast_sdp_m_find_a_next(const struct ast_sdp_m_line *m_line, int last,
+       const char *attr_name, int payload);
+
+/*!
+ * \brief Find an attribute in an SDP stream (m-line)
+ *
+ * \param m_line The SDP m-line in which to search
  * \param attr_name The name of the attribute to search for
  * \param payload Optional payload number to search for. If irrelevant, set to -1
  *
index 019c669..bfb83e8 100644 (file)
@@ -508,44 +508,81 @@ int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_opt
                || sdp_m_add_fmtp(m_line, format, rtp_code) ? -1 : 0;
 }
 
-static struct ast_sdp_a_line *sdp_find_attribute_common(const struct ast_sdp_a_lines *a_lines,
+static int sdp_find_a_common(const struct ast_sdp_a_lines *a_lines, int start,
        const char *attr_name, int payload)
 {
        struct ast_sdp_a_line *a_line;
-       int i;
+       int idx;
+
+       ast_assert(-1 <= start);
 
-       for (i = 0; i < AST_VECTOR_SIZE(a_lines); ++i) {
+       for (idx = start + 1; idx < AST_VECTOR_SIZE(a_lines); ++idx) {
                int a_line_payload;
 
-               a_line = AST_VECTOR_GET(a_lines, i);
+               a_line = AST_VECTOR_GET(a_lines, idx);
                if (strcmp(a_line->name, attr_name)) {
                        continue;
                }
 
                if (payload >= 0) {
                        int sscanf_res;
+
                        sscanf_res = sscanf(a_line->value, "%30d", &a_line_payload);
                        if (sscanf_res == 1 && payload == a_line_payload) {
-                               return a_line;
+                               return idx;
                        }
                } else {
-                       return a_line;
+                       return idx;
                }
        }
 
-       return NULL;
+       return -1;
+}
+
+int ast_sdp_find_a_first(const struct ast_sdp *sdp, const char *attr_name, int payload)
+{
+       return sdp_find_a_common(sdp->a_lines, -1, attr_name, payload);
+}
+
+int ast_sdp_find_a_next(const struct ast_sdp *sdp, int last, const char *attr_name, int payload)
+{
+       return sdp_find_a_common(sdp->a_lines, last, attr_name, payload);
 }
 
 struct ast_sdp_a_line *ast_sdp_find_attribute(const struct ast_sdp *sdp,
        const char *attr_name, int payload)
 {
-       return sdp_find_attribute_common(sdp->a_lines, attr_name, payload);
+       int idx;
+
+       idx = ast_sdp_find_a_first(sdp, attr_name, payload);
+       if (idx < 0) {
+               return NULL;
+       }
+       return ast_sdp_get_a(sdp, idx);
+}
+
+int ast_sdp_m_find_a_first(const struct ast_sdp_m_line *m_line, const char *attr_name,
+       int payload)
+{
+       return sdp_find_a_common(m_line->a_lines, -1, attr_name, payload);
+}
+
+int ast_sdp_m_find_a_next(const struct ast_sdp_m_line *m_line, int last,
+       const char *attr_name, int payload)
+{
+       return sdp_find_a_common(m_line->a_lines, last, attr_name, payload);
 }
 
 struct ast_sdp_a_line *ast_sdp_m_find_attribute(const struct ast_sdp_m_line *m_line,
        const char *attr_name, int payload)
 {
-       return sdp_find_attribute_common(m_line->a_lines, attr_name, payload);
+       int idx;
+
+       idx = ast_sdp_m_find_a_first(m_line, attr_name, payload);
+       if (idx < 0) {
+               return NULL;
+       }
+       return ast_sdp_m_get_a(m_line, idx);
 }
 
 struct ast_sdp_rtpmap *ast_sdp_rtpmap_alloc(int payload, const char *encoding_name,
@@ -644,17 +681,8 @@ static struct ast_sdp_rtpmap *sdp_payload_get_rtpmap(const struct ast_sdp_m_line
        return ast_sdp_a_get_rtpmap(rtpmap_attr);
 }
 
-/*!
- * \brief Find and process fmtp attributes for a given payload
- *
- * \param m_line The stream on which to search for the fmtp attribute
- * \param payload The specific fmtp attribute to search for
- * \param codecs The current RTP codecs that have been built up
- */
-static void process_fmtp(const struct ast_sdp_m_line *m_line, int payload,
-       struct ast_rtp_codecs *codecs)
+static void process_fmtp_value(const char *value, int payload, struct ast_rtp_codecs *codecs)
 {
-       struct ast_sdp_a_line *attr;
        char *param;
        char *param_start;
        char *param_end;
@@ -662,13 +690,11 @@ static void process_fmtp(const struct ast_sdp_m_line *m_line, int payload,
        struct ast_format *replace;
        struct ast_format *format;
 
-       attr = ast_sdp_m_find_attribute(m_line, "fmtp", payload);
-       if (!attr) {
-               return;
-       }
-
-       /* Extract the "a=fmtp:%d %s" attribute parameter string after the payload type. */
-       param_start = ast_skip_nonblanks(attr->value);/* Skip payload type */
+       /*
+        * Extract the "a=fmtp:%d %s" attribute parameter string value which
+        * starts after the colon.
+        */
+       param_start = ast_skip_nonblanks(value);/* Skip payload type */
        param_start = ast_skip_blanks(param_start);
        param_end = ast_skip_nonblanks(param_start);
        if (param_end == param_start) {
@@ -693,6 +719,28 @@ static void process_fmtp(const struct ast_sdp_m_line *m_line, int payload,
        ao2_ref(format, -1);
 }
 
+/*!
+ * \brief Find and process all fmtp attribute lines for a given payload
+ *
+ * \param m_line The stream on which to search for the fmtp attributes
+ * \param payload The specific fmtp attribute to search for
+ * \param codecs The current RTP codecs that have been built up
+ */
+static void process_fmtp_lines(const struct ast_sdp_m_line *m_line, int payload,
+       struct ast_rtp_codecs *codecs)
+{
+       const struct ast_sdp_a_line *a_line;
+       int idx;
+
+       idx = ast_sdp_m_find_a_first(m_line, "fmtp", payload);
+       for (; 0 <= idx; idx = ast_sdp_m_find_a_next(m_line, idx, "fmtp", payload)) {
+               a_line = ast_sdp_m_get_a(m_line, idx);
+               ast_assert(a_line != NULL);
+
+               process_fmtp_value(a_line->value, payload, codecs);
+       }
+}
+
 /*
  * Needed so we don't have an external function referenced as data.
  * The dynamic linker doesn't handle that very well.
@@ -765,7 +813,7 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line,
                        if (!ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, NULL, payload,
                                m_line->type, rtpmap->encoding_name, options, rtpmap->clock_rate)) {
                                /* Successfully mapped the payload type to format */
-                               process_fmtp(m_line, payload, codecs);
+                               process_fmtp_lines(m_line, payload, codecs);
                        }
                        ast_sdp_rtpmap_free(rtpmap);
                }
index 79b9e7b..7eef3f7 100644 (file)
@@ -276,6 +276,7 @@ AST_TEST_DEFINE(find_attr)
        enum ast_test_result_state res = AST_TEST_PASS;
        struct ast_sdp_m_line *m_line;
        struct ast_sdp_a_line *a_line;
+       int idx;
 
        switch(cmd) {
        case TEST_INIT:
@@ -283,7 +284,7 @@ AST_TEST_DEFINE(find_attr)
                info->category = "/main/sdp/";
                info->summary = "Ensure that finding attributes works as expected";
                info->description =
-                       "An SDP m-line is created, and two attributes are added.\n"
+                       "A SDP m-line is created, and attributes are added.\n"
                        "We then attempt a series of attribute-finding calls that are expected to work\n"
                        "followed by a series of attribute-finding calls that are expected fo fail.";
                return AST_TEST_NOT_RUN;
@@ -302,6 +303,12 @@ AST_TEST_DEFINE(find_attr)
                goto end;
        }
        ast_sdp_m_add_a(m_line, a_line);
+       a_line = ast_sdp_a_alloc("foo", "0 bee");
+       if (!a_line) {
+               res = AST_TEST_FAIL;
+               goto end;
+       }
+       ast_sdp_m_add_a(m_line, a_line);
 
        a_line = ast_sdp_a_alloc("baz", "howdy");
        if (!a_line) {
@@ -312,21 +319,77 @@ AST_TEST_DEFINE(find_attr)
 
        /* These should work */
        a_line = ast_sdp_m_find_attribute(m_line, "foo", 0);
-       if (!a_line) {
+       if (!a_line || strcmp(a_line->value, "0 bar")) {
                ast_test_status_update(test, "Failed to find attribute 'foo' with payload '0'\n");
                res = AST_TEST_FAIL;
        }
        a_line = ast_sdp_m_find_attribute(m_line, "foo", -1);
-       if (!a_line) {
+       if (!a_line || strcmp(a_line->value, "0 bar")) {
                ast_test_status_update(test, "Failed to find attribute 'foo' with unspecified payload\n");
                res = AST_TEST_FAIL;
        }
        a_line = ast_sdp_m_find_attribute(m_line, "baz", -1);
-       if (!a_line) {
+       if (!a_line || strcmp(a_line->value, "howdy")) {
                ast_test_status_update(test, "Failed to find attribute 'baz' with unspecified payload\n");
                res = AST_TEST_FAIL;
        }
 
+       idx = ast_sdp_m_find_a_first(m_line, "foo", 0);
+       if (idx < 0) {
+               ast_test_status_update(test, "Failed to find first attribute 'foo' with payload '0'\n");
+               res = AST_TEST_FAIL;
+               goto end;
+       }
+       a_line = ast_sdp_m_get_a(m_line, idx);
+       if (!a_line || strcmp(a_line->value, "0 bar")) {
+               ast_test_status_update(test, "Find first attribute 'foo' with payload '0' didn't match\n");
+               res = AST_TEST_FAIL;
+       }
+       idx = ast_sdp_m_find_a_next(m_line, idx, "foo", 0);
+       if (idx < 0) {
+               ast_test_status_update(test, "Failed to find next attribute 'foo' with payload '0'\n");
+               res = AST_TEST_FAIL;
+               goto end;
+       }
+       a_line = ast_sdp_m_get_a(m_line, idx);
+       if (!a_line || strcmp(a_line->value, "0 bee")) {
+               ast_test_status_update(test, "Find next attribute 'foo' with payload '0' didn't match\n");
+               res = AST_TEST_FAIL;
+       }
+       idx = ast_sdp_m_find_a_next(m_line, idx, "foo", 0);
+       if (0 <= idx) {
+               ast_test_status_update(test, "Find next attribute 'foo' with payload '0' found too many\n");
+               res = AST_TEST_FAIL;
+       }
+
+       idx = ast_sdp_m_find_a_first(m_line, "foo", -1);
+       if (idx < 0) {
+               ast_test_status_update(test, "Failed to find first attribute 'foo' with unspecified payload\n");
+               res = AST_TEST_FAIL;
+               goto end;
+       }
+       a_line = ast_sdp_m_get_a(m_line, idx);
+       if (!a_line || strcmp(a_line->value, "0 bar")) {
+               ast_test_status_update(test, "Find first attribute 'foo' with unspecified payload didn't match\n");
+               res = AST_TEST_FAIL;
+       }
+       idx = ast_sdp_m_find_a_next(m_line, idx, "foo", -1);
+       if (idx < 0) {
+               ast_test_status_update(test, "Failed to find next attribute 'foo' with unspecified payload\n");
+               res = AST_TEST_FAIL;
+               goto end;
+       }
+       a_line = ast_sdp_m_get_a(m_line, idx);
+       if (!a_line || strcmp(a_line->value, "0 bee")) {
+               ast_test_status_update(test, "Find next attribute 'foo' with unspecified payload didn't match\n");
+               res = AST_TEST_FAIL;
+       }
+       idx = ast_sdp_m_find_a_next(m_line, idx, "foo", -1);
+       if (0 <= idx) {
+               ast_test_status_update(test, "Find next attribute 'foo' with unspecified payload found too many\n");
+               res = AST_TEST_FAIL;
+       }
+
        /* These should fail */
        a_line = ast_sdp_m_find_attribute(m_line, "foo", 1);
        if (a_line) {
@@ -345,7 +408,7 @@ AST_TEST_DEFINE(find_attr)
        }
        a_line = ast_sdp_m_find_attribute(m_line, "wibble", -1);
        if (a_line) {
-               ast_test_status_update(test, "Found non-existent attribute 'foo' with unspecified payload\n");
+               ast_test_status_update(test, "Found non-existent attribute 'wibble' with unspecified payload\n");
                res = AST_TEST_FAIL;
        }