fix: route call events via EventProcessor and add video call button
Fix call connection stuck at "Connecting": - Inner events from unwrapped GiftWraps are dispatched through EventProcessor.consumeEvent(), not LocalCache.newEventBundles. The previous approach using newEventBundles observer never saw the inner call events because they're created internally during GiftWrap processing, not from relay arrivals. - Restored callManager routing in EventProcessor.consumeEvent() and wired it via account.newNotesPreProcessor.callManager in AccountViewModel.initCallController() Video call button: - Added Videocam icon button in DM chat header (RenderRoomTopBar) next to the voice call button - onVideoCallClick initiates a VIDEO type call with camera capturer https://claude.ai/code/session_017hZm7yu7CzmcQgZGSaqSXS
This commit is contained in:
+1
-23
@@ -146,12 +146,6 @@ import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent
|
||||
import com.vitorpamplona.quartz.nip90Dvms.contentDiscoveryResponse.NIP90ContentDiscoveryResponseEvent
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallAnswerEvent
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallHangupEvent
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallIceCandidateEvent
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallOfferEvent
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallRejectEvent
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallRenegotiateEvent
|
||||
import com.vitorpamplona.quartz.utils.Hex
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
@@ -222,6 +216,7 @@ class AccountViewModel(
|
||||
)
|
||||
callManager.onAnswerReceived = { event -> controller.onCallAnswerReceived(event.sdpAnswer()) }
|
||||
callManager.onIceCandidateReceived = { event -> controller.onIceCandidateReceived(event) }
|
||||
account.newNotesPreProcessor.callManager = callManager
|
||||
callController = controller
|
||||
}
|
||||
|
||||
@@ -1415,23 +1410,6 @@ class AccountViewModel(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
LocalCache.live.newEventBundles.collect { newNotes ->
|
||||
newNotes.forEach { note ->
|
||||
val event = note.event ?: return@forEach
|
||||
when (event) {
|
||||
is CallOfferEvent,
|
||||
is CallAnswerEvent,
|
||||
is CallIceCandidateEvent,
|
||||
is CallHangupEvent,
|
||||
is CallRejectEvent,
|
||||
is CallRenegotiateEvent,
|
||||
-> callManager.onSignalingEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
|
||||
+21
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.call.CallManager
|
||||
import com.vitorpamplona.amethyst.commons.model.privateChats.ChatroomList
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
@@ -36,6 +37,12 @@ import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.PrivateZapCache
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallAnswerEvent
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallHangupEvent
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallIceCandidateEvent
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallOfferEvent
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallRejectEvent
|
||||
import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallRenegotiateEvent
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import kotlinx.coroutines.CancellationException
|
||||
|
||||
@@ -52,6 +59,8 @@ class EventProcessor(
|
||||
private val zapRequest = LnZapRequestEventHandler(account.privateZapsDecryptionCache)
|
||||
private val zapEvent = LnZapEventHandler(account.privateZapsDecryptionCache)
|
||||
|
||||
var callManager: CallManager? = null
|
||||
|
||||
suspend fun consume(note: Note) {
|
||||
note.event?.let { event ->
|
||||
try {
|
||||
@@ -68,10 +77,22 @@ class EventProcessor(
|
||||
publicNote: Note,
|
||||
) {
|
||||
when (event) {
|
||||
is CallOfferEvent,
|
||||
is CallAnswerEvent,
|
||||
is CallIceCandidateEvent,
|
||||
is CallHangupEvent,
|
||||
is CallRejectEvent,
|
||||
is CallRenegotiateEvent,
|
||||
-> callManager?.onSignalingEvent(event)
|
||||
|
||||
is ChatroomKeyable -> chatHandler.add(event, eventNote, publicNote)
|
||||
|
||||
is DraftWrapEvent -> draftHandler.add(event, eventNote, publicNote)
|
||||
|
||||
is GiftWrapEvent -> giftWrapHandler.add(event, eventNote, publicNote)
|
||||
|
||||
is SealedRumorEvent -> sealHandler.add(event, eventNote, publicNote)
|
||||
|
||||
is LnZapRequestEvent -> zapRequest.add(event, eventNote, publicNote)
|
||||
}
|
||||
}
|
||||
|
||||
+9
-2
@@ -48,12 +48,18 @@ fun ChatroomScreen(
|
||||
nav: INav,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val startCall =
|
||||
val startVoiceCall =
|
||||
rememberCallWithPermission(context) {
|
||||
val peerPubKey = roomId.users.firstOrNull() ?: return@rememberCallWithPermission
|
||||
accountViewModel.callController?.initiateCall(peerPubKey, CallType.VOICE)
|
||||
nav.nav(Route.ActiveCall(callId = "", peerPubKey = peerPubKey))
|
||||
}
|
||||
val startVideoCall =
|
||||
rememberCallWithPermission(context) {
|
||||
val peerPubKey = roomId.users.firstOrNull() ?: return@rememberCallWithPermission
|
||||
accountViewModel.callController?.initiateCall(peerPubKey, CallType.VIDEO)
|
||||
nav.nav(Route.ActiveCall(callId = "", peerPubKey = peerPubKey))
|
||||
}
|
||||
|
||||
DisappearingScaffold(
|
||||
isInvertedLayout = true,
|
||||
@@ -62,7 +68,8 @@ fun ChatroomScreen(
|
||||
room = roomId,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
onCallClick = { _ -> startCall() },
|
||||
onCallClick = { _ -> startVoiceCall() },
|
||||
onVideoCallClick = { _ -> startVideoCall() },
|
||||
)
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
|
||||
+16
@@ -33,6 +33,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Call
|
||||
import androidx.compose.material.icons.filled.EditNote
|
||||
import androidx.compose.material.icons.filled.Videocam
|
||||
import androidx.compose.material3.FilledTonalButton
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -74,6 +75,7 @@ fun RenderRoomTopBar(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
onCallClick: ((String) -> Unit)? = null,
|
||||
onVideoCallClick: ((String) -> Unit)? = null,
|
||||
) {
|
||||
if (room.users.size == 1) {
|
||||
TopBarExtensibleWithBackButton(
|
||||
@@ -90,6 +92,20 @@ fun RenderRoomTopBar(
|
||||
|
||||
UsernameDisplay(baseUser, Modifier.weight(1f), fontWeight = FontWeight.Normal, accountViewModel = accountViewModel)
|
||||
|
||||
if (onVideoCallClick != null) {
|
||||
IconButton(
|
||||
onClick = { onVideoCallClick(baseUser.pubkeyHex) },
|
||||
modifier = Modifier.size(40.dp),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Videocam,
|
||||
contentDescription = "Video call",
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.size(20.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (onCallClick != null) {
|
||||
IconButton(
|
||||
onClick = { onCallClick(baseUser.pubkeyHex) },
|
||||
|
||||
Reference in New Issue
Block a user