silence_core/opus/
encode.rs

1//! Eanbles raw sample encoding to opus.
2
3use opus::{Channels, Encoder};
4
5use crate::io::EncoderType;
6
7use crate::io::SoundPacket;
8
9///
10/// Create an [`opus`] encoder.
11///
12/// # Behavior
13/// Creates an [`opus`] encoder from a [`SupportedStreamConfig`] to know the host's correct configurations, and an [`opus::Application`] to know which mode the user desires.
14///
15/// # Error
16/// Returns an error if some kind of error occured while creating the [`Encoder`].
17/// Example: invalid configurations were found (highly unlikely).
18///
19pub fn create_opus_encoder(
20    sample_rate: u32,
21    opus_mode: opus::Application,
22    bitrate: opus::Bitrate,
23    channels: Channels,
24) -> anyhow::Result<Encoder> {
25    let mut encoder = opus::Encoder::new(sample_rate, channels, opus_mode)?;
26
27    encoder.set_bitrate(bitrate)?;
28
29    if matches!(opus_mode, opus::Application::Voip) {
30        encoder.set_inband_fec(true)?;
31    } else {
32        encoder.set_inband_fec(false)?;
33    }
34
35    Ok(encoder)
36}
37
38///
39/// Encode raw samples with the [`opus`] encoder.
40///
41/// # Behavior
42/// Returns the result of encoding the samples.
43/// In the returned result `(usize, Vec<u8>)` the `usize` will indicate the length of the encoded packet.
44/// The `Vec<u8>` is the output of the encoding process.
45///
46/// # Error
47/// Returns an error if some kind of error occured during the encoding process.
48///
49pub fn encode_sample_set_size_opus(
50    encoder: &mut Encoder,
51    samples: &[f32],
52    samples_per_frame: usize,
53) -> anyhow::Result<SoundPacket> {
54    let mut compressed_buffer = vec![0; 1500];
55
56    let encoded_bytes_count = encoder.encode_float(samples, &mut compressed_buffer)?;
57
58    Ok(SoundPacket {
59        encoder_type: EncoderType::Opus(encoder.get_inband_fec()?),
60        sample_rate: encoder.get_sample_rate()?,
61        channels: 2,
62        bytes: compressed_buffer[..encoded_bytes_count].to_vec(),
63        samples_per_frame: samples_per_frame as u64,
64    })
65}
66
67///
68/// Encodes raw samples (f32) into a list of [`SoundPacket`]-s.
69///
70/// # Behavior
71/// Returns a list of the encoded [`SoundPacket`]-s. The frame duration and the channels ([`Channels`]) is needed to know the [`SoundPacket`]'s size.
72///
73/// # Error
74/// Returns an error if the following arguments are invalid:
75///     * Invalid raw samples
76///     * Invalid frame duration
77///
78pub fn encode_samples_opus(
79    mut encoder: Encoder,
80    samples: &[f32],
81    frame_duration_ms: u32,
82    channels: Channels,
83) -> anyhow::Result<Vec<SoundPacket>> {
84    let samples_per_frame = (encoder.get_sample_rate()? * frame_duration_ms) / 1000;
85    let samples_per_frame = (samples_per_frame * channels as u32) as usize;
86    let mut sound_packets = vec![];
87
88    for sample_chunk in samples.chunks(samples_per_frame) {
89        let sample = if sample_chunk.len() < samples_per_frame {
90            let mut padded_frame = Vec::with_capacity(samples_per_frame);
91            padded_frame.extend_from_slice(sample_chunk);
92            padded_frame.resize(samples_per_frame, 0.);
93            padded_frame
94        } else {
95            sample_chunk.to_vec()
96        };
97
98        let sound_packet = encode_sample_set_size_opus(&mut encoder, &sample, samples_per_frame)?;
99
100        sound_packets.push(sound_packet);
101    }
102
103    Ok(sound_packets)
104}