diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b8e53d91577c9eef69f5a8b875c278a0ba3dec49..9c007655445c5aac8899c86036eb7fba493ff9cb 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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); } } diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample index ba95e6355c9047e6f63edd860be8d9c6f3fb3e75..bdd356c299d3c088027d4a673cef971c615e8fbd 100644 --- a/configs/sip.conf.sample +++ b/configs/sip.conf.sample @@ -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 diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index 5d5ae3f7b1758b57d7a31cc3a55cdc4e43fa0e56..29070d0c7edd393ef71c4aaedfcb60e3bf658bae 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -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 */ @@ -1182,6 +1184,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 * diff --git a/main/rtp_engine.c b/main/rtp_engine.c index cf6d2c6f2df53f0e8b601229bf3f6613dc1eab56..53ed892b2680228bbb6678d4d1081a1c5bd6dda4 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -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) { diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 3abb6c686a971e9578cd7e8fc9427ea0f56641c8..42cce37868f43020f20be502e2fad8cee7a8b415 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -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; }