Skip to content

PlatformAudio stability/shutdown#1193

Draft
alan-george-lk wants to merge 2 commits into
mainfrom
feature/platform-audio-stability
Draft

PlatformAudio stability/shutdown#1193
alan-george-lk wants to merge 2 commits into
mainfrom
feature/platform-audio-stability

Conversation

@alan-george-lk

@alan-george-lk alan-george-lk commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Before you submit your PR

Make sure the following is true before submitting your PR:

  • I have read the contributing guidelines and validated that this PR will be accepted.
  • I have read and followed the principles regarding breaking changes, testing, and code quality.

PR description

It was discovered in client-sdk-cpp action runs that macOS integration tests intermittently crashed during PlatformAudioIntegrationTest.PublishPlatformAudioTrackEndToEnd, often after MediaMultiStreamIntegrationTest completed. The stack showed AudioDeviceMac::CaptureWorkerThread still delivering captured audio into AudioTransportImpl while peer connection transports (JsepTransportController / BundleManager) were being torn down — a native ADM shutdown ordering bug, not a C++ test artifact.

Breaking changes

N/A

MSRV

N/A

Testing

Ideally, unit test the code you add, but ensure you're not repeating existing test cases. Use as many already written scaffolding, utilities as possible; write your own, when needed. If external services, APIs, tokens are required (e.g., running an LK server instance), provide the necessary information. Make sure your tests perform useful, context-aware assertions and do not simply emulate "happy paths".

Async

We want the project to be runtime-agnostic, so please reuse what's already in livekit-runtime and feel free to add anything missing. It's ok to use Tokio directly, when writing unit tests, if necessary. When testing, do not use artificial delays for the state to "catch up"; instead, respect the event flow and subscribe properly using channels or other mechanisms.

alan-george-lk and others added 2 commits June 26, 2026 17:01
Clear remaining FFI handles during dispose so native resources are
released across repeated initialize/shutdown cycles.

Stop and detach platform/synthetic audio I/O before peer connection
factory teardown so macOS CaptureWorkerThread cannot deliver frames
into AudioTransportImpl while transports are being destroyed. Close
rooms before dropping track handles and stop platform capture when
releasing the platform ADM reference.

Co-authored-by: Cursor <cursoragent@cursor.com>
Rename the changeset and document the full ADM teardown + FFI dispose
fix. Bump livekit and libwebrtc as minor for the new shutdown_audio_io
lifecycle hooks; keep livekit-ffi and webrtc-sys as patch.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown
Contributor

Changeset

The following package versions will be affected by this PR:

Package Bump
libwebrtc minor
livekit minor
livekit-ffi patch
webrtc-sys patch

@xianshijing-lk xianshijing-lk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm in general, some comments


// Stops active capture/playout and detaches audio callbacks from both ADMs.
// Must be called with mutex_ held.
void StopAudioIOLocked();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you already document that this function needs to be called under a mutex_, so you don't need to name it StopAudioIOLocked(), just StopAudioIO() or just StopAudio


// Stops platform capture/playout and detaches its callback without touching
// synthetic mode. Must be called with mutex_ held.
void StopPlatformAudioIOLocked();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

if (platform_adm_) {
platform_adm_->RegisterAudioCallback(nullptr);
platform_adm_->StopRecording();
platform_adm_->StopPlayout();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, curiously, why couldn't we set platform_adm_ = nullptr after calling StopXXX() function ?

if (synthetic_adm_) {
synthetic_adm_->RegisterAudioCallback(nullptr);
synthetic_adm_->StopRecording();
synthetic_adm_->StopPlayout();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

///
/// Call before tearing down the peer connection factory so capture worker
/// threads cannot deliver frames into transports that are being destroyed.
void ShutdownAudioIO();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use StopAudioIOLocked directly without ShutdownAudioIO(); ?

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