Skip to content

Avoid unnecessary thread switching in audio cleanup and frame cryptor setup to prevent WebRTC deadlocks#197

Merged
hiroshihorie merged 5 commits intowebrtc-sdk:m137_releasefrom
brainwith:m137_release
Sep 25, 2025
Merged

Avoid unnecessary thread switching in audio cleanup and frame cryptor setup to prevent WebRTC deadlocks#197
hiroshihorie merged 5 commits intowebrtc-sdk:m137_releasefrom
brainwith:m137_release

Conversation

@brainwith
Copy link
Copy Markdown
Contributor

Description

This PR makes two small but important changes to improve thread safety and reduce deadlock risk in the iOS bindings:

1. RTCAudioTrack.mm

  • Remove the explicit [self removeAllRenderers].
  • Instead, iterate _adapters and remove each sink from the native audio track without switching threads, aligning the behavior with RTCVideoTrack.mm.
  • This simplifies teardown and avoids extra synchronization points.

2.RTCFrameCryptor.mm

  • Remove factory.signalingThread->BlockingCall around nativeRtpReceiver->SetDepacketizerToDecoderFrameTransformer(...).
  • The native call path already runs on the worker thread, so performing a BlockingCall from the signaling thread introduces an unnecessary signaling → worker hop that can increase deadlock risk in tight teardown/configuration sequences.

Problem Solved

  • Redundant signaling → worker thread switching during audio renderer cleanup and frame-cryptor configuration could contribute to deadlocks under timing-sensitive conditions (e.g., track teardown overlapping with transformer setup).
  • By eliminating that extra hop, we reduce contention between signaling and worker threads without changing observable behavior.

Impact

  • Lower likelihood of hangs/deadlocks on teardown/configuration paths.
  • Implementation now matches RTCVideoTrack.mm for audio cleanup.
  • No public API changes.

@hiroshihorie
Copy link
Copy Markdown
Member

Thank you @brainwith for the PR, I will take a better look in the following days.

  • Have you actually experienced any deadlock with the audio renderer dealloc ?

@brainwith
Copy link
Copy Markdown
Contributor Author

Thank you @brainwith for the PR, I will take a better look in the following days.

  • Have you actually experienced any deadlock with the audio renderer dealloc ?

@hiroshihorie Yes, I’ve actually hit deadlocks with the audio renderer dealloc.

The scenario is roughly:

  • Multi-party conference with several participants publishing audio (mics on).
  • On iOS, when autoSubscribe = true and e2eeEnable = true, if the client joins and leaves rooms quickly in succession, it tends to trigger a freeze.

Stack observation:

  • When a RemoteAudioTrack is released, RTCAudioTrack.dealloc calls into a BlockingCall on the signaling thread.
  • Meanwhile, as the new room is being joined, a new RTCFrameCryptor is created, which internally issues BlockingCalls on both the signaling and worker threads.
  • These overlapping blocking calls create a circular dependency that can easily lead to a deadlock.

That’s why this patch removes the unnecessary thread switch — to avoid this contention.

@hiroshihorie hiroshihorie merged commit ebd5a9f into webrtc-sdk:m137_release Sep 25, 2025
cloudwebrtc pushed a commit that referenced this pull request Feb 2, 2026
… setup to prevent WebRTC deadlocks (#197)

## Description
This PR makes two small but important changes to improve thread safety
and reduce deadlock risk in the iOS bindings:

### 1. RTCAudioTrack.mm

- Remove the explicit [self removeAllRenderers].
- Instead, iterate _adapters and remove each sink from the native audio
track without switching threads, aligning the behavior with
RTCVideoTrack.mm.
- This simplifies teardown and avoids extra synchronization points.

### 2.RTCFrameCryptor.mm

- Remove factory.signalingThread->BlockingCall around
nativeRtpReceiver->SetDepacketizerToDecoderFrameTransformer(...).
- The native call path already runs on the worker thread, so performing
a BlockingCall from the signaling thread introduces an unnecessary
signaling → worker hop that can increase deadlock risk in tight
teardown/configuration sequences.

## Problem Solved

- Redundant signaling → worker thread switching during audio renderer
cleanup and frame-cryptor configuration could contribute to deadlocks
under timing-sensitive conditions (e.g., track teardown overlapping with
transformer setup).
- By eliminating that extra hop, we reduce contention between signaling
and worker threads without changing observable behavior.

## Impact

- Lower likelihood of hangs/deadlocks on teardown/configuration paths.
- Implementation now matches RTCVideoTrack.mm for audio cleanup.
- No public API changes.

---------

Co-authored-by: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants