Update RingRTC to v2.70.0, add video config settings

Co-authored-by: Cody Henthorne <cody@signal.org>
This commit is contained in:
adel-signal
2026-07-21 13:22:25 -07:00
committed by Michelle Tang
parent 5f22566e10
commit e0603b14bb
12 changed files with 266 additions and 15 deletions
+1
View File
@@ -703,6 +703,7 @@ dependencies {
implementation(project(":core:ui"))
implementation(project(":core:models"))
implementation(project(":core:models-jvm"))
implementation(project(":core:serialization"))
implementation(project(":feature:camera"))
implementation(project(":feature:registration"))
implementation(project(":lib:apng"))
@@ -776,6 +776,50 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
}
)
switchPref(
title = DSLSettingsText.from("Set Video Config:"),
isChecked = state.callingSetVideoConfig,
onClick = {
viewModel.setInternalCallingSetVideoConfig(!state.callingSetVideoConfig)
}
)
switchPref(
title = DSLSettingsText.from(" Use Hardware Vp9 Encode"),
isChecked = state.callingUseHardwareVp9Encode,
isEnabled = state.callingSetVideoConfig,
onClick = {
viewModel.setInternalCallingUseHardwareVp9Encode(!state.callingUseHardwareVp9Encode)
}
)
switchPref(
title = DSLSettingsText.from(" Use Hardware Vp9 Decode"),
isChecked = state.callingUseHardwareVp9Decode,
isEnabled = state.callingSetVideoConfig,
onClick = {
viewModel.setInternalCallingUseHardwareVp9Decode(!state.callingUseHardwareVp9Decode)
}
)
switchPref(
title = DSLSettingsText.from(" Use Software Vp9 Encode"),
isChecked = state.callingUseSoftwareVp9Encode,
isEnabled = state.callingSetVideoConfig,
onClick = {
viewModel.setInternalCallingUseSoftwareVp9Encode(!state.callingUseSoftwareVp9Encode)
}
)
switchPref(
title = DSLSettingsText.from(" Use Software Vp9 Decode"),
isChecked = state.callingUseSoftwareVp9Decode,
isEnabled = state.callingSetVideoConfig,
onClick = {
viewModel.setInternalCallingUseSoftwareVp9Decode(!state.callingUseSoftwareVp9Decode)
}
)
dividerPref()
// TODO [alex] -- db access on main thread!
@@ -19,6 +19,11 @@ data class InternalSettingsState(
val callingUseSoftwareNs: Boolean,
val callingUseInputLowLatency: Boolean,
val callingUseInputVoiceComm: Boolean,
val callingSetVideoConfig: Boolean,
val callingUseHardwareVp9Encode: Boolean,
val callingUseHardwareVp9Decode: Boolean,
val callingUseSoftwareVp9Encode: Boolean,
val callingUseSoftwareVp9Decode: Boolean,
val useBuiltInEmojiSet: Boolean,
val emojiVersion: EmojiFiles.Version?,
val removeSenderKeyMinimium: Boolean,
@@ -142,6 +142,31 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
refresh()
}
fun setInternalCallingSetVideoConfig(enabled: Boolean) {
preferenceDataStore.putBoolean(InternalValues.CALLING_SET_VIDEO_CONFIG, enabled)
refresh()
}
fun setInternalCallingUseHardwareVp9Encode(enabled: Boolean) {
preferenceDataStore.putBoolean(InternalValues.CALLING_USE_HARDWARE_VP9_ENCODE, enabled)
refresh()
}
fun setInternalCallingUseHardwareVp9Decode(enabled: Boolean) {
preferenceDataStore.putBoolean(InternalValues.CALLING_USE_HARDWARE_VP9_DECODE, enabled)
refresh()
}
fun setInternalCallingUseSoftwareVp9Encode(enabled: Boolean) {
preferenceDataStore.putBoolean(InternalValues.CALLING_USE_SOFTWARE_VP9_ENCODE, enabled)
refresh()
}
fun setInternalCallingUseSoftwareVp9Decode(enabled: Boolean) {
preferenceDataStore.putBoolean(InternalValues.CALLING_USE_SOFTWARE_VP9_DECODE, enabled)
refresh()
}
fun setUseConversationItemV2Media(enabled: Boolean) {
SignalStore.internal.useConversationItemV2Media = enabled
refresh()
@@ -228,6 +253,11 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito
callingUseSoftwareNs = SignalStore.internal.callingUseSoftwareNs,
callingUseInputLowLatency = SignalStore.internal.callingUseInputLowLatency,
callingUseInputVoiceComm = SignalStore.internal.callingUseInputVoiceComm,
callingSetVideoConfig = SignalStore.internal.callingSetVideoConfig,
callingUseHardwareVp9Encode = SignalStore.internal.callingUseHardwareVp9Encode,
callingUseHardwareVp9Decode = SignalStore.internal.callingUseHardwareVp9Decode,
callingUseSoftwareVp9Encode = SignalStore.internal.callingUseSoftwareVp9Encode,
callingUseSoftwareVp9Decode = SignalStore.internal.callingUseSoftwareVp9Decode,
useBuiltInEmojiSet = SignalStore.internal.forceBuiltInEmoji,
emojiVersion = null,
removeSenderKeyMinimium = SignalStore.internal.removeSenderKeyMinimum,
@@ -25,6 +25,11 @@ class InternalValues internal constructor(store: KeyValueStore) : SignalStoreVal
const val CALLING_USE_SOFTWARE_NS: String = "internal.calling_use_software_ns"
const val CALLING_USE_INPUT_LOW_LATENCY: String = "internal.calling_use_input_low_latency"
const val CALLING_USE_INPUT_VOICE_COMM: String = "internal.calling_use_input_voice_comm"
const val CALLING_SET_VIDEO_CONFIG: String = "internal.calling_set_video_config"
const val CALLING_USE_HARDWARE_VP9_ENCODE: String = "internal.calling_use_hardware_vp9_encode"
const val CALLING_USE_HARDWARE_VP9_DECODE: String = "internal.calling_use_hardware_vp9_decode"
const val CALLING_USE_SOFTWARE_VP9_ENCODE: String = "internal.calling_use_software_vp9_encode"
const val CALLING_USE_SOFTWARE_VP9_DECODE: String = "internal.calling_use_software_vp9_decode"
const val SHAKE_TO_REPORT: String = "internal.shake_to_report"
const val DISABLE_STORAGE_SERVICE: String = "internal.disable_storage_service"
const val LAST_SCROLL_POSITION: String = "internal.last_scroll_position"
@@ -170,6 +175,31 @@ class InternalValues internal constructor(store: KeyValueStore) : SignalStoreVal
*/
var callingUseInputVoiceComm by booleanValue(CALLING_USE_INPUT_VOICE_COMM, true).defaultForExternalUsers()
/**
* Whether or not to override the video settings from the remote configuration.
*/
var callingSetVideoConfig by booleanValue(CALLING_SET_VIDEO_CONFIG, false).falseForExternalUsers()
/**
* If overriding the video settings, use hardware VP9 encoder or not if available
*/
var callingUseHardwareVp9Encode by booleanValue(CALLING_USE_HARDWARE_VP9_ENCODE, true).defaultForExternalUsers()
/**
* If overriding the video settings, use hardware VP9 decoder or not if available
*/
var callingUseHardwareVp9Decode by booleanValue(CALLING_USE_HARDWARE_VP9_DECODE, true).defaultForExternalUsers()
/**
* If overriding the video settings, use software VP9 encoder or not
*/
var callingUseSoftwareVp9Encode by booleanValue(CALLING_USE_SOFTWARE_VP9_ENCODE, true).defaultForExternalUsers()
/**
* If overriding the video settings, use software VP9 encoder or not
*/
var callingUseSoftwareVp9Decode by booleanValue(CALLING_USE_SOFTWARE_VP9_DECODE, true).defaultForExternalUsers()
var lastScrollPosition: Int by integerValue(LAST_SCROLL_POSITION, 0).defaultForExternalUsers()
var useConversationItemV2Media by booleanValue(CONVERSATION_ITEM_V2_MEDIA, false).defaultForExternalUsers()
@@ -98,7 +98,6 @@ public class IncomingCallActionProcessor extends DeviceAwareActionProcessor {
}
byte dredDuration = (byte) RemoteConfig.dredDuration();
boolean enableVp9 = RemoteConfig.enableSoftwareVp9();
boolean hideIp = !activePeer.getRecipient().isProfileSharing() || callSetupState.isAlwaysTurnServers();
VideoState videoState = currentState.getVideoState();
CallParticipant callParticipant = Objects.requireNonNull(currentState.getCallInfoState().getRemoteCallParticipant(activePeer.getRecipient()));
@@ -108,6 +107,7 @@ public class IncomingCallActionProcessor extends DeviceAwareActionProcessor {
context,
videoState.getLockableEglBase().require(),
RingRtcDynamicConfiguration.getAudioConfig(),
RingRtcDynamicConfiguration.getVideoConfig(),
videoState.requireLocalSink(),
callParticipant.getVideoSink(),
videoState.requireRouter(),
@@ -116,7 +116,6 @@ public class IncomingCallActionProcessor extends DeviceAwareActionProcessor {
NetworkUtil.getCallingDataMode(context),
AUDIO_LEVELS_INTERVAL,
dredDuration,
enableVp9,
false);
} catch (CallException e) {
return callFailure(currentState, "Unable to proceed with call: ", e);
@@ -147,7 +147,6 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor {
}
byte dredDuration = (byte) RemoteConfig.dredDuration();
boolean enableVp9 = RemoteConfig.enableSoftwareVp9();
boolean hideIp = !activePeer.getRecipient().isProfileSharing() || callSetupState.isAlwaysTurnServers();
VideoState videoState = currentState.getVideoState();
CallParticipant callParticipant = Objects.requireNonNull(currentState.getCallInfoState().getRemoteCallParticipant(activePeer.getRecipient()));
@@ -157,6 +156,7 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor {
context,
videoState.getLockableEglBase().require(),
RingRtcDynamicConfiguration.getAudioConfig(),
RingRtcDynamicConfiguration.getVideoConfig(),
videoState.requireLocalSink(),
callParticipant.getVideoSink(),
videoState.requireRouter(),
@@ -165,7 +165,6 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor {
NetworkUtil.getCallingDataMode(context),
AUDIO_LEVELS_INTERVAL,
dredDuration,
enableVp9,
currentState.getCallSetupState(activePeer).isEnableVideoOnCreate());
} catch (CallException e) {
return callFailure(currentState, "Unable to proceed with call: ", e);
@@ -2,10 +2,13 @@ package org.thoughtcrime.securesms.service.webrtc
import android.os.Build
import org.signal.core.util.asListContains
import org.signal.core.util.isNotNullOrBlank
import org.signal.ringrtc.AudioConfig
import org.signal.ringrtc.VideoConfig
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.webrtc.audio.AudioDeviceConfig
import java.io.File
/**
* Utility class to determine the audio configuration that RingRTC should use.
@@ -40,4 +43,65 @@ object RingRtcDynamicConfiguration {
}
return AudioDeviceConfig.getCurrentConfig()
}
@JvmStatic
fun getVideoConfig(): VideoConfig {
if (RemoteConfig.internalUser && SignalStore.internal.callingSetVideoConfig) {
val videoConfig = VideoConfig()
videoConfig.enableHardwareVp9Encode = SignalStore.internal.callingUseHardwareVp9Encode
videoConfig.enableHardwareVp9Decode = SignalStore.internal.callingUseHardwareVp9Decode
videoConfig.enableSoftwareVp9Encode = SignalStore.internal.callingUseSoftwareVp9Encode
videoConfig.enableSoftwareVp9Decode = SignalStore.internal.callingUseSoftwareVp9Decode
return videoConfig
}
val (manufacturer, model) = getSoCInfo()
val soc = "${manufacturer.lowercase()}-${model.lowercase()}"
val videoConfig = VideoConfig()
videoConfig.enableHardwareVp9Encode = !RemoteConfig.disableHardwareVp9EncodeSocList.contains(soc) && !RemoteConfig.disableHardwareVp9EncodeSocList.contains(model)
videoConfig.enableHardwareVp9Decode = !RemoteConfig.disableHardwareVp9DecodeSocList.contains(soc) && !RemoteConfig.disableHardwareVp9DecodeSocList.contains(model)
videoConfig.enableSoftwareVp9Encode = RemoteConfig.enableSoftwareVp9EncodeSoCList.contains(soc) || RemoteConfig.enableSoftwareVp9EncodeSoCList.contains(model)
videoConfig.enableSoftwareVp9Decode = RemoteConfig.enableSoftwareVp9Decode || RemoteConfig.enableSoftwareVp9DecodeSoCList.contains(soc) || RemoteConfig.enableSoftwareVp9DecodeSoCList.contains(model)
return videoConfig
}
private fun getSoCInfo(): Pair<String, String> {
// 1. Native API Method (Android 12 / API 31+)
if (Build.VERSION.SDK_INT >= 31) {
return Build.SOC_MANUFACTURER to Build.SOC_MODEL
} else {
// 2. Fallback Method for Older Devices (Android 11 and below)
val socModel = getSystemProperty("ro.board.platform").takeIf { it.isNotNullOrBlank() && !it.equals("unknown", ignoreCase = true) }
?: parseCpuInfoForHardware().takeIf { it.isNotNullOrBlank() }
?: "unknown"
return "unknown" to socModel
}
}
private fun getSystemProperty(key: String): String {
return try {
val systemProperties = Class.forName("android.os.SystemProperties")
val get = systemProperties.getMethod("get", String::class.java)
get.invoke(null, key) as String
} catch (_: Exception) {
""
}
}
/**
* Helper to parse /proc/cpuinfo for the "Hardware" field
*/
private fun parseCpuInfoForHardware(): String {
return try {
File("/proc/cpuinfo").useLines { lines ->
lines.firstOrNull { it.startsWith("Hardware", ignoreCase = true) }
?.substringAfter(':', "")
?.trim()
?: ""
}
} catch (_: Exception) {
""
}
}
}
@@ -11,6 +11,7 @@ import org.signal.core.util.gibiBytes
import org.signal.core.util.kibiBytes
import org.signal.core.util.logging.Log
import org.signal.core.util.mebiBytes
import org.signal.core.util.serialization.SignalJson
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.groups.SelectionLimits
import org.thoughtcrime.securesms.jobs.RemoteConfigRefreshJob
@@ -545,6 +546,25 @@ object RemoteConfig {
)
}
private fun remoteStringSet(
key: String,
defaultValue: Set<String>,
hotSwappable: Boolean,
active: Boolean = true,
onChangeListener: OnFlagChange? = null
): Config<Set<String>> {
return remoteValue(
key = key,
hotSwappable = hotSwappable,
sticky = false,
active = active,
onChangeListener = onChangeListener,
transformer = { value ->
value?.let { SignalJson.decode<Set<String>>(it.toString()).getOrNull() } ?: defaultValue
}
)
}
private fun <T> remoteValue(
key: String,
hotSwappable: Boolean,
@@ -1309,12 +1329,69 @@ object RemoteConfig {
)
/**
* Enables software Vp9 support for 1:1 calls
* Enables software Vp9 encode support for 1:1 calls
* Contains SoCs that are capable of encoding VP9
*/
@JvmStatic
@get:JvmName("enableSoftwareVp9")
val enableSoftwareVp9: Boolean by remoteBoolean(
key = "android.calling.enableSoftwareVp9",
@get:JvmName("enableSoftwareVp9EncodeSoCList")
val enableSoftwareVp9EncodeSoCList: Set<String> by remoteStringSet(
key = "android.calling.enableSoftwareVp9EncodeSocList",
defaultValue = setOf(),
hotSwappable = true
)
/**
* Enables software Vp9 decode support for 1:1 calls
* Contains SoCs that are capable of decoding VP9
*/
@JvmStatic
@get:JvmName("enableSoftwareVp9DecodeSoCList")
val enableSoftwareVp9DecodeSoCList: Set<String> by remoteStringSet(
key = "android.calling.enableSoftwareVp9DecodeSoCList",
defaultValue = setOf(),
hotSwappable = true
)
/**
* Enables software Vp9 decode support for 1:1 calls for all devices
*/
@JvmStatic
@get:JvmName("enableSoftwareVp9Decode")
val enableSoftwareVp9Decode: Boolean by remoteBoolean(
key = "android.calling.enableSoftwareVp9Decode",
defaultValue = false,
hotSwappable = true
)
/**
* List of devices to skip hardware VP9 on due to reliability issues
*/
@JvmStatic
@get:JvmName("disableHardwareVp9EncodeSocList")
val disableHardwareVp9EncodeSocList: Set<String> by remoteStringSet(
key = "android.calling.disableHardwareVp9EncodeSocList",
defaultValue = setOf(),
hotSwappable = true
)
/**
* List of devices to skip hardware VP9 on due to reliability issues
*/
@JvmStatic
@get:JvmName("disableHardwareVp9DecodeSocList")
val disableHardwareVp9DecodeSocList: Set<String> by remoteStringSet(
key = "android.calling.disableHardwareVp9DecodeSocList",
defaultValue = setOf(),
hotSwappable = true
)
/**
* Enables using VP9 in Group Calls
*/
@JvmStatic
@get:JvmName("enableGroupCallVp9")
val enableGroupCallVp9: Boolean by remoteBoolean(
key = "android.calling.enableGroupCallVp9",
defaultValue = false,
hotSwappable = true
)
@@ -37,7 +37,9 @@ class RemoteConfig_StaticValuesTest {
"100",
"12345678910111213141516",
"*",
"1.0.0"
"1.0.0",
"[]",
"[\"foo\"]"
)
val configKeys = RemoteConfig.configsByKey.keys
+1 -1
View File
@@ -171,7 +171,7 @@ libsignal-client = { module = "org.signal:libsignal-client", version.ref = "libs
libsignal-android = { module = "org.signal:libsignal-android", version.ref = "libsignal-client" }
protobuf-gradle-plugin = { module = "com.google.protobuf:protobuf-gradle-plugin", version.ref = "protobuf-gradle-plugin" }
signal-aesgcmprovider = "org.signal:aesgcmprovider:0.0.4"
signal-ringrtc = "org.signal:ringrtc-android:2.69.7"
signal-ringrtc = "org.signal:ringrtc-android:2.70.0"
# Third Party
signal-android-database-sqlcipher = "net.zetetic:sqlcipher-android:4.17.0"
+5 -5
View File
@@ -8307,12 +8307,12 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="3a8692a8b825848976f2de418052c7fccf0c777f630ca2d95494b5351980a7c3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.signal" name="ringrtc-android" version="2.69.7">
<artifact name="ringrtc-android-2.69.7.aar">
<sha256 value="cd31d1d8742cb84ee6eb7e01e786a20b73f8ca468b8fa509e99ce85f677c3528" origin="Generated by Gradle"/>
<component group="org.signal" name="ringrtc-android" version="2.70.0">
<artifact name="ringrtc-android-2.70.0.aar">
<sha256 value="8ae60d8c48a2eb5119cb12a2eecfd3b788110b009ca8319312c2ca995c97d147" origin="Generated by Gradle"/>
</artifact>
<artifact name="ringrtc-android-2.69.7.module">
<sha256 value="598d92dcbd40a5ee2f55bd59f6adafb07c2ffe419306fe15e38587882966897d" origin="Generated by Gradle"/>
<artifact name="ringrtc-android-2.70.0.module">
<sha256 value="5d72658aa6e0b35f2ea4541f9f8d1c9385bcfbb67e1962a0ca3dec7797630349" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.slf4j" name="slf4j-api" version="1.6.4">