diff --git a/amethyst/src/main/AndroidManifest.xml b/amethyst/src/main/AndroidManifest.xml
index 796a4b8b7..7fff495bb 100644
--- a/amethyst/src/main/AndroidManifest.xml
+++ b/amethyst/src/main/AndroidManifest.xml
@@ -276,7 +276,7 @@
android:exported="false" />
diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt
index 071c39fd9..f432a92b4 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt
@@ -22,10 +22,6 @@ package com.vitorpamplona.amethyst.service.call
import android.content.Context
import android.content.Intent
-import coil3.ImageLoader
-import coil3.asDrawable
-import coil3.request.ImageRequest
-import coil3.request.allowHardware
import com.vitorpamplona.amethyst.commons.call.AnswerRouteAction
import com.vitorpamplona.amethyst.commons.call.CallManager
import com.vitorpamplona.amethyst.commons.call.CallState
@@ -34,11 +30,8 @@ import com.vitorpamplona.amethyst.commons.call.PeerSession
import com.vitorpamplona.amethyst.commons.call.PeerSessionManager
import com.vitorpamplona.amethyst.commons.call.SdpType
import com.vitorpamplona.amethyst.commons.call.SignalingState
-import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.service.notifications.NotificationUtils
import com.vitorpamplona.quartz.nip01Core.core.HexKey
-import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray
-import com.vitorpamplona.quartz.nip19Bech32.toNpub
import com.vitorpamplona.quartz.nip59Giftwrap.wraps.EphemeralGiftWrapEvent
import com.vitorpamplona.quartz.nipACWebRtcCalls.WebRtcCallFactory
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallIceCandidateEvent
@@ -47,30 +40,15 @@ import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.CallType
import com.vitorpamplona.quartz.utils.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import org.webrtc.AudioSource
-import org.webrtc.AudioTrack
-import org.webrtc.Camera2Enumerator
-import org.webrtc.CameraVideoCapturer
-import org.webrtc.DefaultVideoDecoderFactory
-import org.webrtc.DefaultVideoEncoderFactory
import org.webrtc.EglBase
import org.webrtc.IceCandidate
-import org.webrtc.MediaConstraints
-import org.webrtc.PeerConnectionFactory
-import org.webrtc.SurfaceTextureHelper
-import org.webrtc.VideoFrame
-import org.webrtc.VideoSink
-import org.webrtc.VideoSource
import org.webrtc.VideoTrack
import java.util.UUID
-import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.atomic.AtomicLong
private const val TAG = "CallController"
private const val VIDEO_MAX_BITRATE_BPS = 1_500_000
@@ -83,71 +61,31 @@ class CallController(
private val signerProvider: suspend () -> com.vitorpamplona.quartz.nip01Core.signers.NostrSigner,
localPubKey: HexKey,
) {
- // ---- Per-peer session state (delegated to PeerSessionManager) ----
-
private var peerSessionMgr = PeerSessionManager(localPubKey)
- /** Retrieves the underlying WebRtcCallSession for a peer (for WebRTC-specific APIs like addTrack). */
private fun webRtcSession(peerPubKey: HexKey): WebRtcCallSession? = (peerSessionMgr.getSession(peerPubKey)?.session as? WebRtcPeerSessionAdapter)?.webRtcSession
- // ---- Shared WebRTC resources ----
-
- private var peerConnectionFactory: PeerConnectionFactory? = null
- private var sharedEglBase: EglBase? = null
- private var localAudioSource: AudioSource? = null
- private var localVideoSource: VideoSource? = null
- private var localAudioTrackInternal: AudioTrack? = null
- private var localVideoTrackInternal: VideoTrack? = null
- private var cameraCapturer: CameraVideoCapturer? = null
-
- private val callFactory = WebRtcCallFactory()
+ val mediaManager = CallMediaManager(context)
val audioManager = CallAudioManager(context)
+ val videoMonitor = RemoteVideoMonitor(scope)
+ private val callFactory = WebRtcCallFactory()
// ---- UI-exposed state ----
- private val _localVideoTrack = MutableStateFlow(null)
- val localVideoTrack: StateFlow = _localVideoTrack.asStateFlow()
-
- // Primary remote track (first connected peer) for backward-compat with P2P UI
- private val _remoteVideoTrack = MutableStateFlow(null)
- val remoteVideoTrack: StateFlow = _remoteVideoTrack.asStateFlow()
-
- // All remote tracks keyed by peer pubkey (for group call UI)
- private val _remoteVideoTracks = MutableStateFlow