diff --git a/dogfooding/lib/app/app_content.dart b/dogfooding/lib/app/app_content.dart index e61eeeacb..4a6794157 100644 --- a/dogfooding/lib/app/app_content.dart +++ b/dogfooding/lib/app/app_content.dart @@ -80,7 +80,20 @@ class _StreamDogFoodingAppContentState @override void initState() { super.initState(); - initPushNotificationManagerIfAvailable(); + + if (_userAuthController.currentUser != null) { + initPushNotificationManagerIfAvailable(); + } + + _userAuthController.addListener(() { + if (_userAuthController.currentUser != null) { + _compositeSubscription.clear(); + initPushNotificationManagerIfAvailable(); + } else { + _compositeSubscription.clear(); + } + }); + _tryConsumingIncomingCallFromTerminatedState(); } diff --git a/packages/stream_video/lib/src/call/call.dart b/packages/stream_video/lib/src/call/call.dart index 052cc1b1f..4e0535ce7 100644 --- a/packages/stream_video/lib/src/call/call.dart +++ b/packages/stream_video/lib/src/call/call.dart @@ -501,15 +501,13 @@ class Call { if (outgoingCall != null && outgoingCall.callCid != callCid) { _logger.i(() => '[accept] canceling outgoing call: $outgoingCall'); await outgoingCall.reject(reason: CallRejectReason.cancel()); - await _streamVideo.state.setOutgoingCall(null); } final activeCall = _streamVideo.state.activeCall.valueOrNull; if (activeCall != null && activeCall.callCid != callCid) { _logger.i(() => '[accept] canceling another active call: $activeCall'); - await activeCall.reject(reason: CallRejectReason.cancel()); - + await activeCall.leave(reason: DisconnectReason.ended()); await _streamVideo.state.setActiveCall(null); } @@ -1006,6 +1004,8 @@ class Call { Future _onSfuEvent(SfuEvent sfuEvent) async { if (sfuEvent is SfuParticipantLeftEvent) { + if (sfuEvent.callCid != callCid.value) return; + final callParticipants = [...state.value.callParticipants]..removeWhere( (participant) => participant.userId == sfuEvent.participant.userId && diff --git a/packages/stream_video/lib/src/coordinator/open_api/coordinator_client_open_api.dart b/packages/stream_video/lib/src/coordinator/open_api/coordinator_client_open_api.dart index 42c6ef1c3..efab4a973 100644 --- a/packages/stream_video/lib/src/coordinator/open_api/coordinator_client_open_api.dart +++ b/packages/stream_video/lib/src/coordinator/open_api/coordinator_client_open_api.dart @@ -152,7 +152,8 @@ class CoordinatorClientOpenApi extends CoordinatorClient { return const Result.success(none); } - _logger.d(() => '[waitUntilConnected] user.id: ${_user?.id}'); + _logger.d(() => + '[waitUntilConnected] user.id: ${_user?.id}, current state: ${_connectionState.value},'); return _connectionState .firstWhere( (it) => it.isConnected, diff --git a/packages/stream_video/lib/src/push_notification/push_notification_manager.dart b/packages/stream_video/lib/src/push_notification/push_notification_manager.dart index b2c3d6501..58318c2d0 100644 --- a/packages/stream_video/lib/src/push_notification/push_notification_manager.dart +++ b/packages/stream_video/lib/src/push_notification/push_notification_manager.dart @@ -97,6 +97,11 @@ abstract class PushNotificationManager { /// [uuid] is the unique identifier for the call. Future endCall(String uuid); + /// Ends the call. + /// + /// [cid] is the call id for the call. + Future endCallByCid(String cid); + /// Ends all ongoing calls. Future endAllCalls(); diff --git a/packages/stream_video/lib/src/stream_video.dart b/packages/stream_video/lib/src/stream_video.dart index 91f75f019..6c850ecbc 100644 --- a/packages/stream_video/lib/src/stream_video.dart +++ b/packages/stream_video/lib/src/stream_video.dart @@ -481,7 +481,7 @@ class StreamVideo extends Disposable { Future _onActiveCall(Call? activeCall) async { if (activeCall == null) { - await pushNotificationManager?.endAllCalls(); + await pushNotificationManager?.endCallByCid(activeCall!.callCid.value); } } @@ -676,6 +676,8 @@ class StreamVideo extends Disposable { } Future _onCallEnded(ActionCallEnded event) async { + _logger.d(() => '[onCallEnded] event: $event'); + final uuid = event.data.uuid; final cid = event.data.callCid; if (uuid == null || cid == null) return; diff --git a/packages/stream_video_push_notification/lib/src/stream_video_push_notification.dart b/packages/stream_video_push_notification/lib/src/stream_video_push_notification.dart index 9e766ae63..791d3f43d 100644 --- a/packages/stream_video_push_notification/lib/src/stream_video_push_notification.dart +++ b/packages/stream_video_push_notification/lib/src/stream_video_push_notification.dart @@ -13,10 +13,9 @@ import 'stream_video_push_params.dart'; part 'stream_video_push_provider.dart'; const _idToken = 1; -const _idCallKitIncoming = 2; +const _idCallKit = 2; const _idCallEnded = 3; const _idCallAccepted = 4; -const _idCallKitAcceptDecline = 5; const _idCallRejected = 6; const _idCallParticipantCount = 7; @@ -127,7 +126,7 @@ class StreamVideoPushNotificationManager implements PushNotificationManager { '[subscribeToEvents] Call accepted event: ${event.callCid}, accepted by: ${event.acceptedByUserId}'); if (event.acceptedByUserId != streamVideo.currentUser.id) return; - // end CallKit call on other devices if the call was accepted on one of them + // End the CallKit call on this device if the call was accepted on another device if (streamVideo.activeCall?.state.value.status is! CallStatusActive) { _logger.v(() => @@ -135,8 +134,8 @@ class StreamVideoPushNotificationManager implements PushNotificationManager { await endCallByCid(event.callCid.toString()); } - // if the call was accepted on the same device, end the CallKit call silently - // (in case it was accepted from the app and not from the CallKit UI) + // If the call was accepted on this device, end the CallKit call silently + // (useful if the call was accepted via the app instead of the CallKit UI) else { _logger.v(() => '[subscribeToEvents] Call accepted on the same device, ending CallKit silently: ${event.callCid}'); @@ -158,29 +157,24 @@ class StreamVideoPushNotificationManager implements PushNotificationManager { }); _subscriptions.add( - _idCallKitIncoming, - onCallEvent.whereType().listen( - (_) { - if (!client.isConnected) { - client.openConnection(); - } - - subscribeToEvents(); - }, - ), - ); - - _subscriptions.add( - _idCallKitAcceptDecline, - onCallEvent.whereType().map((_) => null).mergeWith([ - onCallEvent.whereType().map((_) => null), - onCallEvent.whereType().map((_) => null), - ]).listen( + _idCallKit, + onCallEvent.listen( (event) { - _subscriptions.cancel(_idCallAccepted); - _subscriptions.cancel(_idCallEnded); - _subscriptions.cancel(_idCallRejected); - _subscriptions.cancel(_idCallParticipantCount); + if (event is ActionCallIncoming) { + if (!client.isConnected) { + client.openConnection(); + } + + subscribeToEvents(); + } else if (event is ActionCallAccept || + event is ActionCallDecline || + event is ActionCallTimeout || + event is ActionCallEnded) { + _subscriptions.cancel(_idCallAccepted); + _subscriptions.cancel(_idCallEnded); + _subscriptions.cancel(_idCallRejected); + _subscriptions.cancel(_idCallParticipantCount); + } }, ), ); @@ -375,6 +369,7 @@ class StreamVideoPushNotificationManager implements PushNotificationManager { @override Future endCall(String uuid) => FlutterCallkitIncoming.endCall(uuid); + @override Future endCallByCid(String cid) async { final activeCalls = await this.activeCalls(); final calls =