<p>Mark Michelson has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/5841">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">chan_pjsip: Multistream: Configure stream maxima<br><br>This adds two new configuration options for PJSIP endpoints:<br><br>max_audio_streams: determines the maximum number of audio streams to<br>offer/accept from an endpoint. Defaults to 1.<br><br>max_video_streams: determines the maximum number of video streams to<br>offer/accept from an endpoint. Defaults to 1.<br><br>This change fixes the four tests that were failing due to the previous<br>change in this series.<br><br>Change-Id: Id4b192c06fb311428d907ece78a131fdebc29163<br>---<br>M channels/chan_pjsip.c<br>M include/asterisk/res_pjsip.h<br>M res/res_pjsip/pjsip_configuration.c<br>M res/res_pjsip_session.c<br>4 files changed, 70 insertions(+), 3 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/41/5841/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c<br>index bd76110..9e60755 100644<br>--- a/channels/chan_pjsip.c<br>+++ b/channels/chan_pjsip.c<br>@@ -479,8 +479,9 @@<br>               struct ast_sip_session_media *session_media;<br> <br>               session_media = AST_VECTOR_GET(&session->media, i);<br>-<br>-                ast_assert(session_media != NULL);<br>+           if (!session_media) {<br>+                        continue;<br>+            }<br> <br>          if (session_media->type == type) {<br>                         return ao2_bump(session_media);<br>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h<br>index ad0dc28..ecad2bf 100644<br>--- a/include/asterisk/res_pjsip.h<br>+++ b/include/asterisk/res_pjsip.h<br>@@ -680,6 +680,10 @@<br>        unsigned int bind_rtp_to_media_address;<br>       /*! Use RTCP-MUX */<br>   unsigned int rtcp_mux;<br>+       /*! Maximum number of audio streams to offer/accept */<br>+       unsigned int max_audio_streams;<br>+      /*! Maximum number of video streams to offer/accept */<br>+       unsigned int max_video_streams;<br> };<br> <br> /*!<br>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c<br>index e6e0821..dc4226b 100644<br>--- a/res/res_pjsip/pjsip_configuration.c<br>+++ b/res/res_pjsip/pjsip_configuration.c<br>@@ -1989,6 +1989,8 @@<br>     ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtcp_mux", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtcp_mux));<br>   ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap));<br>      ast_sorcery_object_field_register(sip_sorcery, "endpoint", "refer_blind_progress", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, refer_blind_progress));<br>+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_audio_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_audio_streams));<br>+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_video_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_video_streams));<br> <br>       if (ast_sip_initialize_sorcery_transport()) {<br>                 ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");<br>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c<br>index 56acbd3..e9f5d51 100644<br>--- a/res/res_pjsip_session.c<br>+++ b/res/res_pjsip_session.c<br>@@ -259,10 +259,45 @@<br>  return session_media;<br> }<br> <br>+static int limitation_reached(enum ast_media_type type, const struct ast_sip_endpoint *endpoint, int *type_streams)<br>+{<br>+       switch (type) {<br>+      case AST_MEDIA_TYPE_AUDIO:<br>+           if (type_streams[type] < endpoint->media.max_audio_streams) {<br>+                  return 0;<br>+            } else {<br>+                     return 1;<br>+            }<br>+    case AST_MEDIA_TYPE_VIDEO:<br>+           if (type_streams[type] < endpoint->media.max_video_streams) {<br>+                  return 0;<br>+            } else {<br>+                     return 1;<br>+            }<br>+    case AST_MEDIA_TYPE_IMAGE:<br>+   case AST_MEDIA_TYPE_TEXT:<br>+            /* We don't have an option for image (T.38) and text streams<br>+              * so we cap these at one<br>+             */<br>+          if (type_streams[type] > 0) {<br>+                     return 1;<br>+            } else {<br>+                     return 0;<br>+            }<br>+    case AST_MEDIA_TYPE_UNKNOWN:<br>+ default:<br>+             /* We don't want any unknown or "other" streams on our endpoint,<br>+                * so always just say we've reached the limit<br>+             */<br>+          return 1;<br>+    }<br>+}<br>+<br> static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)<br> {<br>        int i;<br>        int handled = 0;<br>+     int type_streams[AST_MEDIA_TYPE_END] = {0};<br> <br>        if (session->inv_session && session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {<br>           ast_log(LOG_ERROR, "Failed to handle incoming SDP. Session has been already disconnected\n");<br>@@ -276,9 +311,15 @@<br>                 RAII_VAR(struct sdp_handler_list *, handler_list, NULL, ao2_cleanup);<br>                 struct ast_sip_session_media *session_media = NULL;<br>           int res;<br>+             enum ast_media_type type;<br> <br>          /* We need a null-terminated version of the media string */<br>           ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));<br>+         type = ast_media_type_from_str(media);<br>+<br>+            if (limitation_reached(type, session->endpoint, type_streams)) {<br>+                  continue;<br>+            }<br> <br>          if (i < AST_VECTOR_SIZE(&session->media)) {<br>                         session_media = AST_VECTOR_GET(&session->media, i);<br>@@ -288,7 +329,7 @@<br>                                * on this session media. The session media destructor will ensure that<br>                                * all SDP handlers get a chance to free the memory they allocated<br>                             */<br>-                          session_media->type = ast_media_type_from_str(media);<br>+                             session_media->type = type;<br>                                session_media->handler = NULL;<br>                     }<br>             }<br>@@ -314,6 +355,7 @@<br>                                        session_media->handler->id);<br>                            /* Handled by this handler. Move to the next stream */<br>                                handled = 1;<br>+                         ++type_streams[type];<br>                                 continue;<br>                     }<br>             }<br>@@ -342,6 +384,7 @@<br>                                /* Handled by this handler. Move to the next stream */<br>                                session_media_set_handler(session_media, handler);<br>                            handled = 1;<br>+                         ++type_streams[type];<br>                                 break;<br>                        }<br>             }<br>@@ -419,10 +462,19 @@<br> static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote)<br> {<br>         int i;<br>+       int type_streams[AST_MEDIA_TYPE_END] = {0};<br> <br>        for (i = 0; i < local->media_count; ++i) {<br>              struct ast_sip_session_media *session_media;<br>+         char media[20];<br>+              enum ast_media_type type;<br>+<br>          if (!remote->media[i]) {<br>+                  continue;<br>+            }<br>+            ast_copy_pj_str(media, &local->media[i]->desc.media, sizeof(media));<br>+               type = ast_media_type_from_str(media);<br>+               if (limitation_reached(type, session->endpoint, type_streams)) {<br>                   continue;<br>             }<br> <br>@@ -436,6 +488,7 @@<br>             if (handle_negotiated_sdp_session_media(session_media, session, local, remote, i)) {<br>                  return -1;<br>            }<br>+            ++type_streams[type];<br>         }<br> <br>  return 0;<br>@@ -3038,6 +3091,7 @@<br>      pjmedia_sdp_session *local;<br>   struct ast_stream_topology *topology;<br>         int i;<br>+       int type_streams[AST_MEDIA_TYPE_END] = {0};<br> <br>        if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {<br>          ast_log(LOG_ERROR, "Failed to create session SDP. Session has been already disconnected\n");<br>@@ -3075,6 +3129,11 @@<br>                struct ast_stream *stream;<br> <br>                 stream = ast_stream_topology_get_stream(topology, i);<br>+<br>+             if (limitation_reached(ast_stream_get_type(stream), session->endpoint, type_streams)) {<br>+                   continue;<br>+            }<br>+<br>          if (i < AST_VECTOR_SIZE(&session->media)) {<br>                         session_media = AST_VECTOR_GET(&session->media, i);<br>            } else {<br>@@ -3087,6 +3146,7 @@<br>               if (add_sdp_streams(session_media, session, local, stream)) {<br>                         return NULL;<br>          }<br>+            ++type_streams[ast_stream_get_type(stream)];<br>  }<br> <br>  /* Use the connection details of the first media stream if possible for SDP level */<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/5841">change 5841</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/5841"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Id4b192c06fb311428d907ece78a131fdebc29163 </div>
<div style="display:none"> Gerrit-Change-Number: 5841 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Mark Michelson <mmichelson@digium.com> </div>