diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp index ce1bf5723..c7b9a6304 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp @@ -51,6 +51,47 @@ int32_t srs_seq_distance(uint16_t value, uint16_t pre_value) { return srs_rtp_seq_distance(pre_value, value); } +SrsRtpHeaderExtensionMap::SrsRtpHeaderExtensionMap(){ +} + +SrsRtpHeaderExtensionMap::~SrsRtpHeaderExtensionMap(){ +} + +bool SrsRtpHeaderExtensionMap::register_by_uri(int id, std::string uri) { + for (int i = 0; i < sizeof(kExtensions); ++i) { + if (kExtensions[i].uri == uri) { + return register_id(id, kExtensions[i].type, kExtensions[i].uri); + } + } + return false; +} + +bool SrsRtpHeaderExtensionMap::register_id(int id, SrsRtpExtensionType type, std::string uri) { + if (id < 1 || id > 255) { + return false; + } + + ids_[type] = static_cast(id); + return true; +} + +SrsRtpExtensionType SrsRtpHeaderExtensionMap::get_type(int id) const { + for (int type = kRtpExtensionNone + 1; type < kRtpExtensionNumberOfExtensions; ++type) { + if (ids_[type] == id) { + return static_cast(type); + } + } + return kInvalidType; +} + +SrsRtpHeaderExtension::SrsRtpHeaderExtension() { + has_transport_sequence_number = false; + transport_sequence_number = 0; +} + +SrsRtpHeaderExtension::~SrsRtpHeaderExtension() { +} + SrsRtpHeader::SrsRtpHeader() { padding_length = 0; @@ -68,7 +109,63 @@ SrsRtpHeader::~SrsRtpHeader() { } -srs_error_t SrsRtpHeader::decode(SrsBuffer* buf) +srs_error_t SrsRtpHeader::parse_extension(SrsBuffer* buf, const SrsRtpHeaderExtensionMap *extension_map) { + srs_error_t err = srs_success; + uint16_t profile_id = buf->read_2bytes(); + uint16_t extension_length = buf->read_2bytes(); + + if (!extension_map) { + buf->skip(extension_length * 4); + return err; + } else { + srs_trace("extension_map uri : %d", extension_map->get_type(3)); + } + + // @see: https://tools.ietf.org/html/rfc5285#section-4.2 + if (profile_id == 0xBEDE) { + uint32_t xlen = extension_length * 4; + while (xlen > 0) { + // parse id and len + uint8_t id_len = buf->read_1bytes(); + xlen--; + if(id_len == 0) { + // padding, ignore + continue; + } + // 0 + // 0 1 2 3 4 5 6 7 + // +-+-+-+-+-+-+-+-+ + // | ID | len | + // +-+-+-+-+-+-+-+-+ + // Note that 'len' is the header extension element length, which is the + // number of bytes - 1. + uint8_t id = (id_len & 0xF0) >> 4; + uint8_t len = (id_len & 0x0F); + + SrsRtpExtensionType xtype = extension_map->get_type(id); + if (xtype == kRtpExtensionTransportSequenceNumber) { + // 0 1 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | L=1 |transport wide sequence number | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + header_extension.has_transport_sequence_number = true; + header_extension.transport_sequence_number = buf->read_2bytes(); + srs_trace("get twcc sn:%d", header_extension.transport_sequence_number); + } else { + buf->skip(len + 1); + } + } + } else if (profile_id == 0x1000) { + buf->skip(extension_length * 4); + } else { + return srs_error_new(ERROR_RTC_RTP_MUXER, "fail to parse extension"); + } + + return err; +} + +srs_error_t SrsRtpHeader::decode(SrsBuffer* buf, const SrsRtpHeaderExtensionMap* extmap) { srs_error_t err = srs_success; @@ -114,17 +211,18 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* buf) } if (extension) { - uint16_t profile_id = buf->read_2bytes(); - extension_length = buf->read_2bytes(); - - // TODO: FIXME: Read extensions. - // @see: https://tools.ietf.org/html/rfc3550#section-5.3.1 - buf->skip(extension_length * 4); - - // @see: https://tools.ietf.org/html/rfc5285#section-4.2 - if (profile_id == 0xBEDE) { - // TODO: FIXME: Implements it. - } + /* RTP header extension, RFC 3550. + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | defined by profile | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | header extension | + | .... | + */ + if ((err = parse_extension(buf, extmap)) != srs_success) { + return srs_error_wrap(err, "fail to parse extension"); + } } if (padding && !buf->empty()) { @@ -201,6 +299,15 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* buf) return err; } +srs_error_t SrsRtpHeader::get_twcc_sequence_number(uint16_t& twcc_sn) +{ + if (header_extension.has_transport_sequence_number == true) { + twcc_sn = header_extension.transport_sequence_number; + return srs_success; + } + return srs_error_new(ERROR_RTC_RTP_MUXER, "not find twcc sequence number"); +} + int SrsRtpHeader::nb_bytes() { return kRtpHeaderFixedSize + cc * 4 + (extension ? (extension_length + 1) * 4 : 0); @@ -375,7 +482,7 @@ srs_error_t SrsRtpPacket2::encode(SrsBuffer* buf) return err; } -srs_error_t SrsRtpPacket2::decode(SrsBuffer* buf) +srs_error_t SrsRtpPacket2::decode(SrsBuffer* buf, const SrsRtpHeaderExtensionMap* extmap) { srs_error_t err = srs_success; diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp index 27fe77627..20044c40b 100644 --- a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp @@ -82,6 +82,41 @@ bool srs_seq_is_newer(uint16_t value, uint16_t pre_value); bool srs_seq_is_rollback(uint16_t value, uint16_t pre_value); int32_t srs_seq_distance(uint16_t value, uint16_t pre_value); +enum SrsRtpExtensionType : int { + kRtpExtensionNone, + kRtpExtensionTransportSequenceNumber, + kRtpExtensionNumberOfExtensions // Must be the last entity in the enum. +}; +struct SrsExtensionInfo { + SrsRtpExtensionType type; + std::string uri; +}; +const SrsExtensionInfo kExtensions[] = { + {kRtpExtensionTransportSequenceNumber, std::string("http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")} +}; +class SrsRtpHeaderExtensionMap{ +public: + static const SrsRtpExtensionType kInvalidType = kRtpExtensionNone; + static const int kInvalidId = 0; +public: + bool register_by_uri(int id, std::string uri); + SrsRtpExtensionType get_type(int id) const; +public: + SrsRtpHeaderExtensionMap(); + virtual ~SrsRtpHeaderExtensionMap(); +private: + bool register_id(int id, SrsRtpExtensionType type, std::string uri); +private: + uint8_t ids_[kRtpExtensionNumberOfExtensions]; +}; +class SrsRtpHeaderExtension{ +public: + bool has_transport_sequence_number; + uint16_t transport_sequence_number; +public: + SrsRtpHeaderExtension(); + virtual ~SrsRtpHeaderExtension(); +}; class SrsRtpHeader { private: @@ -95,12 +130,14 @@ private: uint32_t ssrc; uint32_t csrc[15]; uint16_t extension_length; - // TODO:extension field. + SrsRtpHeaderExtension header_extension; public: SrsRtpHeader(); virtual ~SrsRtpHeader(); +private: + srs_error_t parse_extension(SrsBuffer* buf, const SrsRtpHeaderExtensionMap* extension_map); public: - virtual srs_error_t decode(SrsBuffer* buf); + virtual srs_error_t decode(SrsBuffer* buf, const SrsRtpHeaderExtensionMap* extmap = nullptr); virtual srs_error_t encode(SrsBuffer* buf); virtual int nb_bytes(); public: @@ -116,6 +153,7 @@ public: uint32_t get_ssrc() const; void set_padding(uint8_t v); uint8_t get_padding() const; + srs_error_t get_twcc_sequence_number(uint16_t& twcc_sn); }; class ISrsRtpPayloader : public ISrsCodec @@ -175,7 +213,7 @@ public: public: virtual int nb_bytes(); virtual srs_error_t encode(SrsBuffer* buf); - virtual srs_error_t decode(SrsBuffer* buf); + virtual srs_error_t decode(SrsBuffer* buf, const SrsRtpHeaderExtensionMap* extmap = nullptr); }; // Single payload data.