Merge pull request #2206 from vitorpamplona/claude/review-webrtc-calls-0k3G4
fix: start foreground service earlier to prevent call death on Androi…
This commit is contained in:
@@ -110,6 +110,7 @@ class CallController(
|
|||||||
|
|
||||||
is CallState.Offering -> {
|
is CallState.Offering -> {
|
||||||
audioManager.startRingbackTone()
|
audioManager.startRingbackTone()
|
||||||
|
ensureForegroundService()
|
||||||
}
|
}
|
||||||
|
|
||||||
is CallState.Connecting -> {
|
is CallState.Connecting -> {
|
||||||
@@ -118,6 +119,7 @@ class CallController(
|
|||||||
withContext(Dispatchers.IO) { audioManager.switchToCallAudioMode() }
|
withContext(Dispatchers.IO) { audioManager.switchToCallAudioMode() }
|
||||||
audioManager.acquireProximityWakeLock()
|
audioManager.acquireProximityWakeLock()
|
||||||
NotificationUtils.cancelCallNotification(context)
|
NotificationUtils.cancelCallNotification(context)
|
||||||
|
updateForegroundServiceNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
is CallState.Connected -> {
|
is CallState.Connected -> {
|
||||||
@@ -126,6 +128,7 @@ class CallController(
|
|||||||
withContext(Dispatchers.IO) { audioManager.switchToCallAudioMode() }
|
withContext(Dispatchers.IO) { audioManager.switchToCallAudioMode() }
|
||||||
audioManager.acquireProximityWakeLock()
|
audioManager.acquireProximityWakeLock()
|
||||||
NotificationUtils.cancelCallNotification(context)
|
NotificationUtils.cancelCallNotification(context)
|
||||||
|
updateForegroundServiceNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
is CallState.Ended -> {
|
is CallState.Ended -> {
|
||||||
@@ -444,10 +447,7 @@ class CallController(
|
|||||||
Log.d(TAG) { "Peer ${peerPubKey.take(8)} connected!" }
|
Log.d(TAG) { "Peer ${peerPubKey.take(8)} connected!" }
|
||||||
scope.launch {
|
scope.launch {
|
||||||
callManager.onPeerConnected()
|
callManager.onPeerConnected()
|
||||||
if (!foregroundServiceStarted) {
|
ensureForegroundService()
|
||||||
foregroundServiceStarted = true
|
|
||||||
startForegroundService()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRemoteVideoTrack = { track -> videoMonitor.onRemoteVideoTrack(peerPubKey, track) },
|
onRemoteVideoTrack = { track -> videoMonitor.onRemoteVideoTrack(peerPubKey, track) },
|
||||||
@@ -526,6 +526,12 @@ class CallController(
|
|||||||
|
|
||||||
// ---- Foreground service ----
|
// ---- Foreground service ----
|
||||||
|
|
||||||
|
private fun ensureForegroundService() {
|
||||||
|
if (foregroundServiceStarted) return
|
||||||
|
foregroundServiceStarted = true
|
||||||
|
startForegroundService()
|
||||||
|
}
|
||||||
|
|
||||||
private fun startForegroundService() {
|
private fun startForegroundService() {
|
||||||
try {
|
try {
|
||||||
val peerName = callManager.currentPeerPubKey() ?: ""
|
val peerName = callManager.currentPeerPubKey() ?: ""
|
||||||
@@ -542,6 +548,21 @@ class CallController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateForegroundServiceNotification() {
|
||||||
|
if (!foregroundServiceStarted) return
|
||||||
|
try {
|
||||||
|
val peerName = callManager.currentPeerPubKey() ?: ""
|
||||||
|
val intent =
|
||||||
|
Intent(context, CallForegroundService::class.java).apply {
|
||||||
|
action = CallForegroundService.ACTION_UPDATE
|
||||||
|
putExtra(CallForegroundService.EXTRA_PEER_NAME, peerName)
|
||||||
|
}
|
||||||
|
context.startService(intent)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Failed to update foreground service notification", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun stopForegroundService() {
|
private fun stopForegroundService() {
|
||||||
try {
|
try {
|
||||||
val intent =
|
val intent =
|
||||||
|
|||||||
+19
-3
@@ -46,8 +46,10 @@ class CallForegroundService : Service() {
|
|||||||
const val NOTIFICATION_ID = 9001
|
const val NOTIFICATION_ID = 9001
|
||||||
const val ACTION_START = "com.vitorpamplona.amethyst.CALL_START"
|
const val ACTION_START = "com.vitorpamplona.amethyst.CALL_START"
|
||||||
const val ACTION_STOP = "com.vitorpamplona.amethyst.CALL_STOP"
|
const val ACTION_STOP = "com.vitorpamplona.amethyst.CALL_STOP"
|
||||||
|
const val ACTION_UPDATE = "com.vitorpamplona.amethyst.CALL_UPDATE"
|
||||||
const val EXTRA_PEER_NAME = "peer_name"
|
const val EXTRA_PEER_NAME = "peer_name"
|
||||||
const val EXTRA_IS_VIDEO = "is_video"
|
const val EXTRA_IS_VIDEO = "is_video"
|
||||||
|
const val EXTRA_STATUS_TEXT = "status_text"
|
||||||
private const val HANGUP_REQUEST_CODE = 0x70001
|
private const val HANGUP_REQUEST_CODE = 0x70001
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +69,8 @@ class CallForegroundService : Service() {
|
|||||||
ACTION_START -> {
|
ACTION_START -> {
|
||||||
val peerName = intent.getStringExtra(EXTRA_PEER_NAME) ?: "Unknown"
|
val peerName = intent.getStringExtra(EXTRA_PEER_NAME) ?: "Unknown"
|
||||||
val isVideo = intent.getBooleanExtra(EXTRA_IS_VIDEO, false)
|
val isVideo = intent.getBooleanExtra(EXTRA_IS_VIDEO, false)
|
||||||
val notification = buildNotification(peerName)
|
val statusText = intent.getStringExtra(EXTRA_STATUS_TEXT)
|
||||||
|
val notification = buildNotification(peerName, statusText)
|
||||||
val hasAudioPermission =
|
val hasAudioPermission =
|
||||||
ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) ==
|
ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) ==
|
||||||
PackageManager.PERMISSION_GRANTED
|
PackageManager.PERMISSION_GRANTED
|
||||||
@@ -100,6 +103,14 @@ class CallForegroundService : Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ACTION_UPDATE -> {
|
||||||
|
val peerName = intent.getStringExtra(EXTRA_PEER_NAME) ?: "Unknown"
|
||||||
|
val statusText = intent.getStringExtra(EXTRA_STATUS_TEXT)
|
||||||
|
val notification = buildNotification(peerName, statusText)
|
||||||
|
val notificationManager = getSystemService(NotificationManager::class.java)
|
||||||
|
notificationManager.notify(NOTIFICATION_ID, notification)
|
||||||
|
}
|
||||||
|
|
||||||
ACTION_STOP -> {
|
ACTION_STOP -> {
|
||||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||||
stopSelf()
|
stopSelf()
|
||||||
@@ -121,7 +132,10 @@ class CallForegroundService : Service() {
|
|||||||
notificationManager.createNotificationChannel(channel)
|
notificationManager.createNotificationChannel(channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildNotification(peerName: String): Notification {
|
private fun buildNotification(
|
||||||
|
peerName: String,
|
||||||
|
statusText: String? = null,
|
||||||
|
): Notification {
|
||||||
val openCallIntent =
|
val openCallIntent =
|
||||||
PendingIntent.getActivity(
|
PendingIntent.getActivity(
|
||||||
this,
|
this,
|
||||||
@@ -142,10 +156,12 @@ class CallForegroundService : Service() {
|
|||||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
|
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val contentText = statusText ?: getString(R.string.call_with, peerName)
|
||||||
|
|
||||||
return NotificationCompat
|
return NotificationCompat
|
||||||
.Builder(this, CHANNEL_ID)
|
.Builder(this, CHANNEL_ID)
|
||||||
.setContentTitle(getString(R.string.app_name))
|
.setContentTitle(getString(R.string.app_name))
|
||||||
.setContentText(getString(R.string.call_with, peerName))
|
.setContentText(contentText)
|
||||||
.setSmallIcon(R.drawable.amethyst)
|
.setSmallIcon(R.drawable.amethyst)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setContentIntent(openCallIntent)
|
.setContentIntent(openCallIntent)
|
||||||
|
|||||||
Reference in New Issue
Block a user