- Added to Settings possibility to choose which audio modules are loaded.
Codecs provided by loaded modules are available for accounts to use.
This commit is contained in:
@ -23,8 +23,8 @@ net_prefer_ipv6 no
|
||||
module opus.so
|
||||
module amr.so
|
||||
module ilbc.so
|
||||
module g7221.so
|
||||
module g722.so
|
||||
module g7221.so
|
||||
module g726.so
|
||||
module g711.so
|
||||
module webrtc_aec.so
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.content.Context
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class Account(val accp: String) {
|
||||
|
||||
@ -151,6 +153,27 @@ class Account(val accp: String) {
|
||||
return aor.split("@")[1]
|
||||
}
|
||||
|
||||
private fun removeAudioCodecsStartingWith(prefix: String) {
|
||||
val newCodecs = ArrayList<String>()
|
||||
for (acSpec in audioCodec)
|
||||
if (!acSpec.toLowerCase(Locale.ROOT).startsWith(prefix)) newCodecs.add(acSpec)
|
||||
audioCodec = newCodecs
|
||||
}
|
||||
|
||||
fun removeAudioCodecs(codecModule: String) {
|
||||
when (codecModule) {
|
||||
"g711" -> {
|
||||
removeAudioCodecsStartingWith("pcm")
|
||||
}
|
||||
"g722" -> {
|
||||
removeAudioCodecsStartingWith("g722/")
|
||||
}
|
||||
else -> {
|
||||
removeAudioCodecsStartingWith(codecModule)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun accounts(): ArrayList<Account> {
|
||||
|
||||
@ -186,7 +186,7 @@ class BaresipService: Service() {
|
||||
showStatusNotification()
|
||||
|
||||
if (Config.variable("dyn_dns")[0] == "yes")
|
||||
Config.remove("dns_server")
|
||||
Config.removeVariable("dns_server")
|
||||
|
||||
if (AccountsActivity.noAccounts()) {
|
||||
val newIntent = Intent(this, MainActivity::class.java)
|
||||
@ -712,9 +712,9 @@ class BaresipService: Service() {
|
||||
Log.d(LOG_TAG, "Received 'stopped' from baresip with param '$error'")
|
||||
isServiceRunning = false
|
||||
if (error == "ua_init") {
|
||||
Config.remove("sip_listen")
|
||||
Config.remove("sip_certificate")
|
||||
Config.remove("sip_cafile")
|
||||
Config.removeVariable("sip_listen")
|
||||
Config.removeVariable("sip_certificate")
|
||||
Config.removeVariable("sip_cafile")
|
||||
}
|
||||
val intent = Intent("service event")
|
||||
intent.putExtra("event", "stopped")
|
||||
|
||||
@ -21,17 +21,6 @@ object Config {
|
||||
config = "${config}ausrc_format s16\nauplay_format s16\nauenc_format s16\naudec_format s16\nmodule webrtc_aec.so\n"
|
||||
write = true
|
||||
}
|
||||
if (!config.contains(Regex("module[ ]+amr.so"))) {
|
||||
config = config.replace(Regex("module[ ]+g7...?.so\n"), "")
|
||||
config = config.replace(Regex("module[ ]+ilbc.so\n"), "")
|
||||
config = "${config}module amr.so\n"
|
||||
config = "${config}module ilbc.so\n"
|
||||
config = "${config}module g7221.so\n"
|
||||
config = "${config}module g722.so\n"
|
||||
config = "${config}module g726.so\n"
|
||||
config = "${config}module g711.so\n"
|
||||
write = true
|
||||
}
|
||||
if (config.contains(Regex("#module_app[ ]+mwi.so"))) {
|
||||
config = config.replace(Regex("#module_app[ ]+mwi.so"),
|
||||
"module_app mwi.so")
|
||||
@ -69,7 +58,7 @@ object Config {
|
||||
}
|
||||
val preferIpv6 = variable("prefer_ipv6")
|
||||
if (preferIpv6.size > 0) {
|
||||
remove("prefer_ipv6")
|
||||
removeVariable("prefer_ipv6")
|
||||
config = "net_prefer_ipv6 ${preferIpv6[0]}\n${config}"
|
||||
write = true
|
||||
} else {
|
||||
@ -112,18 +101,21 @@ object Config {
|
||||
return result
|
||||
}
|
||||
|
||||
fun add(variable: String, value: String) {
|
||||
config += "$variable $value\n"
|
||||
fun addLine(line: String) {
|
||||
config += "$line\n"
|
||||
}
|
||||
|
||||
fun remove(variable: String) {
|
||||
config = Utils.removeLinesStartingWithName(config, variable)
|
||||
Utils.putFileContents(configPath, config.toByteArray())
|
||||
fun removeLine(line: String) {
|
||||
config = Utils.removeLinesStartingWithString(config, line)
|
||||
}
|
||||
|
||||
fun replace(variable: String, value: String) {
|
||||
remove(variable)
|
||||
add(variable, value)
|
||||
fun removeVariable(variable: String) {
|
||||
config = Utils.removeLinesStartingWithString(config, "$variable ")
|
||||
}
|
||||
|
||||
fun replaceVariable(variable: String, value: String) {
|
||||
removeVariable(variable)
|
||||
addLine("$variable $value")
|
||||
}
|
||||
|
||||
fun reset(ctx: Context) {
|
||||
|
||||
@ -3,14 +3,19 @@ package com.tutpro.baresip
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import android.widget.RelativeLayout.LayoutParams
|
||||
import android.widget.AdapterView
|
||||
|
||||
class ConfigActivity : AppCompatActivity() {
|
||||
|
||||
@ -35,6 +40,7 @@ class ConfigActivity : AppCompatActivity() {
|
||||
private var oldDnsServers = ""
|
||||
private var oldCertificateFile = false
|
||||
private var oldCAFile = false
|
||||
private var oldAudioModules = mutableMapOf<String, Boolean>()
|
||||
private var oldAec = false
|
||||
private var oldOpusBitrate = ""
|
||||
private var oldOpusPacketLoss = ""
|
||||
@ -43,6 +49,7 @@ class ConfigActivity : AppCompatActivity() {
|
||||
private var callVolume = BaresipService.callVolume
|
||||
private var save = false
|
||||
private var restart = false
|
||||
private val audioModules = listOf("opus", "amr", "ilbc", "g722", "g7221", "g726", "g711")
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
@ -91,6 +98,37 @@ class ConfigActivity : AppCompatActivity() {
|
||||
oldCAFile = Config.variable("sip_cafile").isNotEmpty()
|
||||
caFile.isChecked = oldCAFile
|
||||
|
||||
val audioModulesList = findViewById(R.id.AudioModulesList) as LinearLayout
|
||||
var id = 1000
|
||||
for (module in audioModules) {
|
||||
val rl = RelativeLayout(this)
|
||||
val rlParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
|
||||
rlParams.marginStart = 16
|
||||
rl.layoutParams = rlParams
|
||||
val tv = TextView(this)
|
||||
tv.id = id++
|
||||
val tvParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
|
||||
tvParams.addRule(RelativeLayout.ALIGN_PARENT_START)
|
||||
tvParams.addRule(RelativeLayout.CENTER_VERTICAL)
|
||||
tvParams.addRule(RelativeLayout.START_OF, id)
|
||||
tv.layoutParams = tvParams
|
||||
tv.text = module
|
||||
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18f)
|
||||
tv.setTextColor(Color.BLACK)
|
||||
rl.addView(tv)
|
||||
val cb = CheckBox(this)
|
||||
cb.id = id++
|
||||
val cbParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
|
||||
cbParams.addRule(RelativeLayout.ALIGN_PARENT_END)
|
||||
cbParams.addRule(RelativeLayout.CENTER_VERTICAL)
|
||||
cb.layoutParams = cbParams
|
||||
cb.gravity = Gravity.END
|
||||
cb.isChecked = Config.variable("module $module.so").size > 0
|
||||
oldAudioModules.put(module, cb.isChecked)
|
||||
rl.addView(cb)
|
||||
audioModulesList.addView(rl)
|
||||
}
|
||||
|
||||
aec = findViewById(R.id.Aec) as CheckBox
|
||||
val aecCv = Config.variable("module")
|
||||
oldAec = aecCv.contains("webrtc_aec.so")
|
||||
@ -166,7 +204,7 @@ class ConfigActivity : AppCompatActivity() {
|
||||
var autoStartString = "no"
|
||||
if (autoStart.isChecked) autoStartString = "yes"
|
||||
if (oldAutoStart != autoStartString) {
|
||||
Config.replace("auto_start", autoStartString)
|
||||
Config.replaceVariable("auto_start", autoStartString)
|
||||
save = true
|
||||
restart = false
|
||||
}
|
||||
@ -178,8 +216,8 @@ class ConfigActivity : AppCompatActivity() {
|
||||
"${getString(R.string.invalid_listen_address)}: $listenAddr")
|
||||
return false
|
||||
}
|
||||
Config.remove("sip_listen")
|
||||
if (listenAddr != "") Config.add("sip_listen", listenAddr)
|
||||
Config.removeVariable("sip_listen")
|
||||
if (listenAddr != "") Config.addLine("sip_listen $listenAddr")
|
||||
save = true
|
||||
restart = true
|
||||
}
|
||||
@ -191,8 +229,8 @@ class ConfigActivity : AppCompatActivity() {
|
||||
"${getString(R.string.invalid_bind_address)}: $bindAddr")
|
||||
return false
|
||||
}
|
||||
Config.remove("net_interface")
|
||||
if (bindAddr != "") Config.add("net_interface", bindAddr)
|
||||
Config.removeVariable("net_interface")
|
||||
if (bindAddr != "") Config.addLine("net_interface $bindAddr")
|
||||
save = true
|
||||
restart = true
|
||||
}
|
||||
@ -200,7 +238,7 @@ class ConfigActivity : AppCompatActivity() {
|
||||
var preferIPv6String = "no"
|
||||
if (preferIPv6.isChecked) preferIPv6String = "yes"
|
||||
if (oldPreferIPv6 != preferIPv6String) {
|
||||
Config.replace("net_prefer_ipv6", preferIPv6String)
|
||||
Config.replaceVariable("net_prefer_ipv6", preferIPv6String)
|
||||
save = true
|
||||
restart = true
|
||||
}
|
||||
@ -212,19 +250,19 @@ class ConfigActivity : AppCompatActivity() {
|
||||
"${getString(R.string.invalid_dns_servers)}: $dnsServers")
|
||||
return false
|
||||
}
|
||||
Config.remove("dyn_dns")
|
||||
Config.remove("dns_server")
|
||||
Config.removeVariable("dyn_dns")
|
||||
Config.removeVariable("dns_server")
|
||||
if (dnsServers.isNotEmpty()) {
|
||||
for (server in dnsServers.split(","))
|
||||
Config.add("dns_server", server)
|
||||
Config.add("dyn_dns", "no")
|
||||
Config.addLine("dns_server $server")
|
||||
Config.addLine("dyn_dns no")
|
||||
if (Api.net_use_nameserver(dnsServers) != 0) {
|
||||
Utils.alertView(this, getString(R.string.error),
|
||||
"${getString(R.string.failed_to_set_dns_servers)}: $dnsServers")
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
Config.add("dyn_dns", "yes")
|
||||
Config.addLine("dyn_dns yes")
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
Config.updateDnsServers(cm.getLinkProperties(cm.activeNetwork).getDnsServers())
|
||||
@ -249,10 +287,10 @@ class ConfigActivity : AppCompatActivity() {
|
||||
return false
|
||||
}
|
||||
Utils.putFileContents(BaresipService.filesPath + "/cert.pem", content)
|
||||
Config.remove("sip_certificate")
|
||||
Config.add("sip_certificate", BaresipService.filesPath + "/cert.pem")
|
||||
Config.removeVariable("sip_certificate")
|
||||
Config.addLine("sip_certificate ${BaresipService.filesPath}/cert.pem")
|
||||
} else {
|
||||
Config.remove("sip_certificate")
|
||||
Config.removeVariable("sip_certificate")
|
||||
}
|
||||
save = true
|
||||
restart = true
|
||||
@ -272,22 +310,44 @@ class ConfigActivity : AppCompatActivity() {
|
||||
}
|
||||
Utils.putFileContents(BaresipService.filesPath + "/ca_certs.crt",
|
||||
content)
|
||||
Config.remove("sip_cafile")
|
||||
Config.add("sip_cafile", BaresipService.filesPath + "/ca_certs.crt")
|
||||
Config.removeVariable("sip_cafile")
|
||||
Config.addLine("sip_cafile ${BaresipService.filesPath}/ca_certs.crt")
|
||||
} else {
|
||||
Config.remove("sip_cafile")
|
||||
Config.removeVariable("sip_cafile")
|
||||
}
|
||||
save = true
|
||||
restart = true
|
||||
}
|
||||
|
||||
var id = 1001
|
||||
for (module in audioModules) {
|
||||
val box = findViewById<CheckBox>(id++)
|
||||
if (box.isChecked && !oldAudioModules[module]!!) {
|
||||
if (Api.module_load("$module.so") != 0) {
|
||||
Utils.alertView(this, getString(R.string.error),
|
||||
"${getString(R.string.failed_to_load_module)}: $module.so")
|
||||
return false
|
||||
}
|
||||
Config.addLine("module $module.so")
|
||||
save = true
|
||||
}
|
||||
if (!box.isChecked && oldAudioModules[module]!!) {
|
||||
Api.module_unload("$module.so")
|
||||
Config.removeLine("module $module.so")
|
||||
for (ua in UserAgent.uas()) ua.account.removeAudioCodecs(module)
|
||||
AccountsActivity.saveAccounts()
|
||||
save = true
|
||||
}
|
||||
id++
|
||||
}
|
||||
|
||||
if (aec.isChecked != oldAec) {
|
||||
Config.remove("module webrtc_aec.so")
|
||||
Config.removeLine("module webrtc_aec.so")
|
||||
if (aec.isChecked) {
|
||||
Config.add("module", "webrtc_aec.so")
|
||||
Config.addLine("module webrtc_aec.so")
|
||||
if (Api.module_load("webrtc_aec.so") != 0) {
|
||||
Utils.alertView(this, getString(R.string.error),
|
||||
getString(R.string.failed_to_load_aec_module))
|
||||
getString(R.string.failed_to_load_module))
|
||||
aec.isChecked = false
|
||||
return false
|
||||
}
|
||||
@ -304,8 +364,8 @@ class ConfigActivity : AppCompatActivity() {
|
||||
"${getString(R.string.invalid_opus_bitrate)}: $opusBitRate.")
|
||||
return false
|
||||
}
|
||||
Config.remove("opus_bitrate")
|
||||
Config.add("opus_bitrate", opusBitRate)
|
||||
Config.removeVariable("opus_bitrate")
|
||||
Config.addLine("opus_bitrate $opusBitRate")
|
||||
save = true
|
||||
restart = true
|
||||
}
|
||||
@ -317,11 +377,11 @@ class ConfigActivity : AppCompatActivity() {
|
||||
"${getString(R.string.invalid_opus_packet_loss)}: $opusPacketLoss")
|
||||
return false
|
||||
}
|
||||
Config.remove("opus_inbandfec")
|
||||
Config.remove("opus_packet_loss")
|
||||
Config.removeVariable("opus_inbandfec")
|
||||
Config.removeVariable("opus_packet_loss")
|
||||
if (opusPacketLoss != "0") {
|
||||
Config.add("opus_inbandfec", "yes")
|
||||
Config.add("opus_packet_loss", opusPacketLoss)
|
||||
Config.addLine("opus_inbandfec yes")
|
||||
Config.addLine("opus_packet_loss $opusPacketLoss")
|
||||
}
|
||||
save = true
|
||||
restart = true
|
||||
@ -330,21 +390,21 @@ class ConfigActivity : AppCompatActivity() {
|
||||
var iceModeString = "full"
|
||||
if (iceLite.isChecked) iceModeString = "lite"
|
||||
if (oldIceMode != iceModeString) {
|
||||
Config.replace("ice_mode", iceModeString)
|
||||
Config.replaceVariable("ice_mode", iceModeString)
|
||||
save = true
|
||||
restart = true
|
||||
}
|
||||
|
||||
if (BaresipService.callVolume != callVolume) {
|
||||
BaresipService.callVolume = callVolume
|
||||
Config.replace("call_volume", callVolume.toString())
|
||||
Config.replaceVariable("call_volume", callVolume.toString())
|
||||
save = true
|
||||
}
|
||||
|
||||
var logLevelString = "2"
|
||||
if (debug.isChecked) logLevelString = "0"
|
||||
if (oldLogLevel != logLevelString) {
|
||||
Config.replace("log_level", logLevelString)
|
||||
Config.replaceVariable("log_level", logLevelString)
|
||||
Api.log_level_set(logLevelString.toInt())
|
||||
Log.logLevelSet(logLevelString.toInt())
|
||||
save = true
|
||||
@ -415,6 +475,10 @@ class ConfigActivity : AppCompatActivity() {
|
||||
Utils.alertView(this, getString(R.string.tls_ca_file),
|
||||
getString(R.string.tls_ca_file_help))
|
||||
}
|
||||
findViewById(R.id.AudioModulesTitle) as TextView -> {
|
||||
Utils.alertView(this, getString(R.string.audio_modules_title),
|
||||
getString(R.string.audio_modules_help))
|
||||
}
|
||||
findViewById(R.id.AecTitle) as TextView-> {
|
||||
Utils.alertView(this, getString(R.string.aec),
|
||||
getString(R.string.aec_help))
|
||||
|
||||
@ -38,10 +38,10 @@ object Utils {
|
||||
return result
|
||||
}
|
||||
|
||||
fun removeLinesStartingWithName(string: String, name: String): String {
|
||||
fun removeLinesStartingWithString(lines: String, string: String): String {
|
||||
var result = ""
|
||||
for (line in string.split("\n"))
|
||||
if (!line.startsWith(name) && (line.length > 0)) result += line + "\n"
|
||||
for (line in lines.split("\n"))
|
||||
if (!line.startsWith(string) && (line.length > 0)) result += line + "\n"
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
@ -192,7 +192,29 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:orientation="horizontal" >
|
||||
android:orientation="vertical" >
|
||||
<TextView
|
||||
android:id="@+id/AudioModulesTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18sp"
|
||||
android:textColor="@android:color/black"
|
||||
android:onClick="onClick"
|
||||
android:text="@string/audio_modules_title" >
|
||||
</TextView>
|
||||
<LinearLayout
|
||||
android:id="@+id/AudioModulesList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="24dp"
|
||||
android:orientation="vertical" >
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp" >
|
||||
<TextView
|
||||
android:id="@+id/AecTitle"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@ -186,9 +186,23 @@
|
||||
DNS-palvelijoihin.</string>
|
||||
<string name="invalid_dns_servers">Virheelliset DNS-palvelimet</string>
|
||||
<string name="failed_to_set_dns_servers">DNS-palvelinten asetus epäonnistui</string>
|
||||
<string name="tls_certificate_file">TLS-varmennintiedosto</string>
|
||||
<string name="tls_certificate_file_help">Jos merkitty, tiedosto \'cert.pem\', joka sisältää
|
||||
tämän baresip-sovelluksen julkisen ja yksityisen TLS-varmentimen, on joko jo ladattu tai tullaan
|
||||
lataamaan Download-hakemistosta. Turvallisuusyistä tuhoa tiedosto heti lataamisen jälkeen.
|
||||
</string>
|
||||
<string name="tls_ca_file">TLS CA-tiedosto</string>
|
||||
<string name="tls_ca_file_help">Jos merkitty, tiedosto \'ca_certs.crt\', joka sisältää
|
||||
TLS-varmenninauktoriteettien julkiset varmentimen, on joko jo ladattu tai tullaan lataamaan
|
||||
Download-hakemistosta.
|
||||
</string>
|
||||
<string name="audio_modules_title">Audio-modulit</string>
|
||||
<string name="audio_modules_help">Merkittyjen modulien tarjoamat audio-koodekit ovat tilien
|
||||
käytettävissä.
|
||||
</string>
|
||||
<string name="failed_to_load_module">Modulin lataaminen epäonnistui</string>
|
||||
<string name="aec">Akustinen kaiun poisto</string>
|
||||
<string name="aec_help">Jos merkitty, kaikua yritetään poistaa puheluiden aikana.</string>
|
||||
<string name="failed_to_load_aec_module">Kaiunpoistomodulin lataaminen epäonnistui.</string>
|
||||
<string name="opus_bit_rate">Opus-koodekin bittinopeus</string>
|
||||
<string name="opus_bit_rate_help">Opus-koodekin käyttämä
|
||||
keskimääräinen enimmäisnopeus. Mahdollisia arvoja ovat
|
||||
@ -306,15 +320,6 @@
|
||||
<string name="call_is_secure">Tämä pulelu on turvallinen ja kohde on
|
||||
todennettu! Haluatko poistaa todennuksen?</string>
|
||||
<string name="unverify">Poista todennus</string>
|
||||
<string name="tls_ca_file">TLS CA-tiedosto</string>
|
||||
<string name="tls_ca_file_help">Jos merkitty, tiedosto \'ca_certs.crt\', joka sisältää
|
||||
todennusauktoriteettien TLS-sertifikaatit, on ladattu tai ladataan Download-kansiosta.
|
||||
</string>
|
||||
<string name="tls_certificate_file">TLS sertifikaattitiedosto</string>
|
||||
<string name="tls_certificate_file_help">"Jos merkitty, tiedosto \'cert.pem\', joka sisältää
|
||||
tämän baresip-sovelluksen TLS-sertifikaatin ja yksityisen avaimen, on ladattu tai ladataan
|
||||
Download-kansiosta."
|
||||
</string>
|
||||
<string name="backed_up">Sovelluksen tiedot talletettiin Download-kansion tiedostoon
|
||||
\'baresip.bs\'.
|
||||
</string>
|
||||
|
||||
@ -181,9 +181,12 @@
|
||||
<string name="tls_ca_file">TLS CA File</string>
|
||||
<string name="tls_ca_file_help">If checked, file \'ca_certs.crt\' containing TLS certificates
|
||||
of Certificate Authorities has been or will be loaded from Download directory.</string>
|
||||
<string name="audio_modules_title">Audio Modules</string>
|
||||
<string name="audio_modules_help">Audio codecs provided by the checked modules are
|
||||
available for use by the accounts.</string>
|
||||
<string name="failed_to_load_module">Failed to load module.</string>
|
||||
<string name="aec">Acoustic Echo Cancellation</string>
|
||||
<string name="aec_help">If checked, echo cancellation is attempted on call audio.</string>
|
||||
<string name="failed_to_load_aec_module">Failed to load Acoustic Echo Cancellation module.</string>
|
||||
<string name="opus_bit_rate">Opus Bit Rate</string>
|
||||
<string name="opus_bit_rate_help">Average maximum bit rate used by Opus audio stream.
|
||||
Valid values are 6000-510000. Factory default is 28000.</string>
|
||||
|
||||
Reference in New Issue
Block a user