lavende_core/audio/
engine.rs1pub mod standard {
2 use super::Engine;
3 use crate::audio::AudioFrame;
4 use flume::Sender;
5 pub struct StandardEngine {
6 frame_tx: Sender<AudioFrame>,
7 }
8 impl StandardEngine {
9 pub fn new(frame_tx: Sender<AudioFrame>) -> Self {
10 Self { frame_tx }
11 }
12 }
13 impl Engine for StandardEngine {
14 fn push(&mut self, frame: AudioFrame) -> bool {
15 self.frame_tx.send(frame).is_ok()
16 }
17 }
18}
19pub mod encoder {
20 use crate::common::types::AnyResult;
21 use audiopus::{Application, Bitrate, Channels, SampleRate, coder::Encoder as OpusEncoder};
22 pub struct Encoder {
23 encoder: OpusEncoder,
24 }
25 impl Encoder {
26 pub fn new() -> AnyResult<Self> {
27 let mut encoder =
28 OpusEncoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio)
29 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
30 encoder
31 .set_bitrate(Bitrate::Auto)
32 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
33 Ok(Self { encoder })
34 }
35 pub fn encode(&mut self, input: &[i16], output: &mut [u8]) -> AnyResult<usize> {
36 let size = self
37 .encoder
38 .encode(input, output)
39 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
40 Ok(size)
41 }
42 }
43 #[cfg(test)]
44 mod tests {
45 use super::*;
46 #[test]
47 fn test_encoder_new() {
48 let result = Encoder::new();
49 assert!(result.is_ok(), "Encoder creation should succeed");
50 }
51 #[test]
52 fn test_encoder_encode_silence() {
53 let mut encoder = Encoder::new().unwrap();
54 let input = vec![0i16; 960 * 2];
55 let mut output = vec![0u8; 4000];
56 let result = encoder.encode(&input, &mut output);
57 assert!(result.is_ok(), "Encoding silence should succeed");
58 let size = result.unwrap();
59 assert!(size > 0, "Encoded size should be greater than 0");
60 assert!(
61 size < output.len(),
62 "Encoded size should be less than buffer"
63 );
64 }
65 #[test]
66 fn test_encoder_encode_tone() {
67 let mut encoder = Encoder::new().unwrap();
68 let mut input = vec![0i16; 960 * 2];
69 for (i, sample) in input.iter_mut().enumerate() {
70 let t = (i / 2) as f32 / 48000.0;
71 *sample = (10000.0 * (2.0 * std::f32::consts::PI * 440.0 * t).sin()) as i16;
72 }
73 let mut output = vec![0u8; 4000];
74 let result = encoder.encode(&input, &mut output);
75 assert!(result.is_ok(), "Encoding tone should succeed");
76 let size = result.unwrap();
77 assert!(size > 0, "Encoded size should be greater than 0");
78 }
79 #[test]
80 fn test_encoder_encode_max_amplitude() {
81 let mut encoder = Encoder::new().unwrap();
82 let input = vec![i16::MAX; 960 * 2];
83 let mut output = vec![0u8; 4000];
84 let result = encoder.encode(&input, &mut output);
85 assert!(result.is_ok(), "Encoding max amplitude should succeed");
86 assert!(result.unwrap() > 0);
87 }
88 #[test]
89 fn test_encoder_encode_min_amplitude() {
90 let mut encoder = Encoder::new().unwrap();
91 let input = vec![i16::MIN; 960 * 2];
92 let mut output = vec![0u8; 4000];
93 let result = encoder.encode(&input, &mut output);
94 assert!(result.is_ok(), "Encoding min amplitude should succeed");
95 assert!(result.unwrap() > 0);
96 }
97 #[test]
98 fn test_encoder_encode_multiple_frames() {
99 let mut encoder = Encoder::new().unwrap();
100 let input = vec![1000i16; 960 * 2];
101 let mut output = vec![0u8; 4000];
102 for _ in 0..5 {
103 let result = encoder.encode(&input, &mut output);
104 assert!(result.is_ok(), "Multiple encodings should succeed");
105 assert!(result.unwrap() > 0);
106 }
107 }
108 #[test]
109 fn test_encoder_output_varies_with_input() {
110 let mut encoder1 = Encoder::new().unwrap();
111 let mut output1 = vec![0u8; 4000];
112 let silence = vec![0i16; 960 * 2];
113 let size1 = encoder1.encode(&silence, &mut output1).unwrap();
114 let mut encoder2 = Encoder::new().unwrap();
115 let mut output2 = vec![0u8; 4000];
116 let tone = vec![5000i16; 960 * 2];
117 let size2 = encoder2.encode(&tone, &mut output2).unwrap();
118 assert!(size1 > 0);
119 assert!(size2 > 0);
120 assert_ne!(
121 &output1[..size1],
122 &output2[..size2],
123 "Encoded silence and tone payloads should differ"
124 );
125 }
126 }
127}
128use crate::audio::frame::AudioFrame;
129pub use encoder::Encoder;
130pub use standard::StandardEngine;
131pub trait Engine: Send {
132 fn push(&mut self, frame: AudioFrame) -> bool;
133}
134pub type BoxedEngine = Box<dyn Engine>;