moq_audio/activity.rs
1/// Whether a packet carried coded audio, or none at all.
2///
3/// Rides along with the audio it describes: on [`Frame`](crate::Frame) coming
4/// out of [`decode`](crate::decode), and on
5/// [`encode::Encoded`](crate::encode::Encoded) going in. Codecs without a
6/// discontinuous mode (PCM, AAC) are always [`Active`](Self::Active).
7///
8/// Read off the packet, so a consumer gets the same answer as the publisher and
9/// gets one for senders that are not us. Two things follow from that, and both
10/// are why this reports what arrived rather than what the speaker was doing:
11///
12/// - Opus marks withheld audio but not silence itself. A run of
13/// [`Dtx`](Self::Dtx) is interrupted every few hundred milliseconds by an
14/// ordinarily coded frame of the silence, which reads [`Active`](Self::Active)
15/// because nothing distinguishes it from speech resuming. So audio is never
16/// reported as silence, but silence is reported as audio a frame at a time.
17/// Hold a talking indicator across the gap rather than following it frame by
18/// frame.
19/// - A frame that codes nothing usually means the sender withheld it, but RFC
20/// 6716 section 3.2.1 lets one stand for a frame that went missing on the way
21/// instead. A relay that repacketizes loss that way reads as
22/// [`Dtx`](Self::Dtx).
23#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
24#[non_exhaustive]
25pub enum Activity {
26 /// The packet coded audio for this frame.
27 #[default]
28 Active,
29 /// The packet coded no audio for this frame, which the sender does while its
30 /// input is silent.
31 Dtx,
32}
33
34impl Activity {
35 /// Whether the packet coded audio for this frame.
36 pub fn is_active(self) -> bool {
37 matches!(self, Self::Active)
38 }
39
40 /// Whether the packet coded no audio for this frame.
41 pub fn is_dtx(self) -> bool {
42 matches!(self, Self::Dtx)
43 }
44}