<p>George Joseph has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/13945">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">codec_negotiation: Implement outgoing_call_offer_pref<br><br>Based on this new endpoint setting, a joint list of preferred codecs<br>between those received from the Asterisk core (remote), and those<br>specified in the endpoint's "allow" parameter (local) is created and<br>is used to create the outgoing SDP offer.<br><br>* Add outgoing_call_offer_pref to pjsip_configuration (endpoint)<br><br>* Add "call_direction" to res_pjsip_session.<br><br>* Update pjsip_session_caps.c to make the functions more generic<br>  so they could be used for both incoming and outgoing and created<br>  ast_sip_session_join_call_offer_streams().<br><br>* Update ast_sip_session_create_outgoing to create the<br>  pending_media_state->topology with the results of<br>  ast_sip_session_join_call_offer_streams().<br><br>ASTERISK-28777<br><br>Change-Id: Id4ec0b4a906c2ae5885bf947f101c59059935437<br>---<br>M channels/chan_pjsip.c<br>M configs/samples/pjsip.conf.sample<br>A doc/CHANGES-staging/res_pjsip_call_offer_pref.txt<br>D doc/CHANGES-staging/res_pjsip_incoming_call_offer_pref.txt<br>M include/asterisk/res_pjsip.h<br>M include/asterisk/res_pjsip_session.h<br>M include/asterisk/res_pjsip_session_caps.h<br>M res/res_pjsip.c<br>M res/res_pjsip/pjsip_configuration.c<br>M res/res_pjsip_sdp_rtp.c<br>M res/res_pjsip_session.c<br>M res/res_pjsip_session/pjsip_session_caps.c<br>12 files changed, 274 insertions(+), 244 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/45/13945/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c</span><br><span>index 0ec1791..b88f565 100644</span><br><span>--- a/channels/chan_pjsip.c</span><br><span>+++ b/channels/chan_pjsip.c</span><br><span>@@ -2691,7 +2691,6 @@</span><br><span>    }</span><br><span> </span><br><span>        session = req_data.session;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>  if (!(session->channel = chan_pjsip_new(session, AST_STATE_DOWN, NULL, NULL, assignedids, requestor, NULL))) {</span><br><span>            /* Session needs to be terminated prematurely */</span><br><span>             return NULL;</span><br><span>diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample</span><br><span>index 695ba5d..52b64ba 100644</span><br><span>--- a/configs/samples/pjsip.conf.sample</span><br><span>+++ b/configs/samples/pjsip.conf.sample</span><br><span>@@ -798,16 +798,47 @@</span><br><span>                    ; "0" or not enabled)</span><br><span> ;contact_user= ; On outgoing requests, force the user portion of the Contact</span><br><span>                ; header to this value (default: "")</span><br><span style="color: hsl(0, 100%, 40%);">-;incoming_call_offer_pref= ; Sets the preferred codecs, and order to use between</span><br><span style="color: hsl(0, 100%, 40%);">-                           ; those received in the offer, and those set in this</span><br><span style="color: hsl(0, 100%, 40%);">-                           ; configuration's allow line. Valid values include:</span><br><span style="color: hsl(120, 100%, 40%);">+;incoming_call_offer_pref= ; Based on this setting, a joint list of</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; preferred codecs between those received in an</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; incoming SDP offer (remote), and those specified</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; in the endpoint's "allow" parameter (local)</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; is created and is passed to the Asterisk core.</span><br><span>                            ;</span><br><span style="color: hsl(0, 100%, 40%);">-                           ; local - prefer and order by configuration (default).</span><br><span style="color: hsl(0, 100%, 40%);">-                           ; local_single - prefer and order by configuration,</span><br><span style="color: hsl(0, 100%, 40%);">-                           ;     but only choose 'top' most codec</span><br><span style="color: hsl(0, 100%, 40%);">-                           ; remote - prefer and order by incoming sdp.</span><br><span style="color: hsl(0, 100%, 40%);">-                           ; remote_single - prefer and order by incoming sdp,</span><br><span style="color: hsl(0, 100%, 40%);">-                           ;     but only choose 'top' most codec</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; local - Include all codecs in the local list that</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; are also in the remote list preserving the local</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; order. (default).</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; local_first - Include only the first codec in the</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; local list that is also in the remote list.</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; remote - Include all codecs in the remote list that</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; are also in the local list preserving remote list</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; order.</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; remote_first - Include only the first codec in</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; the remote list that is also in the local list.</span><br><span style="color: hsl(120, 100%, 40%);">+;outgoing_call_offer_pref= ; Based on this setting, a joint list of</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; preferred codecs between those received from the</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; Asterisk core (remote), and those specified in</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; the endpoint's "allow" parameter (local) is</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; created and is used to create the outgoing SDP</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; offer.</span><br><span style="color: hsl(120, 100%, 40%);">+                           ;</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; local - Include all codecs in the local list that</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; are also in the remote list preserving the local</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; order. (default).</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; local_merge - Include all codecs in BOTH lists</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; preserving the local list order.  Codes in the</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; remote list not in the local list will be placed</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; at the end of the joint list.</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; local_first - Include only the first codec in the</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; local list.</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; remote - Include all codecs in the remote list that</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; are also in the local list preserving remote list</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; order.</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; remote_merge - Include all codecs in BOTH lists</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; preserving the remote list order.  Codes in the</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; local list not in the remote list will be placed</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; at the end of the joint list.</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; remote_first - Include only the first codec in</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; the remote list.</span><br><span> ;preferred_codec_only=yes       ; Respond to a SIP invite with the single most preferred codec</span><br><span>                                 ; rather than advertising all joint codec capabilities. This</span><br><span>                                 ; limits the other side's codec choice to exactly what we prefer.</span><br><span>diff --git a/doc/CHANGES-staging/res_pjsip_call_offer_pref.txt b/doc/CHANGES-staging/res_pjsip_call_offer_pref.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..c8b8747</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/res_pjsip_call_offer_pref.txt</span><br><span>@@ -0,0 +1,8 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: res_pjsip</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: res_pjsip_session</span><br><span style="color: hsl(120, 100%, 40%);">+Master-Only: True</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Two new options, incoming_call_offer_pref and outgoing_call_offer_pref</span><br><span style="color: hsl(120, 100%, 40%);">+have been added to res_pjsip endpoints that specify the preferred order</span><br><span style="color: hsl(120, 100%, 40%);">+of codecs to use between those received/sent in an SDP offer and those</span><br><span style="color: hsl(120, 100%, 40%);">+set in the endpoint configuration.</span><br><span>diff --git a/doc/CHANGES-staging/res_pjsip_incoming_call_offer_pref.txt b/doc/CHANGES-staging/res_pjsip_incoming_call_offer_pref.txt</span><br><span>deleted file mode 100644</span><br><span>index 5a12052..0000000</span><br><span>--- a/doc/CHANGES-staging/res_pjsip_incoming_call_offer_pref.txt</span><br><span>+++ /dev/null</span><br><span>@@ -1,53 +0,0 @@</span><br><span style="color: hsl(0, 100%, 40%);">-Subject: res_pjsip</span><br><span style="color: hsl(0, 100%, 40%);">-Subject: res_pjsip_session</span><br><span style="color: hsl(0, 100%, 40%);">-Master-Only: True</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-A new option, incoming_call_offer_pref, was added to res_pjsip endpoints that</span><br><span style="color: hsl(0, 100%, 40%);">-specifies the preferred order of codecs to use between those received in the</span><br><span style="color: hsl(0, 100%, 40%);">-offer, and those set in the configuration.</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-Valid values include:</span><br><span style="color: hsl(0, 100%, 40%);">-  local - prefer and order by configuration (default).</span><br><span style="color: hsl(0, 100%, 40%);">-  local_single - prefer and order by configuration, but only choose 'top'</span><br><span style="color: hsl(0, 100%, 40%);">-                 most codec</span><br><span style="color: hsl(0, 100%, 40%);">-  remote - prefer and order by incoming sdp.</span><br><span style="color: hsl(0, 100%, 40%);">-  remote_single - prefer and order by incoming sdp, but only choose 'top' most</span><br><span style="color: hsl(0, 100%, 40%);">-                  most codec</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-Example A:</span><br><span style="color: hsl(0, 100%, 40%);">-  [alice]</span><br><span style="color: hsl(0, 100%, 40%);">-  type=endpoint</span><br><span style="color: hsl(0, 100%, 40%);">-  incoming_call_offer_pref=local</span><br><span style="color: hsl(0, 100%, 40%);">-  allow=!all,opus,alaw,ulaw</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  Alice's incoming sdp=g722,ulaw,alaw</span><br><span style="color: hsl(0, 100%, 40%);">-  RESULT: alaw,ulaw</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-Example B:</span><br><span style="color: hsl(0, 100%, 40%);">-  [alice]</span><br><span style="color: hsl(0, 100%, 40%);">-  type=endpoint</span><br><span style="color: hsl(0, 100%, 40%);">-  incoming_call_offer_pref=local_single</span><br><span style="color: hsl(0, 100%, 40%);">-  allow=!all,opus,alaw,ulaw</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  Alice's incoming sdp=g722,ulaw,alaw</span><br><span style="color: hsl(0, 100%, 40%);">-  RESULT: alaw</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-Example C:</span><br><span style="color: hsl(0, 100%, 40%);">-  [alice]</span><br><span style="color: hsl(0, 100%, 40%);">-  type=endpoint</span><br><span style="color: hsl(0, 100%, 40%);">-  incoming_call_offer_pref=remote</span><br><span style="color: hsl(0, 100%, 40%);">-  allow=!all,opus,alaw,ulaw</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  Alice's incoming sdp=g722,ulaw,alaw</span><br><span style="color: hsl(0, 100%, 40%);">-  RESULT: ulaw,alaw</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-Example D:</span><br><span style="color: hsl(0, 100%, 40%);">-  [alice]</span><br><span style="color: hsl(0, 100%, 40%);">-  type=endpoint</span><br><span style="color: hsl(0, 100%, 40%);">-  incoming_call_offer_pref=remote_single</span><br><span style="color: hsl(0, 100%, 40%);">-  allow=!all,opus,alaw,ulaw</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  Alice's incoming sdp=g722,ulaw,alaw</span><br><span style="color: hsl(0, 100%, 40%);">-  RESULT: ulaw</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h</span><br><span>index 816e614..cda6337 100644</span><br><span>--- a/include/asterisk/res_pjsip.h</span><br><span>+++ b/include/asterisk/res_pjsip.h</span><br><span>@@ -511,22 +511,31 @@</span><br><span> </span><br><span> /*!</span><br><span>  * \brief Incoming/Outgoing call offer/answer joint codec preference.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The default is INTERSECT ALL LOCAL.</span><br><span>  */</span><br><span> enum ast_sip_call_codec_pref {</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! Two bits for merge */</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! Union of local and remote */</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_SIP_CALL_CODEC_PREF_INTERSECT =     1 << 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Intersection of local and remote */</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_SIP_CALL_CODEC_PREF_UNION =         1 << 1,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! Two bits for filter */</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! No filter */</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_SIP_CALL_CODEC_PREF_ALL =           1 << 2,</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Only the first */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_SIP_CALL_CODEC_PREF_FIRST =         1 << 3,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! Two bits for preference and sort   */</span><br><span>    /*! Prefer, and order by local values */</span><br><span style="color: hsl(0, 100%, 40%);">-        AST_SIP_CALL_CODEC_PREF_LOCAL,</span><br><span style="color: hsl(0, 100%, 40%);">-  /*! Prefer, and order by local values (intersection) */</span><br><span style="color: hsl(0, 100%, 40%);">- AST_SIP_CALL_CODEC_PREF_LOCAL_LIMIT,</span><br><span style="color: hsl(0, 100%, 40%);">-    /*! Prefer, and order by local values (top/first only) */</span><br><span style="color: hsl(0, 100%, 40%);">-       AST_SIP_CALL_CODEC_PREF_LOCAL_SINGLE,</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_SIP_CALL_CODEC_PREF_LOCAL =         1 << 4,</span><br><span>        /*! Prefer, and order by remote values */</span><br><span style="color: hsl(0, 100%, 40%);">-       AST_SIP_CALL_CODEC_PREF_REMOTE,</span><br><span style="color: hsl(0, 100%, 40%);">- /*! Prefer, and order by remote values (intersection) */</span><br><span style="color: hsl(0, 100%, 40%);">-        AST_SIP_CALL_CODEC_PREF_REMOTE_LIMIT,</span><br><span style="color: hsl(0, 100%, 40%);">-   /*! Prefer, and order by remote values (top/first only) */</span><br><span style="color: hsl(0, 100%, 40%);">-      AST_SIP_CALL_CODEC_PREF_REMOTE_SINGLE,</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_SIP_CALL_CODEC_PREF_REMOTE =        1 << 5,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_sip_call_codec_pref_test(pref, codec_pref) (!!(pref & AST_SIP_CALL_CODEC_PREF_ ## codec_pref ))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span>  * \brief Session timers options</span><br><span>  */</span><br><span>@@ -770,6 +779,8 @@</span><br><span>   unsigned int webrtc;</span><br><span>         /*! Codec preference for an incoming offer */</span><br><span>        enum ast_sip_call_codec_pref incoming_call_offer_pref;</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! Codec preference for an outgoing offer */</span><br><span style="color: hsl(120, 100%, 40%);">+ enum ast_sip_call_codec_pref outgoing_call_offer_pref;</span><br><span> };</span><br><span> </span><br><span> /*!</span><br><span>@@ -3223,6 +3234,18 @@</span><br><span> int ast_sip_str_to_dtmf(const char *dtmf_mode);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Convert the call codec preference enum to a string</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 18.0.0</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param pref the call codec preference setting</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns a constant string with either the setting value or 'unknown'</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_sip_call_codec_pref_to_str(enum ast_sip_call_codec_pref pref);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Transport shutdown monitor callback.</span><br><span>  * \since 13.18.0</span><br><span>  *</span><br><span>diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h</span><br><span>index a5ae6f1..7879c75 100644</span><br><span>--- a/include/asterisk/res_pjsip_session.h</span><br><span>+++ b/include/asterisk/res_pjsip_session.h</span><br><span>@@ -80,8 +80,6 @@</span><br><span>   struct ast_sip_session_sdp_handler *handler;</span><br><span>         /*! \brief Holds SRTP information */</span><br><span>         struct ast_sdp_srtp *srtp;</span><br><span style="color: hsl(0, 100%, 40%);">-      /*! \brief Media format capabilities */</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_sip_session_caps *caps;</span><br><span>   /*! \brief What type of encryption is in use on this stream */</span><br><span>       enum ast_sip_session_media_encryption encryption;</span><br><span>    /*! \brief The media transport in use for this stream */</span><br><span>@@ -157,6 +155,10 @@</span><br><span> /*! \brief Opaque struct controlling the suspension of the session's serializer. */</span><br><span> struct ast_sip_session_suspender;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_sip_session_call_direction {</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_SIP_SESSION_INCOMING_CALL = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_SIP_SESSION_OUTGOING_CALL,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span> /*!</span><br><span>  * \brief A structure describing a SIP session</span><br><span>  *</span><br><span>@@ -224,6 +226,8 @@</span><br><span>      pjsip_uri *request_uri;</span><br><span>      /* Media statistics for negotiated RTP streams */</span><br><span>    AST_VECTOR(, struct ast_rtp_instance_stats *) media_stats;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* The direction of the call */</span><br><span style="color: hsl(120, 100%, 40%);">+       enum ast_sip_session_call_direction call_direction;</span><br><span> };</span><br><span> </span><br><span> typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);</span><br><span>diff --git a/include/asterisk/res_pjsip_session_caps.h b/include/asterisk/res_pjsip_session_caps.h</span><br><span>index 810a1e6..2518f96 100644</span><br><span>--- a/include/asterisk/res_pjsip_session_caps.h</span><br><span>+++ b/include/asterisk/res_pjsip_session_caps.h</span><br><span>@@ -24,59 +24,37 @@</span><br><span> struct ast_sip_session_caps;</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Allocate a SIP session capabilities object.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Get a new stream with joint capabilities between request and endpoint</span><br><span>  * \since 18.0.0</span><br><span>  *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval An ao2 allocated SIP session capabilities object, or NULL on error</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param session The session</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param request_stream The requested stream from the remote or core</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval A pointer to a new stream with the joint capabilities</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_sip_session_caps *ast_sip_session_caps_alloc(void);</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_stream *ast_sip_session_join_call_offer_streams(const struct ast_sip_session *session,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_stream *request_stream);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Set the incoming call offer capabilities for a session.</span><br><span style="color: hsl(0, 100%, 40%);">- * \since 18.0.0</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This will replace any capabilities already present.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \param caps A session's capabilities object</span><br><span style="color: hsl(0, 100%, 40%);">- * \param cap The capabilities to set it to</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-void ast_sip_session_set_incoming_call_offer_cap(struct ast_sip_session_caps *caps,</span><br><span style="color: hsl(0, 100%, 40%);">-    struct ast_format_cap *cap);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Get the incoming call offer capabilities.</span><br><span style="color: hsl(0, 100%, 40%);">- * \since 18.0.0</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \note Returned objects reference is not incremented.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \param caps A session's capabilities object</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval An incoming call offer capabilities object</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-const struct ast_format_cap *ast_sip_session_get_incoming_call_offer_cap(</span><br><span style="color: hsl(0, 100%, 40%);">-      const struct ast_sip_session_caps *caps);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Make the incoming call offer capabilities for a session.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Make the call offer capabilities for a session.</span><br><span>  * \since 18.0.0</span><br><span>  *</span><br><span>  * Creates and sets a list of joint capabilities between the given remote</span><br><span>  * capabilities, and pre-configured ones. The resulting joint list is then</span><br><span>  * stored, and 'owned' (reference held) by the session.</span><br><span>  *</span><br><span style="color: hsl(0, 100%, 40%);">- * If the incoming capabilities have been set elsewhere, this will not replace</span><br><span style="color: hsl(120, 100%, 40%);">+ * If the capabilities have been set elsewhere, this will not replace</span><br><span>  * those. It will however, return a pointer to the current set.</span><br><span>  *</span><br><span>  * \note Returned object's reference is not incremented.</span><br><span>  *</span><br><span>  * \param session The session</span><br><span style="color: hsl(0, 100%, 40%);">- * \param session_media An associated media session</span><br><span style="color: hsl(0, 100%, 40%);">- * \param remote Capabilities of a device</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param media_type The media type</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param remote Capabilities received in an SDP offer or from the core</span><br><span>  *</span><br><span>  * \retval A pointer to the incoming call offer capabilities</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-const struct ast_format_cap *ast_sip_session_join_incoming_call_offer_cap(</span><br><span style="color: hsl(0, 100%, 40%);">-   const struct ast_sip_session *session, const struct ast_sip_session_media *session_media,</span><br><span style="color: hsl(0, 100%, 40%);">-       const struct ast_format_cap *remote);</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_format_cap *ast_sip_session_join_call_offer_cap(const struct ast_sip_session *session,</span><br><span style="color: hsl(120, 100%, 40%);">+      enum ast_media_type media_type, const struct ast_format_cap *remote);</span><br><span> </span><br><span> #endif /* RES_PJSIP_SESSION_CAPS_H */</span><br><span>diff --git a/res/res_pjsip.c b/res/res_pjsip.c</span><br><span>index 4d77a6d..b918828 100644</span><br><span>--- a/res/res_pjsip.c</span><br><span>+++ b/res/res_pjsip.c</span><br><span>@@ -926,22 +926,62 @@</span><br><span>                                  <synopsis>Respond to a SIP invite with the single most preferred codec rather than advertising all joint codec capabilities. This limits the other side's codec choice to exactly what we prefer.</synopsis></span><br><span>                                 </configOption></span><br><span>                                <configOption name="incoming_call_offer_pref" default="local"></span><br><span style="color: hsl(0, 100%, 40%);">-                                        <synopsis>After receiving an incoming offer create a list of preferred codecs between</span><br><span style="color: hsl(0, 100%, 40%);">-                                     those received in the SDP offer, and those specified in endpoint configuration.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <synopsis>Preferences for selecting codecs for an incoming call.</synopsis></span><br><span>                                      <description></span><br><span style="color: hsl(0, 100%, 40%);">-                                             <note><para>This list will consist of only those codecs found in both.</para></note></span><br><span style="color: hsl(120, 100%, 40%);">+                                          <para>Based on this setting, a joint list of preferred codecs between those</span><br><span style="color: hsl(120, 100%, 40%);">+                                             received in an incoming SDP offer (remote), and those specified in the</span><br><span style="color: hsl(120, 100%, 40%);">+                                                endpoint's "allow" parameter (local) es created and is passed to the Asterisk</span><br><span style="color: hsl(120, 100%, 40%);">+                                           core. </para></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <note><para>This list will consist of only those codecs found in both lists.</para></note></span><br><span>                                           <enumlist></span><br><span>                                                     <enum name="local"><para></span><br><span style="color: hsl(0, 100%, 40%);">-                                                         Order by the endpoint configuration allow line (default)</span><br><span style="color: hsl(120, 100%, 40%);">+                                                              Include all codecs in the local list that are also in the remote list</span><br><span style="color: hsl(120, 100%, 40%);">+                                                         preserving the local order.  (default).</span><br><span>                                                      </para></enum></span><br><span style="color: hsl(0, 100%, 40%);">-                                                      <enum name="local_single"><para></span><br><span style="color: hsl(0, 100%, 40%);">-                                                          Order by the endpoint configuration allow line, but the list will only contain the first, or 'top' item</span><br><span style="color: hsl(120, 100%, 40%);">+                                                       <enum name="local_first"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                         Include only the first codec in the local list that is also in the remote list.</span><br><span>                                                      </para></enum></span><br><span>                                                   <enum name="remote"><para></span><br><span style="color: hsl(0, 100%, 40%);">-                                                                Order by what is received in the SDP offer</span><br><span style="color: hsl(120, 100%, 40%);">+                                                            Include all codecs in the remote list that are also in the local list</span><br><span style="color: hsl(120, 100%, 40%);">+                                                         preserving the remote order.</span><br><span>                                                         </para></enum></span><br><span style="color: hsl(0, 100%, 40%);">-                                                      <enum name="remote_single"><para></span><br><span style="color: hsl(0, 100%, 40%);">-                                                         Order by what is received in the SDP offer, but the list will only contain the first, or 'top' item</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   <enum name="remote_first"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                Include only the first codec in the remote list that is also in the local list.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                       </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                            </enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                     </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="outgoing_call_offer_pref" default="local"></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <synopsis>Preferences for selecting codecs for an outgoing call.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <description></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <para>Based on this setting, a joint list of preferred codecs between</span><br><span style="color: hsl(120, 100%, 40%);">+                                           those received from the Asterisk core (remote), and those specified in</span><br><span style="color: hsl(120, 100%, 40%);">+                                                the endpoint's "allow" parameter (local) is created and is used to create</span><br><span style="color: hsl(120, 100%, 40%);">+                                               the outgoing SDP offer.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                          <enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                                      <enum name="local"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                               Include all codecs in the local list that are also in the remote list</span><br><span style="color: hsl(120, 100%, 40%);">+                                                         preserving the local order. (default).</span><br><span style="color: hsl(120, 100%, 40%);">+                                                        </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <enum name="local_merge"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                         Include all codecs in BOTH lists preserving the local order.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                          Remote codecs not in the local list will be placed at the end</span><br><span style="color: hsl(120, 100%, 40%);">+                                                         of the joint list.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <enum name="local_first"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                         Include only the first codec in the local list.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                       </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <enum name="remote"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                              Include all codecs in the remote list that are also in the local list</span><br><span style="color: hsl(120, 100%, 40%);">+                                                         preserving the remote order.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <enum name="remote_merge"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                Include all codecs in BOTH lists preserving the remote order.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                         Local codecs not in the remote list will be placed at the end</span><br><span style="color: hsl(120, 100%, 40%);">+                                                         of the joint list.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <enum name="remote_first"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                Include only the first codec in the remote list.</span><br><span>                                                     </para></enum></span><br><span>                                           </enumlist></span><br><span>                                    </description></span><br><span>@@ -5044,6 +5084,29 @@</span><br><span>        return result;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_sip_call_codec_pref_to_str(enum ast_sip_call_codec_pref pref)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *value;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ast_sip_call_codec_pref_test(pref, LOCAL) &&  ast_sip_call_codec_pref_test(pref, INTERSECT) && ast_sip_call_codec_pref_test(pref, ALL)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         value = "local";</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (ast_sip_call_codec_pref_test(pref, LOCAL) &&  ast_sip_call_codec_pref_test(pref, UNION) && ast_sip_call_codec_pref_test(pref, ALL)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              value = "local_merge";</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (ast_sip_call_codec_pref_test(pref, LOCAL) &&  ast_sip_call_codec_pref_test(pref, INTERSECT) && ast_sip_call_codec_pref_test(pref, FIRST)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                value = "local_first";</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (ast_sip_call_codec_pref_test(pref, REMOTE) &&  ast_sip_call_codec_pref_test(pref, INTERSECT) && ast_sip_call_codec_pref_test(pref, ALL)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         value = "remote";</span><br><span style="color: hsl(120, 100%, 40%);">+   } else if (ast_sip_call_codec_pref_test(pref, REMOTE) &&  ast_sip_call_codec_pref_test(pref, UNION) && ast_sip_call_codec_pref_test(pref, ALL)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             value = "remote_merge";</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (ast_sip_call_codec_pref_test(pref, REMOTE) &&  ast_sip_call_codec_pref_test(pref, UNION) && ast_sip_call_codec_pref_test(pref, FIRST)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           value = "remote_first";</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              value = "unknown";</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return value;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span>  * \brief Set name and number information on an identity header.</span><br><span>  *</span><br><span>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c</span><br><span>index 1d61558..280aeef 100644</span><br><span>--- a/res/res_pjsip/pjsip_configuration.c</span><br><span>+++ b/res/res_pjsip/pjsip_configuration.c</span><br><span>@@ -1121,43 +1121,57 @@</span><br><span>       return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static const char *sip_call_codec_pref_strings[] = {</span><br><span style="color: hsl(0, 100%, 40%);">-  [AST_SIP_CALL_CODEC_PREF_LOCAL] = "local",</span><br><span style="color: hsl(0, 100%, 40%);">-    [AST_SIP_CALL_CODEC_PREF_LOCAL_LIMIT] = "local_limit",</span><br><span style="color: hsl(0, 100%, 40%);">-        [AST_SIP_CALL_CODEC_PREF_LOCAL_SINGLE] = "local_single",</span><br><span style="color: hsl(0, 100%, 40%);">-      [AST_SIP_CALL_CODEC_PREF_REMOTE] = "remote",</span><br><span style="color: hsl(0, 100%, 40%);">-  [AST_SIP_CALL_CODEC_PREF_REMOTE_LIMIT] = "remote_limit",</span><br><span style="color: hsl(0, 100%, 40%);">-      [AST_SIP_CALL_CODEC_PREF_REMOTE_SINGLE] = "remote_single",</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int incoming_call_offer_pref_handler(const struct aco_option *opt,</span><br><span style="color: hsl(120, 100%, 40%);">+static int call_offer_pref_handler(const struct aco_option *opt,</span><br><span>    struct ast_variable *var, void *obj)</span><br><span> {</span><br><span>    struct ast_sip_endpoint *endpoint = obj;</span><br><span style="color: hsl(0, 100%, 40%);">-        unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum ast_sip_call_codec_pref pref;</span><br><span style="color: hsl(120, 100%, 40%);">+    int outgoing = strcmp(var->name, "outgoing_call_offer_pref") == 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     for (i = 0; i < ARRAY_LEN(sip_call_codec_pref_strings); ++i) {</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!strcmp(var->value, sip_call_codec_pref_strings[i])) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   /* Local and remote limit are not available values for this option */</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (i == AST_SIP_CALL_CODEC_PREF_LOCAL_LIMIT ||</span><br><span style="color: hsl(0, 100%, 40%);">-                         i == AST_SIP_CALL_CODEC_PREF_REMOTE_LIMIT) {</span><br><span style="color: hsl(0, 100%, 40%);">-                            return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-                      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       endpoint->media.incoming_call_offer_pref = i;</span><br><span style="color: hsl(0, 100%, 40%);">-                        return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (strcmp(var->value, "local") == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+          pref = AST_SIP_CALL_CODEC_PREF_LOCAL | AST_SIP_CALL_CODEC_PREF_INTERSECT | AST_SIP_CALL_CODEC_PREF_ALL;</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (outgoing && strcmp(var->value, "local_merge") == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+         pref = AST_SIP_CALL_CODEC_PREF_LOCAL | AST_SIP_CALL_CODEC_PREF_UNION | AST_SIP_CALL_CODEC_PREF_ALL;</span><br><span style="color: hsl(120, 100%, 40%);">+   } else if (strcmp(var->value, "local_first") == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             pref = AST_SIP_CALL_CODEC_PREF_LOCAL | AST_SIP_CALL_CODEC_PREF_INTERSECT | AST_SIP_CALL_CODEC_PREF_FIRST;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (strcmp(var->value, "remote") == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+          pref = AST_SIP_CALL_CODEC_PREF_REMOTE | AST_SIP_CALL_CODEC_PREF_INTERSECT | AST_SIP_CALL_CODEC_PREF_ALL;</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (outgoing && strcmp(var->value, "remote_merge") == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                pref = AST_SIP_CALL_CODEC_PREF_REMOTE | AST_SIP_CALL_CODEC_PREF_UNION | AST_SIP_CALL_CODEC_PREF_ALL;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else if (strcmp(var->value, "remote_first") == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            pref = AST_SIP_CALL_CODEC_PREF_REMOTE | AST_SIP_CALL_CODEC_PREF_UNION | AST_SIP_CALL_CODEC_PREF_FIRST;</span><br><span style="color: hsl(120, 100%, 40%);">+        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (outgoing) {</span><br><span style="color: hsl(120, 100%, 40%);">+               endpoint->media.outgoing_call_offer_pref = pref;</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              endpoint->media.incoming_call_offer_pref = pref;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span> }</span><br><span> </span><br><span> static int incoming_call_offer_pref_to_str(const void *obj, const intptr_t *args, char **buf)</span><br><span> {</span><br><span>     const struct ast_sip_endpoint *endpoint = obj;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      if (ARRAY_IN_BOUNDS(endpoint->media.incoming_call_offer_pref, sip_call_codec_pref_strings)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                *buf = ast_strdup(sip_call_codec_pref_strings[endpoint->media.incoming_call_offer_pref]);</span><br><span style="color: hsl(120, 100%, 40%);">+  *buf = ast_strdup(ast_sip_call_codec_pref_to_str(endpoint->media.incoming_call_offer_pref));</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!(*buf)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int outgoing_call_offer_pref_to_str(const void *obj, const intptr_t *args, char **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct ast_sip_endpoint *endpoint = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      *buf = ast_strdup(ast_sip_call_codec_pref_to_str(endpoint->media.outgoing_call_offer_pref));</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!(*buf)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span>   }</span><br><span> </span><br><span>        return 0;</span><br><span>@@ -2009,7 +2023,9 @@</span><br><span>    ast_sorcery_object_field_register(sip_sorcery, "endpoint", "suppress_q850_reason_headers", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, suppress_q850_reason_headers));</span><br><span>        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ignore_183_without_sdp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, ignore_183_without_sdp));</span><br><span>    ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "incoming_call_offer_pref", "local",</span><br><span style="color: hsl(0, 100%, 40%);">-            incoming_call_offer_pref_handler, incoming_call_offer_pref_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+               call_offer_pref_handler, incoming_call_offer_pref_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outgoing_call_offer_pref", "local",</span><br><span style="color: hsl(120, 100%, 40%);">+          call_offer_pref_handler, outgoing_call_offer_pref_to_str, NULL, 0, 0);</span><br><span> </span><br><span>   if (ast_sip_initialize_sorcery_transport()) {</span><br><span>                ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");</span><br><span>diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c</span><br><span>index 4bbbe92..5b1d1ef 100644</span><br><span>--- a/res/res_pjsip_sdp_rtp.c</span><br><span>+++ b/res/res_pjsip_sdp_rtp.c</span><br><span>@@ -376,13 +376,13 @@</span><br><span> </span><br><span> static int apply_cap_to_bundled(struct ast_sip_session_media *session_media,</span><br><span>        struct ast_sip_session_media *session_media_transport,</span><br><span style="color: hsl(0, 100%, 40%);">-  struct ast_stream *asterisk_stream, const struct ast_format_cap *joint)</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_stream *asterisk_stream, struct ast_format_cap *joint)</span><br><span> {</span><br><span>       if (!joint) {</span><br><span>                return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_stream_set_formats(asterisk_stream, (struct ast_format_cap *)joint);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_stream_set_formats(asterisk_stream, joint);</span><br><span> </span><br><span>  /* If this is a bundled stream then apply the payloads to RTP instance acting as transport to prevent conflicts */</span><br><span>   if (session_media_transport != session_media && session_media->bundled) {</span><br><span>@@ -401,15 +401,16 @@</span><br><span>                         ao2_ref(format, -1);</span><br><span>                 }</span><br><span>    }</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_ref(joint, -1);</span><br><span> </span><br><span>      return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static const struct ast_format_cap *set_incoming_call_offer_cap(</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_format_cap *set_incoming_call_offer_cap(</span><br><span>       struct ast_sip_session *session, struct ast_sip_session_media *session_media,</span><br><span>        const struct pjmedia_sdp_media *stream)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    const struct ast_format_cap *incoming_call_offer_cap;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_format_cap *incoming_call_offer_cap;</span><br><span>      struct ast_format_cap *remote;</span><br><span>       struct ast_rtp_codecs codecs = AST_RTP_CODECS_NULL_INIT;</span><br><span>     int fmts = 0;</span><br><span>@@ -425,8 +426,8 @@</span><br><span>  get_codecs(session, stream, &codecs, session_media);</span><br><span>     ast_rtp_codecs_payload_formats(&codecs, remote, &fmts);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     incoming_call_offer_cap = ast_sip_session_join_incoming_call_offer_cap(</span><br><span style="color: hsl(0, 100%, 40%);">-         session, session_media, remote);</span><br><span style="color: hsl(120, 100%, 40%);">+      incoming_call_offer_cap = ast_sip_session_join_call_offer_cap(</span><br><span style="color: hsl(120, 100%, 40%);">+                session, session_media->type, remote);</span><br><span> </span><br><span>        ao2_ref(remote, -1);</span><br><span> </span><br><span>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c</span><br><span>index 0c752b8..853add2 100644</span><br><span>--- a/res/res_pjsip_session.c</span><br><span>+++ b/res/res_pjsip_session.c</span><br><span>@@ -467,8 +467,6 @@</span><br><span> </span><br><span>  ast_free(session_media->mid);</span><br><span>     ast_free(session_media->remote_mslabel);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     ao2_cleanup(session_media->caps);</span><br><span> }</span><br><span> </span><br><span> struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session,</span><br><span>@@ -527,12 +525,6 @@</span><br><span>               } else {</span><br><span>                     session_media->bundle_group = -1;</span><br><span>                 }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               session_media->caps = ast_sip_session_caps_alloc();</span><br><span style="color: hsl(0, 100%, 40%);">-          if (!session_media->caps) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  ao2_ref(session_media, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-                     return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-            }</span><br><span>    }</span><br><span> </span><br><span>        if (AST_VECTOR_REPLACE(&media_state->sessions, position, session_media)) {</span><br><span>@@ -2699,6 +2691,8 @@</span><br><span>            return NULL;</span><br><span>         }</span><br><span>    session->aor = ao2_bump(found_aor);</span><br><span style="color: hsl(120, 100%, 40%);">+        session->call_direction = AST_SIP_SESSION_OUTGOING_CALL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        ast_party_id_copy(&session->id, &endpoint->id.self);</span><br><span> </span><br><span>       if (ast_stream_topology_get_count(req_topology) > 0) {</span><br><span>@@ -2707,8 +2701,6 @@</span><br><span> </span><br><span>                for (i = 0; i < ast_stream_topology_get_count(req_topology); ++i) {</span><br><span>                       struct ast_stream *req_stream;</span><br><span style="color: hsl(0, 100%, 40%);">-                  struct ast_format_cap *req_cap;</span><br><span style="color: hsl(0, 100%, 40%);">-                 struct ast_format_cap *joint_cap;</span><br><span>                    struct ast_stream *clone_stream;</span><br><span> </span><br><span>                         req_stream = ast_stream_topology_get_stream(req_topology, i);</span><br><span>@@ -2717,37 +2709,7 @@</span><br><span>                               continue;</span><br><span>                    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                   req_cap = ast_stream_get_formats(req_stream);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                   joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);</span><br><span style="color: hsl(0, 100%, 40%);">-                  if (!joint_cap) {</span><br><span style="color: hsl(0, 100%, 40%);">-                               continue;</span><br><span style="color: hsl(0, 100%, 40%);">-                       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       ast_format_cap_get_compatible(req_cap, endpoint->media.codecs, joint_cap);</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (!ast_format_cap_count(joint_cap)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                         ao2_ref(joint_cap, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-                         continue;</span><br><span style="color: hsl(0, 100%, 40%);">-                       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       clone_stream = ast_stream_clone(req_stream, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-                      if (!clone_stream) {</span><br><span style="color: hsl(0, 100%, 40%);">-                            ao2_ref(joint_cap, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-                         continue;</span><br><span style="color: hsl(0, 100%, 40%);">-                       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (ast_stream_get_type(req_stream) == AST_MEDIA_TYPE_AUDIO) {</span><br><span style="color: hsl(0, 100%, 40%);">-                          /*</span><br><span style="color: hsl(0, 100%, 40%);">-                               * By appending codecs from the endpoint after compatible ones this</span><br><span style="color: hsl(0, 100%, 40%);">-                              * guarantees that priority is given to those while also allowing</span><br><span style="color: hsl(0, 100%, 40%);">-                                * translation to occur for non-compatible.</span><br><span style="color: hsl(0, 100%, 40%);">-                              */</span><br><span style="color: hsl(0, 100%, 40%);">-                             ast_format_cap_append_from_cap(joint_cap,</span><br><span style="color: hsl(0, 100%, 40%);">-                                       endpoint->media.codecs, AST_MEDIA_TYPE_AUDIO);</span><br><span style="color: hsl(0, 100%, 40%);">-                       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       ast_stream_set_formats(clone_stream, joint_cap);</span><br><span style="color: hsl(0, 100%, 40%);">-                        ao2_ref(joint_cap, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                       clone_stream = ast_sip_session_join_call_offer_streams(session, req_stream);</span><br><span> </span><br><span>                     if (!session->pending_media_state->topology) {</span><br><span>                                 session->pending_media_state->topology = ast_stream_topology_alloc();</span><br><span>@@ -3283,6 +3245,7 @@</span><br><span> #endif</span><br><span>                return;</span><br><span>      }</span><br><span style="color: hsl(120, 100%, 40%);">+     session->call_direction = AST_SIP_SESSION_INCOMING_CALL;</span><br><span> </span><br><span>      /*</span><br><span>    * The current thread is supposed be the session serializer to prevent</span><br><span>diff --git a/res/res_pjsip_session/pjsip_session_caps.c b/res/res_pjsip_session/pjsip_session_caps.c</span><br><span>index e131200..03a452c 100644</span><br><span>--- a/res/res_pjsip_session/pjsip_session_caps.c</span><br><span>+++ b/res/res_pjsip_session/pjsip_session_caps.c</span><br><span>@@ -24,6 +24,7 @@</span><br><span> #include "asterisk/format_cap.h"</span><br><span> #include "asterisk/logger.h"</span><br><span> #include "asterisk/sorcery.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/stream.h"</span><br><span> </span><br><span> #include <pjsip_ua.h></span><br><span> </span><br><span>@@ -32,17 +33,22 @@</span><br><span> #include "asterisk/res_pjsip_session_caps.h"</span><br><span> </span><br><span> struct ast_sip_session_caps {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct ast_format_cap *incoming_call_offer_cap;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_format_cap *call_offer_cap;</span><br><span> };</span><br><span> </span><br><span> static void log_caps(int level, const char *file, int line, const char *function,</span><br><span>        const char *msg, const struct ast_sip_session *session,</span><br><span style="color: hsl(0, 100%, 40%);">- const struct ast_sip_session_media *session_media, const struct ast_format_cap *local,</span><br><span style="color: hsl(120, 100%, 40%);">+        enum ast_media_type media_type, const struct ast_format_cap *local,</span><br><span>  const struct ast_format_cap *remote, const struct ast_format_cap *joint)</span><br><span> {</span><br><span>        struct ast_str *s1;</span><br><span>  struct ast_str *s2;</span><br><span>  struct ast_str *s3;</span><br><span style="color: hsl(120, 100%, 40%);">+   int outgoing = session->call_direction == AST_SIP_SESSION_OUTGOING_CALL;</span><br><span style="color: hsl(120, 100%, 40%);">+   enum ast_sip_call_codec_pref pref =</span><br><span style="color: hsl(120, 100%, 40%);">+           outgoing</span><br><span style="color: hsl(120, 100%, 40%);">+              ? session->endpoint->media.outgoing_call_offer_pref</span><br><span style="color: hsl(120, 100%, 40%);">+             : session->endpoint->media.incoming_call_offer_pref;</span><br><span> </span><br><span>       if (level == __LOG_DEBUG && !DEBUG_ATLEAST(3)) {</span><br><span>             return;</span><br><span>@@ -52,91 +58,84 @@</span><br><span>        s2 = remote ? ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN) : NULL;</span><br><span>       s3 = joint ? ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN) : NULL;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       ast_log(level, file, line, function, "'%s' %s '%s' capabilities -%s%s%s%s%s%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_log(level, file, line, function, "'%s' %s %s '%s' caps for pref '%s' -%s%s%s%s%s%s\n",</span><br><span>                 session->channel ? ast_channel_name(session->channel) :</span><br><span>                        ast_sorcery_object_get_id(session->endpoint),</span><br><span style="color: hsl(0, 100%, 40%);">-                msg ? msg : "-", ast_codec_media_type2str(session_media->type),</span><br><span style="color: hsl(0, 100%, 40%);">-            s1 ? " local: " : "", s1 ? ast_format_cap_get_names(local, &s1) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+               msg ? msg : "-",</span><br><span style="color: hsl(120, 100%, 40%);">+            outgoing? "outgoing" : "incoming",</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_codec_media_type2str(media_type),</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_sip_call_codec_pref_to_str(pref),</span><br><span>                s2 ? " remote: " : "", s2 ? ast_format_cap_get_names(remote, &s2) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+             s1 ? " local: " : "", s1 ? ast_format_cap_get_names(local, &s1) : "",</span><br><span>              s3 ? " joint: " : "", s3 ? ast_format_cap_get_names(joint, &s3) : "");</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void sip_session_caps_destroy(void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_stream *ast_sip_session_join_call_offer_streams(const struct ast_sip_session *session,</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_stream *remote_stream)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct ast_sip_session_caps *caps = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_stream *joint_stream = ast_stream_clone(remote_stream, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_format_cap *remote = ast_stream_get_formats(remote_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+        enum ast_media_type media_type = ast_stream_get_type(remote_stream);</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_format_cap *joint = ast_sip_session_join_call_offer_cap(session, media_type, remote);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ao2_cleanup(caps->incoming_call_offer_cap);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_stream_set_formats(joint_stream, joint);</span><br><span style="color: hsl(120, 100%, 40%);">+  ao2_cleanup(joint);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return joint_stream;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_sip_session_caps *ast_sip_session_caps_alloc(void)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     return ao2_alloc_options(sizeof(struct ast_sip_session_caps),</span><br><span style="color: hsl(0, 100%, 40%);">-           sip_session_caps_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void ast_sip_session_set_incoming_call_offer_cap(struct ast_sip_session_caps *caps,</span><br><span style="color: hsl(0, 100%, 40%);">-   struct ast_format_cap *cap)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    ao2_cleanup(caps->incoming_call_offer_cap);</span><br><span style="color: hsl(0, 100%, 40%);">-  caps->incoming_call_offer_cap = ao2_bump(cap);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-const struct ast_format_cap *ast_sip_session_get_incoming_call_offer_cap(</span><br><span style="color: hsl(0, 100%, 40%);">-     const struct ast_sip_session_caps *caps)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       return caps->incoming_call_offer_cap;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-const struct ast_format_cap *ast_sip_session_join_incoming_call_offer_cap(</span><br><span style="color: hsl(0, 100%, 40%);">-     const struct ast_sip_session *session, const struct ast_sip_session_media *session_media,</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_format_cap *ast_sip_session_join_call_offer_cap(</span><br><span style="color: hsl(120, 100%, 40%);">+        const struct ast_sip_session *session, enum ast_media_type media_type,</span><br><span>       const struct ast_format_cap *remote)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       enum ast_sip_call_codec_pref pref;</span><br><span>   struct ast_format_cap *joint;</span><br><span>        struct ast_format_cap *local;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum ast_sip_call_codec_pref call_offer_pref =</span><br><span style="color: hsl(120, 100%, 40%);">+                session->call_direction == AST_SIP_SESSION_OUTGOING_CALL</span><br><span style="color: hsl(120, 100%, 40%);">+           ? session->endpoint->media.outgoing_call_offer_pref</span><br><span style="color: hsl(120, 100%, 40%);">+             : session->endpoint->media.incoming_call_offer_pref;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  joint = session_media->caps->incoming_call_offer_cap;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     if (joint) {</span><br><span style="color: hsl(0, 100%, 40%);">-            /*</span><br><span style="color: hsl(0, 100%, 40%);">-               * If the incoming call offer capabilities have been set elsewhere, e.g. dialplan</span><br><span style="color: hsl(0, 100%, 40%);">-                * then those take precedence.</span><br><span style="color: hsl(0, 100%, 40%);">-           */</span><br><span style="color: hsl(0, 100%, 40%);">-             return joint;</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span> </span><br><span>        joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);</span><br><span>   local = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);</span><br><span> </span><br><span>       if (!joint || !local) {</span><br><span style="color: hsl(0, 100%, 40%);">-         ast_log(LOG_ERROR, "Failed to allocate %s incoming call offer capabilities\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                ast_codec_media_type2str(session_media->type));</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "Failed to allocate %s call offer capabilities\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_codec_media_type2str(media_type));</span><br><span> </span><br><span>           ao2_cleanup(joint);</span><br><span>          ao2_cleanup(local);</span><br><span>          return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   pref = session->endpoint->media.incoming_call_offer_pref;</span><br><span style="color: hsl(0, 100%, 40%);">- ast_format_cap_append_from_cap(local, session->endpoint->media.codecs,</span><br><span style="color: hsl(0, 100%, 40%);">-            session_media->type);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_format_cap_append_from_cap(local, session->endpoint->media.codecs, media_type);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (pref < AST_SIP_CALL_CODEC_PREF_REMOTE) {</span><br><span style="color: hsl(0, 100%, 40%);">-         ast_format_cap_get_compatible(local, remote, joint); /* Prefer local */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ast_sip_call_codec_pref_test(call_offer_pref, LOCAL)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ast_sip_call_codec_pref_test(call_offer_pref, INTERSECT)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_format_cap_get_compatible(local, remote, joint); /* Get common, prefer local */</span><br><span style="color: hsl(120, 100%, 40%);">+           } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_format_cap_append_from_cap(joint, local, media_type); /* Add local */</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_format_cap_append_from_cap(joint, remote, media_type); /* Then remote */</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span>    } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_format_cap_get_compatible(remote, local, joint); /* Prefer remote */</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ast_sip_call_codec_pref_test(call_offer_pref, INTERSECT)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_format_cap_get_compatible(remote, local, joint); /* Get common, prefer remote */</span><br><span style="color: hsl(120, 100%, 40%);">+          } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_format_cap_append_from_cap(joint, remote, media_type); /* Add remote */</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_format_cap_append_from_cap(joint, local, media_type); /* Then local */</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span>    }</span><br><span> </span><br><span>        if (ast_format_cap_empty(joint)) {</span><br><span style="color: hsl(0, 100%, 40%);">-              log_caps(LOG_NOTICE, "No joint incoming", session, session_media, local, remote, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+             log_caps(LOG_NOTICE, "No joint", session, media_type, local, remote, NULL);</span><br><span> </span><br><span>            ao2_ref(joint, -1);</span><br><span>          ao2_ref(local, -1);</span><br><span>          return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (pref == AST_SIP_CALL_CODEC_PREF_LOCAL_SINGLE ||</span><br><span style="color: hsl(0, 100%, 40%);">-             pref == AST_SIP_CALL_CODEC_PREF_REMOTE_SINGLE ||</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ast_sip_call_codec_pref_test(call_offer_pref, FIRST) ||</span><br><span>          session->endpoint->preferred_codec_only) {</span><br><span> </span><br><span>                 /*</span><br><span>@@ -152,11 +151,9 @@</span><br><span>            ao2_ref(single, -1);</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   log_caps(LOG_DEBUG, "Joint incoming", session, session_media, local, remote, joint);</span><br><span style="color: hsl(120, 100%, 40%);">+        log_caps(LOG_DEBUG, "Joint", session, media_type, local, remote, joint);</span><br><span> </span><br><span>       ao2_ref(local, -1);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_sip_session_set_incoming_call_offer_cap(session_media->caps, joint);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>  return joint;</span><br><span> }</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/13945">change 13945</a>. To unsubscribe, or for help writing mail filters, 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/c/asterisk/+/13945"/><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-Change-Id: Id4ec0b4a906c2ae5885bf947f101c59059935437 </div>
<div style="display:none"> Gerrit-Change-Number: 13945 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>