From 5b7c3d4b96155400b09fda8b194e1e0ff3af6792 Mon Sep 17 00:00:00 2001 From: Jay Cho Date: Mon, 15 Jun 2026 09:47:07 +0900 Subject: [PATCH 1/2] [Tizen.Multimedia.Remoting] Add RunContinuationsAsynchronously to async TCS The 8 TaskCompletionSource sites in ScreenMirroring, WebRTC, MediaController and MediaControlServer complete on native/event-manager callback threads. Without RunContinuationsAsynchronously their continuations run inline on the completing thread, which can occupy native callback threads and risk deadlock on SynchronizationContext re-entry. Mirrors the WiFi fix in #7620. Fixes #7639 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../MediaController/MediaControlServer.cs | 4 ++-- .../MediaController/MediaController.cs | 4 ++-- .../ScreenMirroring/ScreenMirroring.cs | 2 +- src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Tizen.Multimedia.Remoting/MediaController/MediaControlServer.cs b/src/Tizen.Multimedia.Remoting/MediaController/MediaControlServer.cs index 6b6b227517c..1f50bdff34f 100644 --- a/src/Tizen.Multimedia.Remoting/MediaController/MediaControlServer.cs +++ b/src/Tizen.Multimedia.Remoting/MediaController/MediaControlServer.cs @@ -850,7 +850,7 @@ public static void SetDisplayRotationCapability(Rotation rotation, MediaControlC command.SetRequestInformation(clientId); - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); string reqeustId = null; Bundle bundle = null; @@ -909,7 +909,7 @@ public static async Task RequestAsync(Command command, string clientId) command.SetRequestInformation(clientId); - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); string reqeustId = null; Bundle bundle = null; diff --git a/src/Tizen.Multimedia.Remoting/MediaController/MediaController.cs b/src/Tizen.Multimedia.Remoting/MediaController/MediaController.cs index 6aaf55d5e23..9d52796b4f3 100644 --- a/src/Tizen.Multimedia.Remoting/MediaController/MediaController.cs +++ b/src/Tizen.Multimedia.Remoting/MediaController/MediaController.cs @@ -853,7 +853,7 @@ public IEnumerable GetDisplayRotationCapability() command.SetRequestInformation(ServerAppId); - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); string reqeustId = null; Bundle bundle = null; @@ -918,7 +918,7 @@ public async Task RequestAsync(Command command) command.SetRequestInformation(ServerAppId); - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); string reqeustId = null; Bundle bundle = null; diff --git a/src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.cs b/src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.cs index 80ea9ddd222..1aad04f4c1c 100644 --- a/src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.cs +++ b/src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.cs @@ -262,7 +262,7 @@ private void PrepareCore(Display display, ScreenMirroringResolutions resolutions private Task RunAsync(Func func, string failMessage) { - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); Task.Run(() => { diff --git a/src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs b/src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs index a6d3ce2857e..905c891326a 100755 --- a/src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs +++ b/src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs @@ -168,7 +168,7 @@ public async Task StartAsync() ValidateWebRTCState(WebRTCState.Idle); - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var error = WebRTCError.ConnectionFailed; EventHandler stateChangedEventHandler = (s, e) => @@ -244,7 +244,7 @@ public async Task CreateOfferAsync() ValidateWebRTCState(WebRTCState.Negotiating, WebRTCState.Playing); - var tcsSdpCreated = new TaskCompletionSource(); + var tcsSdpCreated = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); NativeWebRTC.SdpCreatedCallback cb = (handle, sdp, _) => { @@ -283,7 +283,7 @@ public async Task CreateAnswerAsync() ValidateWebRTCState(WebRTCState.Negotiating, WebRTCState.Playing); - var tcsSdpCreated = new TaskCompletionSource(); + var tcsSdpCreated = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); NativeWebRTC.SdpCreatedCallback cb = (handle, sdp, _) => { From 64f1117b189bce4acef37b4136acc684abb2527d Mon Sep 17 00:00:00 2001 From: Jay Cho Date: Wed, 17 Jun 2026 21:04:22 +0900 Subject: [PATCH 2/2] Address review feedback Simplify ScreenMirroring.RunAsync to return Task.Run directly (drop redundant TaskCompletionSource), and remove now-redundant await Task.Yield() after awaiting RunContinuationsAsynchronously TCS in WebRTC.StartAsync/CreateOfferAsync/CreateAnswerAsync. Applied-Human-Comments: 3410546783,3410546787,3410546789,3410546792 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../ScreenMirroring/ScreenMirroring.cs | 14 +++----------- src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs | 3 --- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.cs b/src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.cs index 1aad04f4c1c..5f0091566ba 100644 --- a/src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.cs +++ b/src/Tizen.Multimedia.Remoting/ScreenMirroring/ScreenMirroring.cs @@ -262,23 +262,15 @@ private void PrepareCore(Display display, ScreenMirroringResolutions resolutions private Task RunAsync(Func func, string failMessage) { - var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - - Task.Run(() => + return Task.Run(() => { var ret = func(Handle); - if (ret == ScreenMirroringErrorCode.None) + if (ret != ScreenMirroringErrorCode.None) { - tcs.SetResult(true); - } - else - { - tcs.SetException(ret.AsException(failMessage)); + throw ret.AsException(failMessage); } }); - - return tcs.Task; } /// diff --git a/src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs b/src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs index 905c891326a..c918c827aa6 100755 --- a/src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs +++ b/src/Tizen.Multimedia.Remoting/WebRTC/WebRTC.cs @@ -193,7 +193,6 @@ public async Task StartAsync() NativeWebRTC.Start(Handle).ThrowIfFailed("Failed to start the WebRTC"); var result = await tcs.Task.ConfigureAwait(false); - await Task.Yield(); if (!result) { @@ -258,7 +257,6 @@ public async Task CreateOfferAsync() ThrowIfFailed("Failed to create offer asynchronously"); offer = await tcsSdpCreated.Task.ConfigureAwait(false); - await Task.Yield(); } Log.Info(WebRTCLog.Tag, "Leave"); @@ -297,7 +295,6 @@ public async Task CreateAnswerAsync() ThrowIfFailed("Failed to create answer asynchronously"); answer = await tcsSdpCreated.Task.ConfigureAwait(false); - await Task.Yield(); } Log.Info(WebRTCLog.Tag, "Leave");