Skip to main content

snapcast_proto/message/
codec_header.rs

1//! Codec Header message (type=1).
2//!
3//! Sent from server to client after the Hello handshake. Contains the
4//! codec name and codec-specific header data needed to initialize the decoder.
5
6use std::io::{Read, Write};
7
8use crate::message::base::ProtoError;
9use crate::message::wire;
10
11/// Codec header payload.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct CodecHeader {
14    /// Codec name: "pcm", "flac", "ogg", "opus", or "null".
15    pub codec: String,
16    /// Codec-specific header bytes (e.g. FLAC stream header, RIFF header).
17    pub payload: Vec<u8>,
18}
19
20impl CodecHeader {
21    /// Wire size: u32+codec + u32+payload.
22    pub fn wire_size(&self) -> u32 {
23        wire::string_wire_size(&self.codec) + wire::bytes_wire_size(&self.payload)
24    }
25
26    /// Deserialize a codec header from a reader.
27    pub fn read_from<R: Read>(r: &mut R) -> Result<Self, ProtoError> {
28        let codec = wire::read_string(r)?;
29        let payload = wire::read_bytes(r)?;
30        Ok(Self { codec, payload })
31    }
32
33    /// Serialize a codec header to a writer.
34    pub fn write_to<W: Write>(&self, w: &mut W) -> Result<(), ProtoError> {
35        wire::write_string(w, &self.codec)?;
36        wire::write_bytes(w, &self.payload)?;
37        Ok(())
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn round_trip_flac() {
47        let original = CodecHeader {
48            codec: "flac".into(),
49            payload: vec![0x66, 0x4C, 0x61, 0x43], // "fLaC" magic
50        };
51        let mut buf = Vec::new();
52        original.write_to(&mut buf).unwrap();
53        let mut cursor = std::io::Cursor::new(&buf);
54        let decoded = CodecHeader::read_from(&mut cursor).unwrap();
55        assert_eq!(original, decoded);
56    }
57
58    #[test]
59    fn known_bytes_pcm() {
60        // codec="pcm" (3 chars), payload=empty
61        let expected: Vec<u8> = vec![
62            0x03, 0x00, 0x00, 0x00, // codec len = 3
63            b'p', b'c', b'm', // "pcm"
64            0x00, 0x00, 0x00, 0x00, // payload len = 0
65        ];
66        let msg = CodecHeader {
67            codec: "pcm".into(),
68            payload: vec![],
69        };
70        let mut buf = Vec::new();
71        msg.write_to(&mut buf).unwrap();
72        assert_eq!(buf, expected);
73    }
74
75    #[test]
76    fn wire_size() {
77        let msg = CodecHeader {
78            codec: "opus".into(),
79            payload: vec![0; 12],
80        };
81        // (4+4) + (4+12) = 24
82        assert_eq!(msg.wire_size(), 24);
83    }
84}