diff --git a/android/build.gradle b/android/build.gradle index 5e21874a2..83e3afde4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -31,7 +31,7 @@ android { } dependencies { - api 'io.github.webrtc-sdk:android:125.6422.06.1' + api 'io.getstream:stream-webrtc-android:1.3.8' implementation 'com.facebook.react:react-native:+' implementation "androidx.core:core:1.7.0" } diff --git a/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java b/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java index 6b7908e64..a8c71a69d 100644 --- a/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java +++ b/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java @@ -21,6 +21,8 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.modules.core.DeviceEventManagerModule; +import com.oney.WebRTCModule.audio.AudioProcessingFactoryProvider; +import com.oney.WebRTCModule.audio.AudioProcessingController; import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoDecoderFactory; import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoEncoderFactory; @@ -64,6 +66,8 @@ public WebRTCModule(ReactApplicationContext reactContext) { VideoDecoderFactory decoderFactory = options.videoDecoderFactory; Loggable injectableLogger = options.injectableLogger; Logging.Severity loggingSeverity = options.loggingSeverity; + AudioProcessingFactoryProvider audioProcessingFactoryProvider = options.audioProcessingFactoryProvider; + String fieldTrials = options.fieldTrials; PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(reactContext) @@ -96,10 +100,15 @@ public WebRTCModule(ReactApplicationContext reactContext) { Log.d(TAG, "Using video encoder factory: " + encoderFactory.getClass().getCanonicalName()); Log.d(TAG, "Using video decoder factory: " + decoderFactory.getClass().getCanonicalName()); + if(audioProcessingFactoryProvider == null) { + audioProcessingFactoryProvider = new AudioProcessingController(); + } + mFactory = PeerConnectionFactory.builder() .setAudioDeviceModule(adm) .setVideoEncoderFactory(encoderFactory) .setVideoDecoderFactory(decoderFactory) + .setAudioProcessingFactory(audioProcessingFactoryProvider.getFactory()) .createPeerConnectionFactory(); // PeerConnectionFactory now owns the adm native pointer, and we don't need it anymore. diff --git a/android/src/main/java/com/oney/WebRTCModule/WebRTCModuleOptions.java b/android/src/main/java/com/oney/WebRTCModule/WebRTCModuleOptions.java index 01d31d7b1..6187c9472 100644 --- a/android/src/main/java/com/oney/WebRTCModule/WebRTCModuleOptions.java +++ b/android/src/main/java/com/oney/WebRTCModule/WebRTCModuleOptions.java @@ -1,5 +1,7 @@ package com.oney.WebRTCModule; +import com.oney.WebRTCModule.audio.AudioProcessingFactoryProvider; + import org.webrtc.Loggable; import org.webrtc.Logging; import org.webrtc.VideoDecoderFactory; @@ -16,6 +18,7 @@ public class WebRTCModuleOptions { public Logging.Severity loggingSeverity; public String fieldTrials; public boolean enableMediaProjectionService; + public AudioProcessingFactoryProvider audioProcessingFactoryProvider; public static WebRTCModuleOptions getInstance() { if (instance == null) { diff --git a/android/src/main/java/com/oney/WebRTCModule/audio/AudioProcessingAdapter.java b/android/src/main/java/com/oney/WebRTCModule/audio/AudioProcessingAdapter.java new file mode 100644 index 000000000..7e06ae521 --- /dev/null +++ b/android/src/main/java/com/oney/WebRTCModule/audio/AudioProcessingAdapter.java @@ -0,0 +1,59 @@ +package com.oney.WebRTCModule.audio; + +import org.webrtc.ExternalAudioProcessingFactory; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +public class AudioProcessingAdapter implements ExternalAudioProcessingFactory.AudioProcessing { + public interface ExternalAudioFrameProcessing { + void initialize(int sampleRateHz, int numChannels); + + void reset(int newRate); + + void process(int numBands, int numFrames, ByteBuffer buffer); + } + + public AudioProcessingAdapter() {} + List audioProcessors = new ArrayList<>(); + + public void addProcessor(ExternalAudioFrameProcessing audioProcessor) { + synchronized (audioProcessors) { + audioProcessors.add(audioProcessor); + } + } + + public void removeProcessor(ExternalAudioFrameProcessing audioProcessor) { + synchronized (audioProcessors) { + audioProcessors.remove(audioProcessor); + } + } + + @Override + public void initialize(int sampleRateHz, int numChannels) { + synchronized (audioProcessors) { + for (ExternalAudioFrameProcessing audioProcessor : audioProcessors) { + audioProcessor.initialize(sampleRateHz, numChannels); + } + } + } + + @Override + public void reset(int newRate) { + synchronized (audioProcessors) { + for (ExternalAudioFrameProcessing audioProcessor : audioProcessors) { + audioProcessor.reset(newRate); + } + } + } + + @Override + public void process(int numBands, int numFrames, ByteBuffer buffer) { + synchronized (audioProcessors) { + for (ExternalAudioFrameProcessing audioProcessor : audioProcessors) { + audioProcessor.process(numBands, numFrames, buffer); + } + } + } +} \ No newline at end of file diff --git a/android/src/main/java/com/oney/WebRTCModule/audio/AudioProcessingController.java b/android/src/main/java/com/oney/WebRTCModule/audio/AudioProcessingController.java new file mode 100644 index 000000000..9444eb781 --- /dev/null +++ b/android/src/main/java/com/oney/WebRTCModule/audio/AudioProcessingController.java @@ -0,0 +1,29 @@ +package com.oney.WebRTCModule.audio; + +import org.webrtc.AudioProcessingFactory; +import org.webrtc.ExternalAudioProcessingFactory; + +public class AudioProcessingController implements AudioProcessingFactoryProvider { + /** + * This is the audio processing module that will be applied to the audio stream after it is captured from the microphone. + * This is useful for adding echo cancellation, noise suppression, etc. + */ + public final AudioProcessingAdapter capturePostProcessing = new AudioProcessingAdapter(); + /** + * This is the audio processing module that will be applied to the audio stream before it is rendered to the speaker. + */ + public final AudioProcessingAdapter renderPreProcessing = new AudioProcessingAdapter(); + + public ExternalAudioProcessingFactory externalAudioProcessingFactory; + + public AudioProcessingController() { + this.externalAudioProcessingFactory = new ExternalAudioProcessingFactory(); + this.externalAudioProcessingFactory.setCapturePostProcessing(capturePostProcessing); + this.externalAudioProcessingFactory.setRenderPreProcessing(renderPreProcessing); + } + + @Override + public AudioProcessingFactory getFactory() { + return this.externalAudioProcessingFactory; + } +} \ No newline at end of file diff --git a/android/src/main/java/com/oney/WebRTCModule/audio/AudioProcessingFactoryProvider.java b/android/src/main/java/com/oney/WebRTCModule/audio/AudioProcessingFactoryProvider.java new file mode 100644 index 000000000..0bc1b09c4 --- /dev/null +++ b/android/src/main/java/com/oney/WebRTCModule/audio/AudioProcessingFactoryProvider.java @@ -0,0 +1,8 @@ +package com.oney.WebRTCModule.audio; + +import org.webrtc.AudioProcessingFactory; + +// Define the common interface +public interface AudioProcessingFactoryProvider { + AudioProcessingFactory getFactory(); +} \ No newline at end of file diff --git a/ios/RCTWebRTC/WebRTCModule.m b/ios/RCTWebRTC/WebRTCModule.m index 93ff75097..6917aee12 100644 --- a/ios/RCTWebRTC/WebRTCModule.m +++ b/ios/RCTWebRTC/WebRTCModule.m @@ -43,6 +43,7 @@ - (instancetype)init { id audioDevice = options.audioDevice; id decoderFactory = options.videoDecoderFactory; id encoderFactory = options.videoEncoderFactory; + id audioProcessingModule = options.audioProcessingModule; NSDictionary *fieldTrials = options.fieldTrials; RTCLoggingSeverity loggingSeverity = options.loggingSeverity; @@ -69,9 +70,21 @@ - (instancetype)init { RCTLogInfo(@"Using video encoder factory: %@", NSStringFromClass([encoderFactory class])); RCTLogInfo(@"Using video decoder factory: %@", NSStringFromClass([decoderFactory class])); - _peerConnectionFactory = [[RTCPeerConnectionFactory alloc] initWithEncoderFactory:encoderFactory - decoderFactory:decoderFactory - audioDevice:audioDevice]; + if (audioProcessingModule != nil) { + if (audioDevice != nil) { + NSLog(@"Both audioProcessingModule and audioDevice are provided, but only one can be used. Ignoring audioDevice."); + } + RCTLogInfo(@"Using audio processing module: %@", NSStringFromClass([audioProcessingModule class])); + _peerConnectionFactory = [[RTCPeerConnectionFactory alloc] initWithBypassVoiceProcessing:NO + encoderFactory:encoderFactory + decoderFactory:decoderFactory + audioProcessingModule:audioProcessingModule]; + } else { + RCTLogInfo(@"Using audio device: %@", NSStringFromClass([audioDevice class])); + _peerConnectionFactory = [[RTCPeerConnectionFactory alloc] initWithEncoderFactory:encoderFactory + decoderFactory:decoderFactory + audioDevice:audioDevice]; + } _peerConnections = [NSMutableDictionary new]; _localStreams = [NSMutableDictionary new]; diff --git a/ios/RCTWebRTC/WebRTCModuleOptions.h b/ios/RCTWebRTC/WebRTCModuleOptions.h index d821ec9bf..d99cb8200 100644 --- a/ios/RCTWebRTC/WebRTCModuleOptions.h +++ b/ios/RCTWebRTC/WebRTCModuleOptions.h @@ -8,6 +8,7 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, strong, nullable) id videoDecoderFactory; @property(nonatomic, strong, nullable) id videoEncoderFactory; @property(nonatomic, strong, nullable) id audioDevice; +@property(nonatomic, strong, nullable) id audioProcessingModule; @property(nonatomic, strong, nullable) NSDictionary *fieldTrials; @property(nonatomic, assign) RTCLoggingSeverity loggingSeverity; @property(nonatomic, assign) BOOL enableMultitaskingCameraAccess; diff --git a/package-lock.json b/package-lock.json index 1bf413cf2..8951ca757 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.2.1", + "version": "125.3.0-alpha.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@stream-io/react-native-webrtc", - "version": "125.2.1", + "version": "125.3.0-alpha.4", "license": "MIT", "dependencies": { "base64-js": "1.5.1", diff --git a/package.json b/package.json index 3eeb93efc..bf321568b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.2.1", + "version": "125.3.0-alpha.4", "repository": { "type": "git", "url": "git+https://github.com/GetStream/react-native-webrtc.git"