Browse Source

Own Android call video in the foreground call service

master
evgeny 5 days ago
parent
commit
a59ebcd6db
  1. 2
      tools/chatgui-android/app/src/main/AndroidManifest.xml
  2. 10
      tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallController.kt
  3. 16
      tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallService.kt

2
tools/chatgui-android/app/src/main/AndroidManifest.xml

@ -82,7 +82,7 @@
<service
android:name=".data.CallService"
android:exported="false"
android:foregroundServiceType="phoneCall|microphone" />
android:foregroundServiceType="phoneCall|microphone|camera" />
<service android:name=".data.StreamService" android:exported="false" android:foregroundServiceType="camera|microphone" />

10
tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallController.kt

@ -24,6 +24,14 @@ object CallController : TelecomCallManager.Listener {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
private val _state = MutableStateFlow<CallState?>(null)
val state: StateFlow<CallState?> = _state
private val _video = MutableStateFlow<CallVideoEngine?>(null)
val video: StateFlow<CallVideoEngine?> = _video
fun setVideo(settings: CallVideoSettings) {
checkMain()
val owner = service ?: return
if (_state.value?.phase != CallPhase.ACTIVE) return
if (owner.setVideoCapture(settings.enabled)) owner.video?.select(settings)
}
private val _muted = MutableStateFlow(false)
val muted: StateFlow<Boolean> = _muted
private val _route = MutableStateFlow(AudioRoute.SPEAKER)
@ -202,6 +210,7 @@ object CallController : TelecomCallManager.Listener {
acceptSent = false
answerWhenVisible = 0L
owner?.shutdown()
_video.value = null
proximity.stop()
TelecomCallManager.setDisconnected(id, reason)
TelecomCallManager.removeConnection(id)
@ -327,6 +336,7 @@ object CallController : TelecomCallManager.Listener {
return
}
accepting = false
_video.value = owner.video
TelecomCallManager.setActive(id)
_state.value = st.copy(phase = CallPhase.ACTIVE, durationSeconds = 0, startedAtElapsedRealtime = SystemClock.elapsedRealtime())
owner.audio.router.onChanged = { route, headset -> routeChanged(route, headset) }

16
tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallService.kt

@ -43,6 +43,9 @@ class CallService : Service() {
}
val audio = CallAudioEngine()
var video: CallVideoEngine? = null
private set
private var cameraForeground = false
private var callId = 0L
private var wakeLock: PowerManager.WakeLock? = null
private var powerEventsRegistered = false
@ -137,7 +140,8 @@ class CallService : Service() {
val micType = if (microphone && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE else 0
val types = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL or micType
ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL or micType or
(if (cameraForeground && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA else 0)
} else 0
ServiceCompat.startForeground(this, NOTIFICATION_ID, notification(), types)
LogManager.addLog("INFO", "CallService", "foreground notification id=$callId phase=${CallController.state.value?.phase}")
@ -149,7 +153,14 @@ class CallService : Service() {
return false
}
audio.router.setPreferredRoute(ChatApplication.instance.configProvider.getCallAudioRoute())
return audio.start(id)
if (!audio.start(id)) return false
video = CallVideoEngine(this, id)
return true
}
fun setVideoCapture(enabled: Boolean): Boolean {
return try { cameraForeground = enabled; promote(true); true }
catch (e: Exception) { cameraForeground = false; LogManager.addLog("ERROR", "call", "camera foreground failed: ${e.message}"); false }
}
fun updateNotification() {
@ -202,6 +213,7 @@ class CallService : Service() {
private fun releaseResources() {
val id = callId
video?.stop(); video = null; cameraForeground = false
if (powerEventsRegistered) {
try { unregisterReceiver(powerEvents) }
catch (e: Exception) { LogManager.addLog("WARN", "CallService", "power receiver cleanup failed id=$id: ${e.message}") }

Loading…
Cancel
Save