Skip to content

[DRAFT] Runtime controls for microphone audio processing and bitrate - #1787

Draft
aleksandar-apostolov wants to merge 5 commits into
developfrom
feature/runtime-mic-processing-controls
Draft

[DRAFT] Runtime controls for microphone audio processing and bitrate#1787
aleksandar-apostolov wants to merge 5 commits into
developfrom
feature/runtime-mic-processing-controls

Conversation

@aleksandar-apostolov

@aleksandar-apostolov aleksandar-apostolov commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Goal

Expose each stage as its own runtime control.

Implementation

Three independent controls on MicrophoneManager

  • setHardwareNoiseSuppressorEnabled / hardwareNoiseSuppressorEnabled
  • setSoftwareAudioProcessingEnabled / softwareAudioProcessingEnabled — the goog* constraints
  • setAudioMaxBitrate / audioMaxBitrateBps — applied through the sender's RtpParameters

Using it

Switching a live broadcast to music and back:

call.setAudioProcessingEnabled(false)   // noise-cancellation processor, if one is configured needs to be clelared
call.microphone.setSoftwareAudioProcessingEnabled(false)
call.microphone.setHardwareNoiseSuppressorEnabled(false)
call.microphone.setAudioMaxBitrate(128_000)

Each has a StateFlow for rendering a toggle — hardwareNoiseSuppressorEnabled, softwareAudioProcessingEnabled, audioMaxBitrateBps. They report the requested state; the setter's return value tells you whether the platform took it.

Testing

Check and verify that each toggle affects the audio quality especially when music is playing.

The platform noise suppressor is decided when the audio device module is
built, from the audio bitrate profile alone, and MUSIC_HIGH_QUALITY is the
only thing that turns it off — a profile that cannot be selected once the
call is joined. A broadcaster who starts playing music mid-broadcast is
suppressed to near silence with no way out.

The effect is attached to the live recording session, so unlike the builder
flag it can be changed while capture runs. Expose that on MicrophoneManager
as its own control, independent of the profile: the software audio
processing, the noise-cancellation processor and the bitrate are untouched.

A recording session drops the platform effects and rebuilds them from the
builder flags, so the request is remembered and re-applied whenever capture
starts. Without that it would silently revert on the next reconnect.
Echo cancellation, noise suppression, automatic gain control and the
high-pass filter are all tuned for speech — automatic gain control audibly
pumps sustained music. They are fixed when the audio source is created, from
the audio bitrate profile, so today the only way to change them is to pick
MUSIC_HIGH_QUALITY before joining.

Expose them on MicrophoneManager as their own control. Applying a change
builds a fresh audio source and track and moves the live sender onto it,
which costs a brief gap in captured audio but needs no renegotiation.

The swap is the delicate part. RtpSender.setTrack disposes the track it
currently holds only when it owns it, and MediaManagerImpl already owns and
disposes the audio track, so the sender is handed the new track with
ownership left behind — disposal stays in exactly one place. The rebuild runs
under the media lock and rolls the new pair back if no sender accepted it, so
a failed swap never tears down the source that is still live.
Adds the two runtime controls to the in-call debug submenu so they can be
exercised on a device: each item shows the current state, highlights when the
stage is on, and flips it.

Both setters report whether the platform actually applied the change, and the
menu surfaces a refusal as a toast. Without it a toggle that did nothing —
unsupported device, or no capture running — looks identical to one that
worked, which is the failure the controls are most likely to hit in the
field.
The audio bitrate was fixed when the transceiver was created, from the audio
bitrate profile, so it could only be chosen before joining. It rides on the
sender's encoding rather than the SDP, so it can be changed on a running
call through RtpParameters — the same way the video layers and the
degradation preference already are. No renegotiation, no track swap, no gap.

Verifying that needed stats that did not exist. Every group CallStats
consumed was video; audio was dropped on the floor even though the report
carries it. Adds audio send and receive bitrate measured from the RTP byte
counters, the encoder's target bitrate, and the negotiated audio codec with
its fmtp line.

The two existing bitrate rows are renamed to say what they are. They report
availableOutgoingBitrate from the candidate pair — a bandwidth estimate, not
a transmitted rate — and they sit at zero whenever the selected pair omits
it, which reads as a broken stat rather than an absent one.

Measured on a Pixel 7: outbound-rtp targetBitrate moves 64000 -> 128000 with
the negotiated fmtp untouched, so nothing clamps the request.
@aleksandar-apostolov aleksandar-apostolov added the pr:new-feature Adds new functionality label Aug 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR checklist ❌

The following issues were detected:

  • Linked issue missing. Add a Linear ticket reference (e.g. AND-123, Closes AND-123, or a https://linear.app/... link) or a GitHub issue (Closes #123) to the PR description.

What we check

  1. Title is concise (5–18 words) unless labeled pr:ignore-for-release.
  2. At least one pr: label exists (e.g., pr:bug, pr:new-feature).
  3. Sections ### Goal, ### Implementation, and ### Testing contain content. Bot-authored PRs are exempt.
  4. PR description references an issue (Linear ticket like AND-123, a Linear URL, or a GitHub Closes #N). Bot-authored PRs are exempt.

@github-actions

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-video-android-core 12.29 MB 12.29 MB 0.00 MB 🟢
stream-video-android-ui-xml 5.70 MB 5.70 MB 0.00 MB 🟢
stream-video-android-ui-compose 6.20 MB 6.20 MB 0.00 MB 🟢

@aleksandar-apostolov aleksandar-apostolov changed the title Runtime controls for microphone audio processing and bitrate [DRAFT] Runtime controls for microphone audio processing and bitrate Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:new-feature Adds new functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants