rtp_header_extensions.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. #include "rtp_header_extension/rtp_header_extensions.h"
  2. #include <string.h>
  3. #include <cmath>
  4. #include <limits>
  5. #include "rtp_header_extension/byte_io.h"
  6. // Absolute send time in RTP streams.
  7. //
  8. // The absolute send time is signaled to the receiver in-band using the
  9. // general mechanism for RTP header extensions [RFC8285]. The payload
  10. // of this extension (the transmitted value) is a 24-bit unsigned integer
  11. // containing the sender's current time in seconds as a fixed point number
  12. // with 18 bits fractional part.
  13. //
  14. // The form of the absolute send time extension block:
  15. //
  16. // 0 1 2 3
  17. // 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
  18. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  19. // | ID | len=2 | absolute send time |
  20. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  21. bool AbsoluteSendTime::Parse(const uint8_t *data,
  22. uint32_t* time_24bits) {
  23. *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data);
  24. return true;
  25. }
  26. bool AbsoluteSendTime::Write(uint8_t *data,
  27. uint32_t time_24bits) {
  28. ByteWriter<uint32_t, 3>::WriteBigEndian(data, time_24bits);
  29. return true;
  30. }
  31. const char AbsoluteSendTime::kUri[] =
  32. "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
  33. // An RTP Header Extension for Client-to-Mixer Audio Level Indication
  34. //
  35. // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
  36. //
  37. // The form of the audio level extension block:
  38. //
  39. // 0 1
  40. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
  41. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  42. // | ID | len=0 |V| level |
  43. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  44. //
  45. bool AudioLevel::Parse(const uint8_t *data,
  46. bool* voice_activity,
  47. uint8_t* audio_level) {
  48. *voice_activity = (data[0] & 0x80) != 0;
  49. *audio_level = data[0] & 0x7F;
  50. return true;
  51. }
  52. bool AudioLevel::Write(uint8_t *data,
  53. bool voice_activity,
  54. uint8_t audio_level) {
  55. data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
  56. return true;
  57. }
  58. const char AudioLevel::kUri[] =
  59. "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
  60. // From RFC 5450: Transmission Time Offsets in RTP Streams.
  61. //
  62. // The transmission time is signaled to the receiver in-band using the
  63. // general mechanism for RTP header extensions [RFC8285]. The payload
  64. // of this extension (the transmitted value) is a 24-bit signed integer.
  65. // When added to the RTP timestamp of the packet, it represents the
  66. // "effective" RTP transmission time of the packet, on the RTP
  67. // timescale.
  68. //
  69. // The form of the transmission offset extension block:
  70. //
  71. // 0 1 2 3
  72. // 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
  73. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  74. // | ID | len=2 | transmission offset |
  75. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  76. bool TransmissionOffset::Parse(const uint8_t *data,
  77. int32_t* rtp_time) {
  78. *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data);
  79. return true;
  80. }
  81. bool TransmissionOffset::Write(uint8_t *data, int32_t rtp_time) {
  82. ByteWriter<int32_t, 3>::WriteBigEndian(data, rtp_time);
  83. return true;
  84. }
  85. const char TransmissionOffset::kUri[] = "urn:ietf:params:rtp-hdrext:toffset";
  86. // TransportSequenceNumber
  87. //
  88. // 0 1 2
  89. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
  90. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  91. // | ID | L=1 |transport-wide sequence number |
  92. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  93. bool TransportSequenceNumber::Parse(const uint8_t *data,
  94. uint16_t* transport_sequence_number) {
  95. *transport_sequence_number = ByteReader<uint16_t>::ReadBigEndian(data);
  96. return true;
  97. }
  98. bool TransportSequenceNumber::Write(uint8_t *data,
  99. uint16_t transport_sequence_number) {
  100. ByteWriter<uint16_t>::WriteBigEndian(data, transport_sequence_number);
  101. return true;
  102. }
  103. const char TransportSequenceNumber::kUri[] =
  104. "http://www.ietf.org/id/"
  105. "draft-holmer-rmcat-transport-wide-cc-extensions-01";
  106. // Coordination of Video Orientation in RTP streams.
  107. //
  108. // Coordination of Video Orientation consists in signaling of the current
  109. // orientation of the image captured on the sender side to the receiver for
  110. // appropriate rendering and displaying.
  111. //
  112. // 0 1
  113. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
  114. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  115. // | ID | len=0 |0 0 0 0 C F R R|
  116. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  117. bool VideoOrientation::Parse(const uint8_t *data,
  118. VideoRotation* rotation) {
  119. *rotation = ConvertCVOByteToVideoRotation(data[0]);
  120. return true;
  121. }
  122. bool VideoOrientation::Write(uint8_t *data,
  123. VideoRotation rotation) {
  124. data[0] = ConvertVideoRotationToCVOByte(rotation);
  125. return true;
  126. }
  127. bool VideoOrientation::Parse(const uint8_t *data,
  128. uint8_t* value) {
  129. *value = data[0];
  130. return true;
  131. }
  132. bool VideoOrientation::Write(uint8_t *data, uint8_t value) {
  133. data[0] = value;
  134. return true;
  135. }
  136. const char VideoOrientation::kUri[] = "urn:3gpp:video-orientation";
  137. // 0 1 2 3
  138. // 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
  139. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  140. // | ID | len=2 | MIN delay | MAX delay |
  141. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  142. bool PlayoutDelayLimits::Parse(const uint8_t *data,
  143. PlayoutDelay* playout_delay) {
  144. uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data);
  145. uint16_t min_raw = (raw >> 12);
  146. uint16_t max_raw = (raw & 0xfff);
  147. if (min_raw > max_raw)
  148. return false;
  149. playout_delay->min_ms = min_raw * kGranularityMs;
  150. playout_delay->max_ms = max_raw * kGranularityMs;
  151. return true;
  152. }
  153. bool PlayoutDelayLimits::Write(uint8_t *data,
  154. const PlayoutDelay& playout_delay) {
  155. // Convert MS to value to be sent on extension header.
  156. uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
  157. uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
  158. ByteWriter<uint32_t, 3>::WriteBigEndian(data,
  159. (min_delay << 12) | max_delay);
  160. return true;
  161. }
  162. const char PlayoutDelayLimits::kUri[] =
  163. "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay";
  164. // Video Content Type.
  165. //
  166. // E.g. default video or screenshare.
  167. //
  168. // 0 1
  169. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
  170. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  171. // | ID | len=0 | Content type |
  172. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  173. bool VideoContentTypeExtension::Parse(const uint8_t *data,
  174. VideoContentType* content_type) {
  175. *content_type = static_cast<VideoContentType>(data[0]);
  176. return true;
  177. }
  178. bool VideoContentTypeExtension::Write(uint8_t *data,
  179. VideoContentType content_type) {
  180. data[0] = static_cast<uint8_t>(content_type);
  181. return true;
  182. }
  183. const char VideoContentTypeExtension::kUri[] =
  184. "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type";
  185. bool BaseRtpStringExtension::Parse(const uint8_t *data,
  186. std::string* str) {
  187. if (data[0] == 0) // Valid string extension can't be empty.
  188. return false;
  189. const char* cstr = reinterpret_cast<const char*>(data);
  190. // If there is a \0 character in the middle of the |data|, treat it as end
  191. // of the string. Well-formed string extensions shouldn't contain it.
  192. str->assign(cstr, strlen(cstr));
  193. return true;
  194. }
  195. bool BaseRtpStringExtension::Write(uint8_t *data,
  196. const std::string& str) {
  197. if (str.size() > kMaxValueSizeBytes) {
  198. return false;
  199. }
  200. memcpy(data, str.data(), str.size());
  201. return true;
  202. }
  203. const char RtpStreamId::kUri[] =
  204. "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
  205. const char RepairedRtpStreamId::kUri[] =
  206. "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id";
  207. const char RtpMid::kUri[] = "urn:ietf:params:rtp-hdrext:sdes:mid";
  208. RTPHeaderExtension::RTPHeaderExtension()
  209. : hasTransmissionTimeOffset(false),
  210. transmissionTimeOffset(0),
  211. hasAbsoluteSendTime(false),
  212. absoluteSendTime(0),
  213. hasTransportSequenceNumber(false),
  214. transportSequenceNumber(0),
  215. hasAudioLevel(false),
  216. voiceActivity(false),
  217. audioLevel(0),
  218. hasVideoRotation(false),
  219. videoRotation(kVideoRotation_0),
  220. hasVideoContentType(false),
  221. videoContentType(VideoContentType::UNSPECIFIED) {
  222. playout_delay.max_ms = -1;
  223. playout_delay.min_ms = -1;
  224. }
  225. RtpExtension::RtpExtension(){
  226. id = 0;
  227. encrypt = false;
  228. };
  229. RtpExtension::RtpExtension(const std::string& uri, int id) : uri(uri), id(id) {RtpExtension();}
  230. RtpExtension::RtpExtension(const std::string& uri, int id, bool encrypt)
  231. : uri(uri), id(id), encrypt(encrypt) {RtpExtension();}
  232. RtpExtension::~RtpExtension(){};
  233. const char RtpExtension::kAudioLevelUri[] =
  234. "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
  235. const char RtpExtension::kTimestampOffsetUri[] =
  236. "urn:ietf:params:rtp-hdrext:toffset";
  237. const char RtpExtension::kAbsSendTimeUri[] =
  238. "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
  239. const char RtpExtension::kVideoRotationUri[] = "urn:3gpp:video-orientation";
  240. const char RtpExtension::kTransportSequenceNumberUri[] =
  241. "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01";
  242. // This extension allows applications to adaptively limit the playout delay
  243. // on frames as per the current needs. For example, a gaming application
  244. // has very different needs on end-to-end delay compared to a video-conference
  245. // application.
  246. const char RtpExtension::kPlayoutDelayUri[] =
  247. "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay";
  248. const char RtpExtension::kVideoContentTypeUri[] =
  249. "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type";
  250. const char RtpExtension::kMidUri[] = "urn:ietf:params:rtp-hdrext:sdes:mid";
  251. const char RtpExtension::kEncryptHeaderExtensionsUri[] =
  252. "urn:ietf:params:rtp-hdrext:encrypt";
  253. const char RtpExtension::kRidUri[] =
  254. "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
  255. const char RtpExtension::kRepairedRidUri[] =
  256. "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id";
  257. bool RtpExtension::IsSupportedForAudio(const std::string& uri) {
  258. return uri == RtpExtension::kAudioLevelUri ||
  259. uri == RtpExtension::kTransportSequenceNumberUri ||
  260. uri == RtpExtension::kMidUri ||
  261. uri == RtpExtension::kRidUri ||
  262. uri == RtpExtension::kRepairedRidUri;
  263. }
  264. bool RtpExtension::IsSupportedForVideo(const std::string& uri) {
  265. return uri == RtpExtension::kTimestampOffsetUri ||
  266. uri == RtpExtension::kAbsSendTimeUri ||
  267. uri == RtpExtension::kVideoRotationUri ||
  268. uri == RtpExtension::kTransportSequenceNumberUri ||
  269. uri == RtpExtension::kPlayoutDelayUri ||
  270. uri == RtpExtension::kVideoContentTypeUri ||
  271. uri == RtpExtension::kMidUri ||
  272. uri == RtpExtension::kRidUri ||
  273. uri == RtpExtension::kRepairedRidUri;
  274. }
  275. bool RtpExtension::IsEncryptionSupported(const std::string& uri) {
  276. return uri == RtpExtension::kAudioLevelUri ||
  277. uri == RtpExtension::kTimestampOffsetUri ||
  278. #if !defined(ENABLE_EXTERNAL_AUTH)
  279. // TODO(jbauch): Figure out a way to always allow "kAbsSendTimeUri"
  280. // here and filter out later if external auth is really used in
  281. // srtpfilter. External auth is used by Chromium and replaces the
  282. // extension header value of "kAbsSendTimeUri", so it must not be
  283. // encrypted (which can't be done by Chromium).
  284. uri == RtpExtension::kAbsSendTimeUri ||
  285. #endif
  286. uri == RtpExtension::kVideoRotationUri ||
  287. uri == RtpExtension::kTransportSequenceNumberUri ||
  288. uri == RtpExtension::kPlayoutDelayUri ||
  289. uri == RtpExtension::kVideoContentTypeUri ||
  290. uri == RtpExtension::kMidUri ||
  291. uri == RtpExtension::kRidUri ||
  292. uri == RtpExtension::kRepairedRidUri;
  293. }
  294. const RtpExtension* RtpExtension::FindHeaderExtensionByUri(
  295. const std::vector<RtpExtension>& extensions,
  296. const std::string& uri) {
  297. for(int i = 0; i < extensions.size(); i++){
  298. if (extensions[i].uri == uri) {
  299. return &extensions[i];
  300. }
  301. }
  302. return nullptr;
  303. }