mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-08-05 12:55:11 +01:00
Update RingRTC to v2.70.0, add video config settings
Co-authored-by: Cody Henthorne <cody@signal.org>
This commit is contained in:
committed by
Michelle Tang
parent
5f22566e10
commit
e0603b14bb
@@ -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"))
|
||||
|
||||
+44
@@ -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!
|
||||
|
||||
+5
@@ -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,
|
||||
|
||||
+30
@@ -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()
|
||||
|
||||
+1
-2
@@ -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);
|
||||
|
||||
+1
-2
@@ -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);
|
||||
|
||||
+64
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user