diff --git a/webrtc/RtpExt.cpp b/webrtc/RtpExt.cpp
index 9d291cdc..e1e181a6 100644
--- a/webrtc/RtpExt.cpp
+++ b/webrtc/RtpExt.cpp
@@ -166,10 +166,13 @@ map RtpExt::getExtValue(const RtpHeader *hea
XX(sdes_repaired_rtp_stream_id, "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id") \
XX(video_timing, "http://www.webrtc.org/experiments/rtp-hdrext/video-timing") \
XX(color_space, "http://www.webrtc.org/experiments/rtp-hdrext/color-space") \
+ XX(csrc_audio_level, "urn:ietf:params:rtp-hdrext:csrc-audio-level") \
+ XX(framemarking, "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07") \
XX(video_content_type, "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type") \
XX(playout_delay, "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay") \
XX(video_orientation, "urn:3gpp:video-orientation") \
- XX(toffset, "urn:ietf:params:rtp-hdrext:toffset")
+ XX(toffset, "urn:ietf:params:rtp-hdrext:toffset") \
+ XX(encrypt, "urn:ietf:params:rtp-hdrext:encrypt")
#define XX(type, url) {RtpExtType::type , url},
static unordered_map s_type_to_url = {RTP_EXT_MAP(XX)};
@@ -207,6 +210,291 @@ const char *RtpExt::getExtName(RtpExtType type) {
string RtpExt::dumpString() const {
_StrPrinter printer;
- printer << getExtName(_type) << ", id:" << (int)_id << " " << hexdump(data(), size());
+ switch (_type) {
+ case RtpExtType::ssrc_audio_level : {
+ bool vad;
+ printer << "audio level:" << (int) getAudioLevel(&vad) << ", vad:" << vad;
+ break;
+ }
+ case RtpExtType::abs_send_time : {
+ printer << "abs send time:" << getAbsSendTime();
+ break;
+ }
+ case RtpExtType::transport_cc : {
+ printer << "twcc seq:" << getTransportCCSeq();
+ break;
+ }
+ case RtpExtType::sdes_mid : {
+ printer << "sdes mid:" << getSdesMid();
+ break;
+ }
+ case RtpExtType::sdes_rtp_stream_id : {
+ printer << "rtp stream id:" << getRtpStreamId();
+ break;
+ }
+ case RtpExtType::sdes_repaired_rtp_stream_id : {
+ printer << "rtp repaired stream id:" << getRepairedRtpStreamId();
+ break;
+ }
+ case RtpExtType::video_timing : {
+ uint8_t flags;
+ uint16_t encode_start, encode_finish, packetization_complete, last_pkt_left_pacer, reserved_net0, reserved_net1;
+ getVideoTiming(flags, encode_start, encode_finish, packetization_complete, last_pkt_left_pacer,
+ reserved_net0, reserved_net1);
+ printer << "video timing, flags:" << (int) flags
+ << ",encode:" << encode_start << "-" << encode_finish
+ << ",packetization_complete:" << packetization_complete
+ << ",last_pkt_left_pacer:" << last_pkt_left_pacer
+ << ",reserved_net0:" << reserved_net0
+ << ",reserved_net1:" << reserved_net1;
+ break;
+ }
+ case RtpExtType::video_content_type : {
+ printer << "video content type:" << (int)getVideoContentType();
+ break;
+ }
+ case RtpExtType::video_orientation : {
+ bool camera_bit, flip_bit, first_rotation, second_rotation;
+ getVideoOrientation(camera_bit, flip_bit, first_rotation, second_rotation);
+ printer << "video orientation:" << camera_bit << "-" << flip_bit << "-" << first_rotation << "-" << second_rotation;
+ break;
+ }
+ case RtpExtType::playout_delay : {
+ uint16_t min_delay, max_delay;
+ getPlayoutDelay(min_delay, max_delay);
+ printer << "playout delay:" << min_delay << "-" << max_delay;
+ break;
+ }
+ case RtpExtType::toffset : {
+ printer << "toffset:" << getTransmissionOffset();
+ break;
+ }
+ case RtpExtType::framemarking : {
+ printer << "framemarking tid:" << getFramemarkingTID();
+ break;
+ }
+ default: {
+ printer << getExtName(_type) << ", id:" << (int) _id << ", ";
+ printer << "hex:" << hexdump(data(), size());
+ break;
+ }
+ }
return std::move(printer);
}
+
+//https://tools.ietf.org/html/rfc6464
+// 0 1
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID | len=0 |V| level |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// Figure 1: Sample Audio Level Encoding Using the
+// One-Byte Header Format
+//
+//
+// 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=1 |V| level | 0 (pad) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// Figure 2: Sample Audio Level Encoding Using the
+// Two-Byte Header Format
+uint8_t RtpExt::getAudioLevel(bool *vad) const{
+ CHECK(_type == RtpExtType::ssrc_audio_level && size() >= 1);
+ auto &byte = (*this)[0];
+ if (vad) {
+ *vad = byte & 0x80;
+ }
+ return byte & 0x7F;
+}
+
+//http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
+//Wire format: 1-byte extension, 3 bytes of data. total 4 bytes extra per packet (plus shared 4 bytes for all extensions present: 2 byte magic word 0xBEDE, 2 byte # of extensions). Will in practice replace the “toffset” extension so we should see no long term increase in traffic as a result.
+//
+//Encoding: Timestamp is in seconds, 24 bit 6.18 fixed point, yielding 64s wraparound and 3.8us resolution (one increment for each 477 bytes going out on a 1Gbps interface).
+//
+//Relation to NTP timestamps: abs_send_time_24 = (ntp_timestamp_64 >> 14) & 0x00ffffff ; NTP timestamp is 32 bits for whole seconds, 32 bits fraction of second.
+//
+//Notes: Packets are time stamped when going out, preferably close to metal. Intermediate RTP relays (entities possibly altering the stream) should remove the extension or set its own timestamp.
+uint32_t RtpExt::getAbsSendTime() const {
+ CHECK(_type == RtpExtType::abs_send_time && size() >= 3);
+ uint32_t ret = 0;
+ ret |= (*this)[0] << 16;
+ ret |= (*this)[1] << 8;
+ ret |= (*this)[2];
+ return ret;
+}
+
+//https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | 0xBE | 0xDE | length=1 |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | ID | L=1 |transport-wide sequence number | zero padding |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+uint16_t RtpExt::getTransportCCSeq() const {
+ CHECK(_type == RtpExtType::transport_cc && size() >= 2);
+ uint16_t ret;
+ ret |= (*this)[0] << 8;
+ ret |= (*this)[1];
+ return ret;
+}
+
+//https://tools.ietf.org/html/draft-ietf-avtext-sdes-hdr-ext-07
+// 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 | SDES Item text value ... |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+const string &RtpExt::getSdesMid() const {
+ CHECK(_type == RtpExtType::sdes_mid && size() >= 1);
+ return *this;
+}
+
+
+//https://tools.ietf.org/html/draft-ietf-avtext-rid-06
+//用于simulecast
+//3.1. RTCP 'RtpStreamId' SDES Extension
+//
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |RtpStreamId=TBD| length | RtpStreamId ...
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//
+// The RtpStreamId payload is UTF-8 encoded and is not null-terminated.
+//
+// RFC EDITOR NOTE: Please replace TBD with the assigned SDES
+// identifier value.
+
+//3.2. RTCP 'RepairedRtpStreamId' SDES Extension
+//
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |Repaired...=TBD| length | RepairRtpStreamId ...
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+//
+// The RepairedRtpStreamId payload is UTF-8 encoded and is not null-
+// terminated.
+//
+// RFC EDITOR NOTE: Please replace TBD with the assigned SDES
+// identifier value.
+
+string RtpExt::getRtpStreamId() const {
+ CHECK(_type == RtpExtType::sdes_rtp_stream_id && size() >= 1);
+ return *this;
+}
+
+string RtpExt::getRepairedRtpStreamId() const {
+ CHECK(_type == RtpExtType::sdes_repaired_rtp_stream_id && size() >= 1);
+ return *this;
+}
+
+
+//http://www.webrtc.org/experiments/rtp-hdrext/video-timing
+//Wire format: 1-byte extension, 13 bytes of data. Total 14 bytes extra per packet (plus 1-3 padding byte in some cases, plus shared 4 bytes for all extensions present: 2 byte magic word 0xBEDE, 2 byte # of extensions).
+//
+//First byte is a flags field. Defined flags:
+//
+//0x01 - extension is set due to timer.
+//0x02 - extension is set because the frame is larger than usual.
+//Both flags may be set at the same time. All remaining 6 bits are reserved and should be ignored.
+//
+//Next, 6 timestamps are stored as 16-bit values in big-endian order, representing delta from the capture time of a packet in ms. Timestamps are, in order:
+//
+//Encode start.
+//Encode finish.
+//Packetization complete.
+//Last packet left the pacer.
+//Reserved for network.
+//Reserved for network (2).
+
+void RtpExt::getVideoTiming(uint8_t &flags,
+ uint16_t &encode_start,
+ uint16_t &encode_finish,
+ uint16_t &packetization_complete,
+ uint16_t &last_pkt_left_pacer,
+ uint16_t &reserved_net0,
+ uint16_t &reserved_net1) const {
+ CHECK(_type == RtpExtType::video_timing && size() >= 13);
+ flags = (*this)[0];
+ encode_start = (*this)[1] << 8 | (*this)[2];
+ encode_finish = (*this)[3] << 8 | (*this)[4];
+ packetization_complete = (*this)[5] << 8 | (*this)[6];
+ last_pkt_left_pacer = (*this)[7] << 8 | (*this)[8];
+ reserved_net0 = (*this)[9] << 8 | (*this)[10];
+ reserved_net1 = (*this)[11] << 8 | (*this)[12];
+}
+
+
+//http://www.webrtc.org/experiments/rtp-hdrext/color-space
+// 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 | L = 3 | primaries | transfer | matrix |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |range+chr.sit. |
+// +-+-+-+-+-+-+-+-+
+
+
+//http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
+//Values:
+//0x00: Unspecified. Default value. Treated the same as an absence of an extension.
+//0x01: Screenshare. Video stream is of a screenshare type.
+//0x02: 摄像头?
+//Notes: Extension shoud be present only in the last packet of key-frames.
+// If attached to other packets it should be ignored.
+// If extension is absent, Unspecified value is assumed.
+uint8_t RtpExt::getVideoContentType() const {
+ CHECK(_type == RtpExtType::video_content_type && size() >= 1);
+ return (*this)[0];
+}
+
+//http://www.3gpp.org/ftp/Specs/html-info/26114.htm
+void RtpExt::getVideoOrientation(bool &camera_bit, bool &flip_bit, bool &first_rotation, bool &second_rotation) const {
+ CHECK(_type == RtpExtType::video_orientation && size() >= 1);
+ uint8_t byte = (*this)[0];
+ camera_bit = (byte & 0x08) >> 3;
+ flip_bit = (byte & 0x04) >> 2;
+ first_rotation = (byte & 0x02) >> 1;
+ second_rotation = byte & 0x01;
+}
+
+//http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
+// 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 |
+//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+void RtpExt::getPlayoutDelay(uint16_t &min_delay, uint16_t &max_delay) const {
+ CHECK(_type == RtpExtType::playout_delay && size() >= 3);
+ uint32_t bytes = (*this)[0] << 16 | (*this)[1] << 8 | (*this)[2];
+ min_delay = (bytes & 0x00FFF000) >> 12;
+ max_delay = bytes & 0x00000FFF;
+}
+
+//urn:ietf:params:rtp-hdrext:toffset
+//https://tools.ietf.org/html/rfc5450
+// 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 |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+uint32_t RtpExt::getTransmissionOffset() const {
+ CHECK(_type == RtpExtType::toffset && size() >= 3);
+ return (*this)[0] << 16 | (*this)[1] << 8 | (*this)[2];
+}
+
+//http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07
+// 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=? | L=2 |S|E|I|D|B| TID | LID | TL0PICIDX |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+uint8_t RtpExt::getFramemarkingTID() const {
+ CHECK(_type == RtpExtType::framemarking && size() >= 3);
+ return (*this)[0] & 0x07;
+}
diff --git a/webrtc/RtpExt.h b/webrtc/RtpExt.h
index 742ebd30..0decaeac 100644
--- a/webrtc/RtpExt.h
+++ b/webrtc/RtpExt.h
@@ -30,11 +30,17 @@ enum class RtpExtType : uint8_t {
sdes_repaired_rtp_stream_id = 6,
video_timing = 7,
color_space = 8,
+ //for firefox
+ csrc_audio_level = 9,
+ //svc ?
+ framemarking = 10,
video_content_type = 11,
playout_delay = 12,
video_orientation = 13,
toffset = 14,
reserved = 15,
+ // e2e ?
+ encrypt
};
class RtcMedia;
@@ -51,6 +57,34 @@ public:
string dumpString() const;
+ uint8_t getAudioLevel(bool *vad) const;
+ uint32_t getAbsSendTime() const;
+ uint16_t getTransportCCSeq() const;
+ const string& getSdesMid() const;
+ string getRtpStreamId() const;
+ string getRepairedRtpStreamId() const;
+
+ void getVideoTiming(uint8_t &flags,
+ uint16_t &encode_start,
+ uint16_t &encode_finish,
+ uint16_t &packetization_complete,
+ uint16_t &last_pkt_left_pacer,
+ uint16_t &reserved_net0,
+ uint16_t &reserved_net1) const;
+
+ uint8_t getVideoContentType() const;
+
+ void getVideoOrientation(bool &camera_bit,
+ bool &flip_bit,
+ bool &first_rotation,
+ bool &second_rotation) const;
+
+ void getPlayoutDelay(uint16_t &min_delay, uint16_t &max_delay) const;
+
+ uint32_t getTransmissionOffset() const;
+
+ uint8_t getFramemarkingTID() const;
+
private:
RtpExtType _type;
uint8_t _id;
diff --git a/webrtc/Sdp.cpp b/webrtc/Sdp.cpp
index 830cd52a..0dbb1fdc 100644
--- a/webrtc/Sdp.cpp
+++ b/webrtc/Sdp.cpp
@@ -1297,6 +1297,7 @@ void RtcConfigure::RtcTrackConfigure::setDefaultSetting(TrackType type){
rtcp_fb = {SdpConst::kTWCCRtcpFb, SdpConst::kRembRtcpFb};
extmap = {
RtpExtType::ssrc_audio_level,
+ RtpExtType::csrc_audio_level,
RtpExtType::abs_send_time,
RtpExtType::transport_cc,
RtpExtType::sdes_mid,
@@ -1320,7 +1321,8 @@ void RtcConfigure::RtcTrackConfigure::setDefaultSetting(TrackType type){
RtpExtType::video_content_type,
RtpExtType::playout_delay,
RtpExtType::video_orientation,
- RtpExtType::toffset
+ RtpExtType::toffset,
+ RtpExtType::framemarking
};
break;
}