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, SystemTime};
12
13use crate::util::InstantExt;
14use crate::util::SystemTimeExt;
15use crate::util::already_happened;
16use crate::util::epoch_to_beginning;
17
18use crate::rtp_::Frequency;
19
20use super::mtime::MediaTime;
21use super::{Mid, Rid};
22
23#[derive(Debug, Clone)]
25#[non_exhaustive]
26pub enum Extension {
27 AbsoluteSendTime,
29 AbsoluteCaptureTime,
31 AudioLevel,
33 TransmissionTimeOffset,
39 VideoOrientation,
41 TransportSequenceNumber,
43 PlayoutDelay,
45 VideoContentType,
47 VideoTiming,
49 RtpStreamId,
54 RepairedRtpStreamId,
59 RtpMid,
61 FrameMarking,
63 ColorSpace,
65
66 #[doc(hidden)]
68 UnknownUri(String, Arc<dyn ExtensionSerializer>),
69}
70
71#[repr(u16)]
77#[derive(Clone, Copy, PartialEq, Eq, Debug)]
78pub(crate) enum ExtensionsForm {
79 OneByte = 0xBEDE,
83 TwoByte = 0x1000,
87}
88
89pub const MAX_ID_ONE_BYTE_FORM: u8 = 14;
90pub const MAX_ID: u8 = 16;
93
94impl ExtensionsForm {
95 pub(crate) fn as_u16(self) -> u16 {
96 self as u16
97 }
98
99 pub(crate) fn serialize(self) -> [u8; 2] {
100 self.as_u16().to_be_bytes()
102 }
103
104 pub(crate) fn parse(bytes: [u8; 2]) -> Option<Self> {
105 let serialized = u16::from_be_bytes(bytes);
106 if serialized == ExtensionsForm::OneByte.as_u16() {
107 Some(ExtensionsForm::OneByte)
108 } else if (serialized & 0xFFF0) == ExtensionsForm::TwoByte.as_u16() {
110 Some(ExtensionsForm::TwoByte)
111 } else {
112 None
113 }
114 }
115}
116
117impl UnwindSafe for Extension {}
119
120pub trait ExtensionSerializer: Debug + Send + Sync + 'static {
122 fn write_to(&self, buf: &mut [u8], ev: &ExtensionValues) -> usize;
125
126 fn parse_value(&self, buf: &[u8], ev: &mut ExtensionValues) -> bool;
128
129 fn is_video(&self) -> bool;
131
132 fn is_audio(&self) -> bool;
134
135 fn requires_two_byte_form(&self, _ev: &ExtensionValues) -> bool {
139 false
140 }
141}
142
143impl Extension {
144 fn requires_two_byte_form(&self, ev: &ExtensionValues) -> bool {
145 match self {
146 Extension::UnknownUri(_, serializer) => serializer.requires_two_byte_form(ev),
147 _ => false,
148 }
149 }
150}
151
152#[derive(Debug)]
155struct SdpUnknownUri;
156
157impl ExtensionSerializer for SdpUnknownUri {
158 fn write_to(&self, _buf: &mut [u8], _ev: &ExtensionValues) -> usize {
160 unreachable!("Incorrect ExtensionSerializer::write_to")
161 }
162 fn parse_value(&self, _buf: &[u8], _ev: &mut ExtensionValues) -> bool {
163 unreachable!("Incorrect ExtensionSerializer::parse_value")
164 }
165 fn is_video(&self) -> bool {
166 unreachable!("Incorrect ExtensionSerializer::is_video")
167 }
168 fn is_audio(&self) -> bool {
169 unreachable!("Incorrect ExtensionSerializer::is_audio")
170 }
171}
172
173const EXT_URI: &[(Extension, &str)] = &[
175 (
176 Extension::AbsoluteSendTime,
177 "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time",
178 ),
179 (
180 Extension::AbsoluteCaptureTime,
181 "http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time",
182 ),
183 (
184 Extension::AudioLevel,
185 "urn:ietf:params:rtp-hdrext:ssrc-audio-level",
186 ),
187 (
188 Extension::TransmissionTimeOffset,
189 "urn:ietf:params:rtp-hdrext:toffset",
190 ),
191 (
192 Extension::VideoOrientation, "urn:3gpp:video-orientation",
194 ),
195 (
196 Extension::TransportSequenceNumber,
197 "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",
198 ),
199 (
200 Extension::PlayoutDelay,
201 "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay",
202 ),
203 (
204 Extension::VideoContentType,
205 "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type",
206 ),
207 (
208 Extension::VideoTiming,
209 "http://www.webrtc.org/experiments/rtp-hdrext/video-timing",
210 ),
211 (
212 Extension::RtpStreamId,
213 "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id",
214 ),
215 (
216 Extension::RepairedRtpStreamId,
217 "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id",
218 ),
219 (
220 Extension::RtpMid, "urn:ietf:params:rtp-hdrext:sdes:mid",
222 ),
223 (
224 Extension::FrameMarking,
225 "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07",
226 ),
227 (
228 Extension::ColorSpace,
229 "http://www.webrtc.org/experiments/rtp-hdrext/color-space",
230 ),
231];
232
233impl Extension {
234 pub(crate) fn from_sdp_uri(uri: &str) -> Self {
238 for (t, spec) in EXT_URI.iter() {
239 if *spec == uri {
240 return t.clone();
241 }
242 }
243
244 Extension::UnknownUri(uri.to_string(), Arc::new(SdpUnknownUri))
245 }
246
247 pub fn with_serializer(uri: &str, s: impl ExtensionSerializer) -> Self {
249 Extension::UnknownUri(uri.to_string(), Arc::new(s))
250 }
251
252 pub fn as_uri(&self) -> &str {
254 for (t, spec) in EXT_URI.iter() {
255 if t == self {
256 return spec;
257 }
258 }
259
260 if let Extension::UnknownUri(uri, _) = self {
261 return uri;
262 }
263
264 "unknown"
265 }
266
267 pub(crate) fn is_serialized(&self) -> bool {
268 if let Self::UnknownUri(_, s) = self {
269 let is_sdp = (s as &(dyn Any + 'static))
271 .downcast_ref::<SdpUnknownUri>()
272 .is_some();
273
274 if is_sdp {
279 panic!("is_serialized on SdpUnkownUri, this is a bug");
280 }
281 }
282 true
283 }
284
285 fn is_audio(&self) -> bool {
286 use Extension::*;
287
288 if let UnknownUri(_, serializer) = self {
289 return serializer.is_audio();
290 }
291
292 matches!(
293 self,
294 RtpStreamId
295 | RepairedRtpStreamId
296 | RtpMid
297 | AbsoluteSendTime
298 | AbsoluteCaptureTime
299 | AudioLevel
300 | TransportSequenceNumber
301 | TransmissionTimeOffset
302 | PlayoutDelay
303 )
304 }
305
306 fn is_video(&self) -> bool {
307 use Extension::*;
308
309 if let UnknownUri(_, serializer) = self {
310 return serializer.is_video();
311 }
312
313 matches!(
314 self,
315 RtpStreamId
316 | RepairedRtpStreamId
317 | RtpMid
318 | AbsoluteSendTime
319 | AbsoluteCaptureTime
320 | VideoOrientation
321 | TransportSequenceNumber
322 | TransmissionTimeOffset
323 | PlayoutDelay
324 | VideoContentType
325 | VideoTiming
326 | FrameMarking
327 | ColorSpace
328 )
329 }
330}
331
332#[derive(Clone, PartialEq, Eq)]
353pub struct ExtensionMap([Option<MapEntry>; MAX_ID as usize]); #[derive(Debug, Clone, PartialEq, Eq)]
356struct MapEntry {
357 ext: Extension,
358 locked: bool,
359}
360
361impl ExtensionMap {
362 pub fn empty() -> Self {
364 ExtensionMap(std::array::from_fn(|_| None))
365 }
366
367 pub fn standard() -> Self {
371 let mut exts = Self::empty();
372
373 exts.set(1, Extension::AudioLevel);
374 exts.set(2, Extension::AbsoluteSendTime);
375 exts.set(3, Extension::TransportSequenceNumber);
376 exts.set(4, Extension::RtpMid);
377 exts.set(10, Extension::RtpStreamId);
379 exts.set(11, Extension::RepairedRtpStreamId);
380 exts.set(13, Extension::VideoOrientation);
381
382 exts
383 }
384
385 pub(crate) fn clear(&mut self) {
386 for i in &mut self.0 {
387 *i = None;
388 }
389 }
390
391 pub fn set(&mut self, id: u8, ext: Extension) {
395 if id < 1 || id > MAX_ID {
396 debug!("Set RTP extension out of range 1-{}: {}", MAX_ID, id);
397 return;
398 }
399 let idx = id as usize - 1;
400
401 let m = MapEntry { ext, locked: false };
402
403 self.0[idx] = Some(m);
404 }
405
406 pub fn lookup(&self, id: u8) -> Option<&Extension> {
410 if id >= 1 && id <= MAX_ID {
411 self.0[id as usize - 1].as_ref().map(|m| &m.ext)
412 } else {
413 debug!("Lookup RTP extension out of range 1-{}: {}", MAX_ID, id);
414 None
415 }
416 }
417
418 pub fn id_of(&self, e: Extension) -> Option<u8> {
422 self.0
423 .iter()
424 .position(|x| x.as_ref().map(|e| &e.ext) == Some(&e))
425 .map(|p| p as u8 + 1)
426 }
427
428 pub fn iter(&self) -> impl Iterator<Item = (u8, &Extension)> + '_ {
430 self.0
431 .iter()
432 .enumerate()
433 .filter_map(|(i, e)| e.as_ref().map(|e| (i, e)))
434 .map(|(i, e)| ((i + 1) as u8, &e.ext))
435 }
436
437 pub fn iter_by_media_type(&self, audio: bool) -> impl Iterator<Item = (u8, &Extension)> + '_ {
439 self.iter().filter(move |(_id, ext)| {
440 if audio {
441 ext.is_audio()
442 } else {
443 ext.is_video()
444 }
445 })
446 }
447
448 #[allow(unused)]
450 pub fn iter_audio(&self) -> impl Iterator<Item = (u8, &Extension)> + '_ {
451 self.iter_by_media_type(true)
452 }
453
454 #[allow(unused)]
456 pub fn iter_video(&self) -> impl Iterator<Item = (u8, &Extension)> + '_ {
457 self.iter_by_media_type(false)
458 }
459
460 pub(crate) fn cloned_with_type(&self, audio: bool) -> Self {
461 let mut x = ExtensionMap::empty();
462 for (id, ext) in self.iter_by_media_type(audio) {
463 x.set(id, ext.clone());
464 }
465 x
466 }
467
468 pub(crate) fn parse(
470 &self,
471 mut buf: &[u8],
472 form: ExtensionsForm,
473 ext_vals: &mut ExtensionValues,
474 ) {
475 loop {
476 if buf.is_empty() {
477 return;
478 }
479
480 if buf[0] == 0 {
481 buf = &buf[1..];
483 continue;
484 }
485
486 let (id, len) = match form {
487 ExtensionsForm::OneByte => {
488 let id = buf[0] >> 4;
489 let len = (buf[0] & 0xf) as usize + 1;
490 buf = &buf[1..];
491
492 if id == 15 {
493 return;
499 }
500 (id, len)
501 }
502 ExtensionsForm::TwoByte => {
503 if buf.len() < 2 {
504 trace!("Not enough ext header len: {} < {}", buf.len(), 2);
505 return;
506 }
507 let id = buf[0];
508 let len = buf[1] as usize;
509 buf = &buf[2..];
510 (id, len)
511 }
512 };
513
514 if buf.len() < len {
515 trace!("Not enough type ext len: {} < {}", buf.len(), len);
516 return;
517 }
518
519 let ext_buf = &buf[..len];
520 if let Some(ext) = self.lookup(id) {
521 ext.parse_value(ext_buf, ext_vals);
522 }
523
524 buf = &buf[len..];
525 }
526 }
527
528 pub(crate) fn form(&self, ev: &ExtensionValues) -> ExtensionsForm {
529 if self
530 .iter()
531 .any(|(id, ext)| id > MAX_ID_ONE_BYTE_FORM || ext.requires_two_byte_form(ev))
532 {
533 ExtensionsForm::TwoByte
534 } else {
535 ExtensionsForm::OneByte
536 }
537 }
538
539 pub(crate) fn write_to(
540 &self,
541 ext_buf: &mut [u8],
542 ev: &ExtensionValues,
543 form: ExtensionsForm,
544 ) -> usize {
545 let orig_len = ext_buf.len();
546 let mut b = ext_buf;
547
548 for (idx, x) in self.0.iter().enumerate() {
549 if let Some(v) = x {
550 match form {
551 ExtensionsForm::OneByte => {
552 if let Some(n) = v.ext.write_to(&mut b[1..], ev) {
553 assert!(n <= 16);
554 assert!(n > 0);
555 b[0] = (idx as u8 + 1) << 4 | (n as u8 - 1);
556 b = &mut b[1 + n..];
557 }
558 }
559 ExtensionsForm::TwoByte => {
560 if let Some(n) = v.ext.write_to(&mut b[2..], ev) {
561 b[0] = (idx + 1) as u8;
562 b[1] = n as u8;
563 b = &mut b[2 + n..];
564 }
565 }
566 };
567 }
568 }
569
570 orig_len - b.len()
571 }
572
573 pub(crate) fn remap(&mut self, remote_exts: &[(u8, &Extension)]) {
574 for (id, ext) in remote_exts {
576 self.swap(*id, ext);
577 }
578 }
579
580 fn swap(&mut self, id: u8, ext: &Extension) {
581 if id < 1 || id > MAX_ID {
582 return;
583 }
584
585 let new_index = id as usize - 1;
587
588 let Some(old_index) = self
589 .0
590 .iter()
591 .enumerate()
592 .find(|(_, m)| m.as_ref().map(|m| &m.ext) == Some(ext))
593 .map(|(i, _)| i)
594 else {
595 return;
596 };
597
598 let old = self.0[old_index].as_mut().unwrap();
600
601 let is_change = new_index != old_index;
602
603 if is_change && old.locked {
605 warn!(
606 "Extmap locked by previous negotiation. Ignore change: {} -> {}",
607 old_index, new_index
608 );
609 return;
610 }
611
612 old.locked = true;
614
615 if !is_change {
616 return;
617 }
618
619 self.0.swap(old_index, new_index);
620 }
621}
622
623impl Extension {
624 pub(crate) fn write_to(&self, buf: &mut [u8], ev: &ExtensionValues) -> Option<usize> {
625 use Extension::*;
626 match self {
627 AbsoluteSendTime => {
628 let time_abs = ev.abs_send_time?;
633
634 let dur = time_abs.to_unix_duration();
636
637 let time_24 = MediaTime::from(dur)
639 .rebase(Frequency::FIXED_POINT_6_18)
640 .numer() as u32;
641
642 buf[..3].copy_from_slice(&time_24.to_be_bytes()[1..]);
643 Some(3)
644 }
645 AbsoluteCaptureTime => {
646 let act = ev.abs_capture_time.as_ref()?;
647 let ntp_64 = act.capture_time.as_ntp_64();
648
649 if let Some(offset) = act.clock_offset {
650 if buf.len() < 16 {
651 return None;
652 }
653 buf[..8].copy_from_slice(&ntp_64.to_be_bytes());
654 buf[8..16].copy_from_slice(&offset.to_be_bytes());
655 Some(16)
656 } else {
657 if buf.len() < 8 {
658 return None;
659 }
660 buf[..8].copy_from_slice(&ntp_64.to_be_bytes());
661 Some(8)
662 }
663 }
664 AudioLevel => {
665 let v1 = ev.audio_level?;
666 let v2 = ev.voice_activity?;
667 buf[0] = if v2 { 0x80 } else { 0 } | (-(0x7f & v1) as u8);
668 Some(1)
669 }
670 TransmissionTimeOffset => {
671 let v = ev.tx_time_offs?;
672 buf[..4].copy_from_slice(&v.to_be_bytes());
673 Some(4)
674 }
675 VideoOrientation => {
676 let v = ev.video_orientation?;
677 buf[0] = v as u8;
678 Some(1)
679 }
680 TransportSequenceNumber => {
681 let v = ev.transport_cc?;
682 buf[..2].copy_from_slice(&v.to_be_bytes());
683 Some(2)
684 }
685 PlayoutDelay => {
686 let v1 = ev.play_delay_min?.rebase(Frequency::HUNDREDTHS);
687 let v2 = ev.play_delay_max?.rebase(Frequency::HUNDREDTHS);
688 let min = (v1.numer() & 0xfff) as u32;
689 let max = (v2.numer() & 0xfff) as u32;
690 buf[0] = (min >> 4) as u8;
691 buf[1] = (min << 4) as u8 | (max >> 8) as u8;
692 buf[2] = max as u8;
693 Some(3)
694 }
695 VideoContentType => {
696 let v = ev.video_content_type?;
697 buf[0] = v;
698 Some(1)
699 }
700 VideoTiming => {
701 let v = ev.video_timing?;
702 buf[0] = v.flags;
703 buf[1..3].copy_from_slice(&v.encode_start.to_be_bytes());
704 buf[3..5].copy_from_slice(&v.encode_finish.to_be_bytes());
705 buf[5..7].copy_from_slice(&v.packetize_complete.to_be_bytes());
706 buf[7..9].copy_from_slice(&v.last_left_pacer.to_be_bytes());
707 buf[9..11].copy_from_slice(&0_u16.to_be_bytes());
709 buf[11..13].copy_from_slice(&0_u16.to_be_bytes());
710 Some(13)
711 }
712 RtpStreamId => {
713 let v = ev.rid?;
714 let l = v.len();
715 buf[..l].copy_from_slice(v.as_bytes());
716 Some(l)
717 }
718 RepairedRtpStreamId => {
719 let v = ev.rid_repair?;
720 let l = v.len();
721 buf[..l].copy_from_slice(v.as_bytes());
722 Some(l)
723 }
724 RtpMid => {
725 let v = ev.mid?;
726 let l = v.len();
727 buf[..l].copy_from_slice(v.as_bytes());
728 Some(l)
729 }
730 FrameMarking => {
731 let v = ev.frame_mark?;
732 buf[..4].copy_from_slice(&v.to_be_bytes());
733 Some(4)
734 }
735 ColorSpace => {
736 None
738 }
739 UnknownUri(_, serializer) => {
740 let n = serializer.write_to(buf, ev);
741
742 if n == 0 { None } else { Some(n) }
743 }
744 }
745 }
746
747 pub(crate) fn parse_value(&self, buf: &[u8], ev: &mut ExtensionValues) -> Option<()> {
748 use Extension::*;
749 match self {
750 AbsoluteSendTime => {
752 if buf.len() < 3 {
755 return None;
756 }
757 let time_24 = u32::from_be_bytes([0, buf[0], buf[1], buf[2]]);
758
759 let time_micros = MediaTime::from_fixed_point_6_18(time_24 as u64)
761 .rebase(Frequency::MICROS)
762 .numer();
763
764 let time_dur = Duration::from_micros(time_micros);
768
769 let time_tmp = already_happened() + time_dur;
770 ev.abs_send_time = Some(time_tmp);
771 }
772 AbsoluteCaptureTime => {
774 if buf.len() < 8 {
775 return None;
776 }
777 let ntp_64 = u64::from_be_bytes(buf[..8].try_into().unwrap());
778 let clock_offset =
779 (buf.len() >= 16).then(|| i64::from_be_bytes(buf[8..16].try_into().unwrap()));
780 ev.abs_capture_time = Some(AbsCaptureTime {
781 capture_time: SystemTime::from_ntp_64(ntp_64),
782 clock_offset,
783 });
784 }
785 AudioLevel => {
787 if buf.is_empty() {
788 return None;
789 }
790 ev.audio_level = Some(-(0x7f & buf[0] as i8));
791 ev.voice_activity = Some(buf[0] & 0x80 > 0);
792 }
793 TransmissionTimeOffset => {
795 if buf.len() < 4 {
796 return None;
797 }
798 ev.tx_time_offs = Some(u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]));
799 }
800 VideoOrientation => {
802 if buf.is_empty() {
803 return None;
804 }
805 ev.video_orientation = Some(super::ext::VideoOrientation::from(buf[0] & 3));
806 }
807 TransportSequenceNumber => {
809 if buf.len() < 2 {
810 return None;
811 }
812 ev.transport_cc = Some(u16::from_be_bytes([buf[0], buf[1]]));
813 }
814 PlayoutDelay => {
816 if buf.len() < 3 {
817 return None;
818 }
819 let min = (buf[0] as u32) << 4 | (buf[1] as u32) >> 4;
820 let max = ((buf[1] & 0xf) as u32) << 8 | buf[2] as u32;
821 ev.play_delay_min = Some(MediaTime::from_hundredths(min as u64));
822 ev.play_delay_max = Some(MediaTime::from_hundredths(max as u64));
823 }
824 VideoContentType => {
826 if buf.is_empty() {
827 return None;
828 }
829 ev.video_content_type = Some(buf[0]);
830 }
831 VideoTiming => {
833 if buf.len() < 9 {
834 return None;
835 }
836 ev.video_timing = Some(self::VideoTiming {
837 flags: buf[0],
838 encode_start: u16::from_be_bytes([buf[1], buf[2]]),
839 encode_finish: u16::from_be_bytes([buf[3], buf[4]]),
840 packetize_complete: u16::from_be_bytes([buf[5], buf[6]]),
841 last_left_pacer: u16::from_be_bytes([buf[7], buf[8]]),
842 });
845 }
846 RtpStreamId => {
847 let s = from_utf8(buf).ok()?;
848 ev.rid = Some(s.into());
849 }
850 RepairedRtpStreamId => {
851 let s = from_utf8(buf).ok()?;
852 ev.rid_repair = Some(s.into());
853 }
854 RtpMid => {
855 let s = from_utf8(buf).ok()?;
856 ev.mid = Some(s.into());
857 }
858 FrameMarking => {
859 if buf.len() < 4 {
860 return None;
861 }
862 ev.frame_mark = Some(u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]));
863 }
864 ColorSpace => {
865 }
867 UnknownUri(_, serializer) => {
868 let success = serializer.parse_value(buf, ev);
869 if !success {
870 return None;
871 }
872 }
873 }
874
875 Some(())
876 }
877}
878
879#[derive(Clone, Default, PartialEq, Eq)]
883pub struct ExtensionValues {
884 pub audio_level: Option<i8>,
886
887 pub voice_activity: Option<bool>,
889
890 pub video_orientation: Option<VideoOrientation>,
892
893 #[doc(hidden)]
897 pub video_content_type: Option<u8>, #[doc(hidden)]
899 pub tx_time_offs: Option<u32>,
900 #[doc(hidden)]
901 pub abs_send_time: Option<Instant>,
902 #[doc(hidden)]
903 pub abs_capture_time: Option<AbsCaptureTime>,
904 #[doc(hidden)]
905 pub transport_cc: Option<u16>, #[doc(hidden)]
907 pub play_delay_min: Option<MediaTime>,
909 #[doc(hidden)]
910 pub play_delay_max: Option<MediaTime>,
911 #[doc(hidden)]
912 pub video_timing: Option<VideoTiming>,
913 #[doc(hidden)]
914 pub rid: Option<Rid>,
915 #[doc(hidden)]
916 pub rid_repair: Option<Rid>,
917 #[doc(hidden)]
918 pub mid: Option<Mid>,
919 #[doc(hidden)]
920 pub frame_mark: Option<u32>,
921
922 pub user_values: UserExtensionValues,
924}
925impl ExtensionValues {
926 pub(crate) fn update_absolute_send_time(&mut self, now: Instant) {
927 let Some(v) = self.abs_send_time else {
928 return;
929 };
930
931 let relative_64_secs = v - already_happened();
933 assert!(relative_64_secs <= Duration::from_secs(64));
934
935 let now_since_epoch = now.to_unix_duration();
936
937 let closest_64 = now_since_epoch.saturating_sub(Duration::from_micros(
938 now_since_epoch.as_micros() as u64 % 64_000_000,
939 ));
940
941 let since_beginning = closest_64.saturating_sub(epoch_to_beginning());
942
943 let mut offset = already_happened() + since_beginning;
944
945 if offset + relative_64_secs > now {
946 offset -= Duration::from_secs(64);
947 }
948
949 self.abs_send_time = Some(offset + relative_64_secs);
950 }
951}
952
953#[derive(Clone, Default)]
955pub struct UserExtensionValues {
956 map: Option<AnyMap>,
957}
958
959type AnyMap = HashMap<TypeId, Arc<dyn Any + Send + Sync>, BuildHasherDefault<IdHasher>>;
961
962#[derive(Default)]
964struct IdHasher(u64);
965
966impl Hasher for IdHasher {
967 fn write(&mut self, _: &[u8]) {
968 unreachable!("TypeId calls write_u64");
969 }
970
971 #[inline]
972 fn write_u64(&mut self, id: u64) {
973 self.0 = id;
974 }
975
976 #[inline]
977 fn finish(&self) -> u64 {
978 self.0
979 }
980}
981
982impl PartialEq for UserExtensionValues {
984 fn eq(&self, other: &Self) -> bool {
985 let (Some(m1), Some(m2)) = (&self.map, &other.map) else {
986 return self.map.is_none() == other.map.is_none();
987 };
988
989 for k1 in m1.keys() {
990 if !m2.contains_key(k1) {
991 return false;
992 }
993 }
994
995 for k2 in m2.keys() {
996 if !m1.contains_key(k2) {
997 return false;
998 }
999 }
1000
1001 true
1002 }
1003}
1004
1005impl Eq for UserExtensionValues {}
1006
1007impl UserExtensionValues {
1008 pub fn set<T: Send + Sync + 'static>(&mut self, val: T) {
1024 self.map
1026 .get_or_insert_with(HashMap::default)
1027 .insert(TypeId::of::<T>(), Arc::new(val));
1028 }
1029
1030 pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
1045 self.map
1046 .as_ref()
1047 .and_then(|map| map.get(&TypeId::of::<T>()))
1048 .map(|boxed| (&**boxed as &(dyn Any + 'static)).downcast_ref().unwrap())
1050 }
1051
1052 pub fn set_arc<T: Send + Sync + 'static>(&mut self, val: Arc<T>) {
1055 self.map
1056 .get_or_insert_with(HashMap::default)
1057 .insert(TypeId::of::<T>(), val);
1058 }
1059
1060 pub fn get_arc<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> {
1063 self.map
1064 .as_ref()?
1065 .get(&TypeId::of::<T>())?
1066 .clone()
1067 .downcast()
1068 .ok()
1069 }
1070
1071 pub fn remove<T: Send + Sync + 'static>(&mut self) {
1073 if let Some(map) = &mut self.map {
1074 map.remove(&TypeId::of::<T>());
1075 }
1076 }
1077}
1078
1079impl UnwindSafe for UserExtensionValues {}
1080
1081impl fmt::Debug for ExtensionValues {
1082 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1083 write!(f, "ExtensionValues {{")?;
1084
1085 if let Some(t) = self.mid {
1086 write!(f, " mid: {t}")?;
1087 }
1088 if let Some(t) = self.rid {
1089 write!(f, " rid: {t}")?;
1090 }
1091 if let Some(t) = self.rid_repair {
1092 write!(f, " rid_repair: {t}")?;
1093 }
1094 if let Some(t) = self.abs_send_time {
1095 write!(f, " abs_send_time: {:?}", t)?;
1096 }
1097 if let Some(t) = &self.abs_capture_time {
1098 write!(f, " abs_capture_time: {:?}", t)?;
1099 }
1100 if let Some(t) = self.voice_activity {
1101 write!(f, " voice_activity: {t}")?;
1102 }
1103 if let Some(t) = self.audio_level {
1104 write!(f, " audio_level: {t}")?;
1105 }
1106 if let Some(t) = self.tx_time_offs {
1107 write!(f, " tx_time_offs: {t}")?;
1108 }
1109 if let Some(t) = self.video_orientation {
1110 write!(f, " video_orientation: {t:?}")?;
1111 }
1112 if let Some(t) = self.transport_cc {
1113 write!(f, " transport_cc: {t}")?;
1114 }
1115 if let Some(t) = self.play_delay_min {
1116 write!(f, " play_delay_min: {}", t.as_seconds())?;
1117 }
1118 if let Some(t) = self.play_delay_max {
1119 write!(f, " play_delay_max: {}", t.as_seconds())?;
1120 }
1121 if let Some(t) = self.video_content_type {
1122 write!(f, " video_content_type: {t}")?;
1123 }
1124 if let Some(t) = &self.video_timing {
1125 write!(f, " video_timing: {t:?}")?;
1126 }
1127 if let Some(t) = &self.frame_mark {
1128 write!(f, " frame_mark: {t}")?;
1129 }
1130
1131 write!(f, " }}")?;
1132 Ok(())
1133 }
1134}
1135
1136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1142pub struct AbsCaptureTime {
1143 pub capture_time: SystemTime,
1145 pub clock_offset: Option<i64>,
1149}
1150
1151const NTP_F32: f64 = 4_294_967_296.0;
1153
1154impl AbsCaptureTime {
1155 pub fn clock_offset_secs(&self) -> Option<f64> {
1159 self.clock_offset.map(|v| v as f64 / NTP_F32)
1160 }
1161
1162 pub fn set_clock_offset(&mut self, secs: f64) {
1164 self.clock_offset = Some((secs * NTP_F32) as i64);
1165 }
1166}
1167
1168#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1169pub struct VideoTiming {
1170 pub flags: u8,
1173 pub encode_start: u16,
1174 pub encode_finish: u16,
1175 pub packetize_complete: u16,
1176 pub last_left_pacer: u16,
1177}
1178
1179impl fmt::Display for Extension {
1180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1181 use Extension::*;
1182 write!(
1183 f,
1184 "{}",
1185 match self {
1186 AbsoluteSendTime => "abs-send-time",
1187 AbsoluteCaptureTime => "abs-capture-time",
1188 AudioLevel => "ssrc-audio-level",
1189 TransmissionTimeOffset => "toffset",
1190 VideoOrientation => "video-orientation",
1191 TransportSequenceNumber => "transport-wide-cc",
1192 PlayoutDelay => "playout-delay",
1193 VideoContentType => "video-content-type",
1194 VideoTiming => "video-timing",
1195 RtpStreamId => "rtp-stream-id",
1196 RepairedRtpStreamId => "repaired-rtp-stream-id",
1197 RtpMid => "mid",
1198 FrameMarking => "frame-marking07",
1199 ColorSpace => "color-space",
1200 UnknownUri(uri, _) => uri,
1201 }
1202 )
1203 }
1204}
1205
1206impl fmt::Debug for ExtensionMap {
1207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1208 write!(f, "Extensions(")?;
1209 let joined = self
1210 .0
1211 .iter()
1212 .enumerate()
1213 .filter_map(|(i, v)| v.as_ref().map(|v| (i + 1, v)))
1214 .map(|(i, v)| format!("{}={}", i, v.ext))
1215 .collect::<Vec<_>>()
1216 .join(", ");
1217 write!(f, "{joined}")?;
1218 write!(f, ")")?;
1219 Ok(())
1220 }
1221}
1222
1223#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1225pub enum VideoOrientation {
1226 Deg0 = 0,
1228 Deg90 = 3,
1230 Deg180 = 2,
1232 Deg270 = 1,
1234}
1235
1236#[cfg(feature = "drv")]
1237crate::drv_identity_copy!(VideoOrientation);
1238
1239impl From<u8> for VideoOrientation {
1240 fn from(value: u8) -> Self {
1241 match value {
1242 1 => Self::Deg270,
1243 2 => Self::Deg180,
1244 3 => Self::Deg90,
1245 _ => Self::Deg0,
1246 }
1247 }
1248}
1249
1250impl PartialEq for Extension {
1251 fn eq(&self, other: &Self) -> bool {
1252 match (self, other) {
1253 (Extension::AbsoluteSendTime, Extension::AbsoluteSendTime) => true,
1254 (Extension::AbsoluteCaptureTime, Extension::AbsoluteCaptureTime) => true,
1255 (Extension::AudioLevel, Extension::AudioLevel) => true,
1256 (Extension::TransmissionTimeOffset, Extension::TransmissionTimeOffset) => true,
1257 (Extension::VideoOrientation, Extension::VideoOrientation) => true,
1258 (Extension::TransportSequenceNumber, Extension::TransportSequenceNumber) => true,
1259 (Extension::PlayoutDelay, Extension::PlayoutDelay) => true,
1260 (Extension::VideoContentType, Extension::VideoContentType) => true,
1261 (Extension::VideoTiming, Extension::VideoTiming) => true,
1262 (Extension::RtpStreamId, Extension::RtpStreamId) => true,
1263 (Extension::RepairedRtpStreamId, Extension::RepairedRtpStreamId) => true,
1264 (Extension::RtpMid, Extension::RtpMid) => true,
1265 (Extension::FrameMarking, Extension::FrameMarking) => true,
1266 (Extension::ColorSpace, Extension::ColorSpace) => true,
1267 (Extension::UnknownUri(uri1, _), Extension::UnknownUri(uri2, _)) => uri1 == uri2,
1268 _ => false,
1269 }
1270 }
1271}
1272
1273impl Eq for Extension {}
1274
1275#[cfg(test)]
1276mod test {
1277 use super::*;
1278
1279 #[test]
1280 fn abs_send_time() {
1281 let now = Instant::now() + Duration::from_secs(1000);
1282
1283 let mut exts = ExtensionMap::empty();
1284 exts.set(4, Extension::AbsoluteSendTime);
1285 let ev = ExtensionValues {
1286 abs_send_time: Some(now),
1287 ..Default::default()
1288 };
1289
1290 let mut buf = vec![0_u8; 8];
1291 exts.write_to(&mut buf[..], &ev, ExtensionsForm::OneByte);
1292
1293 let mut ev2 = ExtensionValues::default();
1294 exts.parse(&buf, ExtensionsForm::OneByte, &mut ev2);
1295
1296 ev2.update_absolute_send_time(now + Duration::from_millis(50));
1298
1299 let now2 = ev2.abs_send_time.unwrap();
1300
1301 let abs = if now > now2 { now - now2 } else { now2 - now };
1302
1303 assert!(abs < Duration::from_millis(1));
1304 }
1305
1306 #[test]
1307 fn abs_send_time_two_byte_form() {
1308 let now = Instant::now() + Duration::from_secs(1000);
1309
1310 let mut exts = ExtensionMap::empty();
1311 exts.set(16, Extension::AbsoluteSendTime);
1312 let ev = ExtensionValues {
1313 abs_send_time: Some(now),
1314 ..Default::default()
1315 };
1316
1317 let mut buf = vec![0_u8; 8];
1318 assert_eq!(ExtensionsForm::TwoByte, exts.form(&ev));
1319 exts.write_to(&mut buf[..], &ev, ExtensionsForm::TwoByte);
1320
1321 let mut ev2 = ExtensionValues::default();
1322 exts.parse(&buf, ExtensionsForm::TwoByte, &mut ev2);
1323
1324 ev2.update_absolute_send_time(now + Duration::from_millis(50));
1326
1327 let now2 = ev2.abs_send_time.unwrap();
1328
1329 let abs = if now > now2 { now - now2 } else { now2 - now };
1330
1331 assert!(abs < Duration::from_millis(1));
1332 }
1333
1334 #[test]
1335 fn abs_capture_time_short_form() {
1336 let now = SystemTime::now();
1337
1338 let mut exts = ExtensionMap::empty();
1339 exts.set(5, Extension::AbsoluteCaptureTime);
1340 let ev = ExtensionValues {
1341 abs_capture_time: Some(AbsCaptureTime {
1342 capture_time: now,
1343 clock_offset: None,
1344 }),
1345 ..Default::default()
1346 };
1347
1348 let mut buf = vec![0_u8; 16];
1349 exts.write_to(&mut buf[..], &ev, ExtensionsForm::OneByte);
1350
1351 let mut ev2 = ExtensionValues::default();
1352 exts.parse(&buf, ExtensionsForm::OneByte, &mut ev2);
1353
1354 let act = ev2.abs_capture_time.unwrap();
1355
1356 let abs = if now > act.capture_time {
1358 now.duration_since(act.capture_time)
1359 } else {
1360 act.capture_time.duration_since(now)
1361 }
1362 .unwrap();
1363
1364 assert!(abs < Duration::from_millis(1));
1365 assert_eq!(act.clock_offset, None);
1366 }
1367
1368 #[test]
1369 fn abs_capture_time_extended_form() {
1370 let now = SystemTime::now();
1371 let clock_offset: i64 = 123456789;
1372
1373 let mut exts = ExtensionMap::empty();
1374 exts.set(5, Extension::AbsoluteCaptureTime);
1375 let ev = ExtensionValues {
1376 abs_capture_time: Some(AbsCaptureTime {
1377 capture_time: now,
1378 clock_offset: Some(clock_offset),
1379 }),
1380 ..Default::default()
1381 };
1382
1383 let mut buf = vec![0_u8; 24];
1384 exts.write_to(&mut buf[..], &ev, ExtensionsForm::OneByte);
1385
1386 let mut ev2 = ExtensionValues::default();
1387 exts.parse(&buf, ExtensionsForm::OneByte, &mut ev2);
1388
1389 let act = ev2.abs_capture_time.unwrap();
1390
1391 let abs = if now > act.capture_time {
1393 now.duration_since(act.capture_time)
1394 } else {
1395 act.capture_time.duration_since(now)
1396 }
1397 .unwrap();
1398
1399 assert!(abs < Duration::from_millis(1));
1400 assert_eq!(act.clock_offset, Some(clock_offset));
1401 }
1402
1403 #[test]
1404 fn abs_capture_time_two_byte_form() {
1405 let now = SystemTime::now();
1406 let clock_offset: i64 = -987654321;
1407
1408 let mut exts = ExtensionMap::empty();
1409 exts.set(16, Extension::AbsoluteCaptureTime);
1410 let ev = ExtensionValues {
1411 abs_capture_time: Some(AbsCaptureTime {
1412 capture_time: now,
1413 clock_offset: Some(clock_offset),
1414 }),
1415 ..Default::default()
1416 };
1417
1418 assert_eq!(ExtensionsForm::TwoByte, exts.form(&ev));
1420
1421 let mut buf = vec![0_u8; 24];
1422 exts.write_to(&mut buf[..], &ev, ExtensionsForm::TwoByte);
1423
1424 let mut ev2 = ExtensionValues::default();
1425 exts.parse(&buf, ExtensionsForm::TwoByte, &mut ev2);
1426
1427 let act = ev2.abs_capture_time.unwrap();
1428
1429 let abs = if now > act.capture_time {
1431 now.duration_since(act.capture_time)
1432 } else {
1433 act.capture_time.duration_since(now)
1434 }
1435 .unwrap();
1436
1437 assert!(abs < Duration::from_millis(1));
1438 assert_eq!(act.clock_offset, Some(clock_offset));
1439 }
1440
1441 #[test]
1442 fn playout_delay() {
1443 let mut exts = ExtensionMap::empty();
1444 exts.set(2, Extension::PlayoutDelay);
1445 let ev = ExtensionValues {
1446 play_delay_min: Some(MediaTime::from_hundredths(100)),
1447 play_delay_max: Some(MediaTime::from_hundredths(200)),
1448 ..Default::default()
1449 };
1450
1451 let mut buf = vec![0_u8; 8];
1452 exts.write_to(&mut buf[..], &ev, ExtensionsForm::OneByte);
1453
1454 let mut ev2 = ExtensionValues::default();
1455 exts.parse(&buf, ExtensionsForm::OneByte, &mut ev2);
1456
1457 assert_eq!(ev.play_delay_min, ev2.play_delay_min);
1458 assert_eq!(ev.play_delay_max, ev2.play_delay_max);
1459 }
1460
1461 #[test]
1462 fn remap_exts_audio() {
1463 use Extension::*;
1464
1465 let mut e1 = ExtensionMap::standard();
1466 let mut e2 = ExtensionMap::empty();
1467 e2.set(14, TransportSequenceNumber);
1468
1469 println!("{:?}", e1.iter_video().collect::<Vec<_>>());
1470
1471 e1.remap(&e2.iter_audio().collect::<Vec<_>>());
1472
1473 assert_eq!(
1475 e1.iter_audio().collect::<Vec<_>>(),
1476 vec![
1477 (1, &AudioLevel),
1478 (2, &AbsoluteSendTime),
1479 (4, &RtpMid),
1480 (10, &RtpStreamId),
1481 (11, &RepairedRtpStreamId),
1482 (14, &TransportSequenceNumber)
1483 ]
1484 );
1485
1486 assert_eq!(
1488 e1.iter_video().collect::<Vec<_>>(),
1489 vec![
1490 (2, &AbsoluteSendTime),
1491 (4, &RtpMid),
1492 (10, &RtpStreamId),
1493 (11, &RepairedRtpStreamId),
1494 (13, &VideoOrientation),
1495 (14, &TransportSequenceNumber),
1496 ]
1497 );
1498 }
1499
1500 #[test]
1501 fn remap_exts_video() {
1502 use Extension::*;
1503
1504 let mut e1 = ExtensionMap::empty();
1505 e1.set(3, TransportSequenceNumber);
1506 e1.set(4, VideoOrientation);
1507 e1.set(5, VideoContentType);
1508 let mut e2 = ExtensionMap::empty();
1509 e2.set(14, TransportSequenceNumber);
1510 e2.set(12, VideoOrientation);
1511
1512 e1.remap(&e2.iter_video().collect::<Vec<_>>());
1513
1514 assert_eq!(
1516 e1.iter_video().collect::<Vec<_>>(),
1517 vec![
1518 (5, &VideoContentType),
1519 (12, &VideoOrientation),
1520 (14, &TransportSequenceNumber)
1521 ]
1522 );
1523 }
1524
1525 #[test]
1526 fn remap_exts_swaparoo() {
1527 use Extension::*;
1528
1529 let mut e1 = ExtensionMap::empty();
1530 e1.set(12, TransportSequenceNumber);
1531 e1.set(14, VideoOrientation);
1532 let mut e2 = ExtensionMap::empty();
1533 e2.set(14, TransportSequenceNumber);
1534 e2.set(12, VideoOrientation);
1535
1536 e1.remap(&e2.iter_video().collect::<Vec<_>>());
1537
1538 assert_eq!(
1540 e1.iter_video().collect::<Vec<_>>(),
1541 vec![(12, &VideoOrientation), (14, &TransportSequenceNumber)]
1542 );
1543 }
1544
1545 #[test]
1546 fn remap_exts_illegal() {
1547 use Extension::*;
1548
1549 let mut e1 = ExtensionMap::empty();
1550 e1.set(12, TransportSequenceNumber);
1551 e1.set(14, VideoOrientation);
1552
1553 let mut e2 = ExtensionMap::empty();
1554 e2.set(14, TransportSequenceNumber);
1555 e2.set(12, VideoOrientation);
1556
1557 let mut e3 = ExtensionMap::empty();
1558 e3.set(1, TransportSequenceNumber);
1560 e3.set(12, AudioLevel); e1.remap(&e2.iter_video().collect::<Vec<_>>());
1564
1565 println!("{:#?}", e1.0);
1566 assert_eq!(
1567 e1.iter_video().collect::<Vec<_>>(),
1568 vec![(12, &VideoOrientation), (14, &TransportSequenceNumber)]
1569 );
1570
1571 e1.remap(&e3.iter_audio().collect::<Vec<_>>());
1573
1574 println!("{:#?}", e1.0);
1575 assert_eq!(
1577 e1.iter_video().collect::<Vec<_>>(),
1578 vec![(12, &VideoOrientation), (14, &TransportSequenceNumber)]
1579 );
1580 }
1581}