<p>George Joseph <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/19479">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span></span><br></pre><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_rtp_asterisk: Asterisk Media Experience Score (MES)<br><br>This module has been updated to provide additional<br>quality statistics in the form of an Asterisk<br>Media Experience Score.  The score is avilable using<br>the same mechanisms you'd use to retrieve jitter, loss,<br>and rtt statistics.  For more information about the<br>score and how to retrieve it, see<br>https://wiki.asterisk.org/wiki/display/AST/Media+Experience+Score<br><br>* Updated chan_pjsip to set quality channel variables when a<br>  call ends.<br>* Updated channels/pjsip/dialplan_functions.c to add the ability<br>  to retrieve the MES along with the existing rtcp stats when<br>  using the CHANNEL dialplan function.<br>* Added the ast_debug_rtp_is_allowed and ast_debug_rtcp_is_allowed<br>  checks for debugging purposes.<br>* Added several function to time.h for manipulating time-in-samples<br>  and times represented as double seconds.<br>* Updated rtp_engine.c to pass through the MES when stats are<br>  requested.  Also debug output that dumps the stats when an<br>  rtp instance is destroyed.<br>* Updated res_rtp_asterisk.c to implement the calculation of the<br>  MES.  In the process, also had to update the calculation of<br>  jitter.  Many debugging statements were also changed to be<br>  more informative.<br>* Added a unit test for internal testing.  The test should not be<br>  run during normal operation and is disabled by default.<br><br>ASTERISK-30280<br><br>Change-Id: I458cb9a311e8e5dc1db769b8babbcf2e093f107a<br>---<br>M channels/chan_pjsip.c<br>M channels/pjsip/dialplan_functions.c<br>A doc/CHANGES-staging/res_rtp_asterisk.txt<br>M include/asterisk/rtp_engine.h<br>M include/asterisk/time.h<br>M main/rtp_engine.c<br>M res/res_rtp_asterisk.c<br>M tests/test_res_rtp.c<br>8 files changed, 970 insertions(+), 102 deletions(-)<br><br></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 3e8abd2..22ed5ec 100644</span><br><span>--- a/channels/chan_pjsip.c</span><br><span>+++ b/channels/chan_pjsip.c</span><br><span>@@ -2513,6 +2513,15 @@</span><br><span>            if (session) {</span><br><span>                       int cause = h_data->cause;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+                     if (channel->session->active_media_state &&</span><br><span style="color: hsl(120, 100%, 40%);">+                             channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               struct ast_sip_session_media *media =</span><br><span style="color: hsl(120, 100%, 40%);">+                                 channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];</span><br><span style="color: hsl(120, 100%, 40%);">+                         if (media->rtp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                  ast_rtp_instance_set_stats_vars(ast, media->rtp);</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>                  /*</span><br><span>                   * It's possible that session_terminate might cause the session to be destroyed</span><br><span>                   * immediately so we need to keep a reference to it so we can NULL session->channel</span><br><span>@@ -2993,6 +3002,16 @@</span><br><span>               SCOPE_EXIT_RTN("No channel\n");</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (session->active_media_state &&</span><br><span style="color: hsl(120, 100%, 40%);">+         session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]) {</span><br><span style="color: hsl(120, 100%, 40%);">+           struct ast_sip_session_media *media =</span><br><span style="color: hsl(120, 100%, 40%);">+                 session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];</span><br><span style="color: hsl(120, 100%, 40%);">+             if (media->rtp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_rtp_instance_set_stats_vars(session->channel, media->rtp);</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>  chan_pjsip_remove_hold(ast_channel_uniqueid(session->channel));</span><br><span> </span><br><span>       ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);</span><br><span>diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c</span><br><span>index a433d07..0496f04 100644</span><br><span>--- a/channels/pjsip/dialplan_functions.c</span><br><span>+++ b/channels/pjsip/dialplan_functions.c</span><br><span>@@ -304,6 +304,12 @@</span><br><span>                                                         <enum name="rtt"></span><br><span>                                                            <para>Round trip time</para></span><br><span>                                                     </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="txmes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                           <para>Transmitted Media Experience Score</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                   </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="rxmes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                           <para>Received Media Experience Score</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                      </enum></span><br><span>                                                </enumlist></span><br><span>                                    </enum></span><br><span>                                        <enum name="all_jitter"></span><br><span>@@ -387,6 +393,37 @@</span><br><span>                                                      </enum></span><br><span>                                                </enumlist></span><br><span>                                    </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <enum name="all_mes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                         <para>Retrieve a summary of all RTCP Media Experience Score information.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <para>The following data items are returned in a semi-colon</span><br><span style="color: hsl(120, 100%, 40%);">+                                             delineated list:</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                         <enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                                      <enum name="minmes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                          <para>Minimum MES based on us analysing received packets.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                  </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="maxmes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                          <para>Maximum MES based on us analysing received packets.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                  </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="avgmes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                          <para>Average MES based on us analysing received packets.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                  </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="stdevmes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                <para>Standard deviation MES based on us analysing received packets.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                       </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="reported_minmes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                         <para>Minimum MES based on data we get in Sender and Receiver Reports sent by the remote end</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                       </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="reported_maxmes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                         <para>Maximum MES based on data we get in Sender and Receiver Reports sent by the remote end</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                       </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="reported_avgmes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                         <para>Average MES based on data we get in Sender and Receiver Reports sent by the remote end</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                       </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="reported_stdevmes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                               <para>Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                         </enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                     </enum></span><br><span>                                        <enum name="txcount"><para>Transmitted packet count</para></enum></span><br><span>                                  <enum name="rxcount"><para>Received packet count</para></enum></span><br><span>                                     <enum name="txjitter"><para>Transmitted packet jitter</para></enum></span><br><span>@@ -416,6 +453,24 @@</span><br><span>                                         <enum name="stdevrtt"><para>Standard deviation round trip time</para></enum></span><br><span>                                       <enum name="local_ssrc"><para>Our Synchronization Source identifier</para></enum></span><br><span>                                  <enum name="remote_ssrc"><para>Their Synchronization Source identifier</para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <enum name="txmes"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                       Current MES based on us analyzing rtt, jitter and loss</span><br><span style="color: hsl(120, 100%, 40%);">+                                        in the actual received RTP stream received from the remote end.</span><br><span style="color: hsl(120, 100%, 40%);">+                                       I.E.  This is the MES for the incoming audio stream.</span><br><span style="color: hsl(120, 100%, 40%);">+                                  </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <enum name="rxmes"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                       Current MES based on rtt and the jitter and loss values in</span><br><span style="color: hsl(120, 100%, 40%);">+                                    RTCP sender and receiver reports we receive from the</span><br><span style="color: hsl(120, 100%, 40%);">+                                  remote end. I.E.  This is the MES for the outgoing audio stream.</span><br><span style="color: hsl(120, 100%, 40%);">+                                      </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <enum name="remote_maxmes"><para>Max MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <enum name="remote_minmes"><para>Min MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <enum name="remote_normdevmes"><para>Average MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <enum name="remote_stdevmes"><para>Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                  <enum name="local_maxmes"><para>Max MES based on us analyzing the received RTP stream</para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <enum name="local_minmes"><para>Min MES based on us analyzing the received RTP stream</para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <enum name="local_normdevmes"><para>Average MES based on us analyzing the received RTP stream</para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <enum name="local_stdevmes"><para>Standard deviation MES based on us analyzing the received RTP stream</para></enum></span><br><span>                               </enumlist></span><br><span>                    </parameter></span><br><span>                   <parameter name="media_type" required="false"></span><br><span>@@ -678,6 +733,8 @@</span><br><span>                       stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT;</span><br><span>                } else if (!strcasecmp(type, "all_loss")) {</span><br><span>                        stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS;</span><br><span style="color: hsl(120, 100%, 40%);">+                } else if (!strcasecmp(type, "all_mes")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES;</span><br><span>                }</span><br><span> </span><br><span>                if (!ast_rtp_instance_get_quality(media->rtp, stat_field, buf, buflen)) {</span><br><span>@@ -724,6 +781,16 @@</span><br><span>                  { "stdevrtt",              DBL, { .d8 = &stats.stdevrtt, }, },</span><br><span>                         { "local_ssrc",            INT, { .i4 = &stats.local_ssrc, }, },</span><br><span>                       { "remote_ssrc",           INT, { .i4 = &stats.remote_ssrc, }, },</span><br><span style="color: hsl(120, 100%, 40%);">+                       { "txmes",                 DBL, { .d8 = &stats.txmes, }, },</span><br><span style="color: hsl(120, 100%, 40%);">+                     { "rxmes",                 DBL, { .d8 = &stats.rxmes, }, },</span><br><span style="color: hsl(120, 100%, 40%);">+                     { "remote_maxmes",         DBL, { .d8 = &stats.remote_maxmes, }, },</span><br><span style="color: hsl(120, 100%, 40%);">+                     { "remote_minmes",         DBL, { .d8 = &stats.remote_minmes, }, },</span><br><span style="color: hsl(120, 100%, 40%);">+                     { "remote_normdevmes",     DBL, { .d8 = &stats.remote_normdevmes, }, },</span><br><span style="color: hsl(120, 100%, 40%);">+                 { "remote_stdevmes",       DBL, { .d8 = &stats.remote_stdevmes, }, },</span><br><span style="color: hsl(120, 100%, 40%);">+                   { "local_maxmes",          DBL, { .d8 = &stats.local_maxmes, }, },</span><br><span style="color: hsl(120, 100%, 40%);">+                      { "local_minmes",          DBL, { .d8 = &stats.local_minmes, }, },</span><br><span style="color: hsl(120, 100%, 40%);">+                      { "local_normdevmes",      DBL, { .d8 = &stats.local_normdevmes, }, },</span><br><span style="color: hsl(120, 100%, 40%);">+                  { "local_stdevmes",        DBL, { .d8 = &stats.local_stdevmes, }, },</span><br><span>                   { NULL, },</span><br><span>           };</span><br><span> </span><br><span>diff --git a/doc/CHANGES-staging/res_rtp_asterisk.txt b/doc/CHANGES-staging/res_rtp_asterisk.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..9c8e05f</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/res_rtp_asterisk.txt</span><br><span>@@ -0,0 +1,9 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: res_rtp_asterisk</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+This module has been updated to provide additional</span><br><span style="color: hsl(120, 100%, 40%);">+quality statistics in the form of an Asterisk</span><br><span style="color: hsl(120, 100%, 40%);">+Media Experience Score.  The score is available using</span><br><span style="color: hsl(120, 100%, 40%);">+the same mechanisms you'd use to retrieve jitter, loss,</span><br><span style="color: hsl(120, 100%, 40%);">+and rtt statistics.  For more information about the</span><br><span style="color: hsl(120, 100%, 40%);">+score and how to retrieve it, see</span><br><span style="color: hsl(120, 100%, 40%);">+https://wiki.asterisk.org/wiki/display/AST/Media+Experience+Score</span><br><span>diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h</span><br><span>index 50e2a7b..7834acd 100644</span><br><span>--- a/include/asterisk/rtp_engine.h</span><br><span>+++ b/include/asterisk/rtp_engine.h</span><br><span>@@ -174,6 +174,8 @@</span><br><span>   AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS,</span><br><span>    /*! Retrieve quality information about round trip time */</span><br><span>    AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT,</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! Retrieve quality information about Media Experience Score */</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES,</span><br><span> };</span><br><span> </span><br><span> /*! Statistics that can be retrieved from an RTP instance */</span><br><span>@@ -250,6 +252,29 @@</span><br><span>    AST_RTP_INSTANCE_STAT_TXOCTETCOUNT,</span><br><span>  /*! Retrieve number of octets received */</span><br><span>    AST_RTP_INSTANCE_STAT_RXOCTETCOUNT,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Retrieve ALL statistics relating to Media Experience Score */</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RTP_INSTANCE_STAT_COMBINED_MES,</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! Retrieve MES on transmitted packets */</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_RTP_INSTANCE_STAT_TXMES,</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Retrieve MES on received packets */</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_RTP_INSTANCE_STAT_RXMES,</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Retrieve maximum MES on remote side */</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_RTP_INSTANCE_STAT_REMOTE_MAXMES,</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Retrieve minimum MES on remote side */</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_RTP_INSTANCE_STAT_REMOTE_MINMES,</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Retrieve average MES on remote side */</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVMES,</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! Retrieve standard deviation MES on remote side */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_RTP_INSTANCE_STAT_REMOTE_STDEVMES,</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! Retrieve maximum MES on local side */</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RTP_INSTANCE_STAT_LOCAL_MAXMES,</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! Retrieve minimum MES on local side */</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RTP_INSTANCE_STAT_LOCAL_MINMES,</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! Retrieve average MES on local side */</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVMES,</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! Retrieve standard deviation MES on local side */</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_RTP_INSTANCE_STAT_LOCAL_STDEVMES,</span><br><span> };</span><br><span> </span><br><span> enum ast_rtp_instance_rtcp {</span><br><span>@@ -428,6 +453,27 @@</span><br><span>       unsigned int txoctetcount;</span><br><span>   /*! Number of octets received */</span><br><span>     unsigned int rxoctetcount;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Media Experience Score on transmitted packets */</span><br><span style="color: hsl(120, 100%, 40%);">+  double txmes;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Media Experience Score on received packets */</span><br><span style="color: hsl(120, 100%, 40%);">+     double rxmes;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Maximum MES on remote side */</span><br><span style="color: hsl(120, 100%, 40%);">+     double remote_maxmes;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Minimum MES on remote side */</span><br><span style="color: hsl(120, 100%, 40%);">+     double remote_minmes;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Average MES on remote side */</span><br><span style="color: hsl(120, 100%, 40%);">+     double remote_normdevmes;</span><br><span style="color: hsl(120, 100%, 40%);">+     /*! Standard deviation MES on remote side */</span><br><span style="color: hsl(120, 100%, 40%);">+  double remote_stdevmes;</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! Maximum MES on local side */</span><br><span style="color: hsl(120, 100%, 40%);">+      double local_maxmes;</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Minimum MES on local side */</span><br><span style="color: hsl(120, 100%, 40%);">+      double local_minmes;</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Average MES on local side */</span><br><span style="color: hsl(120, 100%, 40%);">+      double local_normdevmes;</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! Standard deviation MES on local side */</span><br><span style="color: hsl(120, 100%, 40%);">+   double local_stdevmes;</span><br><span> };</span><br><span> </span><br><span> #define AST_RTP_STAT_SET(current_stat, combined, placement, value) \</span><br><span>@@ -2860,6 +2906,10 @@</span><br><span> #define ast_debug_rtp(sublevel, ...) \</span><br><span>  ast_debug_category(sublevel, AST_DEBUG_CATEGORY_RTP,  __VA_ARGS__)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Allow logging of RTP? */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_debug_rtp_is_allowed \</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_RTP)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Allow logging of RTP packets? */</span><br><span> #define ast_debug_rtp_packet_is_allowed \</span><br><span>        ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_RTP_PACKET)</span><br><span>@@ -2873,6 +2923,10 @@</span><br><span> #define ast_debug_rtcp(sublevel, ...) \</span><br><span>   ast_debug_category(sublevel, AST_DEBUG_CATEGORY_RTCP, __VA_ARGS__)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Allow logging of RTCP? */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_debug_rtcp_is_allowed \</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_RTCP)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Allow logging of RTCP packets? */</span><br><span> #define ast_debug_rtcp_packet_is_allowed \</span><br><span>     ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_RTCP_PACKET)</span><br><span>diff --git a/include/asterisk/time.h b/include/asterisk/time.h</span><br><span>index 3e0c064..098f460 100644</span><br><span>--- a/include/asterisk/time.h</span><br><span>+++ b/include/asterisk/time.h</span><br><span>@@ -33,6 +33,8 @@</span><br><span> #include <unistd.h></span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <math.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include "asterisk/inline_api.h"</span><br><span> </span><br><span> /* A time_t can be represented as an unsigned long long (or uint64_t).</span><br><span>@@ -233,6 +235,41 @@</span><br><span> )</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Returns a timeval structure corresponding to the</span><br><span style="color: hsl(120, 100%, 40%);">+ * number of seconds in the double _td.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param _td The number of seconds.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns A timeval structure containing the number of seconds.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is the inverse of ast_tv2double().</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_INLINE_API(</span><br><span style="color: hsl(120, 100%, 40%);">+struct timeval ast_double2tv(double _td),</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct timeval t;</span><br><span style="color: hsl(120, 100%, 40%);">+     t.tv_sec = (typeof(t.tv_sec))floor(_td);</span><br><span style="color: hsl(120, 100%, 40%);">+      t.tv_usec = (typeof(t.tv_usec))(_td - t.tv_sec) / 1000000.0;</span><br><span style="color: hsl(120, 100%, 40%);">+  return t;</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 style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Returns a double corresponding to the number of seconds</span><br><span style="color: hsl(120, 100%, 40%);">+ * in the timeval _tv.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param _tv A pointer to a timeval structure.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns A double containing the number of seconds.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is the inverse of ast_double2tv().</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_INLINE_API(</span><br><span style="color: hsl(120, 100%, 40%);">+double ast_tv2double(const struct timeval *tv),</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return tv->tv_sec + ((double)tv->tv_usec) / 1000000.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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Returns a timeval corresponding to the duration of n samples at rate r.</span><br><span>  * Useful to convert samples to timevals, or even milliseconds to timevals</span><br><span>  * in the form ast_samp2tv(milliseconds, 1000)</span><br><span>@@ -245,6 +282,57 @@</span><br><span> )</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Returns the number of samples at rate _rate in the</span><br><span style="color: hsl(120, 100%, 40%);">+ * duration specified by _tv.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param _tv A pointer to a timeval structure.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param _rate The sample rate in Hz.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns A time_t containing the number of samples.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is the inverse of ast_samp2tv().</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_INLINE_API(</span><br><span style="color: hsl(120, 100%, 40%);">+time_t ast_tv2samp(const struct timeval *_tv, int _rate),</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return (time_t)(ast_tv2double(_tv) * (double)_rate);</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 style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Returns the duration in seconds of _nsamp samples</span><br><span style="color: hsl(120, 100%, 40%);">+ * at rate _rate.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param _nsamp The number of samples</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param _rate The sample rate in Hz.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns A double containing the number of seconds.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is the inverse of ast_sec2samp().</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_INLINE_API(</span><br><span style="color: hsl(120, 100%, 40%);">+double ast_samp2sec(int _nsamp, unsigned int _rate),</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return ((double)_nsamp) / ((double)_rate);</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 style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Returns the number of samples at _rate in the duration</span><br><span style="color: hsl(120, 100%, 40%);">+ * in _seconds.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param _seconds The time interval in seconds.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param _rate The sample rate in Hz.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns The number of samples.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is the inverse of ast_samp2sec().</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_INLINE_API(</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ast_sec2samp(double _seconds, int _rate),</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return (unsigned int)(_seconds * _rate);</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 style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Time units enumeration.</span><br><span>  */</span><br><span> enum TIME_UNIT {</span><br><span>diff --git a/main/rtp_engine.c b/main/rtp_engine.c</span><br><span>index eac3a02..d36f70c 100644</span><br><span>--- a/main/rtp_engine.c</span><br><span>+++ b/main/rtp_engine.c</span><br><span>@@ -143,7 +143,6 @@</span><br><span> </span><br><span> #include "asterisk.h"</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#include <math.h>                       /* for sqrt, MAX */</span><br><span> #include <sched.h>                      /* for sched_yield */</span><br><span> #include <sys/time.h>                   /* for timeval */</span><br><span> #include <time.h>                       /* for time_t */</span><br><span>@@ -457,6 +456,28 @@</span><br><span> </span><br><span> int ast_rtp_instance_destroy(struct ast_rtp_instance *instance)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!instance) {</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%);">+     if (ast_debug_rtp_is_allowed) {</span><br><span style="color: hsl(120, 100%, 40%);">+               char buffer[4][512];</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_debug_rtp(1, "%s:\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                    "  RTT:    %s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                    "  Loss:   %s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                    "  Jitter: %s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                    "  MES:    %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   instance->channel_uniqueid,</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT,</span><br><span style="color: hsl(120, 100%, 40%);">+                               buffer[0], sizeof(buffer[0])),</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS,</span><br><span style="color: hsl(120, 100%, 40%);">+                              buffer[1], sizeof(buffer[1])),</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER,</span><br><span style="color: hsl(120, 100%, 40%);">+                            buffer[2], sizeof(buffer[2])),</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES,</span><br><span style="color: hsl(120, 100%, 40%);">+                               buffer[3], sizeof(buffer[3]))</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>  ao2_cleanup(instance);</span><br><span> </span><br><span>   return 0;</span><br><span>@@ -2463,6 +2484,8 @@</span><br><span>            stat = AST_RTP_INSTANCE_STAT_COMBINED_LOSS;</span><br><span>  } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT) {</span><br><span>               stat = AST_RTP_INSTANCE_STAT_COMBINED_RTT;</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES) {</span><br><span style="color: hsl(120, 100%, 40%);">+                stat = AST_RTP_INSTANCE_STAT_COMBINED_MES;</span><br><span>   } else {</span><br><span>             return NULL;</span><br><span>         }</span><br><span>@@ -2474,16 +2497,25 @@</span><br><span> </span><br><span>      /* Now actually fill the buffer with the good information */</span><br><span>         if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY) {</span><br><span style="color: hsl(0, 100%, 40%);">-             snprintf(buf, size, "ssrc=%u;themssrc=%u;lp=%u;rxjitter=%f;rxcount=%u;txjitter=%f;txcount=%u;rlp=%u;rtt=%f",</span><br><span style="color: hsl(0, 100%, 40%);">-                   stats.local_ssrc, stats.remote_ssrc, stats.rxploss, stats.rxjitter, stats.rxcount, stats.txjitter, stats.txcount, stats.txploss, stats.rtt);</span><br><span style="color: hsl(120, 100%, 40%);">+         snprintf(buf, size, "ssrc=%u;themssrc=%u;lp=%u;rxjitter=%f;rxcount=%u;"</span><br><span style="color: hsl(120, 100%, 40%);">+                     "txjitter=%f;txcount=%u;rlp=%u;rtt=%f;rxmes=%f;txmes=%f",</span><br><span style="color: hsl(120, 100%, 40%);">+                    stats.local_ssrc, stats.remote_ssrc, stats.rxploss, stats.rxjitter,</span><br><span style="color: hsl(120, 100%, 40%);">+                   stats.rxcount, stats.txjitter, stats.txcount, stats.txploss, stats.rtt,</span><br><span style="color: hsl(120, 100%, 40%);">+                       stats.rxmes, stats.txmes);</span><br><span>  } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER) {</span><br><span style="color: hsl(0, 100%, 40%);">-               snprintf(buf, size, "minrxjitter=%f;maxrxjitter=%f;avgrxjitter=%f;stdevrxjitter=%f;reported_minjitter=%f;reported_maxjitter=%f;reported_avgjitter=%f;reported_stdevjitter=%f;",</span><br><span style="color: hsl(0, 100%, 40%);">-                        stats.local_minjitter, stats.local_maxjitter, stats.local_normdevjitter, sqrt(stats.local_stdevjitter), stats.remote_minjitter, stats.remote_maxjitter, stats.remote_normdevjitter, sqrt(stats.remote_stdevjitter));</span><br><span style="color: hsl(120, 100%, 40%);">+         snprintf(buf, size, "minrxjitter=%010.6f;maxrxjitter=%010.6f;avgrxjitter=%010.6f;stdevrxjitter=%010.6f;mintxjitter=%010.6f;maxtxjitter=%010.6f;avgtxjitter=%010.6f;stdevtxjitter=%010.6f;",</span><br><span style="color: hsl(120, 100%, 40%);">+                  stats.local_minjitter, stats.local_maxjitter, stats.local_normdevjitter, stats.local_stdevjitter, stats.remote_minjitter, stats.remote_maxjitter, stats.remote_normdevjitter, stats.remote_stdevjitter);</span><br><span>    } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS) {</span><br><span style="color: hsl(0, 100%, 40%);">-         snprintf(buf, size, "minrxlost=%f;maxrxlost=%f;avgrxlost=%f;stdevrxlost=%f;reported_minlost=%f;reported_maxlost=%f;reported_avglost=%f;reported_stdevlost=%f;",</span><br><span style="color: hsl(0, 100%, 40%);">-                        stats.local_minrxploss, stats.local_maxrxploss, stats.local_normdevrxploss, sqrt(stats.local_stdevrxploss), stats.remote_minrxploss, stats.remote_maxrxploss, stats.remote_normdevrxploss, sqrt(stats.remote_stdevrxploss));</span><br><span style="color: hsl(120, 100%, 40%);">+         snprintf(buf, size, "  minrxlost=%010.6f;  maxrxlost=%010.6f;  avgrxlost=%010.6f;  stdevrxlost=%010.6f;  mintxlost=%010.6f;  maxtxlost=%010.6f;  avgtxlost=%010.6f;  stdevtxlost=%010.6f;",</span><br><span style="color: hsl(120, 100%, 40%);">+                  stats.local_minrxploss, stats.local_maxrxploss, stats.local_normdevrxploss, stats.local_stdevrxploss, stats.remote_minrxploss, stats.remote_maxrxploss, stats.remote_normdevrxploss, stats.remote_stdevrxploss);</span><br><span>    } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT) {</span><br><span style="color: hsl(0, 100%, 40%);">-          snprintf(buf, size, "minrtt=%f;maxrtt=%f;avgrtt=%f;stdevrtt=%f;", stats.minrtt, stats.maxrtt, stats.normdevrtt, stats.stdevrtt);</span><br><span style="color: hsl(120, 100%, 40%);">+            snprintf(buf, size, "     minrtt=%010.6f;     maxrtt=%010.6f;     avgrtt=%010.6f;     stdevrtt=%010.6f;", stats.minrtt, stats.maxrtt, stats.normdevrtt, stats.stdevrtt);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES) {</span><br><span style="color: hsl(120, 100%, 40%);">+                snprintf(buf, size, "   minrxmes=%010.6f;   maxrxmes=%010.6f;   avgrxmes=%010.6f;   stdevrxmes=%010.6f;   mintxmes=%010.6f;   maxtxmes=%010.6f;   avgtxmes=%010.6f;   stdevtxmes=%010.6f;",</span><br><span style="color: hsl(120, 100%, 40%);">+                  stats.local_minmes, stats.local_maxmes,</span><br><span style="color: hsl(120, 100%, 40%);">+                       stats.local_normdevmes, stats.local_stdevmes,</span><br><span style="color: hsl(120, 100%, 40%);">+                         stats.remote_minmes, stats.remote_maxmes,</span><br><span style="color: hsl(120, 100%, 40%);">+                     stats.remote_normdevmes, stats.remote_stdevmes);</span><br><span>    }</span><br><span> </span><br><span>        return buf;</span><br><span>@@ -2540,6 +2572,15 @@</span><br><span>                 }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ quality = ast_rtp_instance_get_quality(instance,</span><br><span style="color: hsl(120, 100%, 40%);">+              AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES, quality_buf, sizeof(quality_buf));</span><br><span style="color: hsl(120, 100%, 40%);">+   if (quality) {</span><br><span style="color: hsl(120, 100%, 40%);">+                pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSMES", quality);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (bridge) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSMESBRIDGED", quality);</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>  ast_channel_stage_snapshot_done(chan);</span><br><span>       ast_channel_unlock(chan);</span><br><span>    if (bridge) {</span><br><span>@@ -3312,6 +3353,7 @@</span><br><span>                struct ast_json *to = ast_json_object_get(payload->blob, "to");</span><br><span>                 struct ast_json *from = ast_json_object_get(payload->blob, "from");</span><br><span>             struct ast_json *rtt = ast_json_object_get(payload->blob, "rtt");</span><br><span style="color: hsl(120, 100%, 40%);">+                struct ast_json *mes = ast_json_object_get(payload->blob, "mes");</span><br><span>               if (to) {</span><br><span>                    ast_str_append(&packet_string, 0, "To: %s\r\n", ast_json_string_get(to));</span><br><span>              }</span><br><span>@@ -3321,6 +3363,9 @@</span><br><span>            if (rtt) {</span><br><span>                   ast_str_append(&packet_string, 0, "RTT: %4.4f\r\n", ast_json_real_get(rtt));</span><br><span>           }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (mes) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_str_append(&packet_string, 0, "MES: %4.1f\r\n", ast_json_real_get(mes));</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span>    }</span><br><span> </span><br><span>        ast_str_append(&packet_string, 0, "SSRC: 0x%.8x\r\n", ssrc);</span><br><span>@@ -4006,6 +4051,19 @@</span><br><span>  SET_AST_JSON_OBJ(j_res, "normdevrtt", ast_json_real_create(stats->normdevrtt));</span><br><span>         SET_AST_JSON_OBJ(j_res, "stdevrtt", ast_json_real_create(stats->stdevrtt));</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  SET_AST_JSON_OBJ(j_res, "txmes", ast_json_integer_create(stats->txmes));</span><br><span style="color: hsl(120, 100%, 40%);">+ SET_AST_JSON_OBJ(j_res, "rxmes", ast_json_integer_create(stats->rxmes));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       SET_AST_JSON_OBJ(j_res, "remote_maxmes", ast_json_real_create(stats->remote_maxmes));</span><br><span style="color: hsl(120, 100%, 40%);">+    SET_AST_JSON_OBJ(j_res, "remote_minmes", ast_json_real_create(stats->remote_minmes));</span><br><span style="color: hsl(120, 100%, 40%);">+    SET_AST_JSON_OBJ(j_res, "remote_normdevmes", ast_json_real_create(stats->remote_normdevmes));</span><br><span style="color: hsl(120, 100%, 40%);">+    SET_AST_JSON_OBJ(j_res, "remote_stdevmes", ast_json_real_create(stats->remote_stdevmes));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      SET_AST_JSON_OBJ(j_res, "local_maxmes", ast_json_real_create(stats->local_maxmes));</span><br><span style="color: hsl(120, 100%, 40%);">+      SET_AST_JSON_OBJ(j_res, "local_minmes", ast_json_real_create(stats->local_minmes));</span><br><span style="color: hsl(120, 100%, 40%);">+      SET_AST_JSON_OBJ(j_res, "local_normdevmes", ast_json_real_create(stats->local_normdevmes));</span><br><span style="color: hsl(120, 100%, 40%);">+      SET_AST_JSON_OBJ(j_res, "local_stdevmes", ast_json_real_create(stats->local_stdevmes));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       return j_res;</span><br><span> }</span><br><span> </span><br><span>diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c</span><br><span>index 0700cbd..41eb636 100644</span><br><span>--- a/res/res_rtp_asterisk.c</span><br><span>+++ b/res/res_rtp_asterisk.c</span><br><span>@@ -194,6 +194,16 @@</span><br><span> #define DEFAULT_STUN_SOFTWARE_ATTRIBUTE 1</span><br><span> #define DEFAULT_DTLS_MTU 1200</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * Because both ends usually don't start sending RTP</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the same time, some of the calculations like</span><br><span style="color: hsl(120, 100%, 40%);">+ * rtt and jitter will probably be unstable for a while</span><br><span style="color: hsl(120, 100%, 40%);">+ * so we'll skip some received packets before starting</span><br><span style="color: hsl(120, 100%, 40%);">+ * analyzing.  This just affects analyzing; we still</span><br><span style="color: hsl(120, 100%, 40%);">+ * process the RTP as normal.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define RTP_IGNORE_FIRST_PACKETS_COUNT 15</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> extern struct ast_srtp_res *res_srtp;</span><br><span> extern struct ast_srtp_policy_res *res_srtp_policy;</span><br><span> </span><br><span>@@ -391,22 +401,32 @@</span><br><span>      unsigned int lastovidtimestamp;</span><br><span>      unsigned int lastitexttimestamp;</span><br><span>     unsigned int lastotexttimestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+      int prevrxseqno;                /*!< Previous received packeted sequence number, from the network */</span><br><span>      int lastrxseqno;                /*!< Last received sequence number, from the network */</span><br><span style="color: hsl(0, 100%, 40%);">-      int expectedrxseqno;            /*!< Next expected sequence number, from the network */</span><br><span style="color: hsl(120, 100%, 40%);">+    int expectedrxseqno;            /*!< Next expected sequence number, from the network */</span><br><span>   AST_VECTOR(, int) missing_seqno; /*!< A vector of sequence numbers we never received */</span><br><span>   int expectedseqno;              /*!< Next expected sequence number, from the core */</span><br><span>      unsigned short seedrxseqno;     /*!< What sequence number did they start with?*/</span><br><span style="color: hsl(0, 100%, 40%);">-     unsigned int seedrxts;          /*!< What RTP timestamp did they start with? */</span><br><span>   unsigned int rxcount;           /*!< How many packets have we received? */</span><br><span>        unsigned int rxoctetcount;      /*!< How many octets have we received? should be rxcount *160*/</span><br><span>   unsigned int txcount;           /*!< How many packets have we sent? */</span><br><span>    unsigned int txoctetcount;      /*!< How many octets have we sent? (txcount*160)*/</span><br><span>        unsigned int cycles;            /*!< Shifted count of sequence number cycles */</span><br><span style="color: hsl(0, 100%, 40%);">-      double rxjitter;                /*!< Interarrival jitter at the moment in seconds to be reported */</span><br><span style="color: hsl(0, 100%, 40%);">-  double rxtransit;               /*!< Relative transit time for previous packet */</span><br><span>         struct ast_format *lasttxformat;</span><br><span>     struct ast_format *lastrxformat;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * RX RTP Timestamp and Jitter calculation.</span><br><span style="color: hsl(120, 100%, 40%);">+    */</span><br><span style="color: hsl(120, 100%, 40%);">+   double rxstart;                       /*!< RX time of the first packet in the session in seconds since EPOCH. */</span><br><span style="color: hsl(120, 100%, 40%);">+   double rxstart_stable;                /*!< RX time of the first packet after RTP_IGNORE_FIRST_PACKETS_COUNT */</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int remote_seed_rx_rtp_ts;         /*!< RTP timestamp of first RX packet. */</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int remote_seed_rx_rtp_ts_stable;  /*!< RTP timestamp of first packet after RTP_IGNORE_FIRST_PACKETS_COUNT */</span><br><span style="color: hsl(120, 100%, 40%);">+     unsigned int last_transit_time_samples;     /*!< The last transit time in samples */</span><br><span style="color: hsl(120, 100%, 40%);">+       double rxjitter;                      /*!< Last calculated Interarrival jitter in seconds. */</span><br><span style="color: hsl(120, 100%, 40%);">+      double rxjitter_samples;              /*!< Last calculated Interarrival jitter in samples. */</span><br><span style="color: hsl(120, 100%, 40%);">+      double rxmes;                         /*!< Media Experince Score at the moment to be reported */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        /* DTMF Reception Variables */</span><br><span>       char resp;                        /*!< The current digit being processed */</span><br><span>       unsigned int last_seqno;          /*!< The last known sequence number for any DTMF packet */</span><br><span>@@ -422,9 +442,8 @@</span><br><span>        int send_payload;</span><br><span>    int send_duration;</span><br><span>   unsigned int flags;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct timeval rxcore;</span><br><span>       struct timeval txcore;</span><br><span style="color: hsl(0, 100%, 40%);">-  double drxcore;                 /*!< The double representation of the first received packet */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  struct timeval dtmfmute;</span><br><span>     struct ast_smoother *smoother;</span><br><span>       unsigned short seqno;           /*!< Sequence number, RFC 3550, page 13. */</span><br><span>@@ -433,6 +452,12 @@</span><br><span>        unsigned int asymmetric_codec;  /*!< Indicate if asymmetric send/receive codecs are allowed */</span><br><span> </span><br><span>        struct ast_rtp_instance *bundled; /*!< The RTP instance we are bundled to */</span><br><span style="color: hsl(120, 100%, 40%);">+       /*!</span><br><span style="color: hsl(120, 100%, 40%);">+    * \brief The RTP instance owning us (used for debugging purposes)</span><br><span style="color: hsl(120, 100%, 40%);">+     * We don't hold a reference to the instance because it created</span><br><span style="color: hsl(120, 100%, 40%);">+    * us in the first place.  It can't go away.</span><br><span style="color: hsl(120, 100%, 40%);">+       */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_rtp_instance *owner;</span><br><span>      int stream_num; /*!< Stream num for this RTP instance */</span><br><span>  AST_VECTOR(, struct rtp_ssrc_mapping) ssrc_mapping; /*!< Mappings of SSRC to RTP instances */</span><br><span>     struct ast_sockaddr bind_address; /*!< Requested bind address for the sockets */</span><br><span>@@ -526,7 +551,7 @@</span><br><span>    unsigned int lastsrtxcount;     /*!< Transmit packet count when last SR sent */</span><br><span>   double accumulated_transit;     /*!< accumulated a-dlsr-lsr */</span><br><span>    double rtt;                     /*!< Last reported rtt */</span><br><span style="color: hsl(0, 100%, 40%);">-    unsigned int reported_jitter;   /*!< The contents of their last jitter entry in the RR */</span><br><span style="color: hsl(120, 100%, 40%);">+  double reported_jitter; /*!< The contents of their last jitter entry in the RR in seconds */</span><br><span>      unsigned int reported_lost;     /*!< Reported lost packets in their RR */</span><br><span> </span><br><span>     double reported_maxjitter; /*!< Maximum reported interarrival jitter */</span><br><span>@@ -560,6 +585,19 @@</span><br><span>    double stdevrtt; /*!< Standard deviation of calculated round trip time */</span><br><span>         unsigned int rtt_count; /*!< Calculated round trip time count */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+       double reported_mes;    /*!< The calculated MES from their last RR */</span><br><span style="color: hsl(120, 100%, 40%);">+      double reported_maxmes; /*!< Maximum reported mes */</span><br><span style="color: hsl(120, 100%, 40%);">+       double reported_minmes; /*!< Minimum reported mes */</span><br><span style="color: hsl(120, 100%, 40%);">+       double reported_normdev_mes; /*!< Mean of reported mes */</span><br><span style="color: hsl(120, 100%, 40%);">+  double reported_stdev_mes; /*!< Standard deviation of reported mes */</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int reported_mes_count; /*!< Reported mes count */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      double maxrxmes; /*!< Maximum of calculated mes */</span><br><span style="color: hsl(120, 100%, 40%);">+ double minrxmes; /*!< Minimum of calculated mes */</span><br><span style="color: hsl(120, 100%, 40%);">+ double normdev_rxmes; /*!< Mean of calculated mes */</span><br><span style="color: hsl(120, 100%, 40%);">+       double stdev_rxmes; /*!< Standard deviation of calculated mes */</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int rxmes_count; /*!< mes count */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     /* VP8: sequence number for the RTCP FIR FCI */</span><br><span>      int firseq;</span><br><span> </span><br><span>@@ -630,6 +668,8 @@</span><br><span> static void ast_rtp_set_stream_num(struct ast_rtp_instance *instance, int stream_num);</span><br><span> static int ast_rtp_extension_enable(struct ast_rtp_instance *instance, enum ast_rtp_extension extension);</span><br><span> static int ast_rtp_bundle(struct ast_rtp_instance *child, struct ast_rtp_instance *parent);</span><br><span style="color: hsl(120, 100%, 40%);">+static void update_reported_mes_stats(struct ast_rtp *rtp);</span><br><span style="color: hsl(120, 100%, 40%);">+static void update_local_mes_stats(struct ast_rtp *rtp);</span><br><span> </span><br><span> #if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP)</span><br><span> static int ast_rtp_activate(struct ast_rtp_instance *instance);</span><br><span>@@ -4024,16 +4064,16 @@</span><br><span>  if (!(rtp = ast_calloc(1, sizeof(*rtp)))) {</span><br><span>          return -1;</span><br><span>   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+     rtp->owner = instance;</span><br><span>    /* Set default parameters on the newly created RTP structure */</span><br><span>      rtp->ssrc = ast_random();</span><br><span>         ast_uuid_generate_str(rtp->cname, sizeof(rtp->cname));</span><br><span>         rtp->seqno = ast_random() & 0x7fff;</span><br><span>   rtp->expectedrxseqno = -1;</span><br><span>        rtp->expectedseqno = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+   rtp->rxstart = -1;</span><br><span>        rtp->sched = sched;</span><br><span>       ast_sockaddr_copy(&rtp->bind_address, addr);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>  /* Transport creation operations can grab the RTP data from the instance, so set it */</span><br><span>       ast_rtp_instance_set_data(instance, rtp);</span><br><span> </span><br><span>@@ -4135,6 +4175,7 @@</span><br><span>        AST_VECTOR_FREE(&rtp->missing_seqno);</span><br><span> </span><br><span>     /* Finally destroy ourselves */</span><br><span style="color: hsl(120, 100%, 40%);">+       rtp->owner = NULL;</span><br><span>        ast_free(rtp);</span><br><span> </span><br><span>   return 0;</span><br><span>@@ -4546,6 +4587,11 @@</span><br><span> </span><br><span>       /* Compute statistics */</span><br><span>     calculate_lost_packet_statistics(rtp, &lost_packets, &fraction_lost);</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * update_local_mes_stats must be called AFTER</span><br><span style="color: hsl(120, 100%, 40%);">+         * calculate_lost_packet_statistics</span><br><span style="color: hsl(120, 100%, 40%);">+    */</span><br><span style="color: hsl(120, 100%, 40%);">+   update_local_mes_stats(rtp);</span><br><span> </span><br><span>     gettimeofday(&now, NULL);</span><br><span>        rtcp_report->reception_report_count = rtp->themssrc_valid ? 1 : 0;</span><br><span>@@ -4569,7 +4615,7 @@</span><br><span>             report_block->lost_count.fraction = (fraction_lost & 0xff);</span><br><span>           report_block->lost_count.packets = (lost_packets & 0xffffff);</span><br><span>                 report_block->highest_seq_no = (rtp->cycles | (rtp->lastrxseqno & 0xffff));</span><br><span style="color: hsl(0, 100%, 40%);">-                report_block->ia_jitter = (unsigned int)(rtp->rxjitter * ast_rtp_get_rate(rtp->f.subclass.format));</span><br><span style="color: hsl(120, 100%, 40%);">+          report_block->ia_jitter = (unsigned int)rtp->rxjitter_samples;</span><br><span>                 report_block->lsr = rtp->rtcp->themrxlsr;</span><br><span>           /* If we haven't received an SR report, DLSR should be 0 */</span><br><span>              if (!ast_tvzero(rtp->rtcp->rxlsr)) {</span><br><span>@@ -4646,20 +4692,24 @@</span><br><span>                         ast_verbose("  Sent octets: %u\n", rtcp_report->sender_information.octet_count);</span><br><span>                }</span><br><span>            if (report_block) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   int rate = ast_rtp_get_rate(rtp->f.subclass.format);</span><br><span>                      ast_verbose("  Report block:\n");</span><br><span>                  ast_verbose("    Their SSRC: %u\n", report_block->source_ssrc);</span><br><span>                         ast_verbose("    Fraction lost: %d\n", report_block->lost_count.fraction);</span><br><span>                      ast_verbose("    Cumulative loss: %u\n", report_block->lost_count.packets);</span><br><span>                     ast_verbose("    Highest seq no: %u\n", report_block->highest_seq_no);</span><br><span style="color: hsl(0, 100%, 40%);">-                     ast_verbose("    IA jitter: %.4f\n", (double)report_block->ia_jitter / ast_rtp_get_rate(rtp->f.subclass.format));</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_verbose("    IA jitter (samp): %u\n", report_block->ia_jitter);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_verbose("    IA jitter (secs): %.6f\n", ast_samp2sec(report_block->ia_jitter, rate));</span><br><span>                       ast_verbose("    Their last SR: %u\n", report_block->lsr);</span><br><span>                      ast_verbose("    DLSR: %4.4f (sec)\n\n", (double)(report_block->dlsr / 65536.0));</span><br><span>               }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   message_blob = ast_json_pack("{s: s, s: s}",</span><br><span style="color: hsl(120, 100%, 40%);">+        message_blob = ast_json_pack("{s: s, s: s, s: f}",</span><br><span>                         "to", ast_sockaddr_stringify(&remote_address),</span><br><span style="color: hsl(0, 100%, 40%);">-                    "from", rtp->rtcp->local_addr_str);</span><br><span style="color: hsl(120, 100%, 40%);">+                   "from", rtp->rtcp->local_addr_str,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "mes", rtp->rxmes);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_sent_type(),</span><br><span>                     rtcp_report, message_blob);</span><br><span> </span><br><span>@@ -5116,7 +5166,8 @@</span><br><span>                      }</span><br><span>            } else {</span><br><span>                     if (rtp->rtcp && rtp->rtcp->schedid < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                          ast_debug_rtcp(1, "(%p) RTCP starting transmission\n", instance);</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_debug_rtcp(2, "(%s) RTCP starting transmission in %u ms\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                     ast_rtp_instance_get_channel_id(instance), ast_rtcp_calc_interval(rtp));</span><br><span>                             ao2_ref(instance, +1);</span><br><span>                               rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance);</span><br><span>                              if (rtp->rtcp->schedid < 0) {</span><br><span>@@ -5374,8 +5425,9 @@</span><br><span>       format = frame->subclass.format;</span><br><span>  if (ast_format_cmp(rtp->lasttxformat, format) == AST_FORMAT_CMP_NOT_EQUAL) {</span><br><span>              /* Oh dear, if the format changed we will have to set up a new smoother */</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_debug_rtp(1, "(%p) RTP ooh, format changed from %s to %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                      instance, ast_format_get_name(rtp->lasttxformat),</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_debug_rtp(1, "(%s) RTP ooh, format changed from %s to %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_rtp_instance_get_channel_id(instance),</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_format_get_name(rtp->lasttxformat),</span><br><span>                   ast_format_get_name(frame->subclass.format));</span><br><span>             ao2_replace(rtp->lasttxformat, format);</span><br><span>           if (rtp->smoother) {</span><br><span>@@ -5438,43 +5490,164 @@</span><br><span>   return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int timestamp, int mark)</span><br><span style="color: hsl(120, 100%, 40%);">+static void calc_rxstamp_and_jitter(struct timeval *tv,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_rtp *rtp, unsigned int rx_rtp_ts,</span><br><span style="color: hsl(120, 100%, 40%);">+  int mark)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct timeval now;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct timeval tmp;</span><br><span style="color: hsl(0, 100%, 40%);">-     double transit;</span><br><span style="color: hsl(0, 100%, 40%);">- double current_time;</span><br><span style="color: hsl(0, 100%, 40%);">-    double d;</span><br><span style="color: hsl(0, 100%, 40%);">-       double dtv;</span><br><span style="color: hsl(0, 100%, 40%);">-     double prog;</span><br><span>         int rate = ast_rtp_get_rate(rtp->f.subclass.format);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) {</span><br><span style="color: hsl(0, 100%, 40%);">-              gettimeofday(&rtp->rxcore, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-                rtp->drxcore = (double) rtp->rxcore.tv_sec + (double) rtp->rxcore.tv_usec / 1000000;</span><br><span style="color: hsl(0, 100%, 40%);">-           /* map timestamp to a real time */</span><br><span style="color: hsl(0, 100%, 40%);">-              rtp->seedrxts = timestamp; /* Their RTP timestamp started with this */</span><br><span style="color: hsl(0, 100%, 40%);">-               tmp = ast_samp2tv(timestamp, rate);</span><br><span style="color: hsl(0, 100%, 40%);">-             rtp->rxcore = ast_tvsub(rtp->rxcore, tmp);</span><br><span style="color: hsl(0, 100%, 40%);">-                /* Round to 0.1ms for nice, pretty timestamps */</span><br><span style="color: hsl(0, 100%, 40%);">-                rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 100;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(120, 100%, 40%);">+     double estimated_elapsed;</span><br><span style="color: hsl(120, 100%, 40%);">+     double jitter = 0.0;</span><br><span style="color: hsl(120, 100%, 40%);">+  double prev_jitter = 0.0;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct timeval now;</span><br><span style="color: hsl(120, 100%, 40%);">+   double rxnow;</span><br><span style="color: hsl(120, 100%, 40%);">+ double arrival_sec;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int arrival;</span><br><span style="color: hsl(120, 100%, 40%);">+ int transit;</span><br><span style="color: hsl(120, 100%, 40%);">+  int d;</span><br><span> </span><br><span>   gettimeofday(&now,NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-    /* rxcore is the mapping between the RTP timestamp and _our_ real time from gettimeofday() */</span><br><span style="color: hsl(0, 100%, 40%);">-   tmp = ast_samp2tv(timestamp, rate);</span><br><span style="color: hsl(0, 100%, 40%);">-     *tv = ast_tvadd(rtp->rxcore, tmp);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       prog = (double)((timestamp-rtp->seedrxts)/(float)(rate));</span><br><span style="color: hsl(0, 100%, 40%);">-    dtv = (double)rtp->drxcore + (double)(prog);</span><br><span style="color: hsl(0, 100%, 40%);">- current_time = (double)now.tv_sec + (double)now.tv_usec/1000000;</span><br><span style="color: hsl(0, 100%, 40%);">-        transit = current_time - dtv;</span><br><span style="color: hsl(0, 100%, 40%);">-   d = transit - rtp->rxtransit;</span><br><span style="color: hsl(0, 100%, 40%);">-        rtp->rxtransit = transit;</span><br><span style="color: hsl(0, 100%, 40%);">-    if (d<0) {</span><br><span style="color: hsl(0, 100%, 40%);">-           d=-d;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rtp->rxcount == 1 || mark) {</span><br><span style="color: hsl(120, 100%, 40%);">+           rtp->rxstart = ast_tv2double(&now);</span><br><span style="color: hsl(120, 100%, 40%);">+            rtp->remote_seed_rx_rtp_ts = rx_rtp_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          *tv = ast_double2tv(rtp->rxstart);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_debug_rtcp(3, "%s: "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Seed ts: %u current time: %f\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_rtp_instance_get_channel_id(rtp->owner)</span><br><span style="color: hsl(120, 100%, 40%);">+                        , rx_rtp_ts</span><br><span style="color: hsl(120, 100%, 40%);">+                   , rtp->rxstart</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;</span><br><span>      }</span><br><span style="color: hsl(0, 100%, 40%);">-       rtp->rxjitter += (1./16.) * (d - rtp->rxjitter);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      estimated_elapsed = ast_samp2sec(rx_rtp_ts - rtp->remote_seed_rx_rtp_ts, rate);</span><br><span style="color: hsl(120, 100%, 40%);">+    *tv = ast_double2tv(rtp->rxstart + estimated_elapsed);</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%);">+     * The first few packets are generally unstable so let's</span><br><span style="color: hsl(120, 100%, 40%);">+   * not use them in the calculations.</span><br><span style="color: hsl(120, 100%, 40%);">+   */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rtp->rxcount < RTP_IGNORE_FIRST_PACKETS_COUNT) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_debug_rtcp(3, "%s: Packet %d < %d.  Ignoring\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_rtp_instance_get_channel_id(rtp->owner)</span><br><span style="color: hsl(120, 100%, 40%);">+                        , rtp->rxcount</span><br><span style="color: hsl(120, 100%, 40%);">+                     , RTP_IGNORE_FIRST_PACKETS_COUNT</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;</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 style="color: hsl(120, 100%, 40%);">+     * First good packet. Capture the start time and timestamp</span><br><span style="color: hsl(120, 100%, 40%);">+     * but don't actually use this packet for calculation.</span><br><span style="color: hsl(120, 100%, 40%);">+     */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rtp->rxcount == RTP_IGNORE_FIRST_PACKETS_COUNT) {</span><br><span style="color: hsl(120, 100%, 40%);">+              rtp->rxstart_stable = ast_tv2double(&now);</span><br><span style="color: hsl(120, 100%, 40%);">+             rtp->remote_seed_rx_rtp_ts_stable = rx_rtp_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+             rtp->last_transit_time_samples = -rx_rtp_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_debug_rtcp(3, "%s: "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "pkt: %5u Stable Seed ts: %u current time: %f\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_rtp_instance_get_channel_id(rtp->owner)</span><br><span style="color: hsl(120, 100%, 40%);">+                        , rtp->rxcount</span><br><span style="color: hsl(120, 100%, 40%);">+                     , rx_rtp_ts</span><br><span style="color: hsl(120, 100%, 40%);">+                   , rtp->rxstart_stable</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;</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 style="color: hsl(120, 100%, 40%);">+     * If the current packet isn't in sequence, don't</span><br><span style="color: hsl(120, 100%, 40%);">+      * use it in any calculations as remote_current_rx_rtp_ts</span><br><span style="color: hsl(120, 100%, 40%);">+      * is not going to be correct.</span><br><span style="color: hsl(120, 100%, 40%);">+         */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rtp->lastrxseqno != rtp->prevrxseqno + 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_debug_rtcp(3, "%s: Current packet seq %d != last packet seq %d + 1.  Ignoring\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_rtp_instance_get_channel_id(rtp->owner)</span><br><span style="color: hsl(120, 100%, 40%);">+                        , rtp->lastrxseqno</span><br><span style="color: hsl(120, 100%, 40%);">+                 , rtp->prevrxseqno</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;</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 style="color: hsl(120, 100%, 40%);">+     * The following calculations are taken from</span><br><span style="color: hsl(120, 100%, 40%);">+   * https://www.rfc-editor.org/rfc/rfc3550#appendix-A.8</span><br><span style="color: hsl(120, 100%, 40%);">+         *</span><br><span style="color: hsl(120, 100%, 40%);">+     * The received rtp timestamp is the random "seed"</span><br><span style="color: hsl(120, 100%, 40%);">+   * timestamp chosen by the sender when they sent the</span><br><span style="color: hsl(120, 100%, 40%);">+   * first packet, plus the number of samples since then.</span><br><span style="color: hsl(120, 100%, 40%);">+        *</span><br><span style="color: hsl(120, 100%, 40%);">+     * To get our arrival time in the same units, we</span><br><span style="color: hsl(120, 100%, 40%);">+       * calculate the time difference in seconds between</span><br><span style="color: hsl(120, 100%, 40%);">+    * when we received the first packet and when we</span><br><span style="color: hsl(120, 100%, 40%);">+       * received this packet and convert that to samples.</span><br><span style="color: hsl(120, 100%, 40%);">+   */</span><br><span style="color: hsl(120, 100%, 40%);">+   rxnow = ast_tv2double(&now);</span><br><span style="color: hsl(120, 100%, 40%);">+      arrival_sec = rxnow - rtp->rxstart_stable;</span><br><span style="color: hsl(120, 100%, 40%);">+ arrival = ast_sec2samp(arrival_sec, rate);</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%);">+     * Now we can use the exact formula in</span><br><span style="color: hsl(120, 100%, 40%);">+         * https://www.rfc-editor.org/rfc/rfc3550#appendix-A.8 :</span><br><span style="color: hsl(120, 100%, 40%);">+       *</span><br><span style="color: hsl(120, 100%, 40%);">+     * int transit = arrival - r->ts;</span><br><span style="color: hsl(120, 100%, 40%);">+   * int d = transit - s->transit;</span><br><span style="color: hsl(120, 100%, 40%);">+    * s->transit = transit;</span><br><span style="color: hsl(120, 100%, 40%);">+    * if (d < 0) d = -d;</span><br><span style="color: hsl(120, 100%, 40%);">+       * s->jitter += (1./16.) * ((double)d - s->jitter);</span><br><span style="color: hsl(120, 100%, 40%);">+      *</span><br><span style="color: hsl(120, 100%, 40%);">+     * Our rx_rtp_ts is their r->ts.</span><br><span style="color: hsl(120, 100%, 40%);">+    * Our rtp->last_transit_time_samples is their s->transit.</span><br><span style="color: hsl(120, 100%, 40%);">+       * Our rtp->rxjitter is their s->jitter.</span><br><span style="color: hsl(120, 100%, 40%);">+         */</span><br><span style="color: hsl(120, 100%, 40%);">+   transit = arrival - rx_rtp_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+        d = transit - rtp->last_transit_time_samples;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (d < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               d = -d;</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%);">+   prev_jitter = rtp->rxjitter_samples;</span><br><span style="color: hsl(120, 100%, 40%);">+       jitter = (1.0/16.0) * (((double)d) - prev_jitter);</span><br><span style="color: hsl(120, 100%, 40%);">+    rtp->rxjitter_samples = prev_jitter + jitter;</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%);">+     * We need to hang on to jitter in both samples and seconds.</span><br><span style="color: hsl(120, 100%, 40%);">+   */</span><br><span style="color: hsl(120, 100%, 40%);">+   rtp->rxjitter = ast_samp2sec(rtp->rxjitter_samples, rate);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_debug_rtcp(3, "%s: pkt: %5u "</span><br><span style="color: hsl(120, 100%, 40%);">+           "Arrival sec: %7.3f  Arrival ts: %10u  RX ts: %10u "</span><br><span style="color: hsl(120, 100%, 40%);">+                "Transit samp: %6d Last transit samp: %6d d: %4d "</span><br><span style="color: hsl(120, 100%, 40%);">+          "Curr jitter: %7.0f(%7.3f) Prev Jitter: %7.0f(%7.3f) New Jitter: %7.0f(%7.3f)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_rtp_instance_get_channel_id(rtp->owner)</span><br><span style="color: hsl(120, 100%, 40%);">+                , rtp->rxcount</span><br><span style="color: hsl(120, 100%, 40%);">+             , arrival_sec</span><br><span style="color: hsl(120, 100%, 40%);">+         , arrival</span><br><span style="color: hsl(120, 100%, 40%);">+             , rx_rtp_ts</span><br><span style="color: hsl(120, 100%, 40%);">+           , transit</span><br><span style="color: hsl(120, 100%, 40%);">+             , rtp->last_transit_time_samples</span><br><span style="color: hsl(120, 100%, 40%);">+           , d</span><br><span style="color: hsl(120, 100%, 40%);">+           , jitter</span><br><span style="color: hsl(120, 100%, 40%);">+              , ast_samp2sec(jitter, rate)</span><br><span style="color: hsl(120, 100%, 40%);">+          , prev_jitter</span><br><span style="color: hsl(120, 100%, 40%);">+         , ast_samp2sec(prev_jitter, rate)</span><br><span style="color: hsl(120, 100%, 40%);">+             , rtp->rxjitter_samples</span><br><span style="color: hsl(120, 100%, 40%);">+            , rtp->rxjitter</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%);">+  rtp->last_transit_time_samples = transit;</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%);">+     * Update all the stats.</span><br><span style="color: hsl(120, 100%, 40%);">+       */</span><br><span>  if (rtp->rtcp) {</span><br><span>          if (rtp->rxjitter > rtp->rtcp->maxrxjitter)</span><br><span>                      rtp->rtcp->maxrxjitter = rtp->rxjitter;</span><br><span>@@ -5483,9 +5656,12 @@</span><br><span>            if (rtp->rtcp && rtp->rxjitter < rtp->rtcp->minrxjitter)</span><br><span>                      rtp->rtcp->minrxjitter = rtp->rxjitter;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-            calc_mean_and_standard_deviation(rtp->rxjitter, &rtp->rtcp->normdev_rxjitter,</span><br><span style="color: hsl(0, 100%, 40%);">-                      &rtp->rtcp->stdev_rxjitter, &rtp->rtcp->rxjitter_count);</span><br><span style="color: hsl(120, 100%, 40%);">+          calc_mean_and_standard_deviation(rtp->rxjitter,</span><br><span style="color: hsl(120, 100%, 40%);">+                    &rtp->rtcp->normdev_rxjitter, &rtp->rtcp->stdev_rxjitter,</span><br><span style="color: hsl(120, 100%, 40%);">+                 &rtp->rtcp->rxjitter_count);</span><br><span>       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return;</span><br><span> }</span><br><span> </span><br><span> static struct ast_frame *create_dtmf_frame(struct ast_rtp_instance *instance, enum ast_frame_type type, int compensate)</span><br><span>@@ -5851,22 +6027,23 @@</span><br><span>  */</span><br><span> static void update_jitter_stats(struct ast_rtp *rtp, unsigned int ia_jitter)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       double reported_jitter;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rate = ast_rtp_get_rate(rtp->f.subclass.format);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     rtp->rtcp->reported_jitter = ia_jitter;</span><br><span style="color: hsl(0, 100%, 40%);">-   reported_jitter = (double) rtp->rtcp->reported_jitter;</span><br><span style="color: hsl(120, 100%, 40%);">+  rtp->rtcp->reported_jitter = ast_samp2sec(ia_jitter, rate);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  if (rtp->rtcp->reported_jitter_count == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-              rtp->rtcp->reported_minjitter = reported_jitter;</span><br><span style="color: hsl(120, 100%, 40%);">+                rtp->rtcp->reported_minjitter = rtp->rtcp->reported_jitter;</span><br><span>      }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (reported_jitter < rtp->rtcp->reported_minjitter) {</span><br><span style="color: hsl(0, 100%, 40%);">-         rtp->rtcp->reported_minjitter = reported_jitter;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rtp->rtcp->reported_jitter < rtp->rtcp->reported_minjitter) {</span><br><span style="color: hsl(120, 100%, 40%);">+              rtp->rtcp->reported_minjitter = rtp->rtcp->reported_jitter;</span><br><span>      }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (reported_jitter > rtp->rtcp->reported_maxjitter) {</span><br><span style="color: hsl(0, 100%, 40%);">-         rtp->rtcp->reported_maxjitter = reported_jitter;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rtp->rtcp->reported_jitter > rtp->rtcp->reported_maxjitter) {</span><br><span style="color: hsl(120, 100%, 40%);">+              rtp->rtcp->reported_maxjitter = rtp->rtcp->reported_jitter;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   calc_mean_and_standard_deviation(reported_jitter, &rtp->rtcp->reported_normdev_jitter,</span><br><span style="color: hsl(0, 100%, 40%);">-                &rtp->rtcp->reported_stdev_jitter, &rtp->rtcp->reported_jitter_count);</span><br><span style="color: hsl(120, 100%, 40%);">+    calc_mean_and_standard_deviation(rtp->rtcp->reported_jitter,</span><br><span style="color: hsl(120, 100%, 40%);">+            &rtp->rtcp->reported_normdev_jitter, &rtp->rtcp->reported_stdev_jitter,</span><br><span style="color: hsl(120, 100%, 40%);">+           &rtp->rtcp->reported_jitter_count);</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span>@@ -5893,6 +6070,158 @@</span><br><span>              &rtp->rtcp->reported_stdev_lost, &rtp->rtcp->reported_lost_count);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define RESCALE(in, inmin, inmax, outmin, outmax) ((((in - inmin)/(inmax-inmin))*(outmax-outmin))+outmin)</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Calculate a "media experience score" based on given data</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Technically, a mean opinion score (MOS) cannot be calculated without the involvement</span><br><span style="color: hsl(120, 100%, 40%);">+ * of human eyes (video) and ears (audio). Thus instead we'll approximate an opinion</span><br><span style="color: hsl(120, 100%, 40%);">+ * using the given parameters, and call it a media experience score.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The tallied score is based upon recommendations and formulas from ITU-T G.107,</span><br><span style="color: hsl(120, 100%, 40%);">+ * ITU-T G.109, ITU-T G.113, and other various internet sources.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param normdevrtt The average round trip time</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param rxjitter The smoothed jitter</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param stdev_rxjitter The jitter standard deviation value</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param normdev_rxlost The average number of packets lost since last check</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return A media experience score.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note The calculations in this function could probably be simplified</span><br><span style="color: hsl(120, 100%, 40%);">+ * but calculating a MOS using the information available publicly,</span><br><span style="color: hsl(120, 100%, 40%);">+ * then re-scaling it to 0.0 -> 100.0 makes the process clearer and</span><br><span style="color: hsl(120, 100%, 40%);">+ * easier to troubleshoot or change.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static double calc_media_experience_score(struct ast_rtp_instance *instance,</span><br><span style="color: hsl(120, 100%, 40%);">+     double normdevrtt, double normdev_rxjitter, double stdev_rxjitter,</span><br><span style="color: hsl(120, 100%, 40%);">+    double normdev_rxlost)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     double r_value;</span><br><span style="color: hsl(120, 100%, 40%);">+       double pseudo_mos;</span><br><span style="color: hsl(120, 100%, 40%);">+    double mes = 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%);">+     * While the media itself might be okay, a significant enough delay could make</span><br><span style="color: hsl(120, 100%, 40%);">+         * for an unpleasant user experience.</span><br><span style="color: hsl(120, 100%, 40%);">+  *</span><br><span style="color: hsl(120, 100%, 40%);">+     * Calculate the effective latency by using the given round trip time, and adding</span><br><span style="color: hsl(120, 100%, 40%);">+      * jitter scaled according to its standard deviation. The scaling is done in order</span><br><span style="color: hsl(120, 100%, 40%);">+     * to increase jitter's weight since a higher deviation can result in poorer overall</span><br><span style="color: hsl(120, 100%, 40%);">+       * quality.</span><br><span style="color: hsl(120, 100%, 40%);">+    */</span><br><span style="color: hsl(120, 100%, 40%);">+   double effective_latency = (normdevrtt * 1000)</span><br><span style="color: hsl(120, 100%, 40%);">+                + ((normdev_rxjitter * 2) * (stdev_rxjitter / 3))</span><br><span style="color: hsl(120, 100%, 40%);">+             + 10;</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%);">+     * Using the defaults for the standard transmission rating factor ("R" value)</span><br><span style="color: hsl(120, 100%, 40%);">+        * one arrives at 93.2 (see ITU-T G.107 for more details), so we'll use that</span><br><span style="color: hsl(120, 100%, 40%);">+       * as the starting value and subtract deficiencies that could affect quality.</span><br><span style="color: hsl(120, 100%, 40%);">+  *</span><br><span style="color: hsl(120, 100%, 40%);">+     * Calculate the impact of the effective latency. Influence increases with</span><br><span style="color: hsl(120, 100%, 40%);">+     * values over 160 as the significant "lag" can degrade user experience.</span><br><span style="color: hsl(120, 100%, 40%);">+     */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (effective_latency < 160) {</span><br><span style="color: hsl(120, 100%, 40%);">+             r_value = 93.2 - (effective_latency / 40);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              r_value = 93.2 - (effective_latency - 120) / 10;</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%);">+   /* Next evaluate the impact of lost packets */</span><br><span style="color: hsl(120, 100%, 40%);">+        r_value = r_value - (normdev_rxlost * 2.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%);">+     * Finally convert the "R" value into a opinion/quality score between 1 (really anything</span><br><span style="color: hsl(120, 100%, 40%);">+     * below 3 should be considered poor) and 4.5 (the highest achievable for VOIP).</span><br><span style="color: hsl(120, 100%, 40%);">+       */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (r_value < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+         pseudo_mos = 1.0;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (r_value > 100) {</span><br><span style="color: hsl(120, 100%, 40%);">+                pseudo_mos = 4.5;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              pseudo_mos = 1 + (0.035 * r_value) + (r_value * (r_value - 60) * (100 - r_value) * 0.0000007);</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 style="color: hsl(120, 100%, 40%);">+     * We're going to rescale the 0.0->5.0 pseudo_mos to the 0.0->100.0 MES.</span><br><span style="color: hsl(120, 100%, 40%);">+     * For those ranges, we could actually just multiply the pseudo_mos</span><br><span style="color: hsl(120, 100%, 40%);">+    * by 20 but we may want to change the scale later.</span><br><span style="color: hsl(120, 100%, 40%);">+    */</span><br><span style="color: hsl(120, 100%, 40%);">+   mes = RESCALE(pseudo_mos, 0.0, 5.0, 0.0, 100.0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return mes;</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 style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Update MES stats based on info received in an SR or RR.</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is RTP we sent and they received.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static void update_reported_mes_stats(struct ast_rtp *rtp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ double mes = calc_media_experience_score(rtp->owner,</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp->rtcp->normdevrtt,</span><br><span style="color: hsl(120, 100%, 40%);">+          rtp->rtcp->reported_jitter,</span><br><span style="color: hsl(120, 100%, 40%);">+             rtp->rtcp->reported_stdev_jitter,</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp->rtcp->reported_normdev_lost);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    rtp->rtcp->reported_mes = mes;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rtp->rtcp->reported_mes_count == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp->rtcp->reported_minmes = mes;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (mes < rtp->rtcp->reported_minmes) {</span><br><span style="color: hsl(120, 100%, 40%);">+              rtp->rtcp->reported_minmes = mes;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (mes > rtp->rtcp->reported_maxmes) {</span><br><span style="color: hsl(120, 100%, 40%);">+              rtp->rtcp->reported_maxmes = mes;</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%);">+   calc_mean_and_standard_deviation(mes, &rtp->rtcp->reported_normdev_mes,</span><br><span style="color: hsl(120, 100%, 40%);">+             &rtp->rtcp->reported_stdev_mes, &rtp->rtcp->reported_mes_count);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_debug_rtcp(2, "%s: rtt: %.9f j: %.9f sjh: %.9f lost: %.9f mes: %4.1f\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_rtp_instance_get_channel_id(rtp->owner),</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp->rtcp->normdevrtt,</span><br><span style="color: hsl(120, 100%, 40%);">+                          rtp->rtcp->reported_jitter,</span><br><span style="color: hsl(120, 100%, 40%);">+                             rtp->rtcp->reported_stdev_jitter,</span><br><span style="color: hsl(120, 100%, 40%);">+                               rtp->rtcp->reported_normdev_lost, mes);</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 style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Update MES stats based on info we will send in an SR or RR.</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is RTP they sent and we received.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static void update_local_mes_stats(struct ast_rtp *rtp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      rtp->rxmes = calc_media_experience_score(rtp->owner,</span><br><span style="color: hsl(120, 100%, 40%);">+            rtp->rtcp->normdevrtt,</span><br><span style="color: hsl(120, 100%, 40%);">+          rtp->rxjitter,</span><br><span style="color: hsl(120, 100%, 40%);">+             rtp->rtcp->stdev_rxjitter,</span><br><span style="color: hsl(120, 100%, 40%);">+              rtp->rtcp->normdev_rxlost);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rtp->rtcp->rxmes_count == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              rtp->rtcp->minrxmes = rtp->rxmes;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rtp->rxmes < rtp->rtcp->minrxmes) {</span><br><span style="color: hsl(120, 100%, 40%);">+           rtp->rtcp->minrxmes = rtp->rxmes;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rtp->rxmes > rtp->rtcp->maxrxmes) {</span><br><span style="color: hsl(120, 100%, 40%);">+           rtp->rtcp->maxrxmes = rtp->rxmes;</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%);">+   calc_mean_and_standard_deviation(rtp->rxmes, &rtp->rtcp->normdev_rxmes,</span><br><span style="color: hsl(120, 100%, 40%);">+          &rtp->rtcp->stdev_rxmes, &rtp->rtcp->rxmes_count);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_debug_rtcp(2, "   %s: rtt: %.9f j: %.9f sjh: %.9f lost: %.9f mes: %4.1f\n",</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_rtp_instance_get_channel_id(rtp->owner),</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp->rtcp->normdevrtt,</span><br><span style="color: hsl(120, 100%, 40%);">+                          rtp->rxjitter,</span><br><span style="color: hsl(120, 100%, 40%);">+                             rtp->rtcp->stdev_rxjitter,</span><br><span style="color: hsl(120, 100%, 40%);">+                              rtp->rtcp->normdev_rxlost, rtp->rxmes);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \pre instance is locked */</span><br><span> static struct ast_rtp_instance *__rtp_find_instance_by_ssrc(struct ast_rtp_instance *instance,</span><br><span>    struct ast_rtp *rtp, unsigned int ssrc, int source)</span><br><span>@@ -6151,23 +6480,26 @@</span><br><span> </span><br><span>    packetwords = len / 4;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      ast_debug_rtcp(1, "(%p) RTCP got report of %d bytes from %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-               instance, len, ast_sockaddr_stringify(addr));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug_rtcp(2, "(%s) RTCP got report of %d bytes from %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_rtp_instance_get_channel_id(instance),</span><br><span style="color: hsl(120, 100%, 40%);">+            len, ast_sockaddr_stringify(addr));</span><br><span> </span><br><span>      /*</span><br><span>    * Validate the RTCP packet according to an adapted and slightly</span><br><span>      * modified RFC3550 validation algorithm.</span><br><span>     */</span><br><span>  if (packetwords < RTCP_HEADER_SSRC_LENGTH) {</span><br><span style="color: hsl(0, 100%, 40%);">-         ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: Frame size (%u words) is too short\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                    instance, transport_rtp, ast_sockaddr_stringify(addr), packetwords);</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_debug_rtcp(2, "(%s) RTCP %p -- from %s: Frame size (%u words) is too short\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_rtp_instance_get_channel_id(instance),</span><br><span style="color: hsl(120, 100%, 40%);">+                    transport_rtp, ast_sockaddr_stringify(addr), packetwords);</span><br><span>           return &ast_null_frame;</span><br><span>  }</span><br><span>    position = 0;</span><br><span>        first_word = ntohl(rtcpheader[position]);</span><br><span>    if ((first_word & RTCP_VALID_MASK) != RTCP_VALID_VALUE) {</span><br><span style="color: hsl(0, 100%, 40%);">-           ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: Failed first packet validity check\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                    instance, transport_rtp, ast_sockaddr_stringify(addr));</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_debug_rtcp(2, "(%s) RTCP %p -- from %s: Failed first packet validity check\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_rtp_instance_get_channel_id(instance),</span><br><span style="color: hsl(120, 100%, 40%);">+                    transport_rtp, ast_sockaddr_stringify(addr));</span><br><span>                return &ast_null_frame;</span><br><span>  }</span><br><span>    do {</span><br><span>@@ -6178,8 +6510,9 @@</span><br><span>                 first_word = ntohl(rtcpheader[position]);</span><br><span>    } while ((first_word & RTCP_VERSION_MASK_SHIFTED) == RTCP_VERSION_SHIFTED);</span><br><span>      if (position != packetwords) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: Failed packet version or length check\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                 instance, transport_rtp, ast_sockaddr_stringify(addr));</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_debug_rtcp(2, "(%s) RTCP %p -- from %s: Failed packet version or length check\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_rtp_instance_get_channel_id(instance),</span><br><span style="color: hsl(120, 100%, 40%);">+                    transport_rtp, ast_sockaddr_stringify(addr));</span><br><span>                return &ast_null_frame;</span><br><span>  }</span><br><span> </span><br><span>@@ -6446,43 +6779,55 @@</span><br><span>                              report_block->ia_jitter =  ntohl(rtcpheader[i + 3]);</span><br><span>                              report_block->lsr = ntohl(rtcpheader[i + 4]);</span><br><span>                             report_block->dlsr = ntohl(rtcpheader[i + 5]);</span><br><span style="color: hsl(0, 100%, 40%);">-                               if (report_block->lsr</span><br><span style="color: hsl(0, 100%, 40%);">-                                        && update_rtt_stats(rtp, report_block->lsr, report_block->dlsr)</span><br><span style="color: hsl(0, 100%, 40%);">-                                   && rtcp_debug_test_addr(addr)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                        struct timeval now;</span><br><span style="color: hsl(0, 100%, 40%);">-                                     unsigned int lsr_now, lsw, msw;</span><br><span style="color: hsl(0, 100%, 40%);">-                                 gettimeofday(&now, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-                                   timeval2ntp(now, &msw, &lsw);</span><br><span style="color: hsl(0, 100%, 40%);">-                                   lsr_now = (((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16));</span><br><span style="color: hsl(0, 100%, 40%);">-                                    ast_verbose("Internal RTCP NTP clock skew detected: "</span><br><span style="color: hsl(0, 100%, 40%);">-                                                    "lsr=%u, now=%u, dlsr=%u (%u:%03ums), "</span><br><span style="color: hsl(120, 100%, 40%);">+                          if (report_block->lsr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                   int skewed = update_rtt_stats(rtp, report_block->lsr, report_block->dlsr);</span><br><span style="color: hsl(120, 100%, 40%);">+                                      if (skewed && rtcp_debug_test_addr(addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                           struct timeval now;</span><br><span style="color: hsl(120, 100%, 40%);">+                                           unsigned int lsr_now, lsw, msw;</span><br><span style="color: hsl(120, 100%, 40%);">+                                               gettimeofday(&now, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                                         timeval2ntp(now, &msw, &lsw);</span><br><span style="color: hsl(120, 100%, 40%);">+                                         lsr_now = (((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16));</span><br><span style="color: hsl(120, 100%, 40%);">+                                          ast_verbose("Internal RTCP NTP clock skew detected: "</span><br><span style="color: hsl(120, 100%, 40%);">+                                                       "lsr=%u, now=%u, dlsr=%u (%u:%03ums), "</span><br><span>                                                    "diff=%u\n",</span><br><span>                                                       report_block->lsr, lsr_now, report_block->dlsr, report_block->dlsr / 65536,</span><br><span>                                                         (report_block->dlsr % 65536) * 1000 / 65536,</span><br><span>                                                      report_block->dlsr - (lsr_now - report_block->lsr));</span><br><span style="color: hsl(120, 100%, 40%);">+                                    }</span><br><span>                            }</span><br><span>                            update_jitter_stats(rtp, report_block->ia_jitter);</span><br><span>                                update_lost_stats(rtp, report_block->lost_count.packets);</span><br><span style="color: hsl(120, 100%, 40%);">+                          /*</span><br><span style="color: hsl(120, 100%, 40%);">+                             * update_reported_mes_stats must be called AFTER</span><br><span style="color: hsl(120, 100%, 40%);">+                              * update_rtt_stats, update_jitter_stats and</span><br><span style="color: hsl(120, 100%, 40%);">+                           * update_lost_stats.</span><br><span style="color: hsl(120, 100%, 40%);">+                          */</span><br><span style="color: hsl(120, 100%, 40%);">+                           update_reported_mes_stats(rtp);</span><br><span> </span><br><span>                          if (rtcp_debug_test_addr(addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                     int rate = ast_rtp_get_rate(rtp->f.subclass.format);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                                    ast_verbose("  Fraction lost: %d\n", report_block->lost_count.fraction);</span><br><span>                                        ast_verbose("  Packets lost so far: %u\n", report_block->lost_count.packets);</span><br><span>                                   ast_verbose("  Highest sequence number: %u\n", report_block->highest_seq_no & 0x0000ffff);</span><br><span>                                  ast_verbose("  Sequence number cycles: %u\n", report_block->highest_seq_no >> 16);</span><br><span style="color: hsl(0, 100%, 40%);">-                                   ast_verbose("  Interarrival jitter: %u\n", report_block->ia_jitter);</span><br><span style="color: hsl(120, 100%, 40%);">+                                     ast_verbose("  Interarrival jitter (samp): %u\n", report_block->ia_jitter);</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_verbose("  Interarrival jitter (secs): %.6f\n", ast_samp2sec(report_block->ia_jitter, rate));</span><br><span>                                       ast_verbose("  Last SR(our NTP): %lu.%010lu\n",(unsigned long)(report_block->lsr) >> 16,((unsigned long)(report_block->lsr) << 16) * 4096);</span><br><span>                                      ast_verbose("  DLSR: %4.4f (sec)\n",(double)report_block->dlsr / 65536.0);</span><br><span>                                      ast_verbose("  RTT: %4.4f(sec)\n", rtp->rtcp->rtt);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   ast_verbose("  MES: %4.1f\n", rtp->rtcp->reported_mes);</span><br><span>                              }</span><br><span>                    }</span><br><span>                    /* If and when we handle more than one report block, this should occur outside</span><br><span>                        * this loop.</span><br><span>                         */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                 message_blob = ast_json_pack("{s: s, s: s, s: f}",</span><br><span style="color: hsl(120, 100%, 40%);">+                  message_blob = ast_json_pack("{s: s, s: s, s: f, s: f}",</span><br><span>                           "from", ast_sockaddr_stringify(addr),</span><br><span>                              "to", transport_rtp->rtcp->local_addr_str,</span><br><span style="color: hsl(0, 100%, 40%);">-                              "rtt", rtp->rtcp->rtt);</span><br><span style="color: hsl(120, 100%, 40%);">+                               "rtt", rtp->rtcp->rtt,</span><br><span style="color: hsl(120, 100%, 40%);">+                                "mes", rtp->rtcp->reported_mes);</span><br><span>                     ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_received_type(),</span><br><span>                                         rtcp_report,</span><br><span>                                         message_blob);</span><br><span>@@ -7366,7 +7711,8 @@</span><br><span>               struct ast_frame *f;</span><br><span> </span><br><span>             /* Update statistics for jitter so they are correct in RTCP */</span><br><span style="color: hsl(0, 100%, 40%);">-          calc_rxstamp(&rxtime, rtp, timestamp, mark);</span><br><span style="color: hsl(120, 100%, 40%);">+              calc_rxstamp_and_jitter(&rxtime, rtp, timestamp, mark);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> </span><br><span>            /* When doing P2P we don't need to raise any frames about SSRC change to the core */</span><br><span>             while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list)) != NULL) {</span><br><span>@@ -7517,7 +7863,7 @@</span><br><span>                if (ast_format_cache_is_slinear(rtp->f.subclass.format)) {</span><br><span>                        ast_frame_byteswap_be(&rtp->f);</span><br><span>               }</span><br><span style="color: hsl(0, 100%, 40%);">-               calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);</span><br><span style="color: hsl(120, 100%, 40%);">+          calc_rxstamp_and_jitter(&rtp->f.delivery, rtp, timestamp, mark);</span><br><span>              /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */</span><br><span>             ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);</span><br><span>            rtp->f.ts = timestamp / (ast_rtp_get_rate(rtp->f.subclass.format) / 1000);</span><br><span>@@ -7526,7 +7872,7 @@</span><br><span>             /* Video -- samples is # of samples vs. 90000 */</span><br><span>             if (!rtp->lastividtimestamp)</span><br><span>                      rtp->lastividtimestamp = timestamp;</span><br><span style="color: hsl(0, 100%, 40%);">-          calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);</span><br><span style="color: hsl(120, 100%, 40%);">+          calc_rxstamp_and_jitter(&rtp->f.delivery, rtp, timestamp, mark);</span><br><span>              ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);</span><br><span>            rtp->f.ts = timestamp / (ast_rtp_get_rate(rtp->f.subclass.format) / 1000);</span><br><span>             rtp->f.samples = timestamp - rtp->lastividtimestamp;</span><br><span>@@ -7975,6 +8321,8 @@</span><br><span>   bundled = (child || AST_VECTOR_SIZE(&rtp->ssrc_mapping)) ? 1 : 0;</span><br><span> </span><br><span>         prev_seqno = rtp->lastrxseqno;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* We need to save lastrxseqno for use by jitter before resetting it. */</span><br><span style="color: hsl(120, 100%, 40%);">+      rtp->prevrxseqno = rtp->lastrxseqno;</span><br><span>   rtp->lastrxseqno = seqno;</span><br><span> </span><br><span>     if (!rtp->recv_buffer) {</span><br><span>@@ -8438,7 +8786,8 @@</span><br><span> #endif</span><br><span>                        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                   ast_debug_rtcp(1, "(%p) RTCP setup on RTP instance\n", instance);</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_debug_rtcp(1, "(%s) RTCP setup on RTP instance\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_rtp_instance_get_channel_id(instance));</span><br><span>          } else {</span><br><span>                     if (rtp->rtcp) {</span><br><span>                          if (rtp->rtcp->schedid > -1) {</span><br><span>@@ -8482,6 +8831,8 @@</span><br><span>                              ast_free(rtp->rtcp->local_addr_str);</span><br><span>                           ast_free(rtp->rtcp);</span><br><span>                              rtp->rtcp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                          ast_debug_rtcp(1, "(%s) RTCP torn down on RTP instance\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  ast_rtp_instance_get_channel_id(instance));</span><br><span>                  }</span><br><span>            }</span><br><span>    } else if (property == AST_RTP_PROPERTY_ASYMMETRIC_CODEC) {</span><br><span>@@ -8722,7 +9073,7 @@</span><br><span>  AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_LOSS);</span><br><span> </span><br><span>    AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->txjitter, rtp->rxjitter);</span><br><span style="color: hsl(0, 100%, 40%);">-  AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->rxjitter, rtp->rtcp->reported_jitter / (unsigned int) 65536.0);</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->rxjitter, rtp->rtcp->reported_jitter);</span><br><span>       AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MAXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_maxjitter, rtp->rtcp->reported_maxjitter);</span><br><span>    AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MINJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_minjitter, rtp->rtcp->reported_minjitter);</span><br><span>    AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_normdevjitter, rtp->rtcp->reported_normdev_jitter);</span><br><span>@@ -8740,6 +9091,19 @@</span><br><span>      AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_STDEVRTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->stdevrtt, rtp->rtcp->stdevrtt);</span><br><span>         AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_RTT);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->txmes, rtp->rxmes);</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->rxmes, rtp->rtcp->reported_mes);</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MAXMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->remote_maxmes, rtp->rtcp->reported_maxmes);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MINMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->remote_minmes, rtp->rtcp->reported_minmes);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->remote_normdevmes, rtp->rtcp->reported_normdev_mes);</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_STDEVMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->remote_stdevmes, rtp->rtcp->reported_stdev_mes);</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MAXMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->local_maxmes, rtp->rtcp->maxrxmes);</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MINMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->local_minmes, rtp->rtcp->minrxmes);</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->local_normdevmes, rtp->rtcp->normdev_rxmes);</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_STDEVMES, AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->local_stdevmes, rtp->rtcp->stdev_rxjitter);</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_MES);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_SSRC, -1, stats->local_ssrc, rtp->ssrc);</span><br><span>  AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_SSRC, -1, stats->remote_ssrc, rtp->themssrc);</span><br><span>    AST_RTP_STAT_STRCPY(AST_RTP_INSTANCE_STAT_CHANNEL_UNIQUEID, -1, stats->channel_uniqueid, ast_rtp_instance_get_channel_id(instance));</span><br><span>@@ -8795,6 +9159,8 @@</span><br><span>      }</span><br><span>    ao2_lock(instance);</span><br><span> #endif</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug_rtp(1, "(%s) RTP Stop\n",</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_rtp_instance_get_channel_id(instance));</span><br><span> </span><br><span>      if (rtp->rtcp && rtp->rtcp->schedid > -1) {</span><br><span>              ao2_unlock(instance);</span><br><span>diff --git a/tests/test_res_rtp.c b/tests/test_res_rtp.c</span><br><span>index 1d36116..2ecf383 100644</span><br><span>--- a/tests/test_res_rtp.c</span><br><span>+++ b/tests/test_res_rtp.c</span><br><span>@@ -36,11 +36,14 @@</span><br><span> #include "asterisk/rtp_engine.h"</span><br><span> #include "asterisk/data_buffer.h"</span><br><span> #include "asterisk/format_cache.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include <assert.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sched.h></span><br><span> </span><br><span> enum test_type {</span><br><span>   TEST_TYPE_NONE = 0,     /* No special setup required */</span><br><span>      TEST_TYPE_NACK,         /* Enable NACK */</span><br><span>    TEST_TYPE_REMB,         /* Enable REMB */</span><br><span style="color: hsl(120, 100%, 40%);">+     TEST_TYPE_STD_RTCP, /* Let the stack do RTCP */</span><br><span> };</span><br><span> </span><br><span> static void ast_sched_context_destroy_wrapper(struct ast_sched_context *sched)</span><br><span>@@ -54,18 +57,30 @@</span><br><span>    struct ast_rtp_instance **instance2, struct ast_sched_context *test_sched,</span><br><span>   enum test_type type)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       struct ast_sockaddr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_sockaddr addr1;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_sockaddr addr2;</span><br><span style="color: hsl(120, 100%, 40%);">+    enum ast_rtp_instance_rtcp rtcp_type = AST_RTP_INSTANCE_RTCP_MUX;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_sockaddr_parse(&addr, "127.0.0.1", 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_sockaddr_parse(&addr1, "127.0.0.1", 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_sockaddr_parse(&addr2, "127.0.0.1", 0);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   *instance1 = ast_rtp_instance_new("asterisk", test_sched, &addr, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   *instance2 = ast_rtp_instance_new("asterisk", test_sched, &addr, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ *instance1 = ast_rtp_instance_new("asterisk", test_sched, &addr1, "instance1");</span><br><span style="color: hsl(120, 100%, 40%);">+       *instance2 = ast_rtp_instance_new("asterisk", test_sched, &addr2, "instance2");</span><br><span>      if (!instance1 || !instance2) {</span><br><span>              return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_rtp_instance_set_prop(*instance1, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_MUX);</span><br><span style="color: hsl(0, 100%, 40%);">-        ast_rtp_instance_set_prop(*instance2, AST_RTP_PROPERTY_RTCP, AST_RTP_INSTANCE_RTCP_MUX);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_rtp_instance_set_channel_id(*instance1, "instance1");</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_rtp_instance_set_channel_id(*instance2, "instance2");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (type == TEST_TYPE_STD_RTCP) {</span><br><span style="color: hsl(120, 100%, 40%);">+             rtcp_type = AST_RTP_INSTANCE_RTCP_STANDARD;</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%);">+   ast_rtp_instance_set_prop(*instance1,</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_RTP_PROPERTY_RTCP, rtcp_type);</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_rtp_instance_set_prop(*instance2,</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_RTP_PROPERTY_RTCP, rtcp_type);</span><br><span> </span><br><span>       if (type == TEST_TYPE_NACK) {</span><br><span>                ast_rtp_instance_set_prop(*instance1, AST_RTP_PROPERTY_RETRANS_RECV, 1);</span><br><span>@@ -77,11 +92,11 @@</span><br><span>               ast_rtp_instance_set_prop(*instance2, AST_RTP_PROPERTY_REMB, 1);</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_rtp_instance_get_local_address(*instance1, &addr);</span><br><span style="color: hsl(0, 100%, 40%);">-      ast_rtp_instance_set_remote_address(*instance2, &addr);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_rtp_instance_get_local_address(*instance1, &addr1);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_rtp_instance_set_remote_address(*instance2, &addr1);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        ast_rtp_instance_get_local_address(*instance2, &addr);</span><br><span style="color: hsl(0, 100%, 40%);">-      ast_rtp_instance_set_remote_address(*instance1, &addr);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_rtp_instance_get_local_address(*instance2, &addr2);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_rtp_instance_set_remote_address(*instance1, &addr2);</span><br><span> </span><br><span>     ast_rtp_instance_reset_test_engine(*instance1);</span><br><span> </span><br><span>@@ -130,6 +145,120 @@</span><br><span>  test_read_frames(instance2, num);</span><br><span> }</span><br><span> </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%);">+ * Unfortunately, we can't use usleep() to create</span><br><span style="color: hsl(120, 100%, 40%);">+ * packet spacing because there are signals in use</span><br><span style="color: hsl(120, 100%, 40%);">+ * which cause usleep to immediately return.  Instead</span><br><span style="color: hsl(120, 100%, 40%);">+ * we have to spin.  :(</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static void SLEEP_SPINNER(int ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct timeval a = ast_tvnow();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     while(1) {</span><br><span style="color: hsl(120, 100%, 40%);">+            sched_yield();</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ast_remaining_ms(a, ms) <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        break;</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 style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * This function is NOT really a reliable implementation.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Its purpose is only to aid in code development in res_rtp_asterisk.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static void test_write_and_read_interleaved_frames(struct ast_rtp_instance *instance1,</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_rtp_instance *instance2, int howlong, int rtcp_interval)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        char data[320] = "";</span><br><span style="color: hsl(120, 100%, 40%);">+        int pktinterval = 20;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_frame frame_out1 = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .frametype = AST_FRAME_VOICE,</span><br><span style="color: hsl(120, 100%, 40%);">+         .subclass.format = ast_format_ulaw,</span><br><span style="color: hsl(120, 100%, 40%);">+           .seqno = 4556,</span><br><span style="color: hsl(120, 100%, 40%);">+                .data.ptr = data,</span><br><span style="color: hsl(120, 100%, 40%);">+             .datalen = 160,</span><br><span style="color: hsl(120, 100%, 40%);">+               .samples = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+         .len = pktinterval,</span><br><span style="color: hsl(120, 100%, 40%);">+           .ts = 4622295,</span><br><span style="color: hsl(120, 100%, 40%);">+        };</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_frame frame_out2 = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .frametype = AST_FRAME_VOICE,</span><br><span style="color: hsl(120, 100%, 40%);">+         .subclass.format = ast_format_ulaw,</span><br><span style="color: hsl(120, 100%, 40%);">+           .seqno = 6554,</span><br><span style="color: hsl(120, 100%, 40%);">+                .data.ptr = data,</span><br><span style="color: hsl(120, 100%, 40%);">+             .datalen = 160,</span><br><span style="color: hsl(120, 100%, 40%);">+               .samples = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+         .len = pktinterval,</span><br><span style="color: hsl(120, 100%, 40%);">+           .ts = 8622295,</span><br><span style="color: hsl(120, 100%, 40%);">+        };</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_frame *frame_in1;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_frame *frame_in2;</span><br><span style="color: hsl(120, 100%, 40%);">+  int index;</span><br><span style="color: hsl(120, 100%, 40%);">+    int num;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rtcpnum;</span><br><span style="color: hsl(120, 100%, 40%);">+  int reverse = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      int send_rtcp = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  num = howlong / pktinterval;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rtcpnum = rtcp_interval / pktinterval;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_set_flag(&frame_out1, AST_FRFLAG_HAS_SEQUENCE_NUMBER);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_set_flag(&frame_out1, AST_FRFLAG_HAS_TIMING_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_set_flag(&frame_out2, AST_FRFLAG_HAS_SEQUENCE_NUMBER);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_set_flag(&frame_out2, AST_FRFLAG_HAS_TIMING_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  for (index = 0; index < num; index++) {</span><br><span style="color: hsl(120, 100%, 40%);">+            struct timeval start = ast_tvnow();</span><br><span style="color: hsl(120, 100%, 40%);">+           time_t ms;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          if (index == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_clear_flag(&frame_out1, AST_FRFLAG_HAS_SEQUENCE_NUMBER);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_clear_flag(&frame_out1, AST_FRFLAG_HAS_TIMING_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_clear_flag(&frame_out2, AST_FRFLAG_HAS_SEQUENCE_NUMBER);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_clear_flag(&frame_out2, AST_FRFLAG_HAS_TIMING_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             frame_out1.seqno += index;</span><br><span style="color: hsl(120, 100%, 40%);">+            frame_out1.delivery = start;</span><br><span style="color: hsl(120, 100%, 40%);">+          frame_out1.ts += frame_out1.len;</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_rtp_instance_write(instance1, &frame_out1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (send_rtcp && index && (index % rtcpnum == 0)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_rtp_instance_queue_report(instance1);</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%);">+           frame_in2 = ast_rtp_instance_read(instance2, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_frfree(frame_in2);</span><br><span style="color: hsl(120, 100%, 40%);">+                frame_in2 = ast_rtp_instance_read(instance2, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_frfree(frame_in2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              if (reverse) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        frame_out2.seqno += index;</span><br><span style="color: hsl(120, 100%, 40%);">+                    frame_out2.delivery = ast_tvnow();</span><br><span style="color: hsl(120, 100%, 40%);">+                    frame_out2.ts += frame_out2.len;</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_rtp_instance_write(instance2, &frame_out2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (send_rtcp && index && (index % rtcpnum == 0)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_rtp_instance_queue_report(instance2);</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%);">+                   frame_in1 = ast_rtp_instance_read(instance1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_frfree(frame_in1);</span><br><span style="color: hsl(120, 100%, 40%);">+                        frame_in1 = ast_rtp_instance_read(instance1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_frfree(frame_in1);</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 style="color: hsl(120, 100%, 40%);">+           ms = frame_out1.len - ast_tvdiff_ms(ast_tvnow(),start);</span><br><span style="color: hsl(120, 100%, 40%);">+               ms += (index % 2 ? 5 : 12);</span><br><span style="color: hsl(120, 100%, 40%);">+           ms += (index % 3 ? 2 : 30);</span><br><span style="color: hsl(120, 100%, 40%);">+           SLEEP_SPINNER(ms);</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> AST_TEST_DEFINE(nack_no_packet_loss)</span><br><span> {</span><br><span>  RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ast_rtp_instance_destroy);</span><br><span>@@ -523,8 +652,47 @@</span><br><span>       return AST_TEST_PASS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * This test should not normally be run.  Its only purpose is to</span><br><span style="color: hsl(120, 100%, 40%);">+ * aid in code development.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_TEST_DEFINE(mes)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ast_rtp_instance_destroy);</span><br><span style="color: hsl(120, 100%, 40%);">+       RAII_VAR(struct ast_rtp_instance *, instance2, NULL, ast_rtp_instance_destroy);</span><br><span style="color: hsl(120, 100%, 40%);">+       RAII_VAR(struct ast_sched_context *, test_sched, NULL, ast_sched_context_destroy_wrapper);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               info->name = "mes";</span><br><span style="color: hsl(120, 100%, 40%);">+              info->category = "/res/res_rtp/";</span><br><span style="color: hsl(120, 100%, 40%);">+                info->summary = "Media Experience Score";</span><br><span style="color: hsl(120, 100%, 40%);">+                info->description =</span><br><span style="color: hsl(120, 100%, 40%);">+                        "Tests calculation of Media Experience Score (only run by explicit request)";</span><br><span style="color: hsl(120, 100%, 40%);">+               info->explicit_only = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+           return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+      case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</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%);">+   test_sched = ast_sched_context_create();</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_sched_start_thread(test_sched);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((test_init_rtp_instances(&instance1, &instance2,</span><br><span style="color: hsl(120, 100%, 40%);">+          test_sched, TEST_TYPE_NONE)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "Failed to initialize test!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return AST_TEST_FAIL;</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%);">+   test_write_and_read_interleaved_frames(</span><br><span style="color: hsl(120, 100%, 40%);">+               instance1, instance2, 1000, 5000);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return AST_TEST_PASS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int unload_module(void)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_TEST_UNREGISTER(mes);</span><br><span>    AST_TEST_UNREGISTER(nack_no_packet_loss);</span><br><span>    AST_TEST_UNREGISTER(nack_nominal);</span><br><span>   AST_TEST_UNREGISTER(nack_overflow);</span><br><span>@@ -544,6 +712,7 @@</span><br><span>    AST_TEST_REGISTER(remb_nominal);</span><br><span>     AST_TEST_REGISTER(sr_rr_nominal);</span><br><span>    AST_TEST_REGISTER(fir_nominal);</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_TEST_REGISTER(mes);</span><br><span>      return AST_MODULE_LOAD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/19479">change 19479</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/+/19479"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 18 </div>
<div style="display:none"> Gerrit-Change-Id: I458cb9a311e8e5dc1db769b8babbcf2e093f107a </div>
<div style="display:none"> Gerrit-Change-Number: 19479 </div>
<div style="display:none"> Gerrit-PatchSet: 8 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <default.enum@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: N A <asterisk@phreaknet.org> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>