- 1
use super::VoiceError; - 2
- 3
/// The socket's only audio shape: mono 16-bit little-endian PCM at 16 kHz. - 4
pub const SOCKET_SAMPLE_RATE_HZ: u32 = 16_000; - 5
- 6
#[derive(Debug, Clone, Copy, PartialEq, Eq)] - 7
pub struct PcmSpec { - 8
pub sample_rate_hz: u32, - 9
pub channels: u16, - 10
} - 11
- 12
impl PcmSpec { - 13
pub const SOCKET: Self = Self { - 14
sample_rate_hz: SOCKET_SAMPLE_RATE_HZ, - 15
channels: 1, - 16
}; - 17
} - 18
- 19
pub fn wrap_wav(pcm: &[u8], spec: PcmSpec) -> Result<Vec<u8>, VoiceError> { - 20
if spec.channels == 0 || spec.sample_rate_hz == 0 || !pcm.len().is_multiple_of(2) { - 21
return Err(VoiceError::InvalidRequest("invalid PCM stream".into())); - 22
} - 23
let data_len = u32::try_from(pcm.len()) - 24
.map_err(|_| VoiceError::InvalidRequest("audio too large".into()))?; - 25
let byte_rate = spec.sample_rate_hz * u32::from(spec.channels) * 2; - 26
let block_align = spec.channels * 2; - 27
let mut out = Vec::with_capacity(44 + pcm.len()); - 28
out.extend_from_slice(b"RIFF"); - 29
out.extend_from_slice(&(36 + data_len).to_le_bytes()); - 30
out.extend_from_slice(b"WAVEfmt "); - 31
out.extend_from_slice(&16u32.to_le_bytes()); - 32
out.extend_from_slice(&1u16.to_le_bytes()); - 33
out.extend_from_slice(&spec.channels.to_le_bytes()); - 34
out.extend_from_slice(&spec.sample_rate_hz.to_le_bytes()); - 35
out.extend_from_slice(&byte_rate.to_le_bytes()); - 36
out.extend_from_slice(&block_align.to_le_bytes()); - 37
out.extend_from_slice(&16u16.to_le_bytes()); - 38
out.extend_from_slice(b"data"); - 39
out.extend_from_slice(&data_len.to_le_bytes()); - 40
out.extend_from_slice(pcm); - 41
Ok(out) - 42
} - 43
- 44
#[cfg(test)] - 45
#[allow(clippy::expect_used, clippy::unwrap_used)] - 46
mod tests { - 47
use super::*; - 48
#[test] - 49
fn wav_header_is_canonical() { - 50
let wav = wrap_wav(&[0, 0, 255, 127], PcmSpec::SOCKET).unwrap(); - 51
assert_eq!(&wav[0..4], b"RIFF"); - 52
assert_eq!(&wav[8..12], b"WAVE"); - 53
assert_eq!(&wav[40..44], &[4, 0, 0, 0]); - 54
} - 55
} - 56
Indexing the workspace…
Vakyartha documentation is discovering safe artifacts, anchors, and source references.