Major rewrite of settings implementation by separating static and dynamic
settings Changed opus expected packed loss default value from 0 to 1 in order to enable forward error correction Restored original audio jitten buffer size to 0-20 now when upstream bug is fixed
This commit is contained in:
@@ -1,37 +1,25 @@
|
|||||||
auto_start yes
|
|
||||||
log_level 2
|
|
||||||
poll_method epoll
|
poll_method epoll
|
||||||
sip_trans_bsize 128
|
|
||||||
sip_verify_server no
|
|
||||||
call_local_timeout 120
|
call_local_timeout 120
|
||||||
call_max_calls 4
|
call_max_calls 4
|
||||||
|
call_hold_other_calls yes
|
||||||
audio_player opensles,nil
|
audio_player opensles,nil
|
||||||
audio_source opensles,nil
|
audio_source opensles,nil
|
||||||
audio_alert opensles,nil
|
audio_alert opensles,nil
|
||||||
audio_level no
|
audio_level no
|
||||||
|
ausrc_format s16
|
||||||
|
auplay_format s16
|
||||||
|
auenc_format s16
|
||||||
|
audec_format s16
|
||||||
audio_buffer 20-300
|
audio_buffer 20-300
|
||||||
audio_buffer_mode adaptive
|
audio_buffer_mode adaptive
|
||||||
ausrc_format s16
|
audio_silence -35.0
|
||||||
auenc_format s16
|
audio_telev_pt 10
|
||||||
auplay_format s16
|
|
||||||
audec_format s16
|
|
||||||
rtp_tos 184
|
rtp_tos 184
|
||||||
|
rtp_video_tos 136
|
||||||
audio_jitter_buffer_type adaptive
|
audio_jitter_buffer_type adaptive
|
||||||
audio_jitter_buffer_delay 0-20
|
audio_jitter_buffer_delay 0-20
|
||||||
video_jitter_buffer_type adaptive
|
|
||||||
video_jitter_buffer_delay 1-50
|
|
||||||
rtp_stats yes
|
rtp_stats yes
|
||||||
rtp_timeout 60
|
rtp_timeout 60
|
||||||
dyn_dns yes
|
|
||||||
module opus.so
|
|
||||||
module amr.so
|
|
||||||
module g722.so
|
|
||||||
module g7221.so
|
|
||||||
module g726.so
|
|
||||||
module g729.so
|
|
||||||
module gsm.so
|
|
||||||
module g711.so
|
|
||||||
module webrtc_aecm.so
|
|
||||||
module opensles.so
|
module opensles.so
|
||||||
module stun.so
|
module stun.so
|
||||||
module turn.so
|
module turn.so
|
||||||
@@ -44,11 +32,10 @@ module_app account.so
|
|||||||
module_app debug_cmd.so
|
module_app debug_cmd.so
|
||||||
module_app mwi.so
|
module_app mwi.so
|
||||||
evdev_device /dev/input/event0
|
evdev_device /dev/input/event0
|
||||||
opus_bitrate 28000
|
|
||||||
opus_samplerate 16000
|
opus_samplerate 16000
|
||||||
|
opus_stereo no
|
||||||
|
opus_sprop_stereo no
|
||||||
opus_cbr no
|
opus_cbr no
|
||||||
opus_inbandfec yes
|
opus_inbandfec yes
|
||||||
opus_application voip
|
opus_application voip
|
||||||
opus_stereo no
|
|
||||||
opus_sprop_stereo no
|
|
||||||
dtls_srtp_use_ec prime256v1
|
dtls_srtp_use_ec prime256v1
|
||||||
@@ -27,8 +27,6 @@ class AudioActivity : AppCompatActivity() {
|
|||||||
private var oldOpusBitrate = ""
|
private var oldOpusBitrate = ""
|
||||||
private var oldOpusPacketLoss = ""
|
private var oldOpusPacketLoss = ""
|
||||||
private var oldAec = false
|
private var oldAec = false
|
||||||
private var oldAudioDelay = BaresipService.audioDelay.toString()
|
|
||||||
private val audioModules = listOf("opus", "amr", "g722", "g7221", "g726", "g729", "g711")
|
|
||||||
|
|
||||||
private val onBackPressedCallback = object : OnBackPressedCallback(true) {
|
private val onBackPressedCallback = object : OnBackPressedCallback(true) {
|
||||||
override fun handleOnBackPressed() {
|
override fun handleOnBackPressed() {
|
||||||
@@ -74,6 +72,8 @@ class AudioActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val modules = Config.variables("module")
|
||||||
|
|
||||||
val audioModulesList = binding.AudioModulesList
|
val audioModulesList = binding.AudioModulesList
|
||||||
var id = 1000
|
var id = 1000
|
||||||
for (module in audioModules) {
|
for (module in audioModules) {
|
||||||
@@ -102,29 +102,26 @@ class AudioActivity : AppCompatActivity() {
|
|||||||
cbParams.addRule(RelativeLayout.CENTER_VERTICAL)
|
cbParams.addRule(RelativeLayout.CENTER_VERTICAL)
|
||||||
cb.layoutParams = cbParams
|
cb.layoutParams = cbParams
|
||||||
cb.gravity = Gravity.END
|
cb.gravity = Gravity.END
|
||||||
cb.isChecked = Config.variable("module $module.so").size > 0
|
cb.isChecked = modules.contains("${module}.so")
|
||||||
oldAudioModules[module] = cb.isChecked
|
oldAudioModules[module] = cb.isChecked
|
||||||
rl.addView(cb)
|
rl.addView(cb)
|
||||||
audioModulesList.addView(rl)
|
audioModulesList.addView(rl)
|
||||||
}
|
}
|
||||||
|
|
||||||
opusBitRate = binding.OpusBitRate
|
opusBitRate = binding.OpusBitRate
|
||||||
val obCv = Config.variable("opus_bitrate")
|
oldOpusBitrate = Config.variable("opus_bitrate")
|
||||||
oldOpusBitrate = if (obCv.size == 0) "28000" else obCv[0]
|
|
||||||
opusBitRate.setText(oldOpusBitrate)
|
opusBitRate.setText(oldOpusBitrate)
|
||||||
|
|
||||||
opusPacketLoss = binding.OpusPacketLoss
|
opusPacketLoss = binding.OpusPacketLoss
|
||||||
val oplCv = Config.variable("opus_packet_loss")
|
oldOpusPacketLoss = Config.variable("opus_packet_loss")
|
||||||
oldOpusPacketLoss = if (oplCv.size == 0) "0" else oplCv[0]
|
|
||||||
opusPacketLoss.setText(oldOpusPacketLoss)
|
opusPacketLoss.setText(oldOpusPacketLoss)
|
||||||
|
|
||||||
aec = binding.Aec
|
aec = binding.Aec
|
||||||
val aecCv = Config.variable("module")
|
oldAec = modules.contains("webrtc_aecm.so")
|
||||||
oldAec = aecCv.contains("webrtc_aecm.so")
|
|
||||||
aec.isChecked = oldAec
|
aec.isChecked = oldAec
|
||||||
|
|
||||||
audioDelay = binding.AudioDelay
|
audioDelay = binding.AudioDelay
|
||||||
audioDelay.setText(oldAudioDelay)
|
audioDelay.setText(BaresipService.audioDelay.toString())
|
||||||
|
|
||||||
bindTitles()
|
bindTitles()
|
||||||
|
|
||||||
@@ -160,18 +157,19 @@ class AudioActivity : AppCompatActivity() {
|
|||||||
for (module in audioModules) {
|
for (module in audioModules) {
|
||||||
val box = findViewById<CheckBox>(id++)
|
val box = findViewById<CheckBox>(id++)
|
||||||
if (box.isChecked && !oldAudioModules[module]!!) {
|
if (box.isChecked && !oldAudioModules[module]!!) {
|
||||||
if (Api.module_load("$module.so") != 0) {
|
if (Api.module_load("${module}.so") != 0) {
|
||||||
Utils.alertView(this, getString(R.string.error),
|
Utils.alertView(this, getString(R.string.error),
|
||||||
"${getString(R.string.failed_to_load_module)}: $module.so")
|
"${getString(R.string.failed_to_load_module)}: ${module}.so")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
Config.addModuleLine("module $module.so")
|
Config.addVariable("module", "${module}.so")
|
||||||
save = true
|
save = true
|
||||||
}
|
}
|
||||||
if (!box.isChecked && oldAudioModules[module]!!) {
|
if (!box.isChecked && oldAudioModules[module]!!) {
|
||||||
Api.module_unload("$module.so")
|
Api.module_unload("${module}.so")
|
||||||
Config.removeLine("module $module.so")
|
Config.removeVariableValue("module", "${module}.so")
|
||||||
for (ua in BaresipService.uas) ua.account.removeAudioCodecs(module)
|
for (ua in BaresipService.uas)
|
||||||
|
ua.account.removeAudioCodecs(module)
|
||||||
AccountsActivity.saveAccounts()
|
AccountsActivity.saveAccounts()
|
||||||
save = true
|
save = true
|
||||||
}
|
}
|
||||||
@@ -185,8 +183,7 @@ class AudioActivity : AppCompatActivity() {
|
|||||||
"${getString(R.string.invalid_opus_bitrate)}: $opusBitRate.")
|
"${getString(R.string.invalid_opus_bitrate)}: $opusBitRate.")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
Config.removeVariable("opus_bitrate")
|
Config.replaceVariable("opus_bitrate", opusBitRate)
|
||||||
Config.addLine("opus_bitrate $opusBitRate")
|
|
||||||
reload = true
|
reload = true
|
||||||
save = true
|
save = true
|
||||||
}
|
}
|
||||||
@@ -198,20 +195,14 @@ class AudioActivity : AppCompatActivity() {
|
|||||||
"${getString(R.string.invalid_opus_packet_loss)}: $opusPacketLoss")
|
"${getString(R.string.invalid_opus_packet_loss)}: $opusPacketLoss")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
Config.removeVariable("opus_inbandfec")
|
Config.replaceVariable("opus_packet_loss", opusPacketLoss)
|
||||||
Config.removeVariable("opus_packet_loss")
|
|
||||||
if (opusPacketLoss != "0") {
|
|
||||||
Config.addLine("opus_inbandfec yes")
|
|
||||||
Config.addLine("opus_packet_loss $opusPacketLoss")
|
|
||||||
}
|
|
||||||
reload = true
|
reload = true
|
||||||
save = true
|
save = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aec.isChecked != oldAec) {
|
if (aec.isChecked != oldAec) {
|
||||||
Config.removeLine("module webrtc_aecm.so")
|
|
||||||
if (aec.isChecked) {
|
if (aec.isChecked) {
|
||||||
Config.addModuleLine("module webrtc_aecm.so")
|
Config.replaceVariable("module", "webrtc_aecm.so")
|
||||||
if (Api.module_load("webrtc_aecm.so") != 0) {
|
if (Api.module_load("webrtc_aecm.so") != 0) {
|
||||||
Utils.alertView(this, getString(R.string.error),
|
Utils.alertView(this, getString(R.string.error),
|
||||||
getString(R.string.failed_to_load_module))
|
getString(R.string.failed_to_load_module))
|
||||||
@@ -220,19 +211,19 @@ class AudioActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Api.module_unload("webrtc_aecm.so")
|
Api.module_unload("webrtc_aecm.so")
|
||||||
|
Config.removeVariableValue("module", "webrtc_aecm.so")
|
||||||
}
|
}
|
||||||
save = true
|
save = true
|
||||||
}
|
}
|
||||||
|
|
||||||
val audioDelay = audioDelay.text.toString().trim()
|
val audioDelay = audioDelay.text.toString().trim()
|
||||||
if (audioDelay != oldAudioDelay) {
|
if (audioDelay != BaresipService.audioDelay.toString()) {
|
||||||
if (!checkAudioDelay(audioDelay)) {
|
if (!checkAudioDelay(audioDelay)) {
|
||||||
Utils.alertView(this, getString(R.string.notice),
|
Utils.alertView(this, getString(R.string.notice),
|
||||||
String.format(getString(R.string.invalid_audio_delay), audioDelay))
|
String.format(getString(R.string.invalid_audio_delay), audioDelay))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
Config.removeVariable("audio_delay")
|
Config.replaceVariable("audio_delay", audioDelay)
|
||||||
Config.addLine("audio_delay $audioDelay")
|
|
||||||
BaresipService.audioDelay = audioDelay.toLong()
|
BaresipService.audioDelay = audioDelay.toLong()
|
||||||
save = true
|
save = true
|
||||||
}
|
}
|
||||||
@@ -303,4 +294,9 @@ class AudioActivity : AppCompatActivity() {
|
|||||||
val number = audioDelay.toIntOrNull() ?: return false
|
val number = audioDelay.toIntOrNull() ?: return false
|
||||||
return (number >= 100) && (number <= 3000)
|
return (number >= 100) && (number <= 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val audioModules = listOf("opus", "amr", "g722", "g7221", "g726", "g729", "g711")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ class BaresipService: Service() {
|
|||||||
}
|
}
|
||||||
for (a in assets) {
|
for (a in assets) {
|
||||||
file = File("${filesPath}/$a")
|
file = File("${filesPath}/$a")
|
||||||
if (!file.exists()) {
|
if (!file.exists() && a != "config") {
|
||||||
Log.i(TAG, "Copying asset '$a'")
|
Log.i(TAG, "Copying asset '$a'")
|
||||||
Utils.copyAssetToFile(applicationContext, a, "$filesPath/$a")
|
Utils.copyAssetToFile(applicationContext, a, "$filesPath/$a")
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -2,156 +2,203 @@ package com.tutpro.baresip
|
|||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import java.io.File
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
object Config {
|
object Config {
|
||||||
|
|
||||||
private val configPath = BaresipService.filesPath + "/config"
|
private val configPath = BaresipService.filesPath + "/config"
|
||||||
private var config = String(Utils.getFileContents(configPath)!!, StandardCharsets.ISO_8859_1)
|
private lateinit var config: String
|
||||||
|
private lateinit var lines: List<String>
|
||||||
|
private lateinit var previousConfig: String
|
||||||
|
private lateinit var previousLines: List<String>
|
||||||
|
|
||||||
fun initialize(ctx: Context) {
|
fun initialize(ctx: Context) {
|
||||||
|
|
||||||
config = config.replace("module_tmp uuid.so", "module uuid.so")
|
config = ctx.assets.open("config.static").bufferedReader().use { it.readText() }
|
||||||
config = config.replace("module_tmp account.so", "module_app account.so")
|
if (!File(configPath).exists()) {
|
||||||
config = config.replace("webrtc_aec.so", "webrtc_aecm.so")
|
for (module in AudioActivity.audioModules)
|
||||||
config = config.replace("module zrtp.so", "module gzrtp.so")
|
config = "${config}module ${module}.so\n"
|
||||||
|
config = "${config}module webrtc_aecm.so\n"
|
||||||
removeLine("module_app contact.so")
|
previousConfig = config
|
||||||
|
} else {
|
||||||
if (!config.contains("module gsm.so")) {
|
previousConfig = String(Utils.getFileContents(configPath)!!, StandardCharsets.ISO_8859_1)
|
||||||
config = "${config}module gsm.so\n"
|
|
||||||
}
|
}
|
||||||
|
previousLines = previousConfig.split("\n")
|
||||||
|
|
||||||
if (config.contains("rtp_stats no"))
|
val logLevel = previousVariable("log_level")
|
||||||
replaceVariable("rtp_stats", "yes")
|
if (logLevel == "") {
|
||||||
|
|
||||||
if (!config.contains(Regex("ausrc_format s16"))) {
|
|
||||||
config = "${config}ausrc_format s16\nauplay_format s16\nauenc_format s16\naudec_format s16\nmodule webrtc_aecm.so\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.contains("log_level")) {
|
|
||||||
config = "${config}log_level 2\n"
|
config = "${config}log_level 2\n"
|
||||||
Log.logLevel = Log.LogLevel.WARN
|
Log.logLevel = Log.LogLevel.WARN
|
||||||
BaresipService.logLevel = 2
|
|
||||||
} else {
|
} else {
|
||||||
val ll = variable("log_level")[0].toInt()
|
config = "${config}log_level $logLevel\n"
|
||||||
replaceVariable("log_level", "$ll")
|
BaresipService.logLevel = logLevel.toInt()
|
||||||
Log.logLevelSet(ll)
|
Log.logLevelSet(BaresipService.logLevel)
|
||||||
BaresipService.logLevel = ll
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.contains("call_volume")) {
|
val autoStart = previousVariable("auto_start")
|
||||||
config = "${config}call_volume 0\n"
|
config = if (autoStart != "")
|
||||||
} else {
|
"${config}auto_start $autoStart\n"
|
||||||
BaresipService.callVolume = variable("call_volume")[0].toInt()
|
else
|
||||||
|
"${config}auto_start no\n"
|
||||||
|
|
||||||
|
val sipListen = previousVariable("sip_listen")
|
||||||
|
if (sipListen != "")
|
||||||
|
config = "${config}sip_listen $sipListen\n"
|
||||||
|
|
||||||
|
val addressFamily = previousVariable("net_af")
|
||||||
|
if (addressFamily != "") {
|
||||||
|
config = "${config}net_af $addressFamily\n"
|
||||||
|
BaresipService.addressFamily = addressFamily
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.contains("audio_delay")) {
|
val sipCertificate = previousVariable("sip_certificate")
|
||||||
BaresipService.audioDelay = variable("audio_delay")[0].toLong()
|
if (sipCertificate != "")
|
||||||
}
|
config = "${config}sip_certificate $sipCertificate\n"
|
||||||
|
|
||||||
if (config.contains("net_af"))
|
val sipVerifyServer = previousVariable("sip_verify_server")
|
||||||
BaresipService.addressFamily = variable("net_af")[0]
|
if (sipVerifyServer != "")
|
||||||
|
config = "${config}sip_verify_server $sipVerifyServer\n"
|
||||||
|
|
||||||
if (!config.contains("dyn_dns")) {
|
val sipCaFile = previousVariable("sip_cafile")
|
||||||
|
if (sipCaFile != "")
|
||||||
|
config = "${config}sip_cafile $sipCaFile\n"
|
||||||
|
|
||||||
|
val dynamicDns = previousVariable("dyn_dns")
|
||||||
|
if (dynamicDns == "no") {
|
||||||
config = "${config}dyn_dns no\n"
|
config = "${config}dyn_dns no\n"
|
||||||
|
for (server in previousVariables("dns_server"))
|
||||||
|
config = "${config}dns_server $server\n"
|
||||||
} else {
|
} else {
|
||||||
if (config.contains(Regex("dyn_dns\\s+yes"))) {
|
config = "${config}dyn_dns yes\n"
|
||||||
removeVariable("dns_server")
|
for (dnsServer in BaresipService.dnsServers)
|
||||||
for (dnsServer in BaresipService.dnsServers)
|
config = if (Utils.checkIpV4(dnsServer.hostAddress!!))
|
||||||
config = if (Utils.checkIpV4(dnsServer.hostAddress!!))
|
"${config}dns_server ${dnsServer.hostAddress}:53\n"
|
||||||
"${config}dns_server ${dnsServer.hostAddress}:53\n"
|
else
|
||||||
else
|
"${config}dns_server [${dnsServer.hostAddress}]:53\n"
|
||||||
"${config}dns_server [${dnsServer.hostAddress}]:53\n"
|
BaresipService.dynDns = true
|
||||||
BaresipService.dynDns = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.contains("audio_buffer_mode"))
|
var contactsMode = previousVariable("contacts_mode").lowercase()
|
||||||
config = "${config}audio_buffer_mode adaptive\n"
|
if (contactsMode != "") {
|
||||||
|
if (contactsMode != "baresip" &&
|
||||||
replaceVariable("audio_buffer", "20-300")
|
|
||||||
|
|
||||||
removeVariable("jitter_buffer_type")
|
|
||||||
removeVariable("jitter_buffer_delay")
|
|
||||||
|
|
||||||
replaceVariable("audio_jitter_buffer_type", "adaptive")
|
|
||||||
replaceVariable("audio_jitter_buffer_delay", "0-20")
|
|
||||||
|
|
||||||
replaceVariable("video_jitter_buffer_type", "adaptive")
|
|
||||||
replaceVariable("video_jitter_buffer_delay", "1-50")
|
|
||||||
|
|
||||||
if (!config.contains("rtp_timeout"))
|
|
||||||
config = "${config}rtp_timeout 60\n"
|
|
||||||
|
|
||||||
if (config.contains("contacts_mode")) {
|
|
||||||
BaresipService.contactsMode = variable("contacts_mode")[0].lowercase()
|
|
||||||
if (BaresipService.contactsMode != "baresip" &&
|
|
||||||
!Utils.checkPermissions(ctx, arrayOf(Manifest.permission.READ_CONTACTS,
|
!Utils.checkPermissions(ctx, arrayOf(Manifest.permission.READ_CONTACTS,
|
||||||
Manifest.permission.WRITE_CONTACTS))) {
|
Manifest.permission.WRITE_CONTACTS)))
|
||||||
BaresipService.contactsMode = "baresip"
|
contactsMode = "baresip"
|
||||||
replaceVariable("contacts_mode", "baresip")
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
BaresipService.contactsMode = "baresip"
|
contactsMode = "baresip"
|
||||||
|
}
|
||||||
|
config = "${config}contacts_mode $contactsMode\n"
|
||||||
|
BaresipService.contactsMode = contactsMode
|
||||||
|
|
||||||
|
config = "${config}snd_path ${BaresipService.filesPath}/recordings\n"
|
||||||
|
|
||||||
|
val callVolume = previousVariable("call_volume")
|
||||||
|
if (callVolume != "") {
|
||||||
|
config = "${config}call_volume $callVolume\n"
|
||||||
|
BaresipService.callVolume = callVolume.toInt()
|
||||||
|
} else {
|
||||||
|
config = "${config}call_volume ${BaresipService.callVolume}\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.contains("dtls_srtp_use_ec"))
|
val previousModules = previousVariables("module")
|
||||||
config = "${config}dtls_srtp_use_ec prime256v1\n"
|
for (module in AudioActivity.audioModules)
|
||||||
|
if ("${module}.so" in previousModules)
|
||||||
|
config = "${config}module ${module}.so\n"
|
||||||
|
|
||||||
replaceVariable("snd_path", "${BaresipService.filesPath}/recordings")
|
if ("webrtc_aecm.so" in previousModules)
|
||||||
|
config = "${config}module webrtc_aecm.so\n"
|
||||||
|
|
||||||
Utils.putFileContents(configPath, config.toByteArray())
|
val opusBitRate = previousVariable("opus_bitrate")
|
||||||
|
config = if (opusBitRate == "")
|
||||||
|
"${config}opus_bit_rate 28000\n"
|
||||||
|
else
|
||||||
|
"${config}opus_bit_rate $opusBitRate\n"
|
||||||
|
|
||||||
|
val opusPacketLoss = previousVariable("opus_packet_loss")
|
||||||
|
config = if (opusPacketLoss == "")
|
||||||
|
"${config}opus_packet_loss 1\n"
|
||||||
|
else
|
||||||
|
"${config}opus_packet_loss $opusPacketLoss\n"
|
||||||
|
|
||||||
|
val audioDelay = previousVariable("audio_delay")
|
||||||
|
if (audioDelay != "") {
|
||||||
|
config = "${config}audio_delay $audioDelay\n"
|
||||||
|
BaresipService.audioDelay = audioDelay.toLong()
|
||||||
|
} else {
|
||||||
|
config = "${config}audio_delay ${BaresipService.audioDelay}\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
save()
|
||||||
BaresipService.isConfigInitialized = true
|
BaresipService.isConfigInitialized = true
|
||||||
Log.i(TAG, "Initialized config to '$config'")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun variable(name: String): ArrayList<String> {
|
private fun previousVariable(name: String): String {
|
||||||
|
for (line in previousLines) {
|
||||||
|
val nameValue = line.split(" ")
|
||||||
|
if (nameValue.size == 2 && nameValue[0] == name)
|
||||||
|
return nameValue[1].trim()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun previousVariables(name: String): ArrayList<String> {
|
||||||
val result = ArrayList<String>()
|
val result = ArrayList<String>()
|
||||||
val lines = config.split("\n")
|
for (line in previousLines) {
|
||||||
for (line in lines) {
|
val nameValue = line.split(" ")
|
||||||
if (line.startsWith(name))
|
if (nameValue.size == 2 && nameValue[0] == name)
|
||||||
result.add((line.substring(name.length).trim()).split("# \t")[0])
|
result.add(nameValue[1].trim())
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addLine(line: String) {
|
fun variable(name: String): String {
|
||||||
config += "$line\n"
|
for (line in lines) {
|
||||||
|
val nameValue = line.split(" ")
|
||||||
|
if (nameValue.size == 2 && nameValue[0] == name)
|
||||||
|
return nameValue[1].trim()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeLine(line: String) {
|
fun variables(name: String): ArrayList<String> {
|
||||||
config = Utils.removeLinesStartingWithString(config, line)
|
val result = ArrayList<String>()
|
||||||
|
for (line in lines) {
|
||||||
|
val nameValue = line.split(" ")
|
||||||
|
if (nameValue.size == 2 && nameValue[0] == name)
|
||||||
|
result.add(nameValue[1].trim())
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addModuleLine(line: String) {
|
fun addVariable(name: String, value: String) {
|
||||||
// Make sure it goes before first 'module_tmp'
|
config += "$name $value\n"
|
||||||
config = config.replace("module opensles.so", "$line\nmodule opensles.so")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeVariable(variable: String) {
|
fun removeVariable(variable: String) {
|
||||||
config = Utils.removeLinesStartingWithString(config, "$variable ")
|
config = Utils.removeLinesStartingWithString(config, "$variable ")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun replaceVariable(variable: String, value: String) {
|
fun removeVariableValue(variable: String, value: String) {
|
||||||
removeVariable(variable)
|
config = Utils.removeLinesStartingWithString(config, "$variable $value")
|
||||||
addLine("$variable $value")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reset(ctx: Context) {
|
fun replaceVariable(variable: String, value: String) {
|
||||||
Utils.copyAssetToFile(ctx, "config", configPath)
|
removeVariable(variable)
|
||||||
|
if (value != "")
|
||||||
|
addVariable(variable, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
Utils.deleteFile(File(configPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save() {
|
fun save() {
|
||||||
var result = ""
|
|
||||||
for (line in config.split("\n"))
|
|
||||||
if (line.isNotEmpty())
|
|
||||||
result = result + line + '\n'
|
|
||||||
config = result
|
|
||||||
Utils.putFileContents(configPath, config.toByteArray())
|
Utils.putFileContents(configPath, config.toByteArray())
|
||||||
Log.d(TAG, "Saved new config '$result'")
|
lines = config.split("\n")
|
||||||
|
Log.d(TAG, "Saved new config '$config'")
|
||||||
// Api.reload_config()
|
// Api.reload_config()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.transition.Visibility
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.tutpro.baresip.Utils.copyInputStreamToFile
|
import com.tutpro.baresip.Utils.copyInputStreamToFile
|
||||||
@@ -62,7 +61,7 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
private var oldListenAddr = ""
|
private var oldListenAddr = ""
|
||||||
private var oldDnsServers = ""
|
private var oldDnsServers = ""
|
||||||
private var oldCertificateFile = false
|
private var oldCertificateFile = false
|
||||||
private var oldVerifyServer = ""
|
private var oldVerifyServer = false
|
||||||
private var oldCAFile = false
|
private var oldCAFile = false
|
||||||
private var oldLogLevel = ""
|
private var oldLogLevel = ""
|
||||||
private var oldDisplayTheme = -1
|
private var oldDisplayTheme = -1
|
||||||
@@ -93,8 +92,7 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
baresipService = Intent(this@ConfigActivity, BaresipService::class.java)
|
baresipService = Intent(this@ConfigActivity, BaresipService::class.java)
|
||||||
|
|
||||||
autoStart = binding.AutoStart
|
autoStart = binding.AutoStart
|
||||||
val asCv = Config.variable("auto_start")
|
oldAutoStart = Config.variable("auto_start")
|
||||||
oldAutoStart = if (asCv.size == 0) "no" else asCv[0]
|
|
||||||
autoStart.isChecked = oldAutoStart == "yes"
|
autoStart.isChecked = oldAutoStart == "yes"
|
||||||
|
|
||||||
val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
|
val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
@@ -145,15 +143,13 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
listenAddr = binding.ListenAddress
|
listenAddr = binding.ListenAddress
|
||||||
val laCv = Config.variable("sip_listen")
|
oldListenAddr = Config.variable("sip_listen")
|
||||||
oldListenAddr = if (laCv.size == 0) "" else laCv[0]
|
|
||||||
listenAddr.setText(oldListenAddr)
|
listenAddr.setText(oldListenAddr)
|
||||||
|
|
||||||
netAfSpinner = binding.NetAfSpinner
|
netAfSpinner = binding.NetAfSpinner
|
||||||
netAfKeys = arrayListOf("", "ipv4", "ipv6")
|
netAfKeys = arrayListOf("", "ipv4", "ipv6")
|
||||||
val netAfVals = arrayListOf("-", "IPv4", "IPv6")
|
val netAfVals = arrayListOf("-", "IPv4", "IPv6")
|
||||||
val netAfCv = Config.variable("net_af")
|
oldNetAf = Config.variable("net_af").lowercase()
|
||||||
oldNetAf = if (netAfCv.size == 0) "" else netAfCv[0].lowercase()
|
|
||||||
netAf = oldNetAf
|
netAf = oldNetAf
|
||||||
val netAfIndex = netAfKeys.indexOf(oldNetAf)
|
val netAfIndex = netAfKeys.indexOf(oldNetAf)
|
||||||
val netAfValue = netAfVals.elementAt(netAfIndex)
|
val netAfValue = netAfVals.elementAt(netAfIndex)
|
||||||
@@ -172,19 +168,20 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dnsServers = binding.DnsServers
|
dnsServers = binding.DnsServers
|
||||||
val ddCv = Config.variable("dyn_dns")
|
val dynamicDns = Config.variable("dyn_dns")
|
||||||
if (ddCv[0] == "yes") {
|
if (dynamicDns == "yes") {
|
||||||
oldDnsServers = ""
|
oldDnsServers = ""
|
||||||
} else {
|
} else {
|
||||||
val dsCv = Config.variable("dns_server")
|
val servers = Config.variables("dns_server")
|
||||||
var dsTv = ""
|
var serverList = ""
|
||||||
for (ds in dsCv) dsTv += ", $ds"
|
for (server in servers)
|
||||||
oldDnsServers = dsTv.trimStart(',').trimStart(' ')
|
serverList += ", $server"
|
||||||
|
oldDnsServers = serverList.trimStart(',').trimStart(' ')
|
||||||
}
|
}
|
||||||
dnsServers.setText(oldDnsServers)
|
dnsServers.setText(oldDnsServers)
|
||||||
|
|
||||||
certificateFile = binding.CertificateFile
|
certificateFile = binding.CertificateFile
|
||||||
oldCertificateFile = Config.variable("sip_certificate").isNotEmpty()
|
oldCertificateFile = Config.variable("sip_certificate") != ""
|
||||||
certificateFile.isChecked = oldCertificateFile
|
certificateFile.isChecked = oldCertificateFile
|
||||||
|
|
||||||
val certificateRequest =
|
val certificateRequest =
|
||||||
@@ -195,11 +192,10 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
val inputStream =
|
val inputStream =
|
||||||
applicationContext.contentResolver.openInputStream(uri)
|
applicationContext.contentResolver.openInputStream(uri)
|
||||||
as FileInputStream
|
as FileInputStream
|
||||||
File(BaresipService.filesPath + "/cert.pem")
|
val certPath = BaresipService.filesPath + "/cert.pem"
|
||||||
.copyInputStreamToFile(inputStream)
|
File(certPath).copyInputStreamToFile(inputStream)
|
||||||
inputStream.close()
|
inputStream.close()
|
||||||
Config.removeVariable("sip_certificate")
|
Config.replaceVariable("sip_certificate", certPath)
|
||||||
Config.addLine("sip_certificate ${BaresipService.filesPath}/cert.pem")
|
|
||||||
save = true
|
save = true
|
||||||
restart = true
|
restart = true
|
||||||
} catch (e: Error) {
|
} catch (e: Error) {
|
||||||
@@ -234,10 +230,9 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
return@setOnCheckedChangeListener
|
return@setOnCheckedChangeListener
|
||||||
}
|
}
|
||||||
val filesPath = BaresipService.filesPath + "/cert.pem"
|
val certPath = BaresipService.filesPath + "/cert.pem"
|
||||||
Utils.putFileContents(filesPath, content)
|
Utils.putFileContents(certPath, content)
|
||||||
Config.removeVariable("sip_certificate")
|
Config.replaceVariable("sip_certificate", certPath)
|
||||||
Config.addLine("sip_certificate $filesPath")
|
|
||||||
certificateFile.isChecked = true
|
certificateFile.isChecked = true
|
||||||
save = true
|
save = true
|
||||||
restart = true
|
restart = true
|
||||||
@@ -270,12 +265,11 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
verifyServer = binding.VerifyServer
|
verifyServer = binding.VerifyServer
|
||||||
val vsCv = Config.variable("sip_verify_server")
|
oldVerifyServer = Config.variable("sip_verify_server") == "yes"
|
||||||
oldVerifyServer = if (vsCv.size == 0) "no" else vsCv[0]
|
verifyServer.isChecked = oldVerifyServer
|
||||||
verifyServer.isChecked = oldVerifyServer == "yes"
|
|
||||||
|
|
||||||
caFile = binding.CAFile
|
caFile = binding.CAFile
|
||||||
oldCAFile = Config.variable("sip_cafile").isNotEmpty()
|
oldCAFile = Config.variable("sip_cafile") != ""
|
||||||
caFile.isChecked = oldCAFile
|
caFile.isChecked = oldCAFile
|
||||||
|
|
||||||
val certificatesRequest =
|
val certificatesRequest =
|
||||||
@@ -286,11 +280,10 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
val inputStream =
|
val inputStream =
|
||||||
applicationContext.contentResolver.openInputStream(uri)
|
applicationContext.contentResolver.openInputStream(uri)
|
||||||
as FileInputStream
|
as FileInputStream
|
||||||
File(BaresipService.filesPath + "/ca_certs.crt")
|
val caCertsPath = BaresipService.filesPath + "/ca_certs.crt"
|
||||||
.copyInputStreamToFile(inputStream)
|
File(caCertsPath).copyInputStreamToFile(inputStream)
|
||||||
inputStream.close()
|
inputStream.close()
|
||||||
Config.removeVariable("sip_cafile")
|
Config.replaceVariable("sip_cafile", caCertsPath)
|
||||||
Config.addLine("sip_cafile ${BaresipService.filesPath}/ca_certs.crt")
|
|
||||||
save = true
|
save = true
|
||||||
restart = true
|
restart = true
|
||||||
} catch (e: Error) {
|
} catch (e: Error) {
|
||||||
@@ -324,10 +317,9 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
return@setOnCheckedChangeListener
|
return@setOnCheckedChangeListener
|
||||||
}
|
}
|
||||||
val filesPath = BaresipService.filesPath + "/ca_certs.crt"
|
val caCertsPath = BaresipService.filesPath + "/ca_certs.crt"
|
||||||
Utils.putFileContents(filesPath, content)
|
Utils.putFileContents(caCertsPath, content)
|
||||||
Config.removeVariable("sip_cafile")
|
Config.replaceVariable("sip_cafile", caCertsPath)
|
||||||
Config.addLine("sip_cafile $filesPath")
|
|
||||||
caFile.isChecked = true
|
caFile.isChecked = true
|
||||||
save = true
|
save = true
|
||||||
restart = true
|
restart = true
|
||||||
@@ -367,8 +359,7 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
contactsModeKeys = arrayListOf("baresip", "android", "both")
|
contactsModeKeys = arrayListOf("baresip", "android", "both")
|
||||||
val contactsModeVals = arrayListOf(getString(R.string.baresip), getString(R.string.android),
|
val contactsModeVals = arrayListOf(getString(R.string.baresip), getString(R.string.android),
|
||||||
getString(R.string.both))
|
getString(R.string.both))
|
||||||
val ctCv = Config.variable("contacts_mode")
|
oldContactsMode = Config.variable("contacts_mode").lowercase()
|
||||||
oldContactsMode = if (ctCv.size == 0) "baresip" else ctCv[0].lowercase()
|
|
||||||
contactsMode = oldContactsMode
|
contactsMode = oldContactsMode
|
||||||
val keyIndex = contactsModeKeys.indexOf(oldContactsMode)
|
val keyIndex = contactsModeKeys.indexOf(oldContactsMode)
|
||||||
val keyValue = contactsModeVals.elementAt(keyIndex)
|
val keyValue = contactsModeVals.elementAt(keyIndex)
|
||||||
@@ -408,11 +399,7 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
debug = binding.Debug
|
debug = binding.Debug
|
||||||
val dbCv = Config.variable("log_level")
|
oldLogLevel = Config.variable("log_level")
|
||||||
oldLogLevel = if (dbCv.size == 0)
|
|
||||||
"2"
|
|
||||||
else
|
|
||||||
dbCv[0]
|
|
||||||
debug.isChecked = oldLogLevel == "0"
|
debug.isChecked = oldLogLevel == "0"
|
||||||
|
|
||||||
sipTrace = binding.SipTrace
|
sipTrace = binding.SipTrace
|
||||||
@@ -427,7 +414,7 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
setTitle(R.string.confirmation)
|
setTitle(R.string.confirmation)
|
||||||
setMessage(getString(R.string.reset_config_alert))
|
setMessage(getString(R.string.reset_config_alert))
|
||||||
setPositiveButton(getText(R.string.reset)) { dialog, _ ->
|
setPositiveButton(getText(R.string.reset)) { dialog, _ ->
|
||||||
Config.reset(this@ConfigActivity)
|
Config.reset()
|
||||||
save = false
|
save = false
|
||||||
restart = true
|
restart = true
|
||||||
done()
|
done()
|
||||||
@@ -523,12 +510,10 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
R.id.checkIcon -> {
|
R.id.checkIcon -> {
|
||||||
|
|
||||||
var autoStartString = "no"
|
val autoStartString = if (autoStart.isChecked) "yes" else "no"
|
||||||
if (autoStart.isChecked) autoStartString = "yes"
|
|
||||||
if (oldAutoStart != autoStartString) {
|
if (oldAutoStart != autoStartString) {
|
||||||
Config.replaceVariable("auto_start", autoStartString)
|
Config.replaceVariable("auto_start", autoStartString)
|
||||||
save = true
|
save = true
|
||||||
restart = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val listenAddr = listenAddr.text.toString().trim()
|
val listenAddr = listenAddr.text.toString().trim()
|
||||||
@@ -538,17 +523,13 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
"${getString(R.string.invalid_listen_address)}: $listenAddr")
|
"${getString(R.string.invalid_listen_address)}: $listenAddr")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
Config.removeVariable("sip_listen")
|
Config.replaceVariable("sip_listen", listenAddr)
|
||||||
if (listenAddr != "") Config.addLine("sip_listen $listenAddr")
|
|
||||||
save = true
|
save = true
|
||||||
restart = true
|
restart = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldNetAf != netAf) {
|
if (oldNetAf != netAf) {
|
||||||
if (netAf == "")
|
Config.replaceVariable("net_af", netAf)
|
||||||
Config.removeVariable("net_af")
|
|
||||||
else
|
|
||||||
Config.replaceVariable("net_af", netAf)
|
|
||||||
save = true
|
save = true
|
||||||
restart = true
|
restart = true
|
||||||
}
|
}
|
||||||
@@ -561,19 +542,18 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
"${getString(R.string.invalid_dns_servers)}: $dnsServers")
|
"${getString(R.string.invalid_dns_servers)}: $dnsServers")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
Config.removeVariable("dyn_dns")
|
|
||||||
Config.removeVariable("dns_server")
|
Config.removeVariable("dns_server")
|
||||||
if (dnsServers.isNotEmpty()) {
|
if (dnsServers.isNotEmpty()) {
|
||||||
for (server in dnsServers.split(","))
|
for (server in dnsServers.split(","))
|
||||||
Config.addLine("dns_server $server")
|
Config.addVariable("dns_server", server)
|
||||||
Config.addLine("dyn_dns no")
|
Config.replaceVariable("dyn_dns", "no")
|
||||||
if (Api.net_use_nameserver(dnsServers) != 0) {
|
if (Api.net_use_nameserver(dnsServers) != 0) {
|
||||||
Utils.alertView(this, getString(R.string.error),
|
Utils.alertView(this, getString(R.string.error),
|
||||||
"${getString(R.string.failed_to_set_dns_servers)}: $dnsServers")
|
"${getString(R.string.failed_to_set_dns_servers)}: $dnsServers")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Config.addLine("dyn_dns yes")
|
Config.replaceVariable("dyn_dns", "yes")
|
||||||
Config.updateDnsServers(BaresipService.dnsServers)
|
Config.updateDnsServers(BaresipService.dnsServers)
|
||||||
}
|
}
|
||||||
// Api.net_dns_debug()
|
// Api.net_dns_debug()
|
||||||
@@ -587,9 +567,9 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val verifyServerString = if (verifyServer.isChecked) "yes" else "no"
|
if (oldVerifyServer != verifyServer.isChecked) {
|
||||||
if (oldVerifyServer != verifyServerString) {
|
Config.replaceVariable("sip_verify_server",
|
||||||
Config.replaceVariable("sip_verify_server", verifyServerString)
|
if (verifyServer.isChecked) "yes" else "no")
|
||||||
save = true
|
save = true
|
||||||
restart = true
|
restart = true
|
||||||
}
|
}
|
||||||
@@ -626,8 +606,7 @@ class ConfigActivity : AppCompatActivity() {
|
|||||||
save = true
|
save = true
|
||||||
}
|
}
|
||||||
|
|
||||||
var logLevelString = "2"
|
val logLevelString = if (debug.isChecked) "0" else "2"
|
||||||
if (debug.isChecked) logLevelString = "0"
|
|
||||||
if (oldLogLevel != logLevelString) {
|
if (oldLogLevel != logLevelString) {
|
||||||
Config.replaceVariable("log_level", logLevelString)
|
Config.replaceVariable("log_level", logLevelString)
|
||||||
Api.log_level_set(logLevelString.toInt())
|
Api.log_level_set(logLevelString.toInt())
|
||||||
|
|||||||
@@ -370,8 +370,8 @@
|
|||||||
</string>
|
</string>
|
||||||
<string name="opus_packet_loss">Odotettu opus-pakettihäviö</string>
|
<string name="opus_packet_loss">Odotettu opus-pakettihäviö</string>
|
||||||
<string name="opus_packet_loss_help">Odotettu opus audio virran pakettihäviö prosentteina.
|
<string name="opus_packet_loss_help">Odotettu opus audio virran pakettihäviö prosentteina.
|
||||||
Mahdolliset arvot ovat 0-100. Oletusarvo on 0, jolloin ennakoiva virheenkorjaus
|
Mahdolliset arvot ovat 0-100. Oletusarvo on 1. Arvo 0 poistaa käytöstä
|
||||||
ei ole käytössä.</string>
|
ennakoivan virheenkorjauksen.</string>
|
||||||
<string name="invalid_opus_bitrate">Virheellinen Opus-koodekin bittinopeus</string>
|
<string name="invalid_opus_bitrate">Virheellinen Opus-koodekin bittinopeus</string>
|
||||||
<string name="invalid_opus_packet_loss">Virheellinen Opus-koodekin odotettu pakettihäviö</string>
|
<string name="invalid_opus_packet_loss">Virheellinen Opus-koodekin odotettu pakettihäviö</string>
|
||||||
<string name="audio_delay">Audioviive</string>
|
<string name="audio_delay">Audioviive</string>
|
||||||
|
|||||||
@@ -345,7 +345,8 @@
|
|||||||
<string name="_28000" translatable="false">28000</string>
|
<string name="_28000" translatable="false">28000</string>
|
||||||
<string name="opus_packet_loss">Expected Opus packet-loss</string>
|
<string name="opus_packet_loss">Expected Opus packet-loss</string>
|
||||||
<string name="opus_packet_loss_help">Expected Opus audio stream packet loss percentage,
|
<string name="opus_packet_loss_help">Expected Opus audio stream packet loss percentage,
|
||||||
from 0–100. By default 0, turning off Opus Forward Error Correction (FEC).</string>
|
from 0–100. Factory default value is 1. Value 0 also turns off Opus Forward Error
|
||||||
|
Correction (FEC).</string>
|
||||||
<string name="_0" translatable="false">0</string>
|
<string name="_0" translatable="false">0</string>
|
||||||
<string name="invalid_opus_bitrate">Invalid Opus bitrate</string>
|
<string name="invalid_opus_bitrate">Invalid Opus bitrate</string>
|
||||||
<string name="invalid_opus_packet_loss">Invalid Opus Packet Loss Percentage</string>
|
<string name="invalid_opus_packet_loss">Invalid Opus Packet Loss Percentage</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user