Skip to content
File

Blob: firmware/vendor/str0m/tests/remove-media-while-pacer-queued.rs

rust87 lines
1use std::time::Duration;
2 
3use str0m::format::Codec;
4use str0m::media::MediaKind;
5use str0m::rtp::{ExtensionValues, RtpWrite, Ssrc};
6use str0m::{Input, RtcError};
7 
8mod common;
9use common::{connect_l_r, init_crypto_default, init_log};
10 
11/// This test triggers the panic in `Session::poll_packet` where the pacer
12/// holds a reference to a MidRid whose media has been removed.
13///
14/// Sequence:
15/// 1. Set up a connected pair with a media + stream via direct API
16/// 2. Write an RTP packet so the stream's send queue is non-empty
17/// 3. Call handle_input(Timeout) so session.handle_timeout populates the pacer
18/// 4. Remove the media via direct_api().remove_media() — pacer still references the mid
19/// 5. Call poll_output() — poll_packet asks pacer for next mid, finds it missing → panic
20#[test]
21pub fn remove_media_while_pacer_queued() -> Result<(), RtcError> {
22 init_log();
23 init_crypto_default();
24 
25 let (mut l, mut r) = connect_l_r();
26 
27 let mid = "aud".into();
28 let ssrc_tx: Ssrc = 42.into();
29 
30 // Declare media and stream on sender
31 l.direct_api().declare_media(mid, MediaKind::Audio);
32 l.direct_api().declare_stream_tx(ssrc_tx, None, mid, None);
33 
34 // Declare matching media on receiver
35 r.direct_api().declare_media(mid, MediaKind::Audio);
36 
37 // Sync time
38 let max = l.last.max(r.last);
39 l.last = max;
40 r.last = max;
41 
42 let params = l.params_opus();
43 assert_eq!(params.spec().codec, Codec::Opus);
44 let pt = params.pt();
45 
46 // Write an RTP packet so the stream's send queue has data
47 let wallclock = l.start + l.duration();
48 {
49 let mut direct = l.direct_api();
50 let stream = direct.stream_tx(&ssrc_tx).unwrap();
51 
52 let exts = ExtensionValues {
53 audio_level: Some(-42),
54 voice_activity: Some(false),
55 ..Default::default()
56 };
57 
58 stream.write_rtp(
59 RtpWrite::new(
60 pt,
61 47_000.into(),
62 47_000_000,
63 wallclock,
64 [0x1, 0x2, 0x3, 0x4],
65 )
66 .ext_vals(exts)
67 .nackable(true),
68 );
69 }
70 
71 // Advance time slightly so the timeout fires
72 let now = l.last + Duration::from_millis(10);
73 l.last = now;
74 
75 // Trigger handle_timeout which calls update_queue_state → pacer captures the MidRid
76 l.handle_input(Input::Timeout(now))?;
77 
78 // Now remove the media — the pacer still holds a reference to mid "aud"
79 l.direct_api().remove_media(mid);
80 
81 // poll_output will call poll_packet → pacer.poll_queue() returns the stale MidRid → panic
82 // (The panic: "Pacer pointed to mid {} which doesn't exist")
83 let _output = l.poll_output()?;
84 
85 Ok(())
86}