File
Blob: firmware/vendor/str0m/tests/audio-inactive-probe.rs
| 1 | use std::net::Ipv4Addr; |
| 2 | use std::time::{Duration, Instant}; |
| 3 | |
| 4 | use netem::Bitrate; |
| 5 | use str0m::media::{Direction, MediaKind}; |
| 6 | use str0m::{Rtc, RtcError}; |
| 7 | |
| 8 | mod common; |
| 9 | use common::{Peer, TestRtc, init_crypto_default, init_log, progress}; |
| 10 | |
| 11 | /// Similar test but with bandwidth estimation enabled to increase probe likelihood |
| 12 | #[test] |
| 13 | pub fn audio_stream_then_inactive_with_bwe() -> Result<(), RtcError> { |
| 14 | init_log(); |
| 15 | init_crypto_default(); |
| 16 | |
| 17 | // Only sender (L) needs BWE enabled |
| 18 | let rtc1 = Rtc::builder() |
| 19 | .enable_bwe(Some(Bitrate::kbps(800))) |
| 20 | .build(Instant::now()); |
| 21 | |
| 22 | let mut l = TestRtc::new_with_rtc(Peer::Left.span(), rtc1); |
| 23 | let mut r = TestRtc::new(Peer::Right); |
| 24 | |
| 25 | l.add_host_candidate((Ipv4Addr::new(1, 1, 1, 1), 1000).into()); |
| 26 | r.add_host_candidate((Ipv4Addr::new(2, 2, 2, 2), 2000).into()); |
| 27 | |
| 28 | // Step 1: Negotiate an audio stream with BWE |
| 29 | let mut change = l.sdp_api(); |
| 30 | let mid = change.add_media(MediaKind::Audio, Direction::SendRecv, None, None, None); |
| 31 | let (offer, pending) = change.apply().unwrap(); |
| 32 | |
| 33 | let answer = r.rtc.sdp_api().accept_offer(offer)?; |
| 34 | l.rtc.sdp_api().accept_answer(pending, answer)?; |
| 35 | |
| 36 | // Wait for connection |
| 37 | loop { |
| 38 | if l.is_connected() || r.is_connected() { |
| 39 | break; |
| 40 | } |
| 41 | progress(&mut l, &mut r)?; |
| 42 | } |
| 43 | |
| 44 | let max = l.last.max(r.last); |
| 45 | l.last = max; |
| 46 | r.last = max; |
| 47 | |
| 48 | let params = l.params_opus(); |
| 49 | let pt = params.pt(); |
| 50 | |
| 51 | // Step 2: Send enough audio data to potentially trigger BWE probing |
| 52 | let data = vec![1_u8; 80]; |
| 53 | |
| 54 | for _ in 0..50 { |
| 55 | let wallclock = l.start + l.duration(); |
| 56 | let time = l.duration().into(); |
| 57 | |
| 58 | if let Some(writer) = l.writer(mid) { |
| 59 | let _ = writer.write(pt, wallclock, time, data.clone()); |
| 60 | } |
| 61 | |
| 62 | progress(&mut l, &mut r)?; |
| 63 | |
| 64 | if l.duration() > Duration::from_secs(2) { |
| 65 | break; |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | // Step 3: Disable the stream immediately (without draining probe queue) |
| 70 | let mut change = l.sdp_api(); |
| 71 | change.set_direction(mid, Direction::Inactive); |
| 72 | let (offer, pending) = change.apply().unwrap(); |
| 73 | |
| 74 | let answer = r.rtc.sdp_api().accept_offer(offer)?; |
| 75 | l.rtc.sdp_api().accept_answer(pending, answer)?; |
| 76 | |
| 77 | // Step 4: Continue progressing - this is where probe_queue access might fail |
| 78 | // if the pacer tries to use probe_queue when there's no video queue available |
| 79 | loop { |
| 80 | progress(&mut l, &mut r)?; |
| 81 | |
| 82 | if l.duration() > Duration::from_secs(240) { |
| 83 | break; |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | Ok(()) |
| 88 | } |