#include "../rtp_header_extension/rtp_header_extension_parser.h" #include #include "../rtp_header_extension/rtp_header_extension_map.h" #include "../rtp_header_extension/byte_io.h" #include "../rtp_header_extension/rtp_header_extensions.h" class RTPHeaderExtensionParserImpl : public RTPHeaderExtensionParser { public: bool Parse(const uint8_t* packet, size_t length, RTPHeaderExtension* header, int *header_length); bool RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id); bool RegisterRtpHeaderExtension(RtpExtension extension) ; bool DeregisterRtpHeaderExtension(RTPExtensionType type) ; bool DeregisterRtpHeaderExtension(RtpExtension extension) ; private: RtpHeaderExtensionMap rtp_header_extension_map_; }; RTPHeaderExtensionParser* RTPHeaderExtensionParser::Create() { return new RTPHeaderExtensionParserImpl(); } bool RTPHeaderExtensionParserImpl::Parse(const uint8_t* packet, size_t length, RTPHeaderExtension* header, int *header_length) { RtpUtility::RTPHeaderExtensionParser rtp_parser(packet, length); *header = RTPHeaderExtension(); RtpHeaderExtensionMap map; { map = rtp_header_extension_map_; } const bool valid_rtpheader = rtp_parser.Parse(header, &map, header_length); if (!valid_rtpheader) { return false; } return true; } bool RTPHeaderExtensionParserImpl::RegisterRtpHeaderExtension(RtpExtension extension) { return rtp_header_extension_map_.RegisterByUri(extension.id, extension.uri); } bool RTPHeaderExtensionParserImpl::RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id) { return rtp_header_extension_map_.RegisterByType(id, type); } bool RTPHeaderExtensionParserImpl::DeregisterRtpHeaderExtension(RtpExtension extension) { return rtp_header_extension_map_.Deregister( rtp_header_extension_map_.GetType(extension.id)); } bool RTPHeaderExtensionParserImpl::DeregisterRtpHeaderExtension(RTPExtensionType type) { return rtp_header_extension_map_.Deregister(type) == 0; } namespace RtpUtility { RTPHeaderExtensionParser::RTPHeaderExtensionParser(const uint8_t* rtpData, const size_t rtpDataLength) : _ptrRTPDataBegin(rtpData), _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) {} bool RTPHeaderExtensionParser::Parse(RTPHeaderExtension* header, const RtpHeaderExtensionMap* ptrExtensionMap, int *header_length) { const int length = _ptrRTPDataEnd - _ptrRTPDataBegin; const uint8_t* ptr = &_ptrRTPDataBegin[0]; // If in effect, MAY be omitted for those packets for which the offset // is zero. header->hasTransmissionTimeOffset = false; header->transmissionTimeOffset = 0; // May not be present in packet. header->hasAbsoluteSendTime = false; header->absoluteSendTime = 0; // May not be present in packet. header->hasAudioLevel = false; header->voiceActivity = false; header->audioLevel = 0; // May not be present in packet. header->hasVideoRotation = false; header->videoRotation = kVideoRotation_0; // May not be present in packet. header->playout_delay.min_ms = -1; header->playout_delay.max_ms = -1; // May not be present in packet. header->hasVideoContentType = false; header->videoContentType = VideoContentType::UNSPECIFIED; *header_length = 0; /* 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 | | .... | */ const int remain = _ptrRTPDataEnd - ptr; if (remain < 4) { return false; } *header_length += 4; uint16_t definedByProfile = ByteReader::ReadBigEndian(ptr); ptr += 2; // in 32 bit words size_t XLen = ByteReader::ReadBigEndian(ptr); ptr += 2; XLen *= 4; // in bytes if (static_cast(remain) < (4 + XLen)) { return false; } static const uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE; if (definedByProfile == kRtpOneByteHeaderExtensionId) { const uint8_t* ptrRTPDataExtensionEnd = ptr + XLen; ParseOneByteExtensionHeader(header, ptrExtensionMap, ptrRTPDataExtensionEnd, ptr); } *header_length += XLen; if (*header_length > static_cast(length)) return false; return true; } void RTPHeaderExtensionParser::ParseOneByteExtensionHeader( RTPHeaderExtension* header, const RtpHeaderExtensionMap* ptrExtensionMap, const uint8_t* ptrRTPDataExtensionEnd, const uint8_t* ptr) const { if (!ptrExtensionMap) { return; } while (ptrRTPDataExtensionEnd - ptr > 0) { // 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. const int id = (*ptr & 0xf0) >> 4; const int len = (*ptr & 0x0f); ptr++; if (id == 0) { // Padding byte, skip ignoring len. continue; } if (id == 15) { return; } if (ptrRTPDataExtensionEnd - ptr < (len + 1)) { return; } RTPExtensionType type = ptrExtensionMap->GetType(id); if (type == RtpHeaderExtensionMap::kInvalidType) { // If we encounter an unknown extension, just skip over it. } else { switch (type) { case kRtpExtensionTransmissionTimeOffset: { if (len != 2) { return; } // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=2 | transmission offset | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ header->transmissionTimeOffset = ByteReader::ReadBigEndian(ptr); header->hasTransmissionTimeOffset = true; break; } case kRtpExtensionAudioLevel: { if (len != 0) { return; } // 0 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=0 |V| level | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // header->audioLevel = ptr[0] & 0x7f; header->voiceActivity = (ptr[0] & 0x80) != 0; header->hasAudioLevel = true; break; } case kRtpExtensionAbsoluteSendTime: { if (len != 2) { return; } // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=2 | absolute send time | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ header->absoluteSendTime = ByteReader::ReadBigEndian(ptr); header->hasAbsoluteSendTime = true; break; } case kRtpExtensionVideoRotation: { if (len != 0) { return; } // 0 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=0 |0 0 0 0 C F R R| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ header->hasVideoRotation = true; header->videoRotation = ConvertCVOByteToVideoRotation(ptr[0]); break; } case kRtpExtensionTransportSequenceNumber: { if (len != 1) { return; } // 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 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ uint16_t sequence_number = ptr[0] << 8; sequence_number += ptr[1]; header->transportSequenceNumber = sequence_number; header->hasTransportSequenceNumber = true; break; } case kRtpExtensionPlayoutDelay: { if (len != 2) { return; } // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=2 | MIN delay | MAX delay | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ int min_playout_delay = (ptr[0] << 4) | ((ptr[1] >> 4) & 0xf); int max_playout_delay = ((ptr[1] & 0xf) << 8) | ptr[2]; header->playout_delay.min_ms = min_playout_delay * PlayoutDelayLimits::kGranularityMs; header->playout_delay.max_ms = max_playout_delay * PlayoutDelayLimits::kGranularityMs; break; } case kRtpExtensionVideoContentType: { if (len != 0) { return; } // 0 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=0 | Content type | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ header->hasVideoContentType = true; header->videoContentType = static_cast(ptr[0]); break; } case kRtpExtensionRtpStreamId: { std::string name(reinterpret_cast(ptr), len + 1); header->stream_id = name; break; } case kRtpExtensionRepairedRtpStreamId: { std::string name(reinterpret_cast(ptr), len + 1); header->repaired_stream_id = name; break; } case kRtpExtensionMid: { std::string name(reinterpret_cast(ptr), len + 1); header->mid = name; break; } case kRtpExtensionNone: case kRtpExtensionNumberOfExtensions: { return; } } } ptr += (len + 1); } } }