Call hold/resume improvements

This commit is contained in:
Juha Heinanen
2026-04-03 13:11:06 +03:00
parent 91f28f03df
commit bdaee6f013
5 changed files with 59 additions and 55 deletions

View File

@ -801,7 +801,7 @@ class BaresipService: Service() {
"incoming call" -> { "incoming call" -> {
val peerUri = ev[1] val peerUri = ev[1]
val bevent = ev[2].toLong() val bevent = ev[2].toLong()
val toastMsg = if (Utils.isAnyCallActive(applicationContext)) val toastMsg = if (Call.isAnyCallActive(applicationContext))
String.format(getString(R.string.call_auto_rejected), String.format(getString(R.string.call_auto_rejected),
Utils.friendlyUri(this, peerUri, ua.account)) Utils.friendlyUri(this, peerUri, ua.account))
else if (ua.account.blockUnknown && Contact.contactName(peerUri) == peerUri) else if (ua.account.blockUnknown && Contact.contactName(peerUri) == peerUri)

View File

@ -1,5 +1,7 @@
package com.tutpro.baresip package com.tutpro.baresip
import android.content.Context
import android.media.AudioManager
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -55,11 +57,15 @@ class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir: Str
} }
fun hold(): Boolean { fun hold(): Boolean {
return Api.call_hold(callp, true) == 0 if (Api.call_hold(callp, true) == 0)
onhold = true
return onhold
} }
fun resume(): Boolean { fun resume(): Boolean {
return Api.call_hold(callp, false) == 0 if (Api.call_hold(callp, false) == 0)
onhold = false
return !onhold
} }
fun transfer(uri: String): Boolean { fun transfer(uri: String): Boolean {
@ -142,5 +148,13 @@ class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir: Str
fun inCall(): Boolean { fun inCall(): Boolean {
return BaresipService.calls.isNotEmpty() return BaresipService.calls.isNotEmpty()
} }
fun isAnyCallActive(ctx: Context): Boolean {
// Check if there exist SIP calls that are not onhold or held
if (BaresipService.calls.any { !it.onhold && !it.held }) return true
// MODE_IN_CALL indicates a PSTN call is active
val am = ctx.getSystemService(Context.AUDIO_SERVICE) as AudioManager
return am.mode == AudioManager.MODE_IN_CALL
}
} }
} }

View File

@ -206,23 +206,17 @@ class ConnectionService : ConnectionService() {
override fun onHold() { override fun onHold() {
Log.d(TAG, "Telecom Connection onHold $callp") Log.d(TAG, "Telecom Connection onHold $callp")
val call = Call.ofCallp(callp) val c = Call.ofCallp(callp)
if (call == null || !call.conferenceCall) { if (c?.conferenceCall != true)
Api.call_hold(callp, true) c?.hold()
} else {
Log.d(TAG, "Call $callp is in conference, skipping baresip hold")
}
setOnHold() setOnHold()
} }
override fun onUnhold() { override fun onUnhold() {
Log.d(TAG, "Telecom Connection onUnhold $callp") Log.d(TAG, "Telecom Connection onUnhold $callp")
val call = Call.ofCallp(callp) val c = Call.ofCallp(callp)
if (call == null || !call.conferenceCall) { if (c?.conferenceCall != true)
Api.call_hold(callp, false) c?.resume()
} else {
Log.d(TAG, "Call $callp is in conference, skipping baresip resume")
}
setActive() setActive()
} }

View File

@ -1534,43 +1534,42 @@ private fun CallRow(
) )
} }
IconButton( if (!call.conferenceCall)
modifier = Modifier.size(48.dp), IconButton(
onClick = { modifier = Modifier.size(48.dp),
val connection = ConnectionService.connections[call.callp] onClick = {
if (call.onhold) { val connection = ConnectionService.connections[call.callp]
Log.d( if (call.onhold) {
TAG, Log.d(
"AoR ${call.ua.account.aor} resuming call ${call.callp} with ${call.callUri.value}" TAG,
) "AoR ${call.ua.account.aor} resuming call ${call.callp} with ${call.callUri.value}"
if (connection != null) )
connection.onUnhold() if (connection != null)
connection.onUnhold()
else
call.resume()
} else {
Log.d(
TAG,
"AoR ${call.ua.account.aor} holding call ${call.callp} with ${call.callUri.value}"
)
if (connection != null)
connection.onHold()
else
call.hold()
}
},
) {
Icon(
imageVector = Icons.Outlined.PauseCircle,
modifier = Modifier.size(42.dp),
tint = if (call.callOnHold.value)
MaterialTheme.colorScheme.error
else else
call.resume() MaterialTheme.colorScheme.secondary,
call.onhold = false contentDescription = null,
} else { )
Log.d( }
TAG,
"AoR ${call.ua.account.aor} holding call ${call.callp} with ${call.callUri.value}"
)
if (connection != null)
connection.onHold()
else
call.hold()
call.onhold = true
}
},
) {
Icon(
imageVector = Icons.Outlined.PauseCircle,
modifier = Modifier.size(42.dp),
tint = if (call.callOnHold.value)
MaterialTheme.colorScheme.error
else
MaterialTheme.colorScheme.secondary,
contentDescription = null,
)
}
var showTransferDialog by remember { mutableStateOf(false) } var showTransferDialog by remember { mutableStateOf(false) }
@ -2129,6 +2128,7 @@ private fun transfer(ctx: Context, viewModel: ViewModel, ua: UserAgent, uriText:
call.onhold = true call.onhold = true
call.referTo = uri call.referTo = uri
makeCall(ctx, viewModel, uri, false, call.callp) makeCall(ctx, viewModel, uri, false, call.callp)
showCall(ctx, viewModel, ua, call)
} }
} }
else { else {

View File

@ -842,10 +842,6 @@ object Utils {
Configuration.UI_MODE_NIGHT_YES Configuration.UI_MODE_NIGHT_YES
} }
fun isAnyCallActive(ctx: Context): Boolean {
return inCall() || isPSTNCallActive(ctx)
}
fun isPSTNCallActive(ctx: Context): Boolean { fun isPSTNCallActive(ctx: Context): Boolean {
// MODE_IN_CALL indicates a PSTN call is active // MODE_IN_CALL indicates a PSTN call is active
val am = ctx.getSystemService(Context.AUDIO_SERVICE) as AudioManager val am = ctx.getSystemService(Context.AUDIO_SERVICE) as AudioManager