diff --git a/addons/chan_ooh323.c b/addons/chan_ooh323.c index d7a4dfc88f..7724c21d44 100644 --- a/addons/chan_ooh323.c +++ b/addons/chan_ooh323.c @@ -1206,10 +1206,12 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d ooManualRingback(callToken); } break; - case AST_CONTROL_SRCUPDATE: - ast_rtp_instance_new_source(p->rtp); + case AST_CONTROL_SRCUPDATE: + ast_rtp_instance_update_source(p->rtp); + break; + case AST_CONTROL_SRCCHANGE: + ast_rtp_instance_change_source(p->rtp); break; - case AST_CONTROL_CONNECTED_LINE: if (gH323Debug) ast_log(LOG_DEBUG, "Sending connected line info for %s (%s)\n", diff --git a/channels/chan_h323.c b/channels/chan_h323.c index 145a3f5bb4..f2a6bc5117 100644 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -914,7 +914,11 @@ static int oh323_indicate(struct ast_channel *c, int condition, const void *data res = 0; break; case AST_CONTROL_SRCUPDATE: - ast_rtp_instance_new_source(pvt->rtp); + ast_rtp_instance_update_source(pvt->rtp); + res = 0; + break; + case AST_CONTROL_SRCCHANGE: + ast_rtp_instance_change_source(pvt->rtp); res = 0; break; case AST_CONTROL_PROCEEDING: diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 5dfafb84ab..16195cb2e8 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -1456,7 +1456,10 @@ static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, siz ast_moh_stop(ast); break; case AST_CONTROL_SRCUPDATE: - ast_rtp_instance_new_source(sub->rtp); + ast_rtp_instance_update_source(sub->rtp); + break; + case AST_CONTROL_SRCCHANGE: + ast_rtp_instance_change_source(sub->rtp); break; case AST_CONTROL_PROGRESS: case AST_CONTROL_PROCEEDING: diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b8f93b5835..ae1cbb3a27 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -3903,7 +3903,6 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) if (dialog->rtp) { /* Audio */ ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833); 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_prop(dialog->rtp, AST_RTP_PROPERTY_CONSTANT_SSRC, ast_test_flag(&dialog->flags[1], SIP_PAGE2_CONSTANT_SSRC)); ast_rtp_instance_set_timeout(dialog->rtp, peer->rtptimeout); ast_rtp_instance_set_hold_timeout(dialog->rtp, peer->rtpholdtimeout); /* Set Frame packetization */ @@ -3913,7 +3912,6 @@ 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); - ast_rtp_instance_set_prop(dialog->vrtp, AST_RTP_PROPERTY_CONSTANT_SSRC, ast_test_flag(&dialog->flags[1], SIP_PAGE2_CONSTANT_SSRC)); } if (dialog->trtp) { /* Realtime text */ ast_rtp_instance_set_timeout(dialog->trtp, peer->rtptimeout); @@ -4970,7 +4968,7 @@ static int sip_answer(struct ast_channel *ast) ast_setstate(ast, AST_STATE_UP); ast_debug(1, "SIP answering channel: %s\n", ast->name); - ast_rtp_instance_new_source(p->rtp); + ast_rtp_instance_update_source(p->rtp); res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE, TRUE); ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); } @@ -5002,7 +5000,7 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame) if ((ast->_state != AST_STATE_UP) && !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { - ast_rtp_instance_new_source(p->rtp); + ast_rtp_instance_update_source(p->rtp); if (!global_prematuremediafilter) { p->invitestate = INV_EARLY_MEDIA; transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE); @@ -5333,11 +5331,11 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data res = -1; break; case AST_CONTROL_HOLD: - ast_rtp_instance_new_source(p->rtp); + ast_rtp_instance_update_source(p->rtp); ast_moh_start(ast, data, p->mohinterpret); break; case AST_CONTROL_UNHOLD: - ast_rtp_instance_new_source(p->rtp); + ast_rtp_instance_update_source(p->rtp); ast_moh_stop(ast); break; case AST_CONTROL_VIDUPDATE: /* Request a video frame update */ @@ -5356,7 +5354,10 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data } break; case AST_CONTROL_SRCUPDATE: - ast_rtp_instance_new_source(p->rtp); + ast_rtp_instance_update_source(p->rtp); + break; + case AST_CONTROL_SRCCHANGE: + ast_rtp_instance_change_source(p->rtp); break; case AST_CONTROL_CONNECTED_LINE: update_connectedline(p, data, datalen); @@ -19232,12 +19233,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int res = -1; goto request_invite_cleanup; } - if (p->rtp) { - ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_CONSTANT_SSRC, ast_test_flag(&p->flags[1], SIP_PAGE2_CONSTANT_SSRC)); - } - if (p->vrtp) { - ast_rtp_instance_set_prop(p->vrtp, AST_RTP_PROPERTY_CONSTANT_SSRC, ast_test_flag(&p->flags[1], SIP_PAGE2_CONSTANT_SSRC)); - } } else { /* No SDP in invite, call control session */ p->jointcapability = p->capability; ast_debug(2, "No SDP in Invite, third party call control\n"); @@ -22595,9 +22590,6 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask } else if (!strcasecmp(v->name, "buggymwi")) { ast_set_flag(&mask[1], SIP_PAGE2_BUGGY_MWI); ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_BUGGY_MWI); - } 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; diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 136e2699cf..a19fdc15fb 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -4304,7 +4304,10 @@ static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, s case AST_CONTROL_PROCEEDING: break; case AST_CONTROL_SRCUPDATE: - ast_rtp_instance_new_source(sub->rtp); + ast_rtp_instance_update_source(sub->rtp); + break; + case AST_CONTROL_SRCCHANGE: + ast_rtp_instance_change_source(sub->rtp); break; case AST_CONTROL_CONNECTED_LINE: update_connectedline(sub, data, datalen); diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 6ae1ce0699..57fac84ca6 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -308,7 +308,6 @@ #define SIP_PAGE2_Q850_REASON (1 << 4) /*!< DP: Get/send cause code via Reason header */ /* 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 */ @@ -346,7 +345,7 @@ 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_CONSTANT_SSRC |\ + SIP_PAGE2_RPID_IMMEDIATE | SIP_PAGE2_RPID_UPDATE | SIP_PAGE2_SYMMETRICRTP |\ SIP_PAGE2_Q850_REASON) /*@}*/ diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample index c4c4b83eac..a2d25f2613 100644 --- a/configs/sip.conf.sample +++ b/configs/sip.conf.sample @@ -789,8 +789,6 @@ 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 @@ -1003,7 +1001,6 @@ 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/frame.h b/include/asterisk/frame.h index f9a9a4f0a3..6f45386cdf 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -85,7 +85,8 @@ struct ast_codec_pref { * \arg \b HOLD Call is placed on hold * \arg \b UNHOLD Call is back from hold * \arg \b VIDUPDATE Video update requested - * \arg \b SRCUPDATE The source of media has changed + * \arg \b SRCUPDATE The source of media has changed (RTP marker bit must change) + * \arg \b SRCCHANGE Media source has changed (RTP marker bit and SSRC must change) * \arg \b CONNECTED_LINE Connected line has changed * \arg \b REDIRECTING Call redirecting information has changed. */ @@ -323,6 +324,7 @@ enum ast_control_frame_type { AST_CONTROL_CONNECTED_LINE = 22,/*!< Indicate connected line has changed */ AST_CONTROL_REDIRECTING = 23, /*!< Indicate redirecting id has changed */ AST_CONTROL_T38_PARAMETERS = 24, /*! T38 state change request/notification with parameters */ + AST_CONTROL_SRCCHANGE = 25, /*!< Media source has changed and requires a new RTP SSRC */ }; enum ast_control_t38 { diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h index 86f7c27e70..770f4d2f5f 100644 --- a/include/asterisk/rtp_engine.h +++ b/include/asterisk/rtp_engine.h @@ -92,8 +92,6 @@ enum ast_rtp_property { AST_RTP_PROPERTY_STUN, /*! Enable RTCP support */ AST_RTP_PROPERTY_RTCP, - /*! Don't force a new SSRC on new source */ - AST_RTP_PROPERTY_CONSTANT_SSRC, /*! * \brief Maximum number of RTP properties supported @@ -322,10 +320,10 @@ struct ast_rtp_engine { int (*dtmf_begin)(struct ast_rtp_instance *instance, char digit); /*! Callback for stopping RFC2833 DTMF transmission */ 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 to indicate that we should update the marker bit */ + void (*update_source)(struct ast_rtp_instance *instance); + /*! Callback to indicate that we should update the marker bit and ssrc */ + void (*change_source)(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 */ @@ -1192,22 +1190,40 @@ 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 Indicate a new source of audio has dropped in + * \brief Indicate that the RTP marker bit should be set on an RTP stream * * \param instance Instance that the new media source is feeding into * * Example usage: * * \code - * ast_rtp_instance_new_source(instance); + * ast_rtp_instance_update_source(instance); * \endcode * - * This indicates that a new source of media is feeding the instance pointed to by - * instance. + * This indicates that the source of media that is feeding the instance pointed to by + * instance has been updated and that the marker bit should be set. * * \since 1.8 */ -void ast_rtp_instance_new_source(struct ast_rtp_instance *instance); +void ast_rtp_instance_update_source(struct ast_rtp_instance *instance); + +/*! + * \brief Indicate a new source of audio has dropped in and the ssrc should change + * + * \param instance Instance that the new media source is feeding into + * + * Example usage: + * + * \code + * ast_rtp_instance_change_source(instance); + * \endcode + * + * This indicates that the source of media that is feeding the instance pointed to by + * instance has changed and that the marker bit should be set and the SSRC updated. + * + * \since 1.8 + */ +void ast_rtp_instance_change_source(struct ast_rtp_instance *instance); /*! * \brief Set QoS parameters on an RTP session diff --git a/main/channel.c b/main/channel.c index 833de79b3f..016453c24a 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2964,6 +2964,7 @@ int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int cmdfd) case AST_CONTROL_RINGING: case AST_CONTROL_ANSWER: case AST_CONTROL_SRCUPDATE: + case AST_CONTROL_SRCCHANGE: case AST_CONTROL_CONNECTED_LINE: case AST_CONTROL_REDIRECTING: /* Unimportant */ @@ -3599,6 +3600,7 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con case AST_CONTROL_PROCEEDING: case AST_CONTROL_VIDUPDATE: case AST_CONTROL_SRCUPDATE: + case AST_CONTROL_SRCCHANGE: case AST_CONTROL_RADIO_KEY: case AST_CONTROL_RADIO_UNKEY: case AST_CONTROL_OPTION: @@ -3739,6 +3741,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition, case AST_CONTROL_PROCEEDING: case AST_CONTROL_VIDUPDATE: case AST_CONTROL_SRCUPDATE: + case AST_CONTROL_SRCCHANGE: case AST_CONTROL_RADIO_KEY: case AST_CONTROL_RADIO_UNKEY: case AST_CONTROL_OPTION: @@ -4474,6 +4477,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, format_t format, co case AST_CONTROL_UNHOLD: case AST_CONTROL_VIDUPDATE: case AST_CONTROL_SRCUPDATE: + case AST_CONTROL_SRCCHANGE: case AST_CONTROL_CONNECTED_LINE: case AST_CONTROL_REDIRECTING: case -1: /* Ignore -- just stopping indications */ @@ -5724,6 +5728,7 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct case AST_CONTROL_UNHOLD: case AST_CONTROL_VIDUPDATE: case AST_CONTROL_SRCUPDATE: + case AST_CONTROL_SRCCHANGE: ast_indicate_data(other, f->subclass.integer, f->data.ptr, f->datalen); if (jb_in_use) { ast_jb_empty_and_reset(c0, c1); diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 8085e9d9e5..88f5346143 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -728,10 +728,17 @@ enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get(struct ast_rtp_instance *i return instance->dtmf_mode; } -void ast_rtp_instance_new_source(struct ast_rtp_instance *instance) +void ast_rtp_instance_update_source(struct ast_rtp_instance *instance) { - if (instance->engine->new_source) { - instance->engine->new_source(instance); + if (instance->engine->update_source) { + instance->engine->update_source(instance); + } +} + +void ast_rtp_instance_change_source(struct ast_rtp_instance *instance) +{ + if (instance->engine->change_source) { + instance->engine->change_source(instance); } } diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index d8a279199c..fb060c75fe 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -254,7 +254,8 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, struct sched_context * 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_update_source(struct ast_rtp_instance *instance); +static void ast_rtp_change_source(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); @@ -276,7 +277,8 @@ static struct ast_rtp_engine asterisk_rtp_engine = { .destroy = ast_rtp_destroy, .dtmf_begin = ast_rtp_dtmf_begin, .dtmf_end = ast_rtp_dtmf_end, - .new_source = ast_rtp_new_source, + .update_source = ast_rtp_update_source, + .change_source = ast_rtp_change_source, .write = ast_rtp_write, .read = ast_rtp_read, .prop_set = ast_rtp_prop_set, @@ -655,16 +657,27 @@ static int ast_rtp_dtmf_end(struct ast_rtp_instance *instance, char digit) return 0; } -static void ast_rtp_new_source(struct ast_rtp_instance *instance) +static void ast_rtp_update_source(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(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); + ast_debug(3, "Setting the marker bit due to a source update\n"); - if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_CONSTANT_SSRC)) { - rtp->ssrc = ast_random(); - } + return; +} + +static void ast_rtp_change_source(struct ast_rtp_instance *instance) +{ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + unsigned int ssrc = ast_random(); + + /* 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); + + ast_debug(3, "Changing ssrc from %u to %u due to a source change\n", rtp->ssrc, ssrc); + rtp->ssrc = ssrc; return; } @@ -1854,6 +1867,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc unsigned int *rtpheader = (unsigned int*)(rtp->rawdata + AST_FRIENDLY_OFFSET), seqno, ssrc, timestamp; struct ast_rtp_payload_type payload; struct sockaddr_in remote_address = { 0, }; + AST_LIST_HEAD_NOLOCK(, ast_frame) frames; /* If this is actually RTCP let's hop on over and handle it */ if (rtcp) { @@ -1951,14 +1965,27 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc timestamp = ntohl(rtpheader[1]); ssrc = ntohl(rtpheader[2]); - /* Force a marker bit if the SSRC changes */ - if (!mark && rtp->rxssrc && rtp->rxssrc != ssrc) { - if (option_debug || rtpdebug) { - ast_debug(1, "Forcing Marker bit, because SSRC has changed\n"); + AST_LIST_HEAD_INIT_NOLOCK(&frames); + /* Force a marker bit and change SSRC if the SSRC changes */ + if (rtp->rxssrc && rtp->rxssrc != ssrc) { + struct ast_frame *f, srcupdate = { + AST_FRAME_CONTROL, + .subclass.integer = AST_CONTROL_SRCCHANGE, + }; + + if (!mark) { + if (option_debug || rtpdebug) { + ast_debug(1, "Forcing Marker bit, because SSRC has changed\n"); + } + mark = 1; } - mark = 1; + + f = ast_frisolate(&srcupdate); + AST_LIST_INSERT_TAIL(&frames, f, frame_list); } + rtp->rxssrc = ssrc; + /* Remove any padding bytes that may be present */ if (padding) { res -= rtp->rawdata[AST_FRIENDLY_OFFSET + res - 1]; @@ -1986,7 +2013,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc /* Make sure after we potentially mucked with the header length that it is once again valid */ if (res < hdrlen) { ast_log(LOG_WARNING, "RTP Read too short (%d, expecting %d\n", res, hdrlen); - return &ast_null_frame; + return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame; } rtp->rxcount++; @@ -2029,7 +2056,11 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n", payloadtype, ast_inet_ntoa(remote_address.sin_addr)); } - return f ? f : &ast_null_frame; + if (f) { + AST_LIST_INSERT_TAIL(&frames, f, frame_list); + return AST_LIST_FIRST(&frames); + } + return &ast_null_frame; } rtp->lastrxformat = rtp->f.subclass.codec = payload.code; @@ -2046,7 +2077,8 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.codec)), ast_tv(0, 0)); rtp->resp = 0; rtp->dtmf_timeout = rtp->dtmf_duration = 0; - return f; + AST_LIST_INSERT_TAIL(&frames, f, frame_list); + return AST_LIST_FIRST(&frames); } } @@ -2081,7 +2113,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->f.subclass.codec = AST_FORMAT_T140; header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen); if (header_end == NULL) { - return &ast_null_frame; + return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame; } header_end++; @@ -2094,7 +2126,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc len += data[x * 4 + 3]; if (!(rtp->f.datalen - len)) - return &ast_null_frame; + return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame; rtp->f.data.ptr += len; rtp->f.datalen -= len; @@ -2150,7 +2182,8 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc rtp->f.delivery.tv_usec = 0; } - return &rtp->f; + AST_LIST_INSERT_TAIL(&frames, &rtp->f, frame_list); + return AST_LIST_FIRST(&frames); } static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value)