mumble_protocol_2x/
voice.rs

1//! Voice channel packets and codecs
2
3use std::fmt::Debug;
4use std::io;
5use std::io::{Cursor, Read};
6use std::marker::PhantomData;
7
8use byteorder::ReadBytesExt;
9use bytes::Buf;
10use bytes::BufMut;
11use bytes::Bytes;
12use bytes::BytesMut;
13
14use super::varint::BufMutExt;
15use super::varint::ReadExt;
16
17/// A packet transmitted via Mumble's voice channel.
18#[derive(Clone, Debug, PartialEq)]
19pub enum VoicePacket<Dst: VoicePacketDst> {
20    /// Ping packets contain opaque timestamp-like values which should simply be echoed back.
21    Ping {
22        /// Opaque timestamp-like value.
23        /// Unless this is the echo, no assumptions about it should be made.
24        timestamp: u64,
25    },
26    /// Packet containing audio data.
27    Audio {
28        /// Destination. Required due to encoding differences depending on packet flow direction.
29        _dst: PhantomData<Dst>,
30        /// The target.
31        ///
32        /// Only values 0-31 are valid (when serialized, this field is 5-bits long).
33        target: u8,
34        /// Session ID. Absent when packet is [Serverbound].
35        session_id: Dst::SessionId,
36        /// Sequence number of the first audio frame in this packet.
37        ///
38        /// Packets may contain multiple frames, so this may increase by more than one per packet.
39        seq_num: u64,
40        /// The actual audio data
41        payload: VoicePacketPayload,
42        /// Positional audio information.
43        ///
44        /// Usually `[f32; 3]` but may contain additional or different data if all clients
45        /// receiving this packet can deal with such values (e.g. games with builtin Mumble
46        /// client may use this field to transmit additional data to other game clients).
47        position_info: Option<Bytes>,
48    },
49}
50
51/// Audio data payload of [VoicePacket]s.
52#[derive(Clone, Debug, PartialEq)]
53#[non_exhaustive]
54pub enum VoicePacketPayload {
55    /// CELT Alpha (0.7.0) encoded audio frames.
56    CeltAlpha(Vec<Bytes>),
57    /// CELT Beta (0.11.0) encoded audio frames.
58    CeltBeta(Vec<Bytes>),
59    /// Speex encoded audio frames.
60    Speex(Vec<Bytes>),
61    /// Opus encoded audio frame with end-of-transmission bit.
62    Opus(Bytes, bool),
63}
64
65/// A `Codec` implementation that parses a stream of data chunks into [VoicePacket]s.
66///
67/// The encoding and decoding of voice packets depends on their destination.
68/// See [ServerVoiceCodec] and [ClientVoiceCodec] for the two most reasonable configurations.
69#[derive(Debug, Default)]
70pub struct VoiceCodec<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> {
71    _encode_dst: PhantomData<EncodeDst>,
72    _decode_dst: PhantomData<DecodeDst>,
73}
74/// The [VoiceCodec] used on the server side.
75pub type ServerVoiceCodec = VoiceCodec<Clientbound, Serverbound>;
76/// The [VoiceCodec] used on the client side.
77pub type ClientVoiceCodec = VoiceCodec<Serverbound, Clientbound>;
78
79impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> VoiceCodec<EncodeDst, DecodeDst> {
80    /// Creates a new control codec.
81    pub fn new() -> Self {
82        Default::default()
83    }
84}
85
86/// Zero-sized struct indicating server-bound packet direction.
87#[derive(Clone, Debug, Default, PartialEq)]
88pub struct Serverbound;
89/// Zero-sized struct indicating client-bound packet direction.
90#[derive(Clone, Debug, Default, PartialEq)]
91pub struct Clientbound;
92
93mod private {
94    pub trait Sealed {}
95    impl Sealed for super::Serverbound {}
96    impl Sealed for super::Clientbound {}
97}
98
99/// Sealed trait for indicating voice packet direction.
100///
101/// The only two implementations are [Serverbound] and [Clientbound].
102pub trait VoicePacketDst: private::Sealed + Default + PartialEq {
103    /// Type of [VoicePacket::Audio::session_id](enum.VoicePacket.html#variant.Audio.field.session_id).
104    type SessionId: Debug + Clone + PartialEq;
105    /// Reads session id of packets traveling in this direction.
106    fn read_session_id<T: Read + Sized>(buf: &mut T) -> Result<Self::SessionId, io::Error>;
107    /// Writes session id to packets traveling in this direction.
108    fn write_session_id(buf: &mut BytesMut, session_id: Self::SessionId);
109}
110
111impl VoicePacketDst for Serverbound {
112    type SessionId = ();
113
114    fn read_session_id<T: Read + Sized>(_buf: &mut T) -> Result<Self::SessionId, io::Error> {
115        Ok(())
116    }
117
118    fn write_session_id(_buf: &mut BytesMut, _session_id: Self::SessionId) {}
119}
120
121impl VoicePacketDst for Clientbound {
122    type SessionId = u32;
123
124    fn read_session_id<T: Read + Sized>(buf: &mut T) -> Result<Self::SessionId, io::Error> {
125        Ok(buf.read_varint()? as u32)
126    }
127
128    fn write_session_id(buf: &mut BytesMut, session_id: Self::SessionId) {
129        buf.put_varint(u64::from(session_id))
130    }
131}
132
133impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> VoiceCodec<EncodeDst, DecodeDst> {
134    // Note: other code assumes this returns Ok(Some(_)) or Err(_) but never Ok(None)
135    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<VoicePacket<DecodeDst>>, io::Error> {
136        let mut buf = Cursor::new(&src);
137        let header = buf.read_u8()?;
138        let kind = header >> 5;
139        let target = header & 0b11111;
140        let result = if kind == 1 {
141            let timestamp = buf.read_varint()?;
142            src.advance(src.len());
143            VoicePacket::Ping { timestamp }
144        } else {
145            let session_id = DecodeDst::read_session_id(&mut buf)?;
146            let seq_num = buf.read_varint()?;
147            let payload = match kind {
148                0 | 2 | 3 => {
149                    let mut frames = Vec::new();
150                    let position = buf.position();
151                    src.advance(position as usize);
152                    loop {
153                        if src.is_empty() {
154                            return Err(io::ErrorKind::UnexpectedEof.into());
155                        }
156                        let header = src[0];
157                        src.advance(1);
158
159                        let len = (header & !0x80) as usize;
160                        if src.len() < len {
161                            return Err(io::ErrorKind::UnexpectedEof.into());
162                        }
163                        frames.push(src.split_to(len).freeze());
164                        if header & 0x80 != 0x80 {
165                            break;
166                        }
167                    }
168                    match kind {
169                        0 => VoicePacketPayload::CeltAlpha(frames),
170                        2 => VoicePacketPayload::Speex(frames),
171                        3 => VoicePacketPayload::CeltBeta(frames),
172                        _ => panic!(),
173                    }
174                }
175                4 => {
176                    let header = buf.read_varint()?;
177                    let position = buf.position();
178                    src.advance(position as usize);
179                    let termination_bit = header & 0x2000 == 0x2000;
180                    let len = (header & !0x2000) as usize;
181                    if src.len() < len {
182                        return Err(io::ErrorKind::UnexpectedEof.into());
183                    }
184                    let frame = src.split_to(len).freeze();
185                    VoicePacketPayload::Opus(frame, termination_bit)
186                }
187                _ => {
188                    return Err(io::Error::new(
189                        io::ErrorKind::InvalidData,
190                        "unknown voice packet type",
191                    ));
192                }
193            };
194            let position_info = if src.is_empty() {
195                None
196            } else {
197                Some(src.split().freeze())
198            };
199            VoicePacket::Audio {
200                _dst: PhantomData,
201                target,
202                session_id,
203                seq_num,
204                payload,
205                position_info,
206            }
207        };
208        Ok(Some(result))
209    }
210}
211
212#[cfg(feature = "tokio-codec")]
213impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> tokio_util::codec::Decoder
214    for VoiceCodec<EncodeDst, DecodeDst>
215{
216    type Item = VoicePacket<DecodeDst>;
217    type Error = io::Error; // never
218
219    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
220        self.decode(src)
221    }
222}
223
224#[cfg(feature = "asynchronous-codec")]
225impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> asynchronous_codec::Decoder
226    for VoiceCodec<EncodeDst, DecodeDst>
227{
228    type Item = VoicePacket<DecodeDst>;
229    type Error = io::Error; // never
230
231    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
232        self.decode(src)
233    }
234}
235
236impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> VoiceCodec<EncodeDst, DecodeDst> {
237    fn encode(
238        &mut self,
239        item: VoicePacket<EncodeDst>,
240        dst: &mut BytesMut,
241    ) -> Result<(), io::Error> {
242        match item {
243            VoicePacket::Ping { timestamp } => {
244                dst.reserve(11);
245                dst.put_u8(0x20);
246                dst.put_varint(timestamp);
247            }
248            VoicePacket::Audio {
249                _dst,
250                target,
251                session_id,
252                seq_num,
253                payload,
254                position_info,
255            } => {
256                let kind = match payload {
257                    VoicePacketPayload::CeltAlpha(_) => 0,
258                    VoicePacketPayload::Speex(_) => 2,
259                    VoicePacketPayload::CeltBeta(_) => 3,
260                    VoicePacketPayload::Opus(_, _) => 4,
261                };
262                dst.reserve(1 /*header*/ + 10 /*session_id*/ + 10 /*seq_num*/);
263                dst.put_u8(kind << 5 | target & 0b11111);
264                EncodeDst::write_session_id(dst, session_id);
265                dst.put_varint(seq_num);
266                match payload {
267                    VoicePacketPayload::CeltAlpha(frames)
268                    | VoicePacketPayload::Speex(frames)
269                    | VoicePacketPayload::CeltBeta(frames) => {
270                        dst.reserve(frames.iter().map(|frame| 1 + frame.len()).sum());
271                        let mut iter = frames.iter().peekable();
272                        while let Some(frame) = iter.next() {
273                            let continuation = iter.peek().map(|_| 0x80).unwrap_or(0);
274                            dst.put_u8(continuation | (frame.len() as u8));
275                            dst.put(frame.as_ref());
276                        }
277                    }
278                    VoicePacketPayload::Opus(frame, termination_bit) => {
279                        dst.reserve(10 + frame.len());
280                        let term_bit = if termination_bit { 0x2000 } else { 0 };
281                        dst.put_varint(term_bit | (frame.len() as u64));
282                        dst.put(frame);
283                    }
284                };
285                if let Some(bytes) = position_info {
286                    dst.extend_from_slice(&bytes);
287                }
288            }
289        }
290        Ok(())
291    }
292}
293
294#[cfg(feature = "tokio-codec")]
295impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst>
296    tokio_util::codec::Encoder<VoicePacket<EncodeDst>> for VoiceCodec<EncodeDst, DecodeDst>
297{
298    type Error = io::Error; // never
299
300    fn encode(
301        &mut self,
302        item: VoicePacket<EncodeDst>,
303        dst: &mut BytesMut,
304    ) -> Result<(), Self::Error> {
305        self.encode(item, dst)
306    }
307}
308
309#[cfg(feature = "asynchronous-codec")]
310impl<EncodeDst: VoicePacketDst, DecodeDst: VoicePacketDst> asynchronous_codec::Encoder
311    for VoiceCodec<EncodeDst, DecodeDst>
312{
313    type Item = VoicePacket<EncodeDst>;
314    type Error = io::Error; // never
315
316    fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
317        self.encode(item, dst)
318    }
319}