diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 73bc97ff2..81ea393f8 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -400,6 +400,11 @@ SrsRtcPlayStream::SrsRtcPlayStream(SrsRtcConnection* s, const SrsContextId& cid) SrsRtcPlayStream::~SrsRtcPlayStream() { + // TODO: FIXME: Should not do callback in de-constructor? + if (_srs_rtc_hijacker) { + _srs_rtc_hijacker->on_stop_play(session_, this, req_); + } + _srs_config->unsubscribe(this); srs_freep(nack_epp); @@ -933,16 +938,20 @@ SrsRtcPublishStream::SrsRtcPublishStream(SrsRtcConnection* session, const SrsCon SrsRtcPublishStream::~SrsRtcPublishStream() { - if (_srs_rtc_hijacker) { - _srs_rtc_hijacker->on_stop_publish(session_, this, req); - } - // TODO: FIXME: Should remove and delete source. if (source) { source->set_publish_stream(NULL); source->on_unpublish(); } + // TODO: FIXME: Should not do callback in de-constructor? + // NOTE: on_stop_publish lead to switch io, + // it must be called after source stream unpublish (set source stream is_created=false). + // if not, it lead to republish failed. + if (_srs_rtc_hijacker) { + _srs_rtc_hijacker->on_stop_publish(session_, this, req); + } + for (int i = 0; i < (int)video_tracks_.size(); ++i) { SrsRtcVideoRecvTrack* track = video_tracks_.at(i); srs_freep(track); @@ -1779,6 +1788,7 @@ srs_error_t SrsRtcConnection::add_publisher(SrsRequest* req, const SrsSdp& remot SrsRtcStreamDescription* stream_desc = new SrsRtcStreamDescription(); SrsAutoFree(SrsRtcStreamDescription, stream_desc); + // TODO: FIXME: Change to api of stream desc. if ((err = negotiate_publish_capability(req, remote_sdp, stream_desc)) != srs_success) { return srs_error_wrap(err, "publish negotiate"); } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index e04c9671e..8b7e2f9cc 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -575,6 +575,8 @@ public: virtual srs_error_t on_before_play(SrsRtcConnection* session, SrsRequest* req) = 0; // When start player by RTC. virtual srs_error_t on_start_play(SrsRtcConnection* session, SrsRtcPlayStream* player, SrsRequest* req) = 0; + // When stop player by RTC. + virtual void on_stop_play(SrsRtcConnection* session, SrsRtcPlayStream* player, SrsRequest* req) = 0; // When start consuming for player for RTC. virtual srs_error_t on_start_consume(SrsRtcConnection* session, SrsRtcPlayStream* player, SrsRequest* req, SrsRtcConsumer* consumer) = 0; }; diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp index 9396d867c..f5f6959d3 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp @@ -179,6 +179,58 @@ void SrsRtpExtensionTwcc::set_sn(uint16_t sn) has_twcc_ = true; } +SrsRtpExtensionOneByte::SrsRtpExtensionOneByte() : has_ext_(false), id_(0), value_(0) +{ +} + +void SrsRtpExtensionOneByte::set_id(int id) +{ + id_ = id; + has_ext_ = true; +} + +void SrsRtpExtensionOneByte::set_value(uint8_t value) +{ + value_ = value; + has_ext_ = true; +} + +srs_error_t SrsRtpExtensionOneByte::decode(SrsBuffer* buf) +{ + srs_error_t err = srs_success; + + if (!buf->require(2)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2); + } + uint8_t v = buf->read_1bytes(); + + id_ = (v & 0xF0) >> 4; + uint8_t len = (v & 0x0F); + if(!id_ || len != 0) { + return srs_error_new(ERROR_RTC_RTP, "invalid rtp extension id=%d, len=%d", id_, len); + } + + value_ = buf->read_1bytes(); + + has_ext_ = true; + return err; +} + +srs_error_t SrsRtpExtensionOneByte::encode(SrsBuffer* buf) +{ + srs_error_t err = srs_success; + + if (!buf->require(2)) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 2); + } + + uint8_t id_len = (id_ & 0x0F)<< 4 | 0x00; + buf->write_1bytes(id_len); + buf->write_1bytes(value_); + + return err; +} + SrsRtpExtensions::SrsRtpExtensions() : has_ext_(false) { } @@ -252,6 +304,11 @@ srs_error_t SrsRtpExtensions::decode_0xbede(SrsBuffer* buf) return srs_error_wrap(err, "decode twcc extension"); } has_ext_ = true; + } else if (xtype == kRtpExtensionAudioLevel) { + if((err = audio_level_.decode(buf)) != srs_success) { + return srs_error_wrap(err, "decode audio level extension"); + } + has_ext_ = true; } else { buf->skip(1 + (len + 1)); } @@ -263,6 +320,7 @@ srs_error_t SrsRtpExtensions::decode_0xbede(SrsBuffer* buf) uint64_t SrsRtpExtensions::nb_bytes() { int size = 4 + (twcc_.has_twcc_ext() ? twcc_.nb_bytes() : 0); + size += (audio_level_.exists() ? audio_level_.nb_bytes() : 0); // add padding size += (size % 4 == 0) ? 0 : (4 - size % 4); return size; @@ -281,6 +339,10 @@ srs_error_t SrsRtpExtensions::encode(SrsBuffer* buf) len += twcc_.nb_bytes(); } + if (audio_level_.exists()) { + len += audio_level_.nb_bytes(); + } + int padding_count = (len % 4 == 0) ? 0 : (4 - len % 4); len += padding_count; @@ -293,6 +355,12 @@ srs_error_t SrsRtpExtensions::encode(SrsBuffer* buf) } } + if (audio_level_.exists()) { + if (srs_success != (err = audio_level_.encode(buf))) { + return srs_error_wrap(err, "encode audio level extension"); + } + } + // add padding while(padding_count > 0) { buf->write_1bytes(0); @@ -331,6 +399,23 @@ srs_error_t SrsRtpExtensions::set_twcc_sequence_number(uint8_t id, uint16_t sn) return srs_success; } +srs_error_t SrsRtpExtensions::get_audio_level(uint8_t& level) +{ + if(audio_level_.exists()) { + level = audio_level_.get_value(); + return srs_success; + } + return srs_error_new(ERROR_RTC_RTP_MUXER, "not find rtp extension audio level"); +} + +srs_error_t SrsRtpExtensions::set_audio_level(int id, uint8_t level) +{ + has_ext_ = true; + audio_level_.set_id(id); + audio_level_.set_value(level); + return srs_success; +} + SrsRtpHeader::SrsRtpHeader() { padding_length = 0; diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp index 76a39fbc5..e5e647b69 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp @@ -86,9 +86,12 @@ enum SrsRtpExtensionType { kRtpExtensionNone, kRtpExtensionTransportSequenceNumber, + kRtpExtensionAudioLevel, kRtpExtensionNumberOfExtensions // Must be the last entity in the enum. }; +const std::string kAudioLevelUri = "urn:ietf:params:rtp-hdrext:ssrc-audio-level"; + struct SrsExtensionInfo { SrsRtpExtensionType type; @@ -96,7 +99,8 @@ struct SrsExtensionInfo }; const SrsExtensionInfo kExtensions[] = { - {kRtpExtensionTransportSequenceNumber, std::string("http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")} + {kRtpExtensionTransportSequenceNumber, std::string("http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")}, + {kRtpExtensionAudioLevel, kAudioLevelUri}, }; class SrsRtpExtensionTypes @@ -138,12 +142,34 @@ public: virtual uint64_t nb_bytes(); }; +class SrsRtpExtensionOneByte : public ISrsCodec +{ + bool has_ext_; + int id_; + uint8_t value_; +public: + SrsRtpExtensionOneByte(); + virtual ~SrsRtpExtensionOneByte() {} + + bool exists() { return has_ext_; } + int get_id() { return id_; } + uint8_t get_value() { return value_; } + void set_id(int id); + void set_value(uint8_t value); +public: + // ISrsCodec + virtual srs_error_t decode(SrsBuffer* buf); + virtual srs_error_t encode(SrsBuffer* buf); + virtual uint64_t nb_bytes() { return 2; }; +}; + class SrsRtpExtensions : public ISrsCodec { private: bool has_ext_; SrsRtpExtensionTypes types_; SrsRtpExtensionTwcc twcc_; + SrsRtpExtensionOneByte audio_level_; public: SrsRtpExtensions(); virtual ~SrsRtpExtensions(); @@ -152,6 +178,8 @@ public: void set_types_(const SrsRtpExtensionTypes* types); srs_error_t get_twcc_sequence_number(uint16_t& twcc_sn); srs_error_t set_twcc_sequence_number(uint8_t id, uint16_t sn); + srs_error_t get_audio_level(uint8_t& level); + srs_error_t set_audio_level(int id, uint8_t level); // ISrsCodec public: @@ -257,7 +285,7 @@ public: // Whether the packet is Audio packet. bool is_audio(); // Copy the RTP packet. - SrsRtpPacket2* copy(); + virtual SrsRtpPacket2* copy(); // Set RTP header extensions for encoding or decoding header extension void set_extension_types(const SrsRtpExtensionTypes* v); // interface ISrsEncoder