mumble_protocol/
voice.rs

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