diff --git a/livekit/src/room/participant/local_participant.rs b/livekit/src/room/participant/local_participant.rs index b4545fc1b..a2f533310 100644 --- a/livekit/src/room/participant/local_participant.rs +++ b/livekit/src/room/participant/local_participant.rs @@ -667,7 +667,11 @@ impl LocalParticipant { let track = publication.track().unwrap(); let sender = track.transceiver().unwrap().sender(); - self.inner.rtc_engine.remove_track(sender)?; + let remove_result = self.inner.rtc_engine.remove_track(sender); + + // The peer connection may already be closed after a server-initiated + // disconnect. Always release the local publication/track graph even + // when removing its sender is no longer possible. track.set_transceiver(None); if let Some(local_track_unpublished) = @@ -677,7 +681,11 @@ impl LocalParticipant { } publication.set_track(None); - self.inner.rtc_engine.publisher_negotiation_needed(); + if remove_result.is_ok() { + self.inner.rtc_engine.publisher_negotiation_needed(); + } + + remove_result?; Ok(publication) } else { diff --git a/livekit/tests/reconnection_test.rs b/livekit/tests/reconnection_test.rs index 2d9d7be1a..ebf360177 100644 --- a/livekit/tests/reconnection_test.rs +++ b/livekit/tests/reconnection_test.rs @@ -39,15 +39,23 @@ use { anyhow::{anyhow, bail, Result}, common::test_rooms, - libwebrtc::native::create_random_uuid, - livekit::{ConnectionState, Room, RoomEvent, RoomOptions, SimulateScenario}, + libwebrtc::{ + native::create_random_uuid, + prelude::{RtcVideoSource, VideoResolution}, + video_source::native::NativeVideoSource, + }, + livekit::{ + options::TrackPublishOptions, + track::{LocalTrack, LocalVideoTrack}, + ConnectionState, Room, RoomEvent, RoomOptions, SimulateScenario, + }, livekit_api::services::room::RoomClient, livekit_token::{AccessToken, VideoGrants}, std::{env, net::SocketAddr, time::Duration}, tokio::{ net::{TcpListener, TcpStream}, sync::{mpsc::UnboundedReceiver, watch}, - time::timeout, + time::{self, timeout}, }, }; @@ -396,6 +404,19 @@ async fn test_room_deleted_disconnects_without_reconnect() -> Result<()> { let (room, mut events) = Room::connect(&server_url, &token, RoomOptions::default()).await?; assert_eq!(room.connection_state(), ConnectionState::Connected); + let session_dropped = room.drop_probe(); + + let source = NativeVideoSource::new(VideoResolution { width: 16, height: 16 }, false); + let track = LocalVideoTrack::create_video_track( + "server-deleted-track", + RtcVideoSource::Native(source.clone()), + ); + let publication = room + .local_participant() + .publish_track(LocalTrack::Video(track), TrackPublishOptions::default()) + .await?; + assert!(publication.track().is_some()); + let http_url = server_url.replacen("ws", "http", 1); RoomClient::with_api_key(&http_url, &api_key, &api_secret).delete_room(&room_name).await?; @@ -413,5 +434,26 @@ async fn test_room_deleted_disconnects_without_reconnect() -> Result<()> { assert_eq!(reason, livekit::DisconnectReason::RoomDeleted); assert_eq!(room.connection_state(), ConnectionState::Disconnected); + + timeout(Duration::from_secs(5), async { + while publication.track().is_some() { + time::sleep(Duration::from_millis(10)).await; + } + }) + .await + .map_err(|_| anyhow!("server deletion did not detach the published local track"))?; + + drop(publication); + drop(source); + drop(events); + drop(room); + + timeout(Duration::from_secs(5), async { + while !session_dropped() { + time::sleep(Duration::from_millis(10)).await; + } + }) + .await + .map_err(|_| anyhow!("published track retained the room session after server deletion"))?; Ok(()) } diff --git a/webrtc-sys/src/nvidia/cuda_context.cpp b/webrtc-sys/src/nvidia/cuda_context.cpp index f46358d7c..9355d8b11 100644 --- a/webrtc-sys/src/nvidia/cuda_context.cpp +++ b/webrtc-sys/src/nvidia/cuda_context.cpp @@ -9,7 +9,6 @@ #include #endif -#include #include #if defined(WIN32) diff --git a/webrtc-sys/src/nvidia/nvidia_decoder_factory.cpp b/webrtc-sys/src/nvidia/nvidia_decoder_factory.cpp index bc8ca2cf7..740e180aa 100644 --- a/webrtc-sys/src/nvidia/nvidia_decoder_factory.cpp +++ b/webrtc-sys/src/nvidia/nvidia_decoder_factory.cpp @@ -52,12 +52,7 @@ bool IsNvdecRuntimeAvailable() { } // namespace -static int GetCudaDeviceCapabilityMajorVersion(CUcontext context) { - cuCtxSetCurrent(context); - - CUdevice device; - cuCtxGetDevice(&device); - +static int GetCudaDeviceCapabilityMajorVersion(CUdevice device) { int major; cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, device); @@ -65,14 +60,14 @@ static int GetCudaDeviceCapabilityMajorVersion(CUcontext context) { return major; } -std::vector SupportedNvDecoderCodecs(CUcontext context) { +std::vector SupportedNvDecoderCodecs(CUdevice device) { std::vector supportedFormats; // HardwareGeneration Kepler is 3.x // https://docs.nvidia.com/deploy/cuda-compatibility/index.html#faq // Kepler support h264 profile Main, Highprofile up to Level4.1 // https://docs.nvidia.com/video-technologies/video-codec-sdk/nvdec-video-decoder-api-prog-guide/index.html#video-decoder-capabilities__table_o3x_fms_3lb - if (GetCudaDeviceCapabilityMajorVersion(context) <= 3) { + if (GetCudaDeviceCapabilityMajorVersion(device) <= 3) { supportedFormats = { CreateH264Format(webrtc::H264Profile::kProfileHigh, webrtc::H264Level::kLevel4_1, "1"), @@ -117,13 +112,12 @@ NvidiaVideoDecoderFactory::NvidiaVideoDecoderFactory() return; } - cu_context_ = livekit_ffi::CudaContext::GetInstance(); - if (cu_context_->Initialize()) { - supported_formats_ = SupportedNvDecoderCodecs(cu_context_->GetContext()); - } else { - RTC_LOG(LS_ERROR) << "Failed to initialize CUDA context."; - cu_context_ = nullptr; + CUdevice device; + if (cuDeviceGet(&device, 0) != CUDA_SUCCESS) { + RTC_LOG(LS_ERROR) << "Failed to get CUDA device."; + return; } + supported_formats_ = SupportedNvDecoderCodecs(device); RTC_LOG(LS_INFO) << "NvidiaVideoDecoderFactory created with " << supported_formats_.size() << " supported formats."; } @@ -154,7 +148,7 @@ bool NvidiaVideoDecoderFactory::IsSupported() { return false; } - std::cout << "Nvidia Decoder is supported." << std::endl; + RTC_LOG(LS_INFO) << "Nvidia Decoder is supported."; return true; } diff --git a/webrtc-sys/src/vaapi/vaapi_display_drm.cpp b/webrtc-sys/src/vaapi/vaapi_display_drm.cpp index be2259711..53cba2bf1 100644 --- a/webrtc-sys/src/vaapi/vaapi_display_drm.cpp +++ b/webrtc-sys/src/vaapi/vaapi_display_drm.cpp @@ -41,6 +41,7 @@ static bool check_h264_encoding_support(VADisplay va_display) { entrypoints = new VAEntrypoint[num_entrypoints * sizeof(*entrypoints)]; if (!entrypoints) { RTC_LOG(LS_ERROR) << "failed to allocate VA entrypoints"; + vaTerminate(va_display); return false; } @@ -75,10 +76,12 @@ static bool check_h264_encoding_support(VADisplay va_display) { << "Can't find VAEntrypointEncSlice or VAEntrypointEncSliceLP for " "H264 profiles"; delete[] entrypoints; + vaTerminate(va_display); return false; } delete[] entrypoints; + vaTerminate(va_display); return true; } diff --git a/webrtc-sys/src/vaapi/vaapi_encoder_factory.cpp b/webrtc-sys/src/vaapi/vaapi_encoder_factory.cpp index d418bbcaf..2926a1c1e 100644 --- a/webrtc-sys/src/vaapi/vaapi_encoder_factory.cpp +++ b/webrtc-sys/src/vaapi/vaapi_encoder_factory.cpp @@ -1,7 +1,6 @@ #include "vaapi_encoder_factory.h" #include -#include #include #include "h264_encoder_impl.h" @@ -64,7 +63,7 @@ bool VAAPIVideoEncoderFactory::IsSupported() { vaapi_display.Close(); // If we can open the VAAPI display, we consider it supported. - std::cout << "VAAPI is supported." << std::endl; + RTC_LOG(LS_INFO) << "VAAPI is supported."; return true; }