1use std::any::Any;
2use std::any::TypeId;
3use std::collections::HashMap;
4use std::fmt;
5use std::fmt::Debug;
6use std::hash::BuildHasherDefault;
7use std::hash::Hasher;
8use std::panic::UnwindSafe;
9use std::str::from_utf8;
10use std::sync::Arc;
11use std::time::{Duration, Instant};
12
13use crate::util::already_happened;
14use crate::util::epoch_to_beginning;
15use crate::util::InstantExt;
16
17use crate::rtp_::Frequency;
18
19use super::mtime::MediaTime;
20use super::{Mid, Rid};
21
22#[derive(Debug, Clone)]
24#[non_exhaustive]
25pub enum Extension {
26 AbsoluteSendTime,
28 AudioLevel,
30 TransmissionTimeOffset,
36 VideoOrientation,
38 TransportSequenceNumber,
40 PlayoutDelay,
42 VideoContentType,
44 VideoTiming,
46 RtpStreamId,
51 RepairedRtpStreamId,
56 RtpMid,
58 FrameMarking,
60 ColorSpace,
62
63 #[doc(hidden)]
65 UnknownUri(String, Arc<dyn ExtensionSerializer>),
66}
67
68#[repr(u16)]
74#[derive(Clone, Copy, PartialEq, Eq, Debug)]
75pub(crate) enum ExtensionsForm {
76 OneByte = 0xBEDE,
80 TwoByte = 0x1000,
84}
85
86pub const MAX_ID_ONE_BYTE_FORM: u8 = 14;
87pub const MAX_ID: u8 = 16;
90
91impl ExtensionsForm {
92 pub(crate) fn as_u16(self) -> u16 {
93 self as u16
94 }
95
96 pub(crate) fn serialize(self) -> [u8; 2] {
97 self.as_u16().to_be_bytes()
99 }
100
101 pub(crate) fn parse(bytes: [u8; 2]) -> Option<Self> {
102 let serialized = u16::from_be_bytes(bytes);
103 if serialized == ExtensionsForm::OneByte.as_u16() {
104 Some(ExtensionsForm::OneByte)
105 } else if (serialized & 0xFFF0) == ExtensionsForm::TwoByte.as_u16() {
107 Some(ExtensionsForm::TwoByte)
108 } else {
109 None
110 }
111 }
112}
113
114impl UnwindSafe for Extension {}
116
117pub trait ExtensionSerializer: Debug + Send + Sync + 'static {
119 fn write_to(&self, buf: &mut [u8], ev: &ExtensionValues) -> usize;
122
123 fn parse_value(&self, buf: &[u8], ev: &mut ExtensionValues) -> bool;
125
126 fn is_video(&self) -> bool;
128
129 fn is_audio(&self) -> bool;
131
132 fn requires_two_byte_form(&self, _ev: &ExtensionValues) -> bool {
136 false
137 }
138}
139
140impl Extension {
141 fn requires_two_byte_form(&self, ev: &ExtensionValues) -> bool {
142 match self {
143 Extension::UnknownUri(_, serializer) => serializer.requires_two_byte_form(ev),
144 _ => false,
145 }
146 }
147}
148
149#[derive(Debug)]
152struct SdpUnknownUri;
153
154impl ExtensionSerializer for SdpUnknownUri {
155 fn write_to(&self, _buf: &mut [u8], _ev: &ExtensionValues) -> usize {
157 unreachable!("Incorrect ExtensionSerializer::write_to")
158 }
159 fn parse_value(&self, _buf: &[u8], _ev: &mut ExtensionValues) -> bool {
160 unreachable!("Incorrect ExtensionSerializer::parse_value")
161 }
162 fn is_video(&self) -> bool {
163 unreachable!("Incorrect ExtensionSerializer::is_video")
164 }
165 fn is_audio(&self) -> bool {
166 unreachable!("Incorrect ExtensionSerializer::is_audio")
167 }
168}
169
170const EXT_URI: &[(Extension, &str)] = &[
172 (
173 Extension::AbsoluteSendTime,
174 "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time",
175 ),
176 (
177 Extension::AudioLevel,
178 "urn:ietf:params:rtp-hdrext:ssrc-audio-level",
179 ),
180 (
181 Extension::TransmissionTimeOffset,
182 "urn:ietf:params:rtp-hdrext:toffset",
183 ),
184 (
185 Extension::VideoOrientation, "urn:3gpp:video-orientation",
187 ),
188 (
189 Extension::TransportSequenceNumber,
190 "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",
191 ),
192 (
193 Extension::PlayoutDelay,
194 "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay",
195 ),
196 (
197 Extension::VideoContentType,
198 "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type",
199 ),
200 (
201 Extension::VideoTiming,
202 "http://www.webrtc.org/experiments/rtp-hdrext/video-timing",
203 ),
204 (
205 Extension::RtpStreamId,
206 "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id",
207 ),
208 (
209 Extension::RepairedRtpStreamId,
210 "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id",
211 ),
212 (
213 Extension::RtpMid, "urn:ietf:params:rtp-hdrext:sdes:mid",
215 ),
216 (
217 Extension::FrameMarking,
218 "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07",
219 ),
220 (
221 Extension::ColorSpace,
222 "http://www.webrtc.org/experiments/rtp-hdrext/color-space",
223 ),
224];
225
226impl Extension {
227 pub(crate) fn from_sdp_uri(uri: &str) -> Self {
231 for (t, spec) in EXT_URI.iter() {
232 if *spec == uri {
233 return t.clone();
234 }
235 }
236
237 Extension::UnknownUri(uri.to_string(), Arc::new(SdpUnknownUri))
238 }
239
240 pub fn with_serializer(uri: &str, s: impl ExtensionSerializer) -> Self {
242 Extension::UnknownUri(uri.to_string(), Arc::new(s))
243 }
244
245 pub fn as_uri(&self) -> &str {
247 for (t, spec) in EXT_URI.iter() {
248 if t == self {
249 return spec;
250 }
251 }
252
253 if let Extension::UnknownUri(uri, _) = self {
254 return uri;
255 }
256
257 "unknown"
258 }
259
260 pub(crate) fn is_serialized(&self) -> bool {
261 if let Self::UnknownUri(_, s) = self {
262 let is_sdp = (s as &(dyn Any + 'static))
264 .downcast_ref::<SdpUnknownUri>()
265 .is_some();
266
267 if is_sdp {
272 panic!("is_serialized on SdpUnkownUri, this is a bug");
273 }
274 }
275 true
276 }
277
278 fn is_audio(&self) -> bool {
279 use Extension::*;
280
281 if let UnknownUri(_, serializer) = self {
282 return serializer.is_audio();
283 }
284
285 matches!(
286 self,
287 RtpStreamId
288 | RepairedRtpStreamId
289 | RtpMid
290 | AbsoluteSendTime
291 | AudioLevel
292 | TransportSequenceNumber
293 | TransmissionTimeOffset
294 | PlayoutDelay
295 )
296 }
297
298 fn is_video(&self) -> bool {
299 use Extension::*;
300
301 if let UnknownUri(_, serializer) = self {
302 return serializer.is_video();
303 }
304
305 matches!(
306 self,
307 RtpStreamId
308 | RepairedRtpStreamId
309 | RtpMid
310 | AbsoluteSendTime
311 | VideoOrientation
312 | TransportSequenceNumber
313 | TransmissionTimeOffset
314 | PlayoutDelay
315 | VideoContentType
316 | VideoTiming
317 | FrameMarking
318 | ColorSpace
319 )
320 }
321}
322
323#[derive(Clone, PartialEq, Eq)]
344pub struct ExtensionMap([Option<MapEntry>; MAX_ID as usize]); #[derive(Debug, Clone, PartialEq, Eq)]
347struct MapEntry {
348 ext: Extension,
349 locked: bool,
350}
351
352impl ExtensionMap {
353 pub fn empty() -> Self {
355 ExtensionMap(std::array::from_fn(|_| None))
356 }
357
358 pub fn standard() -> Self {
362 let mut exts = Self::empty();
363
364 exts.set(1, Extension::AudioLevel);
365 exts.set(2, Extension::AbsoluteSendTime);
366 exts.set(3, Extension::TransportSequenceNumber);
367 exts.set(4, Extension::RtpMid);
368 exts.set(10, Extension::RtpStreamId);
370 exts.set(11, Extension::RepairedRtpStreamId);
371 exts.set(13, Extension::VideoOrientation);
372
373 exts
374 }
375
376 pub(crate) fn clear(&mut self) {
377 for i in &mut self.0 {
378 *i = None;
379 }
380 }
381
382 pub fn set(&mut self, id: u8, ext: Extension) {
386 if id < 1 || id > MAX_ID {
387 debug!("Set RTP extension out of range 1-{}: {}", MAX_ID, id);
388 return;
389 }
390 let idx = id as usize - 1;
391
392 let m = MapEntry { ext, locked: false };
393
394 self.0[idx] = Some(m);
395 }
396
397 pub fn lookup(&self, id: u8) -> Option<&Extension> {
401 if id >= 1 && id <= MAX_ID {
402 self.0[id as usize - 1].as_ref().map(|m| &m.ext)
403 } else {
404 debug!("Lookup RTP extension out of range 1-{}: {}", MAX_ID, id);
405 None
406 }
407 }
408
409 pub fn id_of(&self, e: Extension) -> Option<u8> {
413 self.0
414 .iter()
415 .position(|x| x.as_ref().map(|e| &e.ext) == Some(&e))
416 .map(|p| p as u8 + 1)
417 }
418
419 pub fn iter(&self) -> impl Iterator<Item = (u8, &Extension)> + '_ {
421 self.0
422 .iter()
423 .enumerate()
424 .filter_map(|(i, e)| e.as_ref().map(|e| (i, e)))
425 .map(|(i, e)| ((i + 1) as u8, &e.ext))
426 }
427
428 pub fn iter_by_media_type(&self, audio: bool) -> impl Iterator<Item = (u8, &Extension)> + '_ {
430 self.iter().filter(move |(_id, ext)| {
431 if audio {
432 ext.is_audio()
433 } else {
434 ext.is_video()
435 }
436 })
437 }
438
439 #[allow(unused)]
441 pub fn iter_audio(&self) -> impl Iterator<Item = (u8, &Extension)> + '_ {
442 self.iter_by_media_type(true)
443 }
444
445 #[allow(unused)]
447 pub fn iter_video(&self) -> impl Iterator<Item = (u8, &Extension)> + '_ {
448 self.iter_by_media_type(false)
449 }
450
451 pub(crate) fn cloned_with_type(&self, audio: bool) -> Self {
452 let mut x = ExtensionMap::empty();
453 for (id, ext) in self.iter_by_media_type(audio) {
454 x.set(id, ext.clone());
455 }
456 x
457 }
458
459 pub(crate) fn parse(
461 &self,
462 mut buf: &[u8],
463 form: ExtensionsForm,
464 ext_vals: &mut ExtensionValues,
465 ) {
466 loop {
467 if buf.is_empty() {
468 return;
469 }
470
471 if buf[0] == 0 {
472 buf = &buf[1..];
474 continue;
475 }
476
477 let (id, len) = match form {
478 ExtensionsForm::OneByte => {
479 let id = buf[0] >> 4;
480 let len = (buf[0] & 0xf) as usize + 1;
481 buf = &buf[1..];
482
483 if id == 15 {
484 return;
490 }
491 (id, len)
492 }
493 ExtensionsForm::TwoByte => {
494 if buf.len() < 2 {
495 trace!("Not enough ext header len: {} < {}", buf.len(), 2);
496 return;
497 }
498 let id = buf[0];
499 let len = buf[1] as usize;
500 buf = &buf[2..];
501 (id, len)
502 }
503 };
504
505 if buf.len() < len {
506 trace!("Not enough type ext len: {} < {}", buf.len(), len);
507 return;
508 }
509
510 let ext_buf = &buf[..len];
511 if let Some(ext) = self.lookup(id) {
512 ext.parse_value(ext_buf, ext_vals);
513 }
514
515 buf = &buf[len..];
516 }
517 }
518
519 pub(crate) fn form(&self, ev: &ExtensionValues) -> ExtensionsForm {
520 if self
521 .iter()
522 .any(|(id, ext)| id > MAX_ID_ONE_BYTE_FORM || ext.requires_two_byte_form(ev))
523 {
524 ExtensionsForm::TwoByte
525 } else {
526 ExtensionsForm::OneByte
527 }
528 }
529
530 pub(crate) fn write_to(
531 &self,
532 ext_buf: &mut [u8],
533 ev: &ExtensionValues,
534 form: ExtensionsForm,
535 ) -> usize {
536 let orig_len = ext_buf.len();
537 let mut b = ext_buf;
538
539 for (idx, x) in self.0.iter().enumerate() {
540 if let Some(v) = x {
541 match form {
542 ExtensionsForm::OneByte => {
543 if let Some(n) = v.ext.write_to(&mut b[1..], ev) {
544 assert!(n <= 16);
545 assert!(n > 0);
546 b[0] = (idx as u8 + 1) << 4 | (n as u8 - 1);
547 b = &mut b[1 + n..];
548 }
549 }
550 ExtensionsForm::TwoByte => {
551 if let Some(n) = v.ext.write_to(&mut b[2..], ev) {
552 b[0] = (idx + 1) as u8;
553 b[1] = n as u8;
554 b = &mut b[2 + n..];
555 }
556 }
557 };
558 }
559 }
560
561 orig_len - b.len()
562 }
563
564 pub(crate) fn remap(&mut self, remote_exts: &[(u8, &Extension)]) {
565 for (id, ext) in remote_exts {
567 self.swap(*id, ext);
568 }
569 }
570
571 fn swap(&mut self, id: u8, ext: &Extension) {
572 if id < 1 || id > MAX_ID {
573 return;
574 }
575
576 let new_index = id as usize - 1;
578
579 let Some(old_index) = self
580 .0
581 .iter()
582 .enumerate()
583 .find(|(_, m)| m.as_ref().map(|m| &m.ext) == Some(ext))
584 .map(|(i, _)| i)
585 else {
586 return;
587 };
588
589 let old = self.0[old_index].as_mut().unwrap();
591
592 let is_change = new_index != old_index;
593
594 if is_change && old.locked {
596 warn!(
597 "Extmap locked by previous negotiation. Ignore change: {} -> {}",
598 old_index, new_index
599 );
600 return;
601 }
602
603 old.locked = true;
605
606 if !is_change {
607 return;
608 }
609
610 self.0.swap(old_index, new_index);
611 }
612}
613
614impl Extension {
615 pub(crate) fn write_to(&self, buf: &mut [u8], ev: &ExtensionValues) -> Option<usize> {
616 use Extension::*;
617 match self {
618 AbsoluteSendTime => {
619 let time_abs = ev.abs_send_time?;
624
625 let dur = time_abs.to_unix_duration();
627
628 let time_24 = MediaTime::from(dur)
630 .rebase(Frequency::FIXED_POINT_6_18)
631 .numer() as u32;
632
633 buf[..3].copy_from_slice(&time_24.to_be_bytes()[1..]);
634 Some(3)
635 }
636 AudioLevel => {
637 let v1 = ev.audio_level?;
638 let v2 = ev.voice_activity?;
639 buf[0] = if v2 { 0x80 } else { 0 } | (-(0x7f & v1) as u8);
640 Some(1)
641 }
642 TransmissionTimeOffset => {
643 let v = ev.tx_time_offs?;
644 buf[..4].copy_from_slice(&v.to_be_bytes());
645 Some(4)
646 }
647 VideoOrientation => {
648 let v = ev.video_orientation?;
649 buf[0] = v as u8;
650 Some(1)
651 }
652 TransportSequenceNumber => {
653 let v = ev.transport_cc?;
654 buf[..2].copy_from_slice(&v.to_be_bytes());
655 Some(2)
656 }
657 PlayoutDelay => {
658 let v1 = ev.play_delay_min?.rebase(Frequency::HUNDREDTHS);
659 let v2 = ev.play_delay_max?.rebase(Frequency::HUNDREDTHS);
660 let min = (v1.numer() & 0xfff) as u32;
661 let max = (v2.numer() & 0xfff) as u32;
662 buf[0] = (min >> 4) as u8;
663 buf[1] = (min << 4) as u8 | (max >> 8) as u8;
664 buf[2] = max as u8;
665 Some(3)
666 }
667 VideoContentType => {
668 let v = ev.video_content_type?;
669 buf[0] = v;
670 Some(1)
671 }
672 VideoTiming => {
673 let v = ev.video_timing?;
674 buf[0] = v.flags;
675 buf[1..3].copy_from_slice(&v.encode_start.to_be_bytes());
676 buf[3..5].copy_from_slice(&v.encode_finish.to_be_bytes());
677 buf[5..7].copy_from_slice(&v.packetize_complete.to_be_bytes());
678 buf[7..9].copy_from_slice(&v.last_left_pacer.to_be_bytes());
679 buf[9..11].copy_from_slice(&0_u16.to_be_bytes());
681 buf[11..13].copy_from_slice(&0_u16.to_be_bytes());
682 Some(13)
683 }
684 RtpStreamId => {
685 let v = ev.rid?;
686 let l = v.len();
687 buf[..l].copy_from_slice(v.as_bytes());
688 Some(l)
689 }
690 RepairedRtpStreamId => {
691 let v = ev.rid_repair?;
692 let l = v.len();
693 buf[..l].copy_from_slice(v.as_bytes());
694 Some(l)
695 }
696 RtpMid => {
697 let v = ev.mid?;
698 let l = v.len();
699 buf[..l].copy_from_slice(v.as_bytes());
700 Some(l)
701 }
702 FrameMarking => {
703 let v = ev.frame_mark?;
704 buf[..4].copy_from_slice(&v.to_be_bytes());
705 Some(4)
706 }
707 ColorSpace => {
708 None
710 }
711 UnknownUri(_, serializer) => {
712 let n = serializer.write_to(buf, ev);
713
714 if n == 0 {
715 None
716 } else {
717 Some(n)
718 }
719 }
720 }
721 }
722
723 pub(crate) fn parse_value(&self, buf: &[u8], ev: &mut ExtensionValues) -> Option<()> {
724 use Extension::*;
725 match self {
726 AbsoluteSendTime => {
728 if buf.len() < 3 {
731 return None;
732 }
733 let time_24 = u32::from_be_bytes([0, buf[0], buf[1], buf[2]]);
734
735 let time_micros = MediaTime::from_fixed_point_6_18(time_24 as u64)
737 .rebase(Frequency::MICROS)
738 .numer();
739
740 let time_dur = Duration::from_micros(time_micros);
744
745 let time_tmp = already_happened() + time_dur;
746 ev.abs_send_time = Some(time_tmp);
747 }
748 AudioLevel => {
750 if buf.is_empty() {
751 return None;
752 }
753 ev.audio_level = Some(-(0x7f & buf[0] as i8));
754 ev.voice_activity = Some(buf[0] & 0x80 > 0);
755 }
756 TransmissionTimeOffset => {
758 if buf.len() < 4 {
759 return None;
760 }
761 ev.tx_time_offs = Some(u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]));
762 }
763 VideoOrientation => {
765 if buf.is_empty() {
766 return None;
767 }
768 ev.video_orientation = Some(super::ext::VideoOrientation::from(buf[0] & 3));
769 }
770 TransportSequenceNumber => {
772 if buf.len() < 2 {
773 return None;
774 }
775 ev.transport_cc = Some(u16::from_be_bytes([buf[0], buf[1]]));
776 }
777 PlayoutDelay => {
779 if buf.len() < 3 {
780 return None;
781 }
782 let min = (buf[0] as u32) << 4 | (buf[1] as u32) >> 4;
783 let max = ((buf[1] & 0xf) as u32) << 8 | buf[2] as u32;
784 ev.play_delay_min = Some(MediaTime::from_hundredths(min as u64));
785 ev.play_delay_max = Some(MediaTime::from_hundredths(max as u64));
786 }
787 VideoContentType => {
789 if buf.is_empty() {
790 return None;
791 }
792 ev.video_content_type = Some(buf[0]);
793 }
794 VideoTiming => {
796 if buf.len() < 9 {
797 return None;
798 }
799 ev.video_timing = Some(self::VideoTiming {
800 flags: buf[0],
801 encode_start: u16::from_be_bytes([buf[1], buf[2]]),
802 encode_finish: u16::from_be_bytes([buf[3], buf[4]]),
803 packetize_complete: u16::from_be_bytes([buf[5], buf[6]]),
804 last_left_pacer: u16::from_be_bytes([buf[7], buf[8]]),
805 });
808 }
809 RtpStreamId => {
810 let s = from_utf8(buf).ok()?;
811 ev.rid = Some(s.into());
812 }
813 RepairedRtpStreamId => {
814 let s = from_utf8(buf).ok()?;
815 ev.rid_repair = Some(s.into());
816 }
817 RtpMid => {
818 let s = from_utf8(buf).ok()?;
819 ev.mid = Some(s.into());
820 }
821 FrameMarking => {
822 if buf.len() < 4 {
823 return None;
824 }
825 ev.frame_mark = Some(u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]));
826 }
827 ColorSpace => {
828 }
830 UnknownUri(_, serializer) => {
831 let success = serializer.parse_value(buf, ev);
832 if !success {
833 return None;
834 }
835 }
836 }
837
838 Some(())
839 }
840}
841
842#[derive(Clone, Default, PartialEq, Eq)]
846pub struct ExtensionValues {
847 pub audio_level: Option<i8>,
849
850 pub voice_activity: Option<bool>,
852
853 pub video_orientation: Option<VideoOrientation>,
855
856 #[doc(hidden)]
860 pub video_content_type: Option<u8>, #[doc(hidden)]
862 pub tx_time_offs: Option<u32>,
863 #[doc(hidden)]
864 pub abs_send_time: Option<Instant>,
865 #[doc(hidden)]
866 pub transport_cc: Option<u16>, #[doc(hidden)]
868 pub play_delay_min: Option<MediaTime>,
870 #[doc(hidden)]
871 pub play_delay_max: Option<MediaTime>,
872 #[doc(hidden)]
873 pub video_timing: Option<VideoTiming>,
874 #[doc(hidden)]
875 pub rid: Option<Rid>,
876 #[doc(hidden)]
877 pub rid_repair: Option<Rid>,
878 #[doc(hidden)]
879 pub mid: Option<Mid>,
880 #[doc(hidden)]
881 pub frame_mark: Option<u32>,
882
883 pub user_values: UserExtensionValues,
885}
886impl ExtensionValues {
887 pub(crate) fn update_absolute_send_time(&mut self, now: Instant) {
888 let Some(v) = self.abs_send_time else {
889 return;
890 };
891
892 let relative_64_secs = v - already_happened();
894 assert!(relative_64_secs <= Duration::from_secs(64));
895
896 let now_since_epoch = now.to_unix_duration();
897
898 let closest_64 = now_since_epoch.saturating_sub(Duration::from_micros(
899 now_since_epoch.as_micros() as u64 % 64_000_000,
900 ));
901
902 let since_beginning = closest_64.saturating_sub(epoch_to_beginning());
903
904 let mut offset = already_happened() + since_beginning;
905
906 if offset + relative_64_secs > now {
907 offset -= Duration::from_secs(64);
908 }
909
910 self.abs_send_time = Some(offset + relative_64_secs);
911 }
912}
913
914#[derive(Clone, Default)]
916pub struct UserExtensionValues {
917 map: Option<AnyMap>,
918}
919
920type AnyMap = HashMap<TypeId, Arc<dyn Any + Send + Sync>, BuildHasherDefault<IdHasher>>;
922
923#[derive(Default)]
925struct IdHasher(u64);
926
927impl Hasher for IdHasher {
928 fn write(&mut self, _: &[u8]) {
929 unreachable!("TypeId calls write_u64");
930 }
931
932 #[inline]
933 fn write_u64(&mut self, id: u64) {
934 self.0 = id;
935 }
936
937 #[inline]
938 fn finish(&self) -> u64 {
939 self.0
940 }
941}
942
943impl PartialEq for UserExtensionValues {
945 fn eq(&self, other: &Self) -> bool {
946 let (Some(m1), Some(m2)) = (&self.map, &other.map) else {
947 return self.map.is_none() == other.map.is_none();
948 };
949
950 for k1 in m1.keys() {
951 if !m2.contains_key(k1) {
952 return false;
953 }
954 }
955
956 for k2 in m2.keys() {
957 if !m1.contains_key(k2) {
958 return false;
959 }
960 }
961
962 true
963 }
964}
965
966impl Eq for UserExtensionValues {}
967
968impl UserExtensionValues {
969 pub fn set<T: Send + Sync + 'static>(&mut self, val: T) {
985 self.map
987 .get_or_insert_with(HashMap::default)
988 .insert(TypeId::of::<T>(), Arc::new(val));
989 }
990
991 pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
1006 self.map
1007 .as_ref()
1008 .and_then(|map| map.get(&TypeId::of::<T>()))
1009 .map(|boxed| (&**boxed as &(dyn Any + 'static)).downcast_ref().unwrap())
1011 }
1012
1013 pub fn set_arc<T: Send + Sync + 'static>(&mut self, val: Arc<T>) {
1016 self.map
1017 .get_or_insert_with(HashMap::default)
1018 .insert(TypeId::of::<T>(), val);
1019 }
1020
1021 pub fn get_arc<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> {
1024 self.map
1025 .as_ref()?
1026 .get(&TypeId::of::<T>())?
1027 .clone()
1028 .downcast()
1029 .ok()
1030 }
1031}
1032
1033impl UnwindSafe for UserExtensionValues {}
1034
1035impl fmt::Debug for ExtensionValues {
1036 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1037 write!(f, "ExtensionValues {{")?;
1038
1039 if let Some(t) = self.mid {
1040 write!(f, " mid: {t}")?;
1041 }
1042 if let Some(t) = self.rid {
1043 write!(f, " rid: {t}")?;
1044 }
1045 if let Some(t) = self.rid_repair {
1046 write!(f, " rid_repair: {t}")?;
1047 }
1048 if let Some(t) = self.abs_send_time {
1049 write!(f, " abs_send_time: {:?}", t)?;
1050 }
1051 if let Some(t) = self.voice_activity {
1052 write!(f, " voice_activity: {t}")?;
1053 }
1054 if let Some(t) = self.audio_level {
1055 write!(f, " audio_level: {t}")?;
1056 }
1057 if let Some(t) = self.tx_time_offs {
1058 write!(f, " tx_time_offs: {t}")?;
1059 }
1060 if let Some(t) = self.video_orientation {
1061 write!(f, " video_orientation: {t:?}")?;
1062 }
1063 if let Some(t) = self.transport_cc {
1064 write!(f, " transport_cc: {t}")?;
1065 }
1066 if let Some(t) = self.play_delay_min {
1067 write!(f, " play_delay_min: {}", t.as_seconds())?;
1068 }
1069 if let Some(t) = self.play_delay_max {
1070 write!(f, " play_delay_max: {}", t.as_seconds())?;
1071 }
1072 if let Some(t) = self.video_content_type {
1073 write!(f, " video_content_type: {t}")?;
1074 }
1075 if let Some(t) = &self.video_timing {
1076 write!(f, " video_timing: {t:?}")?;
1077 }
1078 if let Some(t) = &self.frame_mark {
1079 write!(f, " frame_mark: {t}")?;
1080 }
1081
1082 write!(f, " }}")?;
1083 Ok(())
1084 }
1085}
1086
1087#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1088pub struct VideoTiming {
1089 pub flags: u8,
1092 pub encode_start: u16,
1093 pub encode_finish: u16,
1094 pub packetize_complete: u16,
1095 pub last_left_pacer: u16,
1096}
1097
1098impl fmt::Display for Extension {
1099 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1100 use Extension::*;
1101 write!(
1102 f,
1103 "{}",
1104 match self {
1105 AbsoluteSendTime => "abs-send-time",
1106 AudioLevel => "ssrc-audio-level",
1107 TransmissionTimeOffset => "toffset",
1108 VideoOrientation => "video-orientation",
1109 TransportSequenceNumber => "transport-wide-cc",
1110 PlayoutDelay => "playout-delay",
1111 VideoContentType => "video-content-type",
1112 VideoTiming => "video-timing",
1113 RtpStreamId => "rtp-stream-id",
1114 RepairedRtpStreamId => "repaired-rtp-stream-id",
1115 RtpMid => "mid",
1116 FrameMarking => "frame-marking07",
1117 ColorSpace => "color-space",
1118 UnknownUri(uri, _) => uri,
1119 }
1120 )
1121 }
1122}
1123
1124impl fmt::Debug for ExtensionMap {
1125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1126 write!(f, "Extensions(")?;
1127 let joined = self
1128 .0
1129 .iter()
1130 .enumerate()
1131 .filter_map(|(i, v)| v.as_ref().map(|v| (i + 1, v)))
1132 .map(|(i, v)| format!("{}={}", i, v.ext))
1133 .collect::<Vec<_>>()
1134 .join(", ");
1135 write!(f, "{joined}")?;
1136 write!(f, ")")?;
1137 Ok(())
1138 }
1139}
1140
1141#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1143pub enum VideoOrientation {
1144 Deg0 = 0,
1146 Deg90 = 3,
1148 Deg180 = 2,
1150 Deg270 = 1,
1152}
1153
1154impl From<u8> for VideoOrientation {
1155 fn from(value: u8) -> Self {
1156 match value {
1157 1 => Self::Deg270,
1158 2 => Self::Deg180,
1159 3 => Self::Deg90,
1160 _ => Self::Deg0,
1161 }
1162 }
1163}
1164
1165impl PartialEq for Extension {
1166 fn eq(&self, other: &Self) -> bool {
1167 match (self, other) {
1168 (Extension::AbsoluteSendTime, Extension::AbsoluteSendTime) => true,
1169 (Extension::AudioLevel, Extension::AudioLevel) => true,
1170 (Extension::TransmissionTimeOffset, Extension::TransmissionTimeOffset) => true,
1171 (Extension::VideoOrientation, Extension::VideoOrientation) => true,
1172 (Extension::TransportSequenceNumber, Extension::TransportSequenceNumber) => true,
1173 (Extension::PlayoutDelay, Extension::PlayoutDelay) => true,
1174 (Extension::VideoContentType, Extension::VideoContentType) => true,
1175 (Extension::VideoTiming, Extension::VideoTiming) => true,
1176 (Extension::RtpStreamId, Extension::RtpStreamId) => true,
1177 (Extension::RepairedRtpStreamId, Extension::RepairedRtpStreamId) => true,
1178 (Extension::RtpMid, Extension::RtpMid) => true,
1179 (Extension::FrameMarking, Extension::FrameMarking) => true,
1180 (Extension::ColorSpace, Extension::ColorSpace) => true,
1181 (Extension::UnknownUri(uri1, _), Extension::UnknownUri(uri2, _)) => uri1 == uri2,
1182 _ => false,
1183 }
1184 }
1185}
1186
1187impl Eq for Extension {}
1188
1189#[cfg(test)]
1190mod test {
1191 use super::*;
1192
1193 #[test]
1194 fn abs_send_time() {
1195 let now = Instant::now() + Duration::from_secs(1000);
1196
1197 let mut exts = ExtensionMap::empty();
1198 exts.set(4, Extension::AbsoluteSendTime);
1199 let ev = ExtensionValues {
1200 abs_send_time: Some(now),
1201 ..Default::default()
1202 };
1203
1204 let mut buf = vec![0_u8; 8];
1205 exts.write_to(&mut buf[..], &ev, ExtensionsForm::OneByte);
1206
1207 let mut ev2 = ExtensionValues::default();
1208 exts.parse(&buf, ExtensionsForm::OneByte, &mut ev2);
1209
1210 ev2.update_absolute_send_time(now + Duration::from_millis(50));
1212
1213 let now2 = ev2.abs_send_time.unwrap();
1214
1215 let abs = if now > now2 { now - now2 } else { now2 - now };
1216
1217 assert!(abs < Duration::from_millis(1));
1218 }
1219
1220 #[test]
1221 fn abs_send_time_two_byte_form() {
1222 let now = Instant::now() + Duration::from_secs(1000);
1223
1224 let mut exts = ExtensionMap::empty();
1225 exts.set(16, Extension::AbsoluteSendTime);
1226 let ev = ExtensionValues {
1227 abs_send_time: Some(now),
1228 ..Default::default()
1229 };
1230
1231 let mut buf = vec![0_u8; 8];
1232 assert_eq!(ExtensionsForm::TwoByte, exts.form(&ev));
1233 exts.write_to(&mut buf[..], &ev, ExtensionsForm::TwoByte);
1234
1235 let mut ev2 = ExtensionValues::default();
1236 exts.parse(&buf, ExtensionsForm::TwoByte, &mut ev2);
1237
1238 ev2.update_absolute_send_time(now + Duration::from_millis(50));
1240
1241 let now2 = ev2.abs_send_time.unwrap();
1242
1243 let abs = if now > now2 { now - now2 } else { now2 - now };
1244
1245 assert!(abs < Duration::from_millis(1));
1246 }
1247
1248 #[test]
1249 fn playout_delay() {
1250 let mut exts = ExtensionMap::empty();
1251 exts.set(2, Extension::PlayoutDelay);
1252 let ev = ExtensionValues {
1253 play_delay_min: Some(MediaTime::from_hundredths(100)),
1254 play_delay_max: Some(MediaTime::from_hundredths(200)),
1255 ..Default::default()
1256 };
1257
1258 let mut buf = vec![0_u8; 8];
1259 exts.write_to(&mut buf[..], &ev, ExtensionsForm::OneByte);
1260
1261 let mut ev2 = ExtensionValues::default();
1262 exts.parse(&buf, ExtensionsForm::OneByte, &mut ev2);
1263
1264 assert_eq!(ev.play_delay_min, ev2.play_delay_min);
1265 assert_eq!(ev.play_delay_max, ev2.play_delay_max);
1266 }
1267
1268 #[test]
1269 fn remap_exts_audio() {
1270 use Extension::*;
1271
1272 let mut e1 = ExtensionMap::standard();
1273 let mut e2 = ExtensionMap::empty();
1274 e2.set(14, TransportSequenceNumber);
1275
1276 println!("{:?}", e1.iter_video().collect::<Vec<_>>());
1277
1278 e1.remap(&e2.iter_audio().collect::<Vec<_>>());
1279
1280 assert_eq!(
1282 e1.iter_audio().collect::<Vec<_>>(),
1283 vec![
1284 (1, &AudioLevel),
1285 (2, &AbsoluteSendTime),
1286 (4, &RtpMid),
1287 (10, &RtpStreamId),
1288 (11, &RepairedRtpStreamId),
1289 (14, &TransportSequenceNumber)
1290 ]
1291 );
1292
1293 assert_eq!(
1295 e1.iter_video().collect::<Vec<_>>(),
1296 vec![
1297 (2, &AbsoluteSendTime),
1298 (4, &RtpMid),
1299 (10, &RtpStreamId),
1300 (11, &RepairedRtpStreamId),
1301 (13, &VideoOrientation),
1302 (14, &TransportSequenceNumber),
1303 ]
1304 );
1305 }
1306
1307 #[test]
1308 fn remap_exts_video() {
1309 use Extension::*;
1310
1311 let mut e1 = ExtensionMap::empty();
1312 e1.set(3, TransportSequenceNumber);
1313 e1.set(4, VideoOrientation);
1314 e1.set(5, VideoContentType);
1315 let mut e2 = ExtensionMap::empty();
1316 e2.set(14, TransportSequenceNumber);
1317 e2.set(12, VideoOrientation);
1318
1319 e1.remap(&e2.iter_video().collect::<Vec<_>>());
1320
1321 assert_eq!(
1323 e1.iter_video().collect::<Vec<_>>(),
1324 vec![
1325 (5, &VideoContentType),
1326 (12, &VideoOrientation),
1327 (14, &TransportSequenceNumber)
1328 ]
1329 );
1330 }
1331
1332 #[test]
1333 fn remap_exts_swaparoo() {
1334 use Extension::*;
1335
1336 let mut e1 = ExtensionMap::empty();
1337 e1.set(12, TransportSequenceNumber);
1338 e1.set(14, VideoOrientation);
1339 let mut e2 = ExtensionMap::empty();
1340 e2.set(14, TransportSequenceNumber);
1341 e2.set(12, VideoOrientation);
1342
1343 e1.remap(&e2.iter_video().collect::<Vec<_>>());
1344
1345 assert_eq!(
1347 e1.iter_video().collect::<Vec<_>>(),
1348 vec![(12, &VideoOrientation), (14, &TransportSequenceNumber)]
1349 );
1350 }
1351
1352 #[test]
1353 fn remap_exts_illegal() {
1354 use Extension::*;
1355
1356 let mut e1 = ExtensionMap::empty();
1357 e1.set(12, TransportSequenceNumber);
1358 e1.set(14, VideoOrientation);
1359
1360 let mut e2 = ExtensionMap::empty();
1361 e2.set(14, TransportSequenceNumber);
1362 e2.set(12, VideoOrientation);
1363
1364 let mut e3 = ExtensionMap::empty();
1365 e3.set(1, TransportSequenceNumber);
1367 e3.set(12, AudioLevel); e1.remap(&e2.iter_video().collect::<Vec<_>>());
1371
1372 println!("{:#?}", e1.0);
1373 assert_eq!(
1374 e1.iter_video().collect::<Vec<_>>(),
1375 vec![(12, &VideoOrientation), (14, &TransportSequenceNumber)]
1376 );
1377
1378 e1.remap(&e3.iter_audio().collect::<Vec<_>>());
1380
1381 println!("{:#?}", e1.0);
1382 assert_eq!(
1384 e1.iter_video().collect::<Vec<_>>(),
1385 vec![(12, &VideoOrientation), (14, &TransportSequenceNumber)]
1386 );
1387 }
1388}