1use super::{
16 events::*,
17 pipeline::{Pipeline, PipelineOptions},
18 LocalTrackInner,
19};
20use crate::{
21 api::{DataTrackFrame, DataTrackInfo, DataTrackOptions, InternalError, PublishError},
22 e2ee::EncryptionProvider,
23 local::LocalDataTrack,
24 packet::{self, Handle},
25};
26use anyhow::{anyhow, Context};
27use futures_core::Stream;
28use std::{
29 collections::HashMap,
30 pin::Pin,
31 sync::Arc,
32 task::{Context as TaskContext, Poll},
33 time::Duration,
34};
35use tokio::sync::{mpsc, oneshot, watch};
36use tokio_stream::wrappers::ReceiverStream;
37
38#[derive(Debug)]
40pub struct ManagerOptions {
41 pub encryption_provider: Option<Arc<dyn EncryptionProvider>>,
46}
47
48pub struct Manager {
50 encryption_provider: Option<Arc<dyn EncryptionProvider>>,
51 event_in_tx: mpsc::Sender<InputEvent>,
52 event_in_rx: mpsc::Receiver<InputEvent>,
53 event_out_tx: mpsc::Sender<OutputEvent>,
54 handle_allocator: packet::HandleAllocator,
55 descriptors: HashMap<Handle, Descriptor>,
56}
57
58impl Manager {
59 pub fn new(options: ManagerOptions) -> (Self, ManagerInput, ManagerOutput) {
68 let (event_in_tx, event_in_rx) = mpsc::channel(Self::EVENT_BUFFER_COUNT);
69 let (event_out_tx, event_out_rx) = mpsc::channel(Self::EVENT_BUFFER_COUNT);
70
71 let event_in = ManagerInput::new(event_in_tx.clone());
72 let manager = Manager {
73 encryption_provider: options.encryption_provider,
74 event_in_tx,
75 event_in_rx,
76 event_out_tx,
77 handle_allocator: packet::HandleAllocator::default(),
78 descriptors: HashMap::new(),
79 };
80
81 let event_out = ManagerOutput(ReceiverStream::new(event_out_rx));
82 (manager, event_in, event_out)
83 }
84
85 pub async fn run(mut self) {
90 log::debug!("Task started");
91 while let Some(event) = self.event_in_rx.recv().await {
92 log::debug!("Input event: {:?}", event);
93 match event {
94 InputEvent::PublishRequest(event) => self.on_publish_request(event).await,
95 InputEvent::PublishCancelled(event) => self.on_publish_cancelled(event).await,
96 InputEvent::QueryPublished(event) => self.on_query_published(event).await,
97 InputEvent::UnpublishRequest(event) => self.on_unpublish_request(event).await,
98 InputEvent::SfuPublishResponse(event) => self.on_sfu_publish_response(event).await,
99 InputEvent::SfuUnpublishResponse(event) => {
100 self.on_sfu_unpublish_response(event).await
101 }
102 InputEvent::RepublishTracks => self.on_republish_tracks().await,
103 InputEvent::Shutdown => break,
104 }
105 }
106 self.shutdown().await;
107 log::debug!("Task ended");
108 }
109
110 async fn on_publish_request(&mut self, event: PublishRequest) {
111 if let Err(error) = crate::schema::validate_schema(
112 event.options.frame_encoding.as_ref(),
113 event.options.schema.as_ref().map(|id| id.encoding()),
114 ) {
115 _ = event.result_tx.send(Err(PublishError::InvalidSchema(error)));
116 return;
117 }
118
119 let Some(handle) = self.handle_allocator.get() else {
120 _ = event.result_tx.send(Err(PublishError::LimitReached));
121 return;
122 };
123
124 if self.descriptors.contains_key(&handle) {
125 _ = event.result_tx.send(Err(PublishError::Internal(
126 anyhow!("Descriptor for handle already exists").into(),
127 )));
128 return;
129 }
130
131 let (result_tx, result_rx) = oneshot::channel();
132 self.descriptors.insert(handle, Descriptor::Pending(result_tx));
133
134 livekit_runtime::spawn(Self::forward_publish_result(
135 handle,
136 result_rx,
137 event.result_tx,
138 self.event_in_tx.downgrade(),
139 ));
140
141 let event = SfuPublishRequest {
142 handle,
143 name: event.options.name,
144 uses_e2ee: self.encryption_provider.is_some(),
145 schema: event.options.schema,
146 frame_encoding: event.options.frame_encoding,
147 };
148 _ = self.event_out_tx.send(event.into()).await;
149 }
150
151 async fn forward_publish_result(
157 handle: Handle,
158 result_rx: oneshot::Receiver<Result<LocalDataTrack, PublishError>>,
159 mut forward_result_tx: oneshot::Sender<Result<LocalDataTrack, PublishError>>,
160 event_in_tx: mpsc::WeakSender<InputEvent>,
161 ) {
162 tokio::select! {
163 biased;
164 Ok(result) = result_rx => {
165 _ = forward_result_tx.send(result);
166 }
167 _ = forward_result_tx.closed() => {
168 let Some(tx) = event_in_tx.upgrade() else { return };
169 let event = PublishCancelled { handle };
170 _ = tx.try_send(event.into());
171 }
172 }
173 }
174
175 async fn on_publish_cancelled(&mut self, event: PublishCancelled) {
176 if self.descriptors.remove(&event.handle).is_none() {
177 log::warn!("No descriptor for {}", event.handle);
178 }
179 }
180
181 async fn on_query_published(&self, event: QueryPublished) {
182 let published_info: Vec<_> = self
183 .descriptors
184 .iter()
185 .filter_map(|descriptor| {
186 let (_, Descriptor::Active { info, .. }) = descriptor else {
187 return None;
188 };
189 info.clone().into()
190 })
191 .collect();
192 _ = event.result_tx.send(published_info);
193 }
194
195 async fn on_unpublish_request(&mut self, event: UnpublishRequest) {
196 self.remove_descriptor(event.handle);
197
198 let event = SfuUnpublishRequest { handle: event.handle };
199 _ = self.event_out_tx.send(event.into()).await;
200 }
201
202 async fn on_sfu_publish_response(&mut self, event: SfuPublishResponse) {
203 let Some(descriptor) = self.descriptors.remove(&event.handle) else {
204 _ = self.event_out_tx.send(SfuUnpublishRequest { handle: event.handle }.into()).await;
207 return;
208 };
209 match descriptor {
210 Descriptor::Pending(result_tx) => {
211 if result_tx.is_closed() {
213 return;
214 }
215 let result = event.result.map(|track_info| self.create_local_track(track_info));
216 _ = result_tx.send(result);
217 return;
218 }
219 Descriptor::Active { ref state_tx, ref info, .. } => {
220 if *state_tx.borrow() != PublishState::Republishing {
221 log::warn!("Track {} already active", event.handle);
222 return;
223 }
224 let Ok(updated_info) = event.result else {
225 log::warn!("Republish failed for track {}", event.handle);
226 return;
227 };
228
229 log::debug!("Track {} republished", event.handle);
230 {
231 let mut sid = info.sid.write().unwrap();
232 *sid = updated_info.sid();
233 }
234 _ = state_tx.send(PublishState::Published);
235 self.descriptors.insert(event.handle, descriptor);
236 }
237 }
238 }
239
240 fn create_local_track(&mut self, info: DataTrackInfo) -> LocalDataTrack {
241 let info = Arc::new(info);
242 let encryption_provider =
243 if info.uses_e2ee() { self.encryption_provider.as_ref().map(Arc::clone) } else { None };
244
245 let pipeline_opts = PipelineOptions { info: info.clone(), encryption_provider };
246 let pipeline = Pipeline::new(pipeline_opts);
247
248 let (frame_tx, frame_rx) = mpsc::channel(Self::FRAME_BUFFER_COUNT);
249 let (state_tx, state_rx) = watch::channel(PublishState::Published);
250
251 let track_task = TrackTask {
252 info: info.clone(),
253 pipeline,
254 state_rx,
255 frame_rx,
256 event_in_tx: self.event_in_tx.clone(),
257 event_out_tx: self.event_out_tx.clone(),
258 };
259 let task_handle = livekit_runtime::spawn(track_task.run());
260
261 self.descriptors.insert(
262 info.pub_handle,
263 Descriptor::Active { info: info.clone(), state_tx: state_tx.clone(), task_handle },
264 );
265
266 let inner = LocalTrackInner { frame_tx, state_tx };
267 LocalDataTrack::new(info, inner)
268 }
269
270 async fn on_sfu_unpublish_response(&mut self, event: SfuUnpublishResponse) {
271 self.remove_descriptor(event.handle);
272 }
273
274 fn remove_descriptor(&mut self, handle: Handle) {
275 let Some(descriptor) = self.descriptors.remove(&handle) else {
276 return;
277 };
278 let Descriptor::Active { state_tx, .. } = descriptor else {
279 return;
280 };
281 if *state_tx.borrow() != PublishState::Unpublished {
282 _ = state_tx.send(PublishState::Unpublished);
283 }
284 }
285
286 async fn on_republish_tracks(&mut self) {
287 let descriptors = std::mem::take(&mut self.descriptors);
288 for (handle, descriptor) in descriptors {
289 match descriptor {
290 Descriptor::Pending(result_tx) => {
291 _ = result_tx.send(Err(PublishError::Disconnected));
293 }
294 Descriptor::Active { ref info, ref state_tx, .. } => {
295 let event = SfuPublishRequest {
296 handle: info.pub_handle,
297 name: info.name.clone(),
298 uses_e2ee: info.uses_e2ee,
299 schema: info.schema.clone(),
300 frame_encoding: info.frame_encoding.clone(),
301 };
302 _ = state_tx.send(PublishState::Republishing);
303 _ = self.event_out_tx.send(event.into()).await;
304 self.descriptors.insert(handle, descriptor);
305 }
306 }
307 }
308 }
309
310 async fn shutdown(self) {
312 for (_, descriptor) in self.descriptors {
313 match descriptor {
314 Descriptor::Pending(result_tx) => {
315 _ = result_tx.send(Err(PublishError::Disconnected))
316 }
317 Descriptor::Active { state_tx, task_handle, .. } => {
318 _ = state_tx.send(PublishState::Unpublished);
319 task_handle.await;
320 }
321 }
322 }
323 }
324
325 const FRAME_BUFFER_COUNT: usize = 16;
327
328 const EVENT_BUFFER_COUNT: usize = 16;
330}
331
332struct TrackTask {
334 info: Arc<DataTrackInfo>,
335 pipeline: Pipeline,
336 state_rx: watch::Receiver<PublishState>,
337 frame_rx: mpsc::Receiver<DataTrackFrame>,
338 event_in_tx: mpsc::Sender<InputEvent>,
339 event_out_tx: mpsc::Sender<OutputEvent>,
340}
341
342impl TrackTask {
343 async fn run(mut self) {
344 let sid = self.info.sid();
345 log::debug!("Track task started: sid={}", sid);
346
347 let mut state = *self.state_rx.borrow();
348 while state != PublishState::Unpublished {
349 tokio::select! {
350 _ = self.state_rx.changed() => {
351 state = *self.state_rx.borrow();
352 }
353 Some(frame) = self.frame_rx.recv() => {
354 if state == PublishState::Republishing {
355 continue;
357 }
358 self.process_and_send(frame);
359 }
360 }
361 }
362
363 let event = UnpublishRequest { handle: self.info.pub_handle };
364 _ = self.event_in_tx.send(event.into()).await;
365
366 log::debug!("Track task ended: sid={}", sid);
367 }
368
369 fn process_and_send(&mut self, frame: DataTrackFrame) {
370 let Ok(packets) = self
371 .pipeline
372 .process_frame(frame)
373 .inspect_err(|err| log::debug!("Process failed: {}", err))
374 else {
375 return;
376 };
377 let packets: Vec<_> = packets.into_iter().map(|packet| packet.serialize()).collect();
378 _ = self
379 .event_out_tx
380 .try_send(packets.into())
381 .inspect_err(|err| log::debug!("Cannot send packets to transport: {}", err));
382 }
383}
384
385#[derive(Debug)]
386enum Descriptor {
387 Pending(oneshot::Sender<Result<LocalDataTrack, PublishError>>),
393 Active {
398 info: Arc<DataTrackInfo>,
399 state_tx: watch::Sender<PublishState>,
400 task_handle: livekit_runtime::JoinHandle<()>,
401 },
402}
403
404#[derive(Debug, Clone, Copy, PartialEq, Eq)]
405pub(crate) enum PublishState {
406 Published,
408 Republishing,
410 Unpublished,
412}
413
414#[derive(Debug, Clone)]
416pub struct ManagerInput {
417 event_in_tx: mpsc::Sender<InputEvent>,
418 _drop_guard: Arc<DropGuard>,
419}
420
421#[derive(Debug)]
423pub struct ManagerOutput(ReceiverStream<OutputEvent>);
424
425impl Stream for ManagerOutput {
426 type Item = OutputEvent;
427
428 fn poll_next(mut self: Pin<&mut Self>, cx: &mut TaskContext<'_>) -> Poll<Option<Self::Item>> {
429 Pin::new(&mut self.0).poll_next(cx)
430 }
431}
432
433#[derive(Debug)]
435struct DropGuard {
436 event_in_tx: mpsc::Sender<InputEvent>,
437}
438
439impl Drop for DropGuard {
440 fn drop(&mut self) {
441 _ = self.event_in_tx.try_send(InputEvent::Shutdown);
442 }
443}
444
445impl ManagerInput {
446 fn new(event_in_tx: mpsc::Sender<InputEvent>) -> Self {
447 Self { event_in_tx: event_in_tx.clone(), _drop_guard: DropGuard { event_in_tx }.into() }
448 }
449
450 pub fn send(&self, event: InputEvent) -> Result<(), InternalError> {
452 Ok(self.event_in_tx.try_send(event).context("Failed to handle input event")?)
453 }
454
455 pub async fn publish_track(
457 &self,
458 options: DataTrackOptions,
459 ) -> Result<LocalDataTrack, PublishError> {
460 let (result_tx, result_rx) = oneshot::channel();
461
462 let event = PublishRequest { options, result_tx };
463 self.event_in_tx.try_send(event.into()).map_err(|_| PublishError::Disconnected)?;
464
465 let track = tokio::time::timeout(Self::PUBLISH_TIMEOUT, result_rx)
466 .await
467 .map_err(|_| PublishError::Timeout)?
468 .map_err(|_| PublishError::Disconnected)??;
469
470 Ok(track)
471 }
472
473 pub async fn query_tracks(&self) -> Vec<Arc<DataTrackInfo>> {
478 let (result_tx, result_rx) = oneshot::channel();
479
480 let event = QueryPublished { result_tx };
481 if self.event_in_tx.send(event.into()).await.is_err() {
482 return vec![];
483 }
484
485 result_rx.await.unwrap_or_default()
486 }
487
488 const PUBLISH_TIMEOUT: Duration = Duration::from_secs(10);
490}
491
492#[cfg(test)]
493mod tests {
494 use super::*;
495 use crate::{
496 api::DataTrackSid,
497 e2ee::{EncryptedPayload, EncryptionError, EncryptionProvider},
498 packet::Packet,
499 utils::testing::expect_event,
500 };
501 use bytes::Bytes;
502 use fake::{Fake, Faker};
503 use futures_util::StreamExt;
504 use livekit_runtime::{sleep, timeout};
505 use std::sync::RwLock;
506
507 #[derive(Debug)]
508 struct PrefixingEncryptor;
509
510 impl EncryptionProvider for PrefixingEncryptor {
511 fn encrypt(&self, payload: Bytes) -> Result<EncryptedPayload, EncryptionError> {
512 let mut output = Vec::with_capacity(4 + payload.len());
513 output.extend_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]);
514 output.extend_from_slice(&payload);
515 Ok(EncryptedPayload { payload: output.into(), iv: [0; 12], key_index: 0 })
516 }
517 }
518
519 #[tokio::test]
520 async fn test_task_shutdown() {
521 let options = ManagerOptions { encryption_provider: None };
522 let (manager, input, _) = Manager::new(options);
523
524 let join_handle = livekit_runtime::spawn(manager.run());
525 _ = input.send(InputEvent::Shutdown);
526
527 timeout(Duration::from_secs(1), join_handle).await.unwrap();
528 }
529
530 #[tokio::test]
531 async fn test_publish() {
532 let payload_size = 256;
533 let packet_count = 10;
534
535 let track_name: String = Faker.fake();
536 let track_sid: DataTrackSid = Faker.fake();
537 let pub_handle: Handle = Faker.fake();
538
539 let options = ManagerOptions { encryption_provider: None };
540 let (manager, input, mut output) = Manager::new(options);
541 livekit_runtime::spawn(manager.run());
542
543 let track_name_clone = track_name.clone();
544 let handle_events = async {
545 let mut packets_sent = 0;
546 while let Some(event) = output.next().await {
547 match event {
548 OutputEvent::SfuPublishRequest(event) => {
549 assert!(!event.uses_e2ee);
550 assert_eq!(event.name, track_name_clone);
551
552 let info = DataTrackInfo {
554 sid: RwLock::new(track_sid.clone()).into(),
555 pub_handle,
556 name: event.name,
557 uses_e2ee: event.uses_e2ee,
558 schema: None,
559 frame_encoding: None,
560 };
561 let event = SfuPublishResponse { handle: event.handle, result: Ok(info) };
562 _ = input.send(event.into());
563 }
564 OutputEvent::PacketsAvailable(packets) => {
565 let packet = packets.into_iter().nth(0).unwrap();
566 let payload = Packet::deserialize(packet).unwrap().payload;
567 assert_eq!(payload.len(), payload_size);
568 packets_sent += 1;
569 }
570 OutputEvent::SfuUnpublishRequest(event) => {
571 assert_eq!(event.handle, pub_handle);
572 assert_eq!(packets_sent, packet_count);
573 break;
574 }
575 }
576 }
577 };
578 let publish_track = async {
579 let track_options = DataTrackOptions::new(track_name.clone());
580 let track = input.publish_track(track_options).await.unwrap();
581 assert!(!track.info().uses_e2ee());
582 assert_eq!(track.info().name(), track_name);
583 assert_eq!(track.info().sid(), track_sid);
584
585 for _ in 0..packet_count {
586 track.try_push(vec![0xFA; payload_size].into()).unwrap();
587 sleep(Duration::from_millis(10)).await;
588 }
589 };
591 timeout(Duration::from_secs(1), async { tokio::join!(publish_track, handle_events) })
592 .await
593 .unwrap();
594 }
595
596 #[tokio::test]
597 async fn test_publish_sfu_error() {
598 let options = ManagerOptions { encryption_provider: None };
599 let (manager, input, mut output) = Manager::new(options);
600 livekit_runtime::spawn(manager.run());
601
602 let (result_tx, result_rx) = oneshot::channel();
603 let event = PublishRequest { options: DataTrackOptions::new("test"), result_tx };
604 input.send(event.into()).unwrap();
605
606 let event = expect_event!(output, OutputEvent::SfuPublishRequest);
608 let event =
609 SfuPublishResponse { handle: event.handle, result: Err(PublishError::LimitReached) };
610 input.send(event.into()).unwrap();
611
612 assert!(result_rx.await.unwrap().is_err());
613 }
614
615 #[tokio::test]
616 async fn test_publish_cancelled() {
617 let options = ManagerOptions { encryption_provider: None };
618 let (manager, input, mut output) = Manager::new(options);
619 livekit_runtime::spawn(manager.run());
620
621 let (result_tx, result_rx) = oneshot::channel();
622 let event = PublishRequest { options: DataTrackOptions::new("test"), result_tx };
623 input.send(event.into()).unwrap();
624
625 let event = expect_event!(output, OutputEvent::SfuPublishRequest);
626 let handle = event.handle;
627
628 drop(result_rx);
630 sleep(Duration::from_millis(50)).await;
631
632 let track_sid: DataTrackSid = Faker.fake();
634 let info = DataTrackInfo {
635 sid: RwLock::new(track_sid).into(),
636 pub_handle: handle,
637 name: "test".into(),
638 uses_e2ee: false,
639 schema: None,
640 frame_encoding: None,
641 };
642 let event = SfuPublishResponse { handle, result: Ok(info) };
643 input.send(event.into()).unwrap();
644
645 let event = expect_event!(output, OutputEvent::SfuUnpublishRequest);
647 assert_eq!(event.handle, handle);
648 }
649
650 #[tokio::test]
651 async fn test_publish_with_e2ee() {
652 let options = ManagerOptions { encryption_provider: Some(Arc::new(PrefixingEncryptor)) };
653 let (manager, input, mut output) = Manager::new(options);
654 livekit_runtime::spawn(manager.run());
655
656 let (result_tx, result_rx) = oneshot::channel();
657 let event = PublishRequest { options: DataTrackOptions::new("secure"), result_tx };
658 input.send(event.into()).unwrap();
659
660 let event = expect_event!(output, OutputEvent::SfuPublishRequest);
662 assert!(event.uses_e2ee);
663
664 let track_sid: DataTrackSid = Faker.fake();
666 let info = DataTrackInfo {
667 sid: RwLock::new(track_sid).into(),
668 pub_handle: event.handle,
669 name: "secure".into(),
670 uses_e2ee: true,
671 schema: None,
672 frame_encoding: None,
673 };
674 let event = SfuPublishResponse { handle: event.handle, result: Ok(info) };
675 input.send(event.into()).unwrap();
676
677 let track = result_rx.await.unwrap().unwrap();
678 assert!(track.info().uses_e2ee());
679
680 track.try_push(vec![1, 2, 3, 4, 5].into()).unwrap();
682
683 let packets = expect_event!(output, OutputEvent::PacketsAvailable);
684 let packet = Packet::deserialize(packets.into_iter().next().unwrap()).unwrap();
685 assert_eq!(&packet.payload[..4], &[0xDE, 0xAD, 0xBE, 0xEF]);
686 assert_eq!(&packet.payload[4..], &[1, 2, 3, 4, 5]);
687 assert!(packet.header.extensions.e2ee.is_some());
688 }
689
690 #[tokio::test]
691 async fn test_republish_tracks() {
692 let options = ManagerOptions { encryption_provider: None };
693 let (manager, input, mut output) = Manager::new(options);
694 livekit_runtime::spawn(manager.run());
695
696 let track_name: String = Faker.fake();
698 let track_sid: DataTrackSid = Faker.fake();
699
700 let (result_tx, result_rx) = oneshot::channel();
701 let event =
702 PublishRequest { options: DataTrackOptions::new(track_name.clone()), result_tx };
703 input.send(event.into()).unwrap();
704
705 let event = expect_event!(output, OutputEvent::SfuPublishRequest);
706 let handle = event.handle;
707
708 let info = DataTrackInfo {
709 sid: RwLock::new(track_sid.clone()).into(),
710 pub_handle: handle,
711 name: track_name.clone(),
712 uses_e2ee: false,
713 schema: None,
714 frame_encoding: None,
715 };
716 let event = SfuPublishResponse { handle, result: Ok(info) };
717 input.send(event.into()).unwrap();
718
719 let track = result_rx.await.unwrap().unwrap();
720 assert_eq!(track.info().sid(), track_sid);
721
722 input.send(InputEvent::RepublishTracks).unwrap();
724 sleep(Duration::from_millis(50)).await;
725
726 assert!(track.try_push(vec![0xFF].into()).is_err());
728
729 let event = expect_event!(output, OutputEvent::SfuPublishRequest);
731 assert_eq!(event.handle, handle);
732 assert_eq!(event.name, track_name);
733
734 let new_sid: DataTrackSid = Faker.fake();
735 let info = DataTrackInfo {
736 sid: RwLock::new(new_sid.clone()).into(),
737 pub_handle: handle,
738 name: track_name.clone(),
739 uses_e2ee: false,
740 schema: None,
741 frame_encoding: None,
742 };
743 let event = SfuPublishResponse { handle, result: Ok(info) };
744 input.send(event.into()).unwrap();
745 sleep(Duration::from_millis(50)).await;
746
747 assert_eq!(track.info().sid(), new_sid);
749 assert!(track.try_push(vec![0xFF].into()).is_ok());
750 }
751
752 #[tokio::test]
753 async fn test_query_published() {
754 let options = ManagerOptions { encryption_provider: None };
755 let (manager, input, mut output) = Manager::new(options);
756 livekit_runtime::spawn(manager.run());
757
758 let mut tracks = Vec::new();
760 for name in ["track_a", "track_b"] {
761 let (result_tx, result_rx) = oneshot::channel();
762 let event = PublishRequest { options: DataTrackOptions::new(name), result_tx };
763 input.send(event.into()).unwrap();
764
765 let event = expect_event!(output, OutputEvent::SfuPublishRequest);
766 let info = DataTrackInfo {
767 sid: RwLock::new(Faker.fake()).into(),
768 pub_handle: event.handle,
769 name: name.into(),
770 uses_e2ee: false,
771 schema: None,
772 frame_encoding: None,
773 };
774 let event = SfuPublishResponse { handle: event.handle, result: Ok(info) };
775 input.send(event.into()).unwrap();
776
777 tracks.push(result_rx.await.unwrap().unwrap());
778 }
779
780 let published = input.query_tracks().await;
781 assert_eq!(published.len(), 2);
782
783 let names: Vec<&str> = published.iter().map(|i| i.name()).collect();
784 assert!(names.contains(&"track_a"));
785 assert!(names.contains(&"track_b"));
786 }
787
788 #[tokio::test]
789 async fn test_shutdown_with_pending_and_active() {
790 let options = ManagerOptions { encryption_provider: None };
791 let (manager, input, mut output) = Manager::new(options);
792 livekit_runtime::spawn(manager.run());
793
794 let (result_tx, pending_rx) = oneshot::channel();
796 let event = PublishRequest { options: DataTrackOptions::new("pending"), result_tx };
797 input.send(event.into()).unwrap();
798
799 expect_event!(output, OutputEvent::SfuPublishRequest);
800
801 let (result_tx, result_rx) = oneshot::channel();
803 let event = PublishRequest { options: DataTrackOptions::new("active"), result_tx };
804 input.send(event.into()).unwrap();
805
806 let event = expect_event!(output, OutputEvent::SfuPublishRequest);
807 let info = DataTrackInfo {
808 sid: RwLock::new(Faker.fake()).into(),
809 pub_handle: event.handle,
810 name: "active".into(),
811 uses_e2ee: false,
812 schema: None,
813 frame_encoding: None,
814 };
815 let event = SfuPublishResponse { handle: event.handle, result: Ok(info) };
816 input.send(event.into()).unwrap();
817
818 let active_track = result_rx.await.unwrap().unwrap();
819 assert!(active_track.is_published());
820
821 input.send(InputEvent::Shutdown).unwrap();
823 sleep(Duration::from_millis(50)).await;
824
825 let pending_result = pending_rx.await.unwrap();
827 assert!(pending_result.is_err());
828
829 assert!(!active_track.is_published());
831 }
832}