Solved call hangup issues

This commit is contained in:
Juha Heinanen
2026-05-13 18:33:05 +03:00
parent 70a4efd5ba
commit b00e5b7a3c
3 changed files with 54 additions and 56 deletions

View File

@ -1075,7 +1075,6 @@ class BaresipService: Service() {
if (!Call.inCall())
proximitySensing(false)
}
ConnectionService.lastDisconnectTime = System.currentTimeMillis()
val connection = ConnectionService.connections[callp]
if (connection != null) {
val cause = when {
@ -1086,13 +1085,10 @@ class BaresipService: Service() {
else -> DisconnectCause.REMOTE
}
connection.setDisconnected(DisconnectCause(cause))
Handler(Looper.getMainLooper()).postDelayed({
connection.destroy()
ConnectionService.connections.remove(callp)
updateStatusNotification()
}, 500)
connection.destroy()
ConnectionService.connections.remove(callp)
}
nm.cancel(CALL_NOTIFICATION_ID)
updateStatusNotification()
if (call != null) {
stopRinging()
stopMediaPlayer()
@ -1229,6 +1225,7 @@ class BaresipService: Service() {
}
}
}
break
}
}
@ -1671,35 +1668,32 @@ class BaresipService: Service() {
try {
if (activeCall != null) {
if (VERSION.SDK_INT >= 29)
startForeground(
STATUS_NOTIFICATION_ID,
notification,
foregroundServiceType(activeCall)
)
if (!isNotificationInCall) {
// Only call startForeground when the FIRST call starts.
if (VERSION.SDK_INT >= 29)
startForeground(STATUS_NOTIFICATION_ID, notification, foregroundServiceType(activeCall))
else
startForeground(STATUS_NOTIFICATION_ID, notification)
isNotificationInCall = true
}
else
startForeground(STATUS_NOTIFICATION_ID, notification)
isNotificationInCall = true
nm.notify(STATUS_NOTIFICATION_ID, notification)
} else {
// If we are currently in a call notification mode, downgrade to standby FGS.
// We call stopForeground(REMOVE) to explicitly clear the system's telephony UI context
// that might be persisting the timer/peer info on the lock screen.
if (isNotificationInCall) {
stopForeground(STOP_FOREGROUND_REMOVE)
// Only call startForeground to drop the "Call" type when the LAST call ends.
if (VERSION.SDK_INT >= 29)
startForeground(STATUS_NOTIFICATION_ID, notification, foregroundServiceType())
else
startForeground(STATUS_NOTIFICATION_ID, notification)
isNotificationInCall = false
}
if (VERSION.SDK_INT >= 29)
startForeground(
STATUS_NOTIFICATION_ID,
notification,
foregroundServiceType()
)
else
startForeground(STATUS_NOTIFICATION_ID, notification)
// Already in standby, just keep the notification current.
nm.notify(STATUS_NOTIFICATION_ID, notification)
}
} catch (e: Exception) {
Log.e(TAG, "Failed to update foreground notification: ${e.message}")
// Fallback to standard notification if promotion/update fails
Log.e(TAG, "Failed to update notification: ${e.message}")
nm.notify(STATUS_NOTIFICATION_ID, notification)
}
}
@ -1847,7 +1841,6 @@ class BaresipService: Service() {
fun handleExternalCallRemoved(telecomCall: android.telecom.Call) {
val callp = telecomCall.hashCode().toLong()
val call = calls.find { it.callp == callp }
nm.cancel(CALL_NOTIFICATION_ID)
if (call != null) {
stopRinging()
stopMediaPlayer()

View File

@ -232,36 +232,48 @@ open class Call(val callp: Long, val ua: UserAgent, val peerUri: String, val dir
companion object {
fun calls(): ArrayList<Call> {
return BaresipService.calls
synchronized(BaresipService.calls) {
return ArrayList(BaresipService.calls)
}
}
fun ofCallp(callp: Long): Call? {
for (c in BaresipService.calls)
if (c.callp == callp) return c
return null
synchronized(BaresipService.calls) {
for (c in BaresipService.calls)
if (c.callp == callp) return c
return null
}
}
fun call(status: String): Call? {
for (c in BaresipService.calls)
if (c.status.value == status) return c
return null
synchronized(BaresipService.calls) {
for (c in BaresipService.calls)
if (c.status.value == status) return c
return null
}
}
fun inCall(): Boolean {
return BaresipService.calls.isNotEmpty()
synchronized(BaresipService.calls) {
return BaresipService.calls.isNotEmpty()
}
}
fun hasTelecomCall(): Boolean {
return BaresipService.calls.any {
it is ExternalCall || ConnectionService.connections.containsKey(it.callp)
} || ConnectionService.pendingOutgoingConnection != null
synchronized(BaresipService.calls) {
return BaresipService.calls.any {
it is ExternalCall || ConnectionService.connections.containsKey(it.callp)
} || ConnectionService.pendingOutgoingConnection != null
}
}
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
return Utils.isAudioMode(ctx, AudioManager.MODE_IN_CALL)
synchronized(BaresipService.calls) {
// 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
return Utils.isAudioMode(ctx, AudioManager.MODE_IN_CALL)
}
}
}
}

View File

@ -176,14 +176,11 @@ class ConnectionService : ConnectionService() {
}
override fun onDisconnect() {
if (isDisconnecting) {
Log.d(TAG, "onDisconnect already in progress for $callp")
return
}
val now = System.currentTimeMillis()
if (now - lastDisconnectTime < 500) return
lastDisconnectTime = now
Log.d(TAG, "Telecom Connection onDisconnect $callp")
isDisconnecting = true
lastDisconnectTime = System.currentTimeMillis()
if (callp == 0L) {
pendingOutgoingConnection = null
@ -191,16 +188,12 @@ class ConnectionService : ConnectionService() {
destroy()
return
}
val call = Call.ofCallp(callp)
if (call != null)
Api.ua_hangup(uap, callp, 0, "")
Api.ua_hangup(uap, callp, 0, "")
setDisconnected(DisconnectCause(DisconnectCause.LOCAL))
connections.remove(callp)
destroy()
// Allow other disconnects after a short period to prevent the "Telecom Cascade" effect
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
isDisconnecting = false
}, 500)
}
override fun onAbort() {