Skip to content

fix: workaround for android non-telecom path MODE_IN_COMMUNICATION reset edge-case - #2360

Open
santhoshvai wants to merge 4 commits into
mainfrom
android-workaround-for-audiomode-reset
Open

fix: workaround for android non-telecom path MODE_IN_COMMUNICATION reset edge-case#2360
santhoshvai wants to merge 4 commits into
mainfrom
android-workaround-for-audiomode-reset

Conversation

@santhoshvai

@santhoshvai santhoshvai commented Aug 5, 2026

Copy link
Copy Markdown
Member

💡 Overview

Fixes Android audio routing breaking mid-call on Android 11+. The OS resets
AudioManager.MODE_IN_COMMUNICATION ~6s after it's set when the app has no active
voice-comm playback or recording — dropping the
call to the default media route and disabling AEC (https://issuetracker.google.com/issues/209493718).

This PR adds a workaround that plays a silent, looping voice-communication AudioTrack for the
duration of a communicator-role call, so the OS always sees active playback and holds the
mode. Android-only; no-op below API 30 and for the listener role / Telecom-managed calls.

📝 Implementation notes

  • CommunicationModeKeepAlive.kt: plays a silent-AudioTrack to keep-alive; falls back to a periodic
    MODE_IN_COMMUNICATION re-assert watchdog if the track can't be built.

🎫 Ticket: https://linear.app/stream/issue/XYZ-123

📑 Docs: https://github.com/GetStream/docs-content/pull/

Summary by CodeRabbit

  • New Features
    • Added an Android-only option to disable the communication-mode workaround for communicator calls.
    • Added a public API to configure this option before a call starts.
    • On Android 11 and later, audio communication mode is maintained more reliably during supported calls.
    • The setting is ignored on iOS and unsupported call types, and remains compatible with native modules that do not provide the new capability.
  • Bug Fixes
    • Improved audio state cleanup when calls end, including when activity availability changes.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an Android 11+ communication-mode keep-alive workaround with configuration and setter APIs. Integrates it with call audio lifecycle handling, diagnostics, compatibility fallbacks, and forwarding tests.

Changes

Communication mode workaround

Layer / File(s) Summary
SDK configuration and forwarding
packages/react-native-sdk/src/modules/call-manager/types.ts, packages/react-native-sdk/src/modules/call-manager/native-module.d.ts, packages/react-native-sdk/src/modules/call-manager/CallManager.ts, packages/react-native-sdk/__tests__/call-manager/CallManager.test.ts
Adds the optional configuration property and setter API. Forwards explicit values for Android classic Communicator calls. Tests cover omitted values, platform exclusions, call-mode exclusions, and missing native methods.
Android keep-alive implementation
packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/audio/CommunicationModeKeepAlive.kt
Adds silent AudioTrack playback on Android API 30+, a polling fallback, lifecycle management, state reporting, and a no-op implementation for older versions.
Audio lifecycle integration
packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/audio/AudioDeviceManager.kt, packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt
Starts the keep-alive for eligible calls, stops it before route teardown, releases it during close, restores normal audio mode, validates setter timing, and exposes state diagnostics.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CallManager
  participant StreamInCallManagerModule
  participant AudioDeviceManager
  participant CommunicationModeKeepAlive
  participant AudioTrack
  CallManager->>StreamInCallManagerModule: Start communicator call with optional setting
  StreamInCallManagerModule->>AudioDeviceManager: Configure workaround
  AudioDeviceManager->>CommunicationModeKeepAlive: Start for eligible Android calls
  CommunicationModeKeepAlive->>AudioTrack: Play silent voice-communication audio
  AudioDeviceManager->>CommunicationModeKeepAlive: Stop before audio teardown
  CommunicationModeKeepAlive->>AudioTrack: Release resources
Loading

Suggested reviewers: oliverlaz, greenfrvr

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the Android non-Telecom communication-mode reset workaround.
Description check ✅ Passed The description includes the required overview, implementation notes, ticket, and documentation sections with relevant details.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch android-workaround-for-audiomode-reset

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@santhoshvai santhoshvai changed the title fix: workaround for android non-telecom path MODE_NORMAL switch by platform case fix: workaround for android non-telecom path MODE_IN_COMMUNICATION reset edge-case Aug 5, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/audio/AudioDeviceManager.kt`:
- Around line 173-180: The stop flow in AudioDeviceManager.stop() currently
depends on currentActivity being available before releasing audio state.
Decouple teardown from the Activity-dependent block so audioManagerActivated is
reset and communicationWorkaround.stop() always runs, including when
currentActivity is null; keep only Activity-specific cleanup conditional on the
activity.
- Around line 301-305: Update AudioDeviceManager.close() to queue
communicationWorkaround disposal and all related audio cleanup on the same audio
executor used by start() and stop(), rather than performing it directly. Ensure
close() cannot race pending audio work or allow a queued start() to access
audioTrack or watchdog after cleanup, while preserving the existing callback
unregistration and proximityManager teardown behavior.

In
`@packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/audio/CommunicationWorkaround.kt`:
- Around line 223-231: The watchdog repair in CommunicationWorkaround is still
able to run after stop() has restored MODE_NORMAL, so update the
AudioDeviceManager.runInAudioThread closure to check the active state before
touching AudioManager.mode. Keep the existing mode re-assertion logic in the
same watchdog block, but gate the read/write with the component’s current
running/active flag so stale queued work exits without setting
MODE_IN_COMMUNICATION after shutdown.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 31a96c71-a814-4394-a6a8-4ebfce921611

📥 Commits

Reviewing files that changed from the base of the PR and between 5ae2dfe and 912904c.

📒 Files selected for processing (7)
  • packages/react-native-sdk/__tests__/call-manager/CallManager.test.ts
  • packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/audio/AudioDeviceManager.kt
  • packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/audio/CommunicationWorkaround.kt
  • packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt
  • packages/react-native-sdk/src/modules/call-manager/CallManager.ts
  • packages/react-native-sdk/src/modules/call-manager/native-module.d.ts
  • packages/react-native-sdk/src/modules/call-manager/types.ts

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Bundle size

Built package output. Sizes in KB; delta vs main@3e6b675.

Package Unminified Minified Δ min vs main
@stream-io/video-react-native-sdk 408.7 KB 194.6 KB +345 B (+0.2%)
↳ install total (+ client + react-bindings) 1187.0 KB 468.7 KB +345 B (+0.1%)

@santhoshvai
santhoshvai marked this pull request as draft August 6, 2026 10:11
@santhoshvai
santhoshvai marked this pull request as ready for review August 10, 2026 10:19
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.

1 participant