Skip to content

feat: hi-fi audio - #50

Open
greenfrvr wants to merge 10 commits into
masterfrom
hi-fi-audio
Open

feat: hi-fi audio#50
greenfrvr wants to merge 10 commits into
masterfrom
hi-fi-audio

Conversation

@greenfrvr

@greenfrvr greenfrvr commented Jun 25, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features
    • Added native camera previews for Android and iOS with camera selection, mirroring, sizing, and object-fit controls.
    • Camera previews can transfer directly into video calls without restarting capture.
    • Added a public CallFactory API for creating and disposing call resources.
  • Bug Fixes
    • Improved WebRTC factory, media-track, and audio resource lifecycle management.
    • Improved voice-processing and audio-device handling.
  • Documentation
    • Removed outdated Android audio-category setup instructions.

@greenfrvr greenfrvr self-assigned this Jun 25, 2026
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds per-call PeerConnectionFactory providers and registries on Android and iOS. It routes media resources through these providers. It adds native camera preview components with active-capture handoff to WebRTC tracks. JavaScript exports expose factory lifecycle and camera preview APIs.

Changes

Factory lifecycle, media routing, and camera preview

Layer / File(s) Summary
Android factory and media lifecycle
android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java, android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryRegistry.java, android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java, android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java
Per-call factories own audio modules and media resources. Android module, peer connection, track, stream, screen-share, codec, and disposal paths use registry providers.
Android camera preview
android/src/main/java/com/oney/WebRTCModule/RTCCameraPreviewView.java, android/src/main/java/com/oney/WebRTCModule/FanoutCapturerObserver.java, android/src/main/java/com/oney/WebRTCModule/RTCCameraPreviewViewManager.java, android/src/main/java/com/oney/WebRTCModule/WebRTCModulePackage.java
Adds direct camera capture with prop reconciliation, renderer and downstream fan-out, handoff to video tracks, cleanup, and React Native registration.
iOS factory and module lifecycle
ios/RCTWebRTC/Utils/PeerConnectionFactory/*, ios/RCTWebRTC/WebRTCModule.h, ios/RCTWebRTC/WebRTCModule.m, ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m, ios/RCTWebRTC/Utils/AudioDeviceModule/AudioDeviceModule.swift
Adds provider and registry lifecycle management, call-factory exports, current audio-device access, preview adoption, and ADM wrapper methods.
iOS camera preview
ios/RCTWebRTC/RTCCameraPreviewViewManager.h, ios/RCTWebRTC/RTCCameraPreviewViewManager.m
Adds a prop-driven camera preview view and manager with rendering, capture lifecycle, constraints, and capturer adoption.
JavaScript API surface
src/CallFactory.ts, src/RTCCameraPreviewView.ts, src/index.ts
Exports call-factory lifecycle methods, options, and the native camera preview component.
Android installation documentation
Documentation/AndroidInstallation.md
Removes the obsolete audio-category setup section.

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

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant CallFactory
  participant WebRTCModule
  participant PeerConnectionFactoryRegistry
  App->>CallFactory: create(options)
  CallFactory->>WebRTCModule: createCallFactory(options)
  WebRTCModule->>PeerConnectionFactoryRegistry: create(bypassVoiceProcessing)
  PeerConnectionFactoryRegistry-->>WebRTCModule: provider
  App->>CallFactory: dispose()
  CallFactory->>WebRTCModule: disposeCallFactory()
  WebRTCModule->>PeerConnectionFactoryRegistry: disposeCurrent()
Loading
sequenceDiagram
  participant App
  participant CameraPreview
  participant WebRTCModule
  participant MediaTrackCreation
  App->>CameraPreview: activate with camera props
  CameraPreview->>WebRTCModule: register active preview
  MediaTrackCreation->>WebRTCModule: request preview adoption
  WebRTCModule->>CameraPreview: adopt or yield capture
  CameraPreview-->>MediaTrackCreation: capture handoff
  MediaTrackCreation->>MediaTrackCreation: attach capture to video track
Loading

Suggested reviewers: santhoshvai

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the pull request's primary audio-quality changes, including audio processing and factory updates.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hi-fi-audio

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.

@greenfrvr
greenfrvr requested a review from santhoshvai July 17, 2026 13:05
@greenfrvr
greenfrvr marked this pull request as ready for review July 17, 2026 13:05

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java (1)

241-260: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate video prerequisites before creating the audio track.

For an audio-and-video request with no current Activity, the audio source and track are registered before this early return. Since no track ID reaches JavaScript, they remain leaked until factory or module teardown. Resolve the Activity first or dispose the partially created audio track before invoking the error callback.

🤖 Prompt for 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.

In `@android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java` around
lines 241 - 260, Update getUserMedia around createAudioTrack and the
currentActivity null check so video prerequisites are validated before creating
and registering the audio track. Preserve the existing InvalidStateError
callback and return behavior, ensuring audio-only requests still create their
track normally.
🤖 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 `@android/src/main/java/com/oney/WebRTCModule/FanoutCapturerObserver.java`:
- Around line 49-53: Update FanoutCapturerObserver.setDownstream and the
capturer lifecycle and frame-delivery methods to use one shared lock or
executor, serializing observer attachment with started-state callbacks and
downstream frame delivery. Ensure assignment and any onCapturerStarted
notification occur atomically with respect to concurrent start/stop operations,
preventing missed or incorrect lifecycle notifications.

In
`@android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java`:
- Around line 188-217: Update mixScreenAudioIntoBuffer so mixing is limited to
the writable microphone sample count, micSamples. Iterate only across
overlapping samples and remove the screen-only branch that writes beyond
micShorts’ range; preserve saturation for summed microphone and screen samples.
- Around line 87-89: Track whether the ADM in the factory was created by
buildAudioDeviceModule or supplied through options.injectedAudioDeviceModule,
and only release owned instances in dispose(); preserve shared injected
instances for reuse by later factories. In mixScreenAudioIntoBuffer(), clamp the
write loop to the mic buffer/sample count so screen audio cannot cause
micShorts.put to exceed its capacity.

In
`@android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryRegistry.java`:
- Around line 93-101: Update the replacement logic around currentFactory and
currentIsBareForkDefault to never dispose a live default factory directly.
Reject creation of the call factory while that default or its dependents remain
active, or route replacement through WebRTCModule’s ordered dependent cleanup
and disposeCallFactory before creating the new factory.
- Around line 102-105: Update the concurrent-factory branch in createCallFactory
to throw an appropriate exception instead of logging a warning and returning
existing. Ensure the native promise rejects and the second CallFactory cannot
proceed with ignored options or dispose the shared factory.

In `@android/src/main/java/com/oney/WebRTCModule/RTCCameraPreviewView.java`:
- Around line 115-125: Update commitProps and its running-configuration
comparison to snapshot captureWidth and captureHeight alongside facing and
device ID, then treat either dimension changing as configChanged so active
capture is restarted or reconfigured. Ensure the setters’ updated dimensions are
reflected in the committed configuration.
- Around line 241-261: Update yieldForAdoption() so handedOff and
clearActivePreview() are performed inside the captureExecutor task only after
confirming running, captureController, surfaceTextureHelper, and fanoutObserver
are all available. Do not mark the preview handed off or clear the active
preview before the prerequisite check succeeds, and preserve the existing
ownership transfer and null return behavior.
- Around line 268-280: Move the `fanoutObserver` snapshot and related
renderer-detachment decision into the `captureExecutor` task, so
`fanoutObserver` is read on its owning executor before calling
`fanout.setRenderer(null)`. Preserve the existing `releaseRenderer` behavior and
ensure detachment occurs for adopted captures before
`surfaceViewRenderer.release()`.

In `@android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java`:
- Around line 64-65: Make activeCameraPreview thread-safe across React lifecycle
callbacks and WebRTC executor access: synchronize or otherwise safely publish
writes and reads, including the getUserMedia path and the callbacks around lines
275-287. Ensure getUserMedia observes the currently active preview before
attempting to open another camera.
- Around line 153-185: Update disposeCallFactory() to abort factory disposal
when any owned PeerConnection or track fails to dispose, rather than continuing
to factoryRegistry.disposeCurrent(). Track failures, PeerConnection failures,
and any remaining local streams must cause the promise to reject while leaving
the factory and ADM undisposed; only resolve after all dependents are
successfully removed and the ordering invariant is satisfied.

In `@ios/RCTWebRTC/RTCCameraPreviewViewManager.m`:
- Around line 195-228: Serialize all `_captureController` access in the capture
queue: update the start, stop, and constraint-update branches in
`RTCameraPreviewViewManager` to resolve the controller inside `_captureQueue`
rather than snapshotting it beforehand. Before creating or starting capture,
re-check the latest `isActive`/`_capturing` state and abort or stop when
inactive, while preserving queued stop and constraint updates.
- Around line 204-207: Update the fresh preview-controller initialization in the
capture setup around _captureController and VideoCaptureController so the
existing enableMultitaskingCameraAccess setting is also passed to an adopted
preview controller. Preserve the current capturer and constraints initialization
while ensuring both fresh-track and handoff paths use the same multitasking
camera access option.

In `@ios/RCTWebRTC/WebRTCModule.m`:
- Around line 215-219: Update disposeCallFactory to dispose all factory-owned
peer connections and media tracks before invoking self.factoryRegistry
disposeCurrent. Preserve the existing promise resolution, and ensure factory
teardown occurs only after those dependent WebRTC objects have been released.

In `@src/CallFactory.ts`:
- Around line 25-38: Scope each CallFactory handle to its native factory ID: in
src/CallFactory.ts lines 25-38, store the ID returned by createCallFactory and
pass that ID from dispose; in ios/RCTWebRTC/WebRTCModule.m lines 202-219,
resolve creation with the provider ID and require it when disposing; in
ios/RCTWebRTC/Utils/PeerConnectionFactory/PeerConnectionFactoryRegistry.swift
lines 66-86, reject a second live factory instead of reusing the existing
provider and only dispose when the requested ID matches.

---

Outside diff comments:
In `@android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java`:
- Around line 241-260: Update getUserMedia around createAudioTrack and the
currentActivity null check so video prerequisites are validated before creating
and registering the audio track. Preserve the existing InvalidStateError
callback and return behavior, ensuring audio-only requests still create their
track normally.
🪄 Autofix (Beta)

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

Run ID: e0f04110-1d20-4236-b823-20142a7d54de

📥 Commits

Reviewing files that changed from the base of the PR and between 8972b28 and 30614ca.

📒 Files selected for processing (19)
  • android/src/main/java/com/oney/WebRTCModule/FanoutCapturerObserver.java
  • android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java
  • android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java
  • android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryRegistry.java
  • android/src/main/java/com/oney/WebRTCModule/RTCCameraPreviewView.java
  • android/src/main/java/com/oney/WebRTCModule/RTCCameraPreviewViewManager.java
  • android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java
  • android/src/main/java/com/oney/WebRTCModule/WebRTCModulePackage.java
  • ios/RCTWebRTC/RTCCameraPreviewViewManager.h
  • ios/RCTWebRTC/RTCCameraPreviewViewManager.m
  • ios/RCTWebRTC/Utils/AudioDeviceModule/AudioDeviceModule.swift
  • ios/RCTWebRTC/Utils/PeerConnectionFactory/PeerConnectionFactoryProvider.swift
  • ios/RCTWebRTC/Utils/PeerConnectionFactory/PeerConnectionFactoryRegistry.swift
  • ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m
  • ios/RCTWebRTC/WebRTCModule.h
  • ios/RCTWebRTC/WebRTCModule.m
  • src/CallFactory.ts
  • src/RTCCameraPreviewView.ts
  • src/index.ts

Comment thread android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java Outdated
Comment thread android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java Outdated
Comment thread ios/RCTWebRTC/RTCCameraPreviewViewManager.m
Comment thread ios/RCTWebRTC/RTCCameraPreviewViewManager.m
Comment thread ios/RCTWebRTC/WebRTCModule.m
Comment thread src/CallFactory.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java (1)

84-96: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Release adm if factory construction fails.
dispose() cleans up the module on the normal path, but if createPeerConnectionFactory() throws, this native resource is left allocated. Wrap factory construction and release adm on the failure path.

🤖 Prompt for 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.

In
`@android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java`
around lines 84 - 96, Update the factory construction flow around
PeerConnectionFactory.Builder.createPeerConnectionFactory() to release the
AudioDeviceModule via adm.release() if construction throws, then rethrow the
original failure. Preserve the existing successful return path and normal
dispose() ownership behavior.
🤖 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.

Outside diff comments:
In
`@android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java`:
- Around line 84-96: Update the factory construction flow around
PeerConnectionFactory.Builder.createPeerConnectionFactory() to release the
AudioDeviceModule via adm.release() if construction throws, then rethrow the
original failure. Preserve the existing successful return path and normal
dispose() ownership behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1255f264-1c0e-4f71-8f78-3c91e8a18a5b

📥 Commits

Reviewing files that changed from the base of the PR and between 30614ca and 4214690.

📒 Files selected for processing (7)
  • Documentation/AndroidInstallation.md
  • android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java
  • android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryRegistry.java
  • android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java
  • android/src/main/java/com/oney/WebRTCModule/WebRTCModuleOptions.java
  • ios/RCTWebRTC/RTCCameraPreviewViewManager.m
  • ios/RCTWebRTC/WebRTCModule.m
💤 Files with no reviewable changes (2)
  • android/src/main/java/com/oney/WebRTCModule/WebRTCModuleOptions.java
  • Documentation/AndroidInstallation.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryRegistry.java
  • ios/RCTWebRTC/WebRTCModule.m
  • ios/RCTWebRTC/RTCCameraPreviewViewManager.m
  • android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java (2)

103-112: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Apply the bypass voice-profile capture settings.

When bypassVoiceProcessing is true, stereoInputEnabled currently has no effect and the audio source remains the default voice-communication path instead of raw MediaRecorder.AudioSource.MIC. Enable both builders matching the documented profile, or remove the options and update callers.

Proposed fix
             builder.setUseHardwareAcousticEchoCanceler(false)
                     .setUseHardwareNoiseSuppressor(false)
                     .setUseStereoOutput(true)
-                    // .setUseStereoInput(options.stereoInputEnabled)
-                    // .setAudioSource(MediaRecorder.AudioSource.MIC)
+                    .setUseStereoInput(options.stereoInputEnabled)
+                    .setAudioSource(MediaRecorder.AudioSource.MIC)
                     .setOutputSampleRate(nativeOutputSampleRate(options.context));
🤖 Prompt for 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.

In
`@android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java`
around lines 103 - 112, Update the bypassVoiceProcessing branch in
PeerConnectionFactoryProvider so it applies options.stereoInputEnabled through
setUseStereoInput and selects MediaRecorder.AudioSource.MIC via setAudioSource,
while preserving the existing hardware-processing, stereo-output, and native
sample-rate settings.

84-96: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Release adm when build() fails.

createAudioDeviceModule() hands callers ownership of native audio resources. If the PeerConnectionFactory builder setup or createPeerConnectionFactory() throws, PeerConnectionFactoryProvider.build() returns without owning the AudioDeviceModule, so adm.release() is never called. Catch and wrap the failure path to release adm, then rethrow the original exception.

🤖 Prompt for 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.

In
`@android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java`
around lines 84 - 96, Update PeerConnectionFactoryProvider.build() to guard the
PeerConnectionFactory builder setup and createPeerConnectionFactory() call with
failure handling that invokes adm.release() when any step throws, then rethrows
the original exception without altering successful creation behavior.
🤖 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.

Outside diff comments:
In
`@android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java`:
- Around line 103-112: Update the bypassVoiceProcessing branch in
PeerConnectionFactoryProvider so it applies options.stereoInputEnabled through
setUseStereoInput and selects MediaRecorder.AudioSource.MIC via setAudioSource,
while preserving the existing hardware-processing, stereo-output, and native
sample-rate settings.
- Around line 84-96: Update PeerConnectionFactoryProvider.build() to guard the
PeerConnectionFactory builder setup and createPeerConnectionFactory() call with
failure handling that invokes adm.release() when any step throws, then rethrows
the original exception without altering successful creation behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 696ae0ab-38b6-4699-9bd2-bff0f9a84e58

📥 Commits

Reviewing files that changed from the base of the PR and between f6dcf78 and a6f6100.

📒 Files selected for processing (1)
  • android/src/main/java/com/oney/WebRTCModule/PeerConnectionFactoryProvider.java

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