Merged revisions 221086 via svnmerge from
authorTerry Wilson <twilson@digium.com>
Wed, 30 Sep 2009 17:52:30 +0000 (17:52 +0000)
committerTerry Wilson <twilson@digium.com>
Wed, 30 Sep 2009 17:52:30 +0000 (17:52 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
  r221086 | twilson | 2009-09-30 09:49:11 -0500 (Wed, 30 Sep 2009) | 25 lines

  Change the SSRC by default when our media stream changes

  Be default, change SSRC when doing an audio stream changes Asterisk doesn't
  honor marker bit when reinvited to already-bridged RTP streams,resulting in
  far-end stack discarding packets with "old" timestamps that areactually part of
  a new stream.  This patch sends AST_CONTROL_SRCUPDATE whenever there is a
  reinvite, unless the 'constantssrc' is set to true in sip.conf.

  The original issue reported to Digium support detailed the following situation:
  ITSP <-> Asterisk 1.4.26.2 <-> SIP-based Application Server Call comes in
  fromITSP, Asterisk dials the app server which sends a re-invite back
  toAsterisk--not to negotiate to send media directly to the ITSP, but to
  indicatethat it's changing the stream it's sending to Asterisk.  The app
  servergenerates a new SSRC, sequence numbers, timestamps, and sets the marker
  bit on the new stream.  Asterisk passes through the teimstamp of the new stream,
  butdoes not reset the SSRC, sequence numbers, or set the marker bit.

  When the timestamp on the new stream is older than the timestamp on the
  originalstream, the ITSP (which doesn't know there has been any change) discards
  the newframes because it thinks they are too old.  This patch addresses this by
  changing the SSRC on a stream update unless constantssrc=true is set in
  sip.conf.

  Review: https://reviewboard.asterisk.org/r/374/
........

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@221266 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c
configs/sip.conf.sample
include/asterisk/rtp_engine.h
main/rtp_engine.c
res/res_rtp_asterisk.c

index b8e53d9..9c00765 100644 (file)
@@ -1503,6 +1503,7 @@ struct sip_auth {
 #define SIP_PAGE2_RTAUTOCLEAR          (1 << 2)        /*!< GP: Should we clean memory from peers after expiry? */
 #define SIP_PAGE2_RPID_UPDATE          (1 << 3)
 /* Space for addition of other realtime flags in the future */
+#define SIP_PAGE2_CONSTANT_SSRC         (1 << 7)       /*!< GDP: Don't change SSRC on reinvite */
 #define SIP_PAGE2_SYMMETRICRTP          (1 << 8)        /*!< GDP: Whether symmetric RTP is enabled or not */
 #define SIP_PAGE2_STATECHANGEQUEUE     (1 << 9)        /*!< D: Unsent state pending change exists */
 
@@ -1540,7 +1541,7 @@ struct sip_auth {
        SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | \
        SIP_PAGE2_BUGGY_MWI | SIP_PAGE2_TEXTSUPPORT | SIP_PAGE2_FAX_DETECT | \
        SIP_PAGE2_UDPTL_DESTINATION | SIP_PAGE2_VIDEOSUPPORT_ALWAYS | SIP_PAGE2_PREFERRED_CODEC | \
-       SIP_PAGE2_RPID_IMMEDIATE | SIP_PAGE2_RPID_UPDATE | SIP_PAGE2_SYMMETRICRTP)
+       SIP_PAGE2_RPID_IMMEDIATE | SIP_PAGE2_RPID_UPDATE | SIP_PAGE2_SYMMETRICRTP | SIP_PAGE2_CONSTANT_SSRC)
 
 /*@}*/
 
@@ -5192,6 +5193,9 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
                ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
                ast_rtp_instance_set_timeout(dialog->rtp, peer->rtptimeout);
                ast_rtp_instance_set_hold_timeout(dialog->rtp, peer->rtpholdtimeout);
+               if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_CONSTANT_SSRC)) {
+                       ast_rtp_instance_set_constantssrc(dialog->rtp);
+               }
                /* Set Frame packetization */
                ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(dialog->rtp), dialog->rtp, &dialog->prefs);
                dialog->autoframing = peer->autoframing;
@@ -5199,6 +5203,9 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
        if (dialog->vrtp) { /* Video */
                ast_rtp_instance_set_timeout(dialog->vrtp, peer->rtptimeout);
                ast_rtp_instance_set_hold_timeout(dialog->vrtp, peer->rtpholdtimeout);
+               if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_CONSTANT_SSRC)) {
+                       ast_rtp_instance_set_constantssrc(dialog->vrtp);
+               }
        }
        if (dialog->trtp) { /* Realtime text */
                ast_rtp_instance_set_timeout(dialog->trtp, peer->rtptimeout);
@@ -20437,6 +20444,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                                                sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
                                        return -1;
                                }
+                               ast_queue_control(p->owner, AST_CONTROL_SRCUPDATE);
                        } else {
                                p->jointcapability = p->capability;
                                ast_debug(1, "Hm....  No sdp for the moment\n");
@@ -20487,6 +20495,14 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                                ast_debug(1, "No compatible codecs for this SIP call.\n");
                                return -1;
                        }
+                       if (ast_test_flag(&p->flags[1], SIP_PAGE2_CONSTANT_SSRC)) {
+                               if (p->rtp) {
+                                       ast_rtp_instance_set_constantssrc(p->rtp);
+                               }
+                               if (p->vrtp) {
+                                       ast_rtp_instance_set_constantssrc(p->vrtp);
+                               }
+                       }
                } else {        /* No SDP in invite, call control session */
                        p->jointcapability = p->capability;
                        ast_debug(2, "No SDP in Invite, third party call control\n");
@@ -23854,6 +23870,9 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
        } else if (!strcasecmp(v->name, "t38pt_usertpsource")) {
                ast_set_flag(&mask[1], SIP_PAGE2_UDPTL_DESTINATION);
                ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_UDPTL_DESTINATION);
+       } else if (!strcasecmp(v->name, "constantssrc")) {
+               ast_set_flag(&mask[1], SIP_PAGE2_CONSTANT_SSRC);
+               ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_CONSTANT_SSRC);
        } else
                res = 0;
 
@@ -25357,6 +25376,8 @@ static int reload_config(enum channelreloadreason reason)
                } else if (!strcasecmp(v->name, "disallowed_methods")) {
                        char *disallow = ast_strdupa(v->value);
                        mark_parsed_methods(&sip_cfg.disallowed_methods, disallow);
+               } else if (!strcasecmp(v->name, "constantssrc")) {
+                       ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_CONSTANT_SSRC);
                }
        }
 
index ba95e63..bdd356c 100644 (file)
@@ -730,6 +730,8 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ;sdpowner=root                  ; Allows you to change the username field in the SDP owner string, (o=)
                                 ; This field MUST NOT contain spaces
 
+;constantssrc=yes               ; Don't change the RTP SSRC when our media stream changes
+
 ;----------------------------------------- REALTIME SUPPORT ------------------------
 ; For additional information on ARA, the Asterisk Realtime Architecture,
 ; please read realtime.txt and extconfig.txt in the /doc directory of the
@@ -935,6 +937,7 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ; timerb
 ; qualifyfreq
 ; t38pt_usertpsource
+; constantssrc
 ; contactpermit         ; Limit what a host may register as (a neat trick
 ; contactdeny           ; is to register at the same IP as a SIP provider,
 ;                       ; then call oneself, and get redirected to that
index 5d5ae3f..29070d0 100644 (file)
@@ -317,6 +317,8 @@ struct ast_rtp_engine {
        int (*dtmf_end)(struct ast_rtp_instance *instance, char digit);
        /*! Callback to indicate that a new source of media has come in */
        void (*new_source)(struct ast_rtp_instance *instance);
+       /*! Callback to tell new_source not to change SSRC */
+       void (*constant_ssrc_set)(struct ast_rtp_instance *instance);
        /*! Callback for setting an extended RTP property */
        int (*extended_prop_set)(struct ast_rtp_instance *instance, int property, void *value);
        /*! Callback for getting an extended RTP property */
@@ -1183,6 +1185,23 @@ int ast_rtp_instance_dtmf_mode_set(struct ast_rtp_instance *instance, enum ast_r
 enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get(struct ast_rtp_instance *instance);
 
 /*!
+ * \brief Mark an RTP instance not to update SSRC on a new source
+ *
+ * \param instance Instance to update
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_rtp_instance_set_constantssrc(instance);
+ * \endcode
+ *
+ * This sets the indicated instance to not update the RTP SSRC when new_source
+ * is called.
+ *
+ * \since 1.6.3
+ */
+void ast_rtp_instance_set_constantssrc(struct ast_rtp_instance *instance);
+/*!
  * \brief Indicate a new source of audio has dropped in
  *
  * \param instance Instance that the new media source is feeding into
index cf6d2c6..53ed892 100644 (file)
@@ -726,6 +726,13 @@ enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get(struct ast_rtp_instance *i
        return instance->dtmf_mode;
 }
 
+void ast_rtp_instance_set_constantssrc(struct ast_rtp_instance *instance)
+{
+       if (instance->engine->constant_ssrc_set) {
+               instance->engine->constant_ssrc_set(instance);
+       }
+}
+
 void ast_rtp_instance_new_source(struct ast_rtp_instance *instance)
 {
        if (instance->engine->new_source) {
index 3abb6c6..42cce37 100644 (file)
@@ -103,6 +103,7 @@ enum strict_rtp_state {
 #define FLAG_NAT_INACTIVE_NOWARN        (1 << 1)
 #define FLAG_NEED_MARKER_BIT            (1 << 3)
 #define FLAG_DTMF_COMPENSATE            (1 << 4)
+#define FLAG_CONSTANT_SSRC              (1 << 5)
 
 /*! \brief RTP session description */
 struct ast_rtp {
@@ -253,6 +254,7 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance);
 static int ast_rtp_dtmf_begin(struct ast_rtp_instance *instance, char digit);
 static int ast_rtp_dtmf_end(struct ast_rtp_instance *instance, char digit);
 static void ast_rtp_new_source(struct ast_rtp_instance *instance);
+static void ast_rtp_set_constantssrc(struct ast_rtp_instance *instance);
 static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame);
 static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp);
 static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value);
@@ -275,6 +277,7 @@ static struct ast_rtp_engine asterisk_rtp_engine = {
        .dtmf_begin = ast_rtp_dtmf_begin,
        .dtmf_end = ast_rtp_dtmf_end,
        .new_source = ast_rtp_new_source,
+       .constant_ssrc_set = ast_rtp_set_constantssrc,
        .write = ast_rtp_write,
        .read = ast_rtp_read,
        .prop_set = ast_rtp_prop_set,
@@ -653,6 +656,13 @@ static int ast_rtp_dtmf_end(struct ast_rtp_instance *instance, char digit)
        return 0;
 }
 
+void ast_rtp_set_constantssrc(struct ast_rtp_instance *instance)
+{
+       struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+
+       ast_set_flag(rtp, FLAG_CONSTANT_SSRC);
+}
+
 static void ast_rtp_new_source(struct ast_rtp_instance *instance)
 {
        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
@@ -660,6 +670,10 @@ static void ast_rtp_new_source(struct ast_rtp_instance *instance)
        /* We simply set this bit so that the next packet sent will have the marker bit turned on */
        ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
 
+       if (!ast_test_flag(rtp, FLAG_CONSTANT_SSRC)) {
+               rtp->ssrc = ast_random();
+       }
+
        return;
 }