From 7ec7bc577c75726d5c2c57cc0c84cc938839ce69 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 22 Aug 2025 15:15:57 +0200 Subject: [PATCH 01/12] feat: align encoder/decoder with stream android sdk --- .gitignore | 10 ++- android/build.gradle | 42 ++++++++++- android/src/main/AndroidManifestNew.xml | 10 +++ .../com/oney/WebRTCModule/WebRTCModule.java | 13 +--- .../SelectiveVideoDecoderFactory.kt | 67 +++++++++++++++++ .../SelectiveVideoEncoderFactory.kt | 75 +++++++++++++++++++ .../android/app/src/main/AndroidManifest.xml | 6 ++ 7 files changed, 209 insertions(+), 14 deletions(-) create mode 100644 android/src/main/AndroidManifestNew.xml create mode 100644 android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt create mode 100644 android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoEncoderFactory.kt diff --git a/.gitignore b/.gitignore index d5a1b496f..ba4d9bdf9 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,12 @@ examples/GumTestApp_macOS/package-lock.json *.zip lib/ src/*.js - +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml +*.hprof +.cxx/ diff --git a/android/build.gradle b/android/build.gradle index 83e3afde4..c16d96f94 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,15 +1,48 @@ import java.nio.file.Paths -apply plugin: 'com.android.library' +buildscript { + ext.getExtOrDefault = {name, fallback -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : fallback + } + + repositories { + google() + mavenCentral() + maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } + } + + dependencies { + classpath("com.android.tools.build:gradle:7.3.1") + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion', '1.8.10')}" + } +} + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" def safeExtGet(prop, fallback) { rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback } +def supportsNamespace() { + def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.') + def major = parsed[0].toInteger() + def minor = parsed[1].toInteger() + + // Namespace support was added in 7.3.0 + return (major == 7 && minor >= 3) || major >= 8 +} + android { - def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION - if (agpVersion.tokenize('.')[0].toInteger() >= 7) { - namespace "com.oney.WebRTCModule" + if (supportsNamespace()) { + namespace "com.oney.WebRTCModule" + + sourceSets { + main { + manifest.srcFile "src/main/AndroidManifestNew.xml" + } + } } compileSdkVersion safeExtGet('compileSdkVersion', 24) @@ -33,5 +66,6 @@ android { dependencies { api 'io.getstream:stream-webrtc-android:1.3.8' implementation 'com.facebook.react:react-native:+' + implementation "org.jetbrains.kotlin:kotlin-stdlib:${getExtOrDefault('kotlinVersion', '1.8.10')}" implementation "androidx.core:core:1.7.0" } diff --git a/android/src/main/AndroidManifestNew.xml b/android/src/main/AndroidManifestNew.xml new file mode 100644 index 000000000..0d246d51b --- /dev/null +++ b/android/src/main/AndroidManifestNew.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java b/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java index 23528fe12..486296d69 100644 --- a/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java +++ b/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java @@ -23,14 +23,14 @@ 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; +import com.oney.WebRTCModule.webrtcutils.SelectiveVideoDecoderFactory; import org.webrtc.*; import org.webrtc.audio.AudioDeviceModule; import org.webrtc.audio.JavaAudioDeviceModule; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -83,14 +83,9 @@ public WebRTCModule(ReactApplicationContext reactContext) { if (encoderFactory == null || decoderFactory == null) { // Initialize EGL context required for HW acceleration. EglBase.Context eglContext = EglUtils.getRootEglBaseContext(); + encoderFactory = new SimulcastAlignedVideoEncoderFactory(eglContext, true, true, ResolutionAdjustment.MULTIPLE_OF_16); + decoderFactory = new SelectiveVideoDecoderFactory(eglContext, false, Arrays.asList("VP9", "AV1")); - if (eglContext != null) { - encoderFactory = new H264AndSoftwareVideoEncoderFactory(eglContext); - decoderFactory = new H264AndSoftwareVideoDecoderFactory(eglContext); - } else { - encoderFactory = new SoftwareVideoEncoderFactory(); - decoderFactory = new SoftwareVideoDecoderFactory(); - } } if (adm == null) { diff --git a/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt new file mode 100644 index 000000000..6e92d9344 --- /dev/null +++ b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014-2024 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.oney.WebRTCModule.webrtcutils + +import org.webrtc.EglBase +import org.webrtc.SoftwareVideoDecoderFactory +import org.webrtc.VideoCodecInfo +import org.webrtc.VideoDecoder +import org.webrtc.VideoDecoderFactory +import org.webrtc.WrappedVideoDecoderFactory + +internal class SelectiveVideoDecoderFactory( + sharedContext: EglBase.Context?, + private var forceSWCodec: Boolean = false, + private var forceSWCodecs: List = listOf("VP9", "AV1"), +) : VideoDecoderFactory { + private val softwareVideoDecoderFactory = SoftwareVideoDecoderFactory() + private val wrappedVideoDecoderFactory = WrappedVideoDecoderFactory(sharedContext) + + /** + * Set to true to force software codecs. + */ + fun setForceSWCodec(forceSWCodec: Boolean) { + this.forceSWCodec = forceSWCodec + } + + /** + * Set a list of codecs for which to use software codecs. + */ + fun setForceSWCodecList(forceSWCodecs: List) { + this.forceSWCodecs = forceSWCodecs + } + + override fun createDecoder(videoCodecInfo: VideoCodecInfo): VideoDecoder? { + if (forceSWCodec) { + return softwareVideoDecoderFactory.createDecoder(videoCodecInfo) + } + if (forceSWCodecs.isNotEmpty()) { + if (forceSWCodecs.contains(videoCodecInfo.name)) { + return softwareVideoDecoderFactory.createDecoder(videoCodecInfo) + } + } + return wrappedVideoDecoderFactory.createDecoder(videoCodecInfo) + } + + override fun getSupportedCodecs(): Array { + return if (forceSWCodec && forceSWCodecs.isEmpty()) { + softwareVideoDecoderFactory.supportedCodecs + } else { + wrappedVideoDecoderFactory.supportedCodecs + } + } +} diff --git a/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoEncoderFactory.kt b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoEncoderFactory.kt new file mode 100644 index 000000000..fa2be1ba1 --- /dev/null +++ b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoEncoderFactory.kt @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014-2024 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.oney.WebRTCModule.webrtcutils + +import org.webrtc.EglBase +import org.webrtc.ResolutionAdjustment +import org.webrtc.SimulcastAlignedVideoEncoderFactory +import org.webrtc.SoftwareVideoEncoderFactory +import org.webrtc.VideoCodecInfo +import org.webrtc.VideoEncoder +import org.webrtc.VideoEncoderFactory + +internal class SelectiveVideoEncoderFactory( + sharedContext: EglBase.Context?, + enableIntelVp8Encoder: Boolean, + enableH264HighProfile: Boolean, + private var forceSWCodec: Boolean = false, + private var forceSWCodecs: List = listOf("VP9", "AV1"), +) : VideoEncoderFactory { + private val softwareVideoEncoderFactory = SoftwareVideoEncoderFactory() + private val simulcastVideoEncoderFactoryWrapper: SimulcastAlignedVideoEncoderFactory + + init { + simulcastVideoEncoderFactoryWrapper = + SimulcastAlignedVideoEncoderFactory(sharedContext, enableIntelVp8Encoder, enableH264HighProfile, ResolutionAdjustment.NONE) + } + + /** + * Set to true to force software codecs. + */ + fun setForceSWCodec(forceSWCodec: Boolean) { + this.forceSWCodec = forceSWCodec + } + + /** + * Set a list of codecs for which to use software codecs. + */ + fun setForceSWCodecList(forceSWCodecs: List) { + this.forceSWCodecs = forceSWCodecs + } + + override fun createEncoder(videoCodecInfo: VideoCodecInfo): VideoEncoder? { + if (forceSWCodec) { + return softwareVideoEncoderFactory.createEncoder(videoCodecInfo) + } + if (forceSWCodecs.isNotEmpty()) { + if (forceSWCodecs.contains(videoCodecInfo.name)) { + return softwareVideoEncoderFactory.createEncoder(videoCodecInfo) + } + } + return simulcastVideoEncoderFactoryWrapper.createEncoder(videoCodecInfo) + } + + override fun getSupportedCodecs(): Array { + return if (forceSWCodec && forceSWCodecs.isEmpty()) { + softwareVideoEncoderFactory.supportedCodecs + } else { + simulcastVideoEncoderFactoryWrapper.supportedCodecs + } + } +} diff --git a/examples/GumTestApp/android/app/src/main/AndroidManifest.xml b/examples/GumTestApp/android/app/src/main/AndroidManifest.xml index 3b3580cc6..55f770abe 100644 --- a/examples/GumTestApp/android/app/src/main/AndroidManifest.xml +++ b/examples/GumTestApp/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,11 @@ + + + + + + From 0d72214f09ffb64387aeb8f5ac5203ec69c435b2 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 22 Aug 2025 15:19:42 +0200 Subject: [PATCH 02/12] 125.4.3-alpha.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 157fb6cb0..7de1c3c9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.2", + "version": "125.4.3-alpha.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@stream-io/react-native-webrtc", - "version": "125.4.2", + "version": "125.4.3-alpha.1", "license": "MIT", "dependencies": { "base64-js": "1.5.1", diff --git a/package.json b/package.json index 3c925ff28..421f41165 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.2", + "version": "125.4.3-alpha.1", "repository": { "type": "git", "url": "git+https://github.com/GetStream/react-native-webrtc.git" From 72752461f6cb9ef30b3f93ee9bfcff4542dba8cd Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Mon, 25 Aug 2025 13:35:20 +0200 Subject: [PATCH 03/12] fix: disable direct-to-SurfaceTextureFrame rendering for c2.exynos.* hardware decoder --- .../SelectiveVideoDecoderFactory.kt | 1 - .../WrappedVideoDecoderFactory.java | 79 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java diff --git a/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt index 6e92d9344..adf790d36 100644 --- a/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt +++ b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt @@ -21,7 +21,6 @@ import org.webrtc.SoftwareVideoDecoderFactory import org.webrtc.VideoCodecInfo import org.webrtc.VideoDecoder import org.webrtc.VideoDecoderFactory -import org.webrtc.WrappedVideoDecoderFactory internal class SelectiveVideoDecoderFactory( sharedContext: EglBase.Context?, diff --git a/android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java new file mode 100644 index 000000000..0c67ad6ed --- /dev/null +++ b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014-2025 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.oney.WebRTCModule.webrtcutils; + +import androidx.annotation.Nullable; + +import org.webrtc.*; +import java.util.Arrays; +import java.util.LinkedHashSet; + +/** + * A patch on top of https://github.com/GetStream/webrtc/blob/main/sdk/android/api/org/webrtc/WrappedVideoDecoderFactory.java + * It disables direct-to-SurfaceTextureFrame rendering for c2.exynos.* hardware decoder + */ +public class WrappedVideoDecoderFactory implements VideoDecoderFactory { + public WrappedVideoDecoderFactory(@Nullable EglBase.Context eglContext) { + this.hardwareVideoDecoderFactory = new HardwareVideoDecoderFactory(eglContext); + this.platformSoftwareVideoDecoderFactory = new PlatformSoftwareVideoDecoderFactory(eglContext); + } + + private final VideoDecoderFactory hardwareVideoDecoderFactory; + private final VideoDecoderFactory hardwareVideoDecoderFactoryWithoutEglContext = new HardwareVideoDecoderFactory(null) ; + private final VideoDecoderFactory softwareVideoDecoderFactory = new SoftwareVideoDecoderFactory(); + @Nullable + private final VideoDecoderFactory platformSoftwareVideoDecoderFactory; + + @Override + public VideoDecoder createDecoder(VideoCodecInfo codecType) { + VideoDecoder softwareDecoder = this.softwareVideoDecoderFactory.createDecoder(codecType); + VideoDecoder hardwareDecoder = this.hardwareVideoDecoderFactory.createDecoder(codecType); + if (softwareDecoder == null && this.platformSoftwareVideoDecoderFactory != null) { + softwareDecoder = this.platformSoftwareVideoDecoderFactory.createDecoder(codecType); + } + + if(hardwareDecoder != null && disableSurfaceTextureFrame(hardwareDecoder.getImplementationName())) { + hardwareDecoder.release(); + hardwareDecoder = this.hardwareVideoDecoderFactoryWithoutEglContext.createDecoder(codecType); + } + + if (hardwareDecoder != null && softwareDecoder != null) { + return new VideoDecoderFallback(softwareDecoder, hardwareDecoder); + } else { + return hardwareDecoder != null ? hardwareDecoder : softwareDecoder; + } + } + + private boolean disableSurfaceTextureFrame(String name) { + if (name.startsWith("OMX.qcom.") || name.startsWith("OMX.hisi.") || name.startsWith("c2.exynos.")) { + return true; + } + return false; + } + + @Override + public VideoCodecInfo[] getSupportedCodecs() { + LinkedHashSet supportedCodecInfos = new LinkedHashSet(); + supportedCodecInfos.addAll(Arrays.asList(this.softwareVideoDecoderFactory.getSupportedCodecs())); + supportedCodecInfos.addAll(Arrays.asList(this.hardwareVideoDecoderFactory.getSupportedCodecs())); + if (this.platformSoftwareVideoDecoderFactory != null) { + supportedCodecInfos.addAll(Arrays.asList(this.platformSoftwareVideoDecoderFactory.getSupportedCodecs())); + } + + return (VideoCodecInfo[])supportedCodecInfos.toArray(new VideoCodecInfo[supportedCodecInfos.size()]); + } +} From 63f1fe792c78feb72823593d5fa0c4dbe60b5aef Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Mon, 25 Aug 2025 13:36:04 +0200 Subject: [PATCH 04/12] 125.4.3-alpha.2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7de1c3c9a..b6747048a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.1", + "version": "125.4.3-alpha.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.1", + "version": "125.4.3-alpha.2", "license": "MIT", "dependencies": { "base64-js": "1.5.1", diff --git a/package.json b/package.json index 421f41165..bf19f16ae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.1", + "version": "125.4.3-alpha.2", "repository": { "type": "git", "url": "git+https://github.com/GetStream/react-native-webrtc.git" From 38083c6cb30c1766b3fd1f548d0aec62ee95a3d9 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Tue, 26 Aug 2025 09:47:36 +0200 Subject: [PATCH 05/12] add more hardware decoders --- .../WrappedVideoDecoderFactory.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java index 0c67ad6ed..b56402a83 100644 --- a/android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java +++ b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java @@ -24,9 +24,21 @@ /** * A patch on top of https://github.com/GetStream/webrtc/blob/main/sdk/android/api/org/webrtc/WrappedVideoDecoderFactory.java - * It disables direct-to-SurfaceTextureFrame rendering for c2.exynos.* hardware decoder + * It disables direct-to-SurfaceTextureFrame rendering for c2 exynos/qualcomm/mediatek hardware decoder */ public class WrappedVideoDecoderFactory implements VideoDecoderFactory { + // Known hardware decoders to have failures when it outputs to a SurfaceTexture directly + // Happens possibly when SurfaceTexture data buffer queue is flushed and reused + private static final String[] DECODER_DENYLIST_PREFIXES = { + "OMX.qcom.", + "OMX.hisi.", + // https://github.com/androidx/media/issues/2003 + "c2.exynos.", + "c2.qti.", + // https://github.com/androidx/media/blob/bfe5930f7f29c6492d60e3d01a90abd3c138b615/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java#L1499 + "c2.mtk.", + }; + public WrappedVideoDecoderFactory(@Nullable EglBase.Context eglContext) { this.hardwareVideoDecoderFactory = new HardwareVideoDecoderFactory(eglContext); this.platformSoftwareVideoDecoderFactory = new PlatformSoftwareVideoDecoderFactory(eglContext); @@ -59,8 +71,10 @@ public VideoDecoder createDecoder(VideoCodecInfo codecType) { } private boolean disableSurfaceTextureFrame(String name) { - if (name.startsWith("OMX.qcom.") || name.startsWith("OMX.hisi.") || name.startsWith("c2.exynos.")) { - return true; + for (String prefix : DECODER_DENYLIST_PREFIXES) { + if (name.startsWith(prefix)) { + return true; + } } return false; } @@ -74,6 +88,6 @@ public VideoCodecInfo[] getSupportedCodecs() { supportedCodecInfos.addAll(Arrays.asList(this.platformSoftwareVideoDecoderFactory.getSupportedCodecs())); } - return (VideoCodecInfo[])supportedCodecInfos.toArray(new VideoCodecInfo[supportedCodecInfos.size()]); + return supportedCodecInfos.toArray(new VideoCodecInfo[supportedCodecInfos.size()]); } } From c306b3eba39792cd5270bdaf211c2c1160734e4d Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Tue, 26 Aug 2025 09:47:59 +0200 Subject: [PATCH 06/12] 125.4.3-alpha.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b6747048a..47872537a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.2", + "version": "125.4.3-alpha.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.2", + "version": "125.4.3-alpha.3", "license": "MIT", "dependencies": { "base64-js": "1.5.1", diff --git a/package.json b/package.json index bf19f16ae..3d1d0c4a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.2", + "version": "125.4.3-alpha.3", "repository": { "type": "git", "url": "git+https://github.com/GetStream/react-native-webrtc.git" From 6c17c9a823209bd5c00f56f15a0c33f47c2ffe52 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Wed, 27 Aug 2025 14:00:10 +0200 Subject: [PATCH 07/12] try snapshot webrtc build --- android/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index c16d96f94..f5ed5e90c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,7 +8,7 @@ buildscript { repositories { google() mavenCentral() - maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } + maven { url 'https://central.sonatype.com/repository/maven-snapshots/' } } dependencies { @@ -64,7 +64,7 @@ android { } dependencies { - api 'io.getstream:stream-webrtc-android:1.3.8' + api 'io.getstream:stream-webrtc-android:1.3.9-SNAPSHOT' implementation 'com.facebook.react:react-native:+' implementation "org.jetbrains.kotlin:kotlin-stdlib:${getExtOrDefault('kotlinVersion', '1.8.10')}" implementation "androidx.core:core:1.7.0" From 72345c6f2df734383fc5c51acac16758ab80f14e Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Wed, 27 Aug 2025 14:00:40 +0200 Subject: [PATCH 08/12] 125.4.3-alpha.4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 47872537a..356e2d20e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.3", + "version": "125.4.3-alpha.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.3", + "version": "125.4.3-alpha.4", "license": "MIT", "dependencies": { "base64-js": "1.5.1", diff --git a/package.json b/package.json index 3d1d0c4a1..c1db183a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.3", + "version": "125.4.3-alpha.4", "repository": { "type": "git", "url": "git+https://github.com/GetStream/react-native-webrtc.git" From 705a9f72750ac4e773aafa8ed7887abc10632651 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Wed, 27 Aug 2025 21:12:40 +0200 Subject: [PATCH 09/12] force sw codec now also works for h264 --- .../java/com/oney/WebRTCModule/EglUtils.java | 43 +------------------ .../com/oney/WebRTCModule/WebRTCModule.java | 8 ++-- .../SelectiveVideoDecoderFactory.kt | 14 +++--- .../WrappedVideoDecoderFactory.java | 26 ++++++----- 4 files changed, 28 insertions(+), 63 deletions(-) diff --git a/android/src/main/java/com/oney/WebRTCModule/EglUtils.java b/android/src/main/java/com/oney/WebRTCModule/EglUtils.java index f315b36b5..1310a68c9 100644 --- a/android/src/main/java/com/oney/WebRTCModule/EglUtils.java +++ b/android/src/main/java/com/oney/WebRTCModule/EglUtils.java @@ -1,16 +1,11 @@ package com.oney.WebRTCModule; - -import android.os.Build.VERSION; -import android.util.Log; - import org.webrtc.EglBase; public class EglUtils { /** * The root {@link EglBase} instance shared by the entire application for * the sake of reducing the utilization of system resources (such as EGL - * contexts). It selects between {@link EglBase10} and {@link EglBase14} - * by performing a runtime check. + * contexts). */ private static EglBase rootEglBase; @@ -20,47 +15,13 @@ public class EglUtils { */ public static synchronized EglBase getRootEglBase() { if (rootEglBase == null) { - // XXX EglBase14 will report that isEGL14Supported() but its - // getEglConfig() will fail with a RuntimeException with message - // "Unable to find any matching EGL config". Fall back to EglBase10 - // in the described scenario. - EglBase eglBase = null; - int[] configAttributes = EglBase.CONFIG_PLAIN; - RuntimeException cause = null; - - try { - // WebRTC internally does this check in isEGL14Supported, but it's no longer exposed - // in the public API - if (VERSION.SDK_INT >= 18) { - eglBase = EglBase.createEgl14(configAttributes); - } - } catch (RuntimeException ex) { - // Fall back to EglBase10. - cause = ex; - } - - if (eglBase == null) { - try { - eglBase = EglBase.createEgl10(configAttributes); - } catch (RuntimeException ex) { - // Neither EglBase14, nor EglBase10 succeeded to initialize. - cause = ex; - } - } - - if (cause != null) { - Log.e(EglUtils.class.getName(), "Failed to create EglBase", cause); - } else { - rootEglBase = eglBase; - } + rootEglBase = EglBase.create(); } - return rootEglBase; } public static EglBase.Context getRootEglBaseContext() { EglBase eglBase = getRootEglBase(); - return eglBase == null ? null : eglBase.getEglBaseContext(); } } diff --git a/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java b/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java index 486296d69..012cd7929 100644 --- a/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java +++ b/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java @@ -129,9 +129,11 @@ private PeerConnection getPeerConnection(int id) { } void sendEvent(String eventName, @Nullable ReadableMap params) { - getReactApplicationContext() - .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) - .emit(eventName, params); + if (getReactApplicationContext().hasActiveReactInstance()) { + getReactApplicationContext() + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(eventName, params); + } } private PeerConnection.IceServer createIceServer(String url) { diff --git a/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt index adf790d36..441bfc4dc 100644 --- a/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt +++ b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/SelectiveVideoDecoderFactory.kt @@ -28,7 +28,7 @@ internal class SelectiveVideoDecoderFactory( private var forceSWCodecs: List = listOf("VP9", "AV1"), ) : VideoDecoderFactory { private val softwareVideoDecoderFactory = SoftwareVideoDecoderFactory() - private val wrappedVideoDecoderFactory = WrappedVideoDecoderFactory(sharedContext) + private val wrappedVideoDecoderFactory = WrappedVideoDecoderFactory(sharedContext, forceSWCodec) /** * Set to true to force software codecs. @@ -45,22 +45,18 @@ internal class SelectiveVideoDecoderFactory( } override fun createDecoder(videoCodecInfo: VideoCodecInfo): VideoDecoder? { - if (forceSWCodec) { - return softwareVideoDecoderFactory.createDecoder(videoCodecInfo) - } if (forceSWCodecs.isNotEmpty()) { if (forceSWCodecs.contains(videoCodecInfo.name)) { return softwareVideoDecoderFactory.createDecoder(videoCodecInfo) } } + if (forceSWCodec) { + return wrappedVideoDecoderFactory.createDecoder(videoCodecInfo) + } return wrappedVideoDecoderFactory.createDecoder(videoCodecInfo) } override fun getSupportedCodecs(): Array { - return if (forceSWCodec && forceSWCodecs.isEmpty()) { - softwareVideoDecoderFactory.supportedCodecs - } else { - wrappedVideoDecoderFactory.supportedCodecs - } + return wrappedVideoDecoderFactory.supportedCodecs } } diff --git a/android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java index b56402a83..c94910d5a 100644 --- a/android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java +++ b/android/src/main/java/com/oney/WebRTCModule/webrtcutils/WrappedVideoDecoderFactory.java @@ -28,20 +28,22 @@ */ public class WrappedVideoDecoderFactory implements VideoDecoderFactory { // Known hardware decoders to have failures when it outputs to a SurfaceTexture directly - // Happens possibly when SurfaceTexture data buffer queue is flushed and reused private static final String[] DECODER_DENYLIST_PREFIXES = { "OMX.qcom.", "OMX.hisi.", // https://github.com/androidx/media/issues/2003 - "c2.exynos.", - "c2.qti.", - // https://github.com/androidx/media/blob/bfe5930f7f29c6492d60e3d01a90abd3c138b615/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java#L1499 - "c2.mtk.", +// "c2.exynos.", +// "c2.qti.", +// // https://github.com/androidx/media/blob/bfe5930f7f29c6492d60e3d01a90abd3c138b615/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java#L1499 +// "c2.mtk.", }; - public WrappedVideoDecoderFactory(@Nullable EglBase.Context eglContext) { + private final boolean forceSWCodec; + + public WrappedVideoDecoderFactory(@Nullable EglBase.Context eglContext, boolean forceSWCodec) { this.hardwareVideoDecoderFactory = new HardwareVideoDecoderFactory(eglContext); this.platformSoftwareVideoDecoderFactory = new PlatformSoftwareVideoDecoderFactory(eglContext); + this.forceSWCodec = forceSWCodec; } private final VideoDecoderFactory hardwareVideoDecoderFactory; @@ -53,11 +55,13 @@ public WrappedVideoDecoderFactory(@Nullable EglBase.Context eglContext) { @Override public VideoDecoder createDecoder(VideoCodecInfo codecType) { VideoDecoder softwareDecoder = this.softwareVideoDecoderFactory.createDecoder(codecType); - VideoDecoder hardwareDecoder = this.hardwareVideoDecoderFactory.createDecoder(codecType); + VideoDecoder hardwareDecoder = null; + if (!forceSWCodec) { + hardwareDecoder = this.hardwareVideoDecoderFactory.createDecoder(codecType); + } if (softwareDecoder == null && this.platformSoftwareVideoDecoderFactory != null) { softwareDecoder = this.platformSoftwareVideoDecoderFactory.createDecoder(codecType); } - if(hardwareDecoder != null && disableSurfaceTextureFrame(hardwareDecoder.getImplementationName())) { hardwareDecoder.release(); hardwareDecoder = this.hardwareVideoDecoderFactoryWithoutEglContext.createDecoder(codecType); @@ -81,9 +85,11 @@ private boolean disableSurfaceTextureFrame(String name) { @Override public VideoCodecInfo[] getSupportedCodecs() { - LinkedHashSet supportedCodecInfos = new LinkedHashSet(); + LinkedHashSet supportedCodecInfos = new LinkedHashSet<>(); supportedCodecInfos.addAll(Arrays.asList(this.softwareVideoDecoderFactory.getSupportedCodecs())); - supportedCodecInfos.addAll(Arrays.asList(this.hardwareVideoDecoderFactory.getSupportedCodecs())); + if (!forceSWCodec) { + supportedCodecInfos.addAll(Arrays.asList(this.hardwareVideoDecoderFactory.getSupportedCodecs())); + } if (this.platformSoftwareVideoDecoderFactory != null) { supportedCodecInfos.addAll(Arrays.asList(this.platformSoftwareVideoDecoderFactory.getSupportedCodecs())); } From 38268a644e705d316423174978ac6f71dd42c70b Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Wed, 27 Aug 2025 21:14:07 +0200 Subject: [PATCH 10/12] 125.4.3-alpha.5 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 356e2d20e..d132f7609 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.4", + "version": "125.4.3-alpha.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.4", + "version": "125.4.3-alpha.5", "license": "MIT", "dependencies": { "base64-js": "1.5.1", diff --git a/package.json b/package.json index c1db183a7..0dac8dd5f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.4", + "version": "125.4.3-alpha.5", "repository": { "type": "git", "url": "git+https://github.com/GetStream/react-native-webrtc.git" From 7546174a76f0ec74c594e03a093cfcb21889a053 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Thu, 28 Aug 2025 00:12:05 +0200 Subject: [PATCH 11/12] 125.4.3-rc.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d132f7609..26cb9b478 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.5", + "version": "125.4.3-rc.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.5", + "version": "125.4.3-rc.1", "license": "MIT", "dependencies": { "base64-js": "1.5.1", diff --git a/package.json b/package.json index 0dac8dd5f..7c7164a8a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.4.3-alpha.5", + "version": "125.4.3-rc.1", "repository": { "type": "git", "url": "git+https://github.com/GetStream/react-native-webrtc.git" From 95ae42380fd38beb469e75d7f5e0be29825a7df1 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Wed, 3 Sep 2025 11:00:22 +0200 Subject: [PATCH 12/12] update to the stable version --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index f5ed5e90c..a113bdb28 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -64,7 +64,7 @@ android { } dependencies { - api 'io.getstream:stream-webrtc-android:1.3.9-SNAPSHOT' + api 'io.getstream:stream-webrtc-android:1.3.9' implementation 'com.facebook.react:react-native:+' implementation "org.jetbrains.kotlin:kotlin-stdlib:${getExtOrDefault('kotlinVersion', '1.8.10')}" implementation "androidx.core:core:1.7.0"