@@ -536,9 +536,11 @@ class Call {
536536 // Notify the client about the permission request.
537537 return onPermissionRequest? .call (event);
538538 case StreamCallRejectedEvent _:
539- return _stateManager.coordinatorCallRejected (event);
539+ await _handleCoordinatorCallRejected (event);
540+ return ;
540541 case StreamCallAcceptedEvent _:
541- return _stateManager.coordinatorCallAccepted (event);
542+ await _handleCoordinatorCallAccepted (event);
543+ return ;
542544 case StreamCallEndedEvent _:
543545 return _stateManager.coordinatorCallEnded (event);
544546 case StreamCallPermissionsUpdatedEvent _:
@@ -645,6 +647,46 @@ class Call {
645647 }
646648 }
647649
650+ Future <void > _handleCoordinatorCallAccepted (
651+ StreamCallAcceptedEvent event,
652+ ) async {
653+ final currentUserId = _stateManager.callState.currentUserId;
654+ final status = state.value.status;
655+
656+ if (event.acceptedByUserId == currentUserId &&
657+ status is CallStatusIncoming &&
658+ ! status.acceptedByMe) {
659+ _logger.i (
660+ () => '[onCoordinatorEvent] call accepted on another device, '
661+ 'rejecting locally with userRespondedElsewhere' ,
662+ );
663+ await reject (reason: CallRejectReason .userRespondedElsewhere ());
664+ return ;
665+ }
666+
667+ _stateManager.coordinatorCallAccepted (event);
668+ }
669+
670+ Future <void > _handleCoordinatorCallRejected (
671+ StreamCallRejectedEvent event,
672+ ) async {
673+ final currentUserId = _stateManager.callState.currentUserId;
674+ final status = state.value.status;
675+
676+ if (event.rejectedByUserId == currentUserId &&
677+ status is CallStatusIncoming &&
678+ ! status.acceptedByMe) {
679+ _logger.i (
680+ () => '[onCoordinatorEvent] call rejected on another device, '
681+ 'rejecting locally with userRespondedElsewhere' ,
682+ );
683+ await reject (reason: CallRejectReason .userRespondedElsewhere ());
684+ return ;
685+ }
686+
687+ _stateManager.coordinatorCallRejected (event);
688+ }
689+
648690 void _handleModerationWarningEvent (
649691 StreamCallModerationWarningEvent event,
650692 ) {
@@ -779,7 +821,7 @@ class Call {
779821 /// Rejects the incoming call.
780822 Future <Result <None >> reject ({CallRejectReason ? reason}) async {
781823 final state = this .state.value;
782- _logger.i (() => '[reject] state : $state ' );
824+ _logger.i (() => '[reject] reason : $reason ' );
783825
784826 final result = await _coordinatorClient.rejectCall (
785827 cid: state.callCid,
@@ -2005,7 +2047,7 @@ class Call {
20052047 }
20062048
20072049 try {
2008- _session? .leave (reason: 'user is leaving the call' );
2050+ _session? .leave (reason: _sfuLeaveReason (reason) );
20092051 } finally {
20102052 await _clear ('leave' );
20112053 }
@@ -2020,6 +2062,30 @@ class Call {
20202062 }
20212063 }
20222064
2065+ String _sfuLeaveReason (DisconnectReason ? reason) {
2066+ if (reason == null ) return 'user is leaving the call' ;
2067+ if (reason is DisconnectReasonRejected ) {
2068+ return 'rejected: ${reason .reason ?.value ?? 'unspecified' }' ;
2069+ } else if (reason is DisconnectReasonReplaced ) {
2070+ return 'replaced by another call' ;
2071+ } else if (reason is DisconnectReasonReconnectionFailed ) {
2072+ return 'reconnection failed' ;
2073+ } else if (reason is DisconnectReasonLastParticipantLeft ) {
2074+ return 'last participant left' ;
2075+ } else if (reason is DisconnectReasonFailure ) {
2076+ return 'failure: ${reason .error }' ;
2077+ } else if (reason is DisconnectReasonSfuError ) {
2078+ return 'sfu error: ${reason .error }' ;
2079+ } else if (reason is DisconnectReasonCallEnded ) {
2080+ return 'call ended externally' ;
2081+ } else if (reason is DisconnectReasonEnded ) {
2082+ return 'call ended' ;
2083+ } else if (reason is DisconnectReasonTimeout ) {
2084+ return 'timeout' ;
2085+ }
2086+ return 'user is leaving the call' ;
2087+ }
2088+
20232089 Future <void > _clear (String src) async {
20242090 _logger.d (() => '[clear] src: $src ' );
20252091
0 commit comments