Текстовый файл из учебного комплекта, не свидетельство установленного runtime. Вернуться к учебнику · Исходный файл
1 use super::*; 2 use pretty_assertions::assert_eq; 3 4 #[test] 5 fn rendered_reference_changes_decoded_echo_capture() { 6 let mut processors = [ 7 Processor::new(/*input_rate*/ 48_000, /*output_rate*/ 44_100).unwrap(), 8 Processor::new(/*input_rate*/ 48_000, /*output_rate*/ 44_100).unwrap(), 9 ]; 10 for processor in &mut processors { 11 // Isolate echo cancellation from independent noise/gain adaptation. 12 processor.apm.apply_config(sonora::Config { 13 echo_canceller: Some(EchoCanceller::default()), 14 ..Default::default() 15 }); 16 } 17 let start = Instant::now(); 18 let signal = |seconds: f32| { 19 [311.0, 719.0, 1_423.0] 20 .into_iter() 21 .map(|frequency| (std::f32::consts::TAU * frequency * seconds).sin() * 0.1) 22 .sum::<f32>() 23 }; 24 let mut packets = [Vec::new(), Vec::new()]; 25 // Two seconds of deterministic samples allow AEC startup, without sleeping. 26 for block in 0..200 { 27 for offset in [0, 256] { 28 let mut frame = Frame { 29 samples: [0.0; 256], 30 len: 256.min(441 - offset), 31 at: start - Duration::from_secs(/*secs*/ 10) 32 + Duration::from_secs_f64((block * 441 + offset) as f64 / 44_100.0), 33 generation: 0, 34 }; 35 for (index, sample) in frame.samples[..frame.len].iter_mut().enumerate() { 36 *sample = signal((block * 441 + offset + index) as f32 / 44_100.0); 37 } 38 processors[0].render(&frame).unwrap(); 39 } 40 // Keep delay metadata identical: only consuming reference samples may 41 // explain the difference in the decoded capture signal. 42 processors[1].render_delay = processors[0].render_delay; 43 for offset in [0, 256] { 44 let mut frame = Frame { 45 samples: [0.0; 256], 46 len: 256.min(480 - offset), 47 at: start + Duration::from_secs_f64((block * 480 + offset) as f64 / 48_000.0), 48 generation: 2, 49 }; 50 for (index, sample) in frame.samples[..frame.len].iter_mut().enumerate() { 51 *sample = signal((block * 480 + offset + index) as f32 / 48_000.0 - 0.05); 52 } 53 for (processor, packets) in processors.iter_mut().zip(&mut packets) { 54 packets.extend(processor.capture(&frame, || frame.at).unwrap()); 55 } 56 } 57 } 58 let decoded = packets.map(|packets| { 59 let mut decoder = opus::Decoder::new(/*sample_rate*/ 48_000, opus::Channels::Mono).unwrap(); 60 let mut decoded = Vec::new(); 61 for packet in packets { 62 let mut samples = [0.0; 960]; 63 assert_eq!( 64 decoder 65 .decode_float(&packet.data, &mut samples, /*fec*/ false) 66 .unwrap(), 67 960 68 ); 69 assert!(samples.iter().all(|sample| sample.is_finite())); 70 decoded.extend(samples); 71 } 72 decoded 73 }); 74 assert_eq!(decoded[0].len(), decoded[1].len()); 75 assert!(decoded[0].len() > 48_000); 76 let energy = decoded.map(|samples| { 77 samples[48_000..] 78 .iter() 79 .map(|sample| sample * sample) 80 .sum::<f32>() 81 }); 82 assert!( 83 energy[1] > 1.0, 84 "control capture must contain the echo signal" 85 ); 86 assert!( 87 energy[0] < energy[1] * 0.5, 88 "reference/control echo energy: {energy:?}" 89 ); 90 } 91 92 #[test] 93 fn real_encoder_produces_twenty_millisecond_opus_packets() { 94 for rate in [44_100, 48_000] { 95 let mut processor = Processor::new(rate, /*output_rate*/ 48_000).unwrap(); 96 let mut packets = Vec::new(); 97 for block in 0..40 { 98 let mut frame = Frame { 99 samples: [0.0; 256], 100 len: 256, 101 at: Instant::now(), 102 generation: 2, 103 }; 104 for (index, sample) in frame.samples.iter_mut().enumerate() { 105 *sample = (std::f32::consts::TAU * 440.0 * (block as usize * 256 + index) as f32 106 / rate as f32) 107 .sin() 108 * 0.1; 109 } 110 packets.extend(processor.capture(&frame, || frame.at).unwrap()); 111 } 112 assert!(!packets.is_empty()); 113 let mut decoder = opus::Decoder::new(/*sample_rate*/ 48_000, opus::Channels::Mono).unwrap(); 114 let mut energy = 0.0_f32; 115 for packet in packets { 116 let mut output = [0.0; 960]; 117 assert_eq!( 118 decoder 119 .decode_float(&packet.data, &mut output, /*fec*/ false) 120 .unwrap(), 121 960 122 ); 123 assert!(output.iter().all(|sample| sample.is_finite())); 124 energy += output.iter().map(|sample| sample * sample).sum::<f32>(); 125 } 126 assert!( 127 energy > 0.01, 128 "decoded capture must contain signal at {rate} Hz" 129 ); 130 } 131 } 132 133 #[test] 134 fn unmute_reset_rejects_delayed_pre_unmute_audio_and_partial_history() { 135 let mut processor = Processor::new(/*input_rate*/ 48_000, /*output_rate*/ 48_000).unwrap(); 136 let frame = Frame { 137 samples: [0.25; 256], 138 len: 256, 139 at: Instant::now(), 140 generation: 2, 141 }; 142 assert!(processor.capture(&frame, || frame.at).unwrap().is_empty()); 143 assert_eq!( 144 (0..10).find_map(|_| processor 145 .capture(&frame, || frame.at + Duration::from_secs(1)) 146 .err()), 147 Some("voice processing fell behind") 148 ); 149 processor.reset().unwrap(); 150 for _ in 0..10 { 151 assert!(processor.capture(&frame, || frame.at).unwrap().is_empty()); 152 } 153 assert!(processor.pending.is_empty()); 154 assert!(processor.capture.input.is_empty()); 155 assert!(processor.capture.output.is_empty()); 156 } 157 158 #[test] 159 fn speaker_rate_change_discards_old_reference_but_keeps_capture_history() { 160 for rate in [48_000, 24_000, 44_100] { 161 let mut processor = Processor::new(/*input_rate*/ 48_000, /*output_rate*/ 48_000).unwrap(); 162 let mut fresh = Processor::new(/*input_rate*/ 48_000, rate).unwrap(); 163 let start = Instant::now(); 164 let mut frame = Frame { 165 samples: [0.75; 256], 166 len: 256, 167 at: start, 168 generation: 2, 169 }; 170 processor.render.push(&frame).unwrap(); 171 processor.render.output.push_back(0.75); 172 processor.capture.input.extend([0.25; 256]); 173 processor.pending.extend([0.25; 480]); 174 processor.render_delay = 123; 175 processor.set_render_rate(rate).unwrap(); 176 assert_eq!(processor.capture.input, VecDeque::from(vec![0.25; 256])); 177 assert_eq!(processor.pending, vec![0.25; 480]); 178 assert_eq!(processor.render_delay, 0); 179 180 frame.samples.fill(0.0); 181 let mut actual = Vec::new(); 182 let mut expected = Vec::new(); 183 for index in 0..5 { 184 frame.at = start + Duration::from_secs_f64(index as f64 * 256.0 / f64::from(rate)); 185 processor.render.push(&frame).unwrap(); 186 fresh.render.push(&frame).unwrap(); 187 actual.extend(std::iter::from_fn(|| processor.render.next())); 188 expected.extend(std::iter::from_fn(|| fresh.render.next())); 189 } 190 assert!(!actual.is_empty()); 191 assert_eq!(actual, expected); 192 } 193 } 194 195 #[test] 196 fn capture_gap_discards_old_partial_packet_and_preserves_unmute_cutoff() { 197 let mut processor = Processor::new(/*input_rate*/ 48_000, /*output_rate*/ 48_000).unwrap(); 198 let mut fresh = Processor::new(/*input_rate*/ 48_000, /*output_rate*/ 48_000).unwrap(); 199 let cutoff = processor.cutoff; 200 let start = Instant::now(); 201 let mut frame = Frame { 202 samples: [0.25; 256], 203 len: 240, 204 at: start, 205 generation: 2, 206 }; 207 for index in 0..5 { 208 frame.at = start + Duration::from_millis(index * 5); 209 assert!(processor.capture(&frame, || frame.at).unwrap().is_empty()); 210 } 211 assert!(!processor.pending.is_empty()); 212 assert!(!processor.capture.input.is_empty()); 213 214 let resumed = start + Duration::from_millis(/*millis*/ 100); 215 frame.samples.fill(0.0); 216 let mut packets = Vec::new(); 217 let mut expected = Vec::new(); 218 for index in 0..12 { 219 frame.at = resumed + Duration::from_millis(index * 5); 220 let emitted = processor.capture(&frame, || frame.at).unwrap(); 221 if index < 2 { 222 assert!(emitted.is_empty()); 223 } 224 packets.extend(emitted.into_iter().map(|packet| (packet.at, packet.data))); 225 expected.extend( 226 fresh 227 .capture(&frame, || frame.at) 228 .unwrap() 229 .into_iter() 230 .map(|packet| (packet.at, packet.data)), 231 ); 232 } 233 assert!(!packets.is_empty()); 234 assert_eq!(packets, expected); 235 assert_eq!(processor.cutoff, cutoff); 236 } 237 238 #[test] 239 fn ordinary_capture_timestamp_jitter_keeps_partial_audio() { 240 for jitter_ms in [-2_i64, 0, 2] { 241 let mut processor = Processor::new(/*input_rate*/ 48_000, /*output_rate*/ 48_000).unwrap(); 242 let start = Instant::now(); 243 let mut frame = Frame { 244 samples: [0.1; 256], 245 len: 240, 246 at: start, 247 generation: 2, 248 }; 249 for index in 0..5 { 250 frame.at = start + Duration::from_millis(index * 5); 251 assert!(processor.capture(&frame, || frame.at).unwrap().is_empty()); 252 } 253 frame.at = start + Duration::from_millis((25 + jitter_ms) as u64); 254 assert_eq!(processor.capture(&frame, || frame.at).unwrap().len(), 1); 255 } 256 } 257 258 #[test] 259 fn callback_gap_cannot_hide_in_a_packed_partial_block() { 260 let mut processor = Processor::new(/*input_rate*/ 48_000, /*output_rate*/ 48_000).unwrap(); 261 let mut packer = super::super::buffers::FramePacker::default(); 262 let queue = crossbeam_queue::ArrayQueue::new(/*capacity*/ 8); 263 let start = Instant::now(); 264 // Leave both an incomplete callback block and a processed half-packet. 265 for index in 0..6 { 266 let at = start + Duration::from_millis(index * 5); 267 packer.discard_capture_gap(at, /*rate*/ 48_000.0); 268 assert!(packer.push( 269 Frame { 270 samples: [0.25; 256], 271 len: 240, 272 at, 273 generation: 2 274 }, 275 /*rate*/ 48_000.0, 276 &queue 277 )); 278 while let Some(frame) = queue.pop() { 279 assert!(processor.capture(&frame, || frame.at).unwrap().is_empty()); 280 } 281 } 282 assert!(!processor.pending.is_empty()); 283 let resumed = start + Duration::from_millis(/*millis*/ 100); 284 packer.discard_capture_gap(resumed, /*rate*/ 48_000.0); 285 assert!(packer.push( 286 Frame { 287 samples: [0.0; 256], 288 len: 256, 289 at: resumed, 290 generation: 2 291 }, 292 /*rate*/ 48_000.0, 293 &queue 294 )); 295 let frame = queue.pop().unwrap(); 296 assert_eq!( 297 (frame.samples, frame.len, frame.at, frame.generation), 298 ([0.0; 256], 256, resumed, 2) 299 ); 300 assert!(processor.capture(&frame, || resumed).unwrap().is_empty()); 301 assert!(processor.pending.is_empty()); 302 } 303 304 #[test] 305 fn stale_echo_reference_cannot_cancel_capture_age() { 306 for render_delay in [0, -750] { 307 let mut processor = Processor::new(/*input_rate*/ 48_000, /*output_rate*/ 48_000).unwrap(); 308 processor.render_delay = render_delay; 309 let start = Instant::now(); 310 let now = start + Duration::from_millis(/*millis*/ 750); 311 let failure = (0..8).find_map(|index| { 312 let frame = Frame { 313 samples: [0.25; 256], 314 len: 256, 315 at: start + Duration::from_secs_f64((index * 256) as f64 / 48_000.0), 316 generation: 2, 317 }; 318 processor.capture(&frame, || now).err() 319 }); 320 assert_eq!(failure, Some("voice processing fell behind")); 321 } 322 }