Skip to content

Commit

Permalink
fix: fixed accepting ringing during call (#699)
Browse files Browse the repository at this point in the history
* [PBE-1710] make example app Firebase friendly

* [PBE-1710] support reject.reason & show notification

* fix ios, improve setup

* support pronto-staging

* write openapi script + generate new API

* fixed accepting incoming call during another call (or outgoing call)

* Update packages/stream_video/lib/src/core/client_state.dart

---------

Co-authored-by: kanat <kijalbaev@gmail.com>
  • Loading branch information
Brazol and kanat authored Jun 14, 2024
1 parent eb89b63 commit 0a3965c
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 30 deletions.
72 changes: 59 additions & 13 deletions packages/stream_video/lib/src/call/call.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ typedef OnCallPermissionRequest = void Function(
typedef GetCurrentUserId = String? Function();

typedef SetActiveCall = Future<void> Function(Call?);
typedef GetActiveCallCid = StreamCallCid? Function();
typedef SetOutgoingCall = Future<void> Function(Call?);
typedef GetActiveCall = Call? Function();
typedef GetOutgoingCall = Call? Function();

const _idState = 1;
const _idUserId = 2;
Expand All @@ -68,7 +70,9 @@ class Call {
required CoordinatorClient coordinatorClient,
required StateEmitter<User?> currentUser,
required SetActiveCall setActiveCall,
required GetActiveCallCid getActiveCallCid,
required SetOutgoingCall setOutgoingCall,
required GetActiveCall getActiveCall,
required GetOutgoingCall getOutgoingCall,
RetryPolicy? retryPolicy,
SdpPolicy? sdpPolicy,
CallPreferences? preferences,
Expand All @@ -79,7 +83,9 @@ class Call {
coordinatorClient: coordinatorClient,
currentUser: currentUser,
setActiveCall: setActiveCall,
getActiveCallCid: getActiveCallCid,
setOutgoingCall: setOutgoingCall,
getActiveCall: getActiveCall,
getOutgoingCall: getOutgoingCall,
retryPolicy: retryPolicy,
sdpPolicy: sdpPolicy,
preferences: preferences,
Expand All @@ -94,7 +100,9 @@ class Call {
required CoordinatorClient coordinatorClient,
required StateEmitter<User?> currentUser,
required SetActiveCall setActiveCall,
required GetActiveCallCid getActiveCallCid,
required SetOutgoingCall setOutgoingCall,
required GetActiveCall getActiveCall,
required GetOutgoingCall getOutgoingCall,
RetryPolicy? retryPolicy,
SdpPolicy? sdpPolicy,
CallPreferences? preferences,
Expand All @@ -105,7 +113,9 @@ class Call {
coordinatorClient: coordinatorClient,
currentUser: currentUser,
setActiveCall: setActiveCall,
getActiveCallCid: getActiveCallCid,
setOutgoingCall: setOutgoingCall,
getActiveCall: getActiveCall,
getOutgoingCall: getOutgoingCall,
retryPolicy: retryPolicy,
sdpPolicy: sdpPolicy,
preferences: preferences,
Expand All @@ -125,7 +135,9 @@ class Call {
required CoordinatorClient coordinatorClient,
required StateEmitter<User?> currentUser,
required SetActiveCall setActiveCall,
required GetActiveCallCid getActiveCallCid,
required SetOutgoingCall setOutgoingCall,
required GetActiveCall getActiveCall,
required GetOutgoingCall getOutgoingCall,
RetryPolicy? retryPolicy,
SdpPolicy? sdpPolicy,
CallPreferences? preferences,
Expand All @@ -136,7 +148,9 @@ class Call {
coordinatorClient: coordinatorClient,
currentUser: currentUser,
setActiveCall: setActiveCall,
getActiveCallCid: getActiveCallCid,
setOutgoingCall: setOutgoingCall,
getActiveCall: getActiveCall,
getOutgoingCall: getOutgoingCall,
retryPolicy: retryPolicy,
sdpPolicy: sdpPolicy,
preferences: preferences,
Expand All @@ -148,7 +162,9 @@ class Call {
required CoordinatorClient coordinatorClient,
required StateEmitter<User?> currentUser,
required SetActiveCall setActiveCall,
required GetActiveCallCid getActiveCallCid,
required SetOutgoingCall setOutgoingCall,
required GetActiveCall getActiveCall,
required GetOutgoingCall getOutgoingCall,
RetryPolicy? retryPolicy,
SdpPolicy? sdpPolicy,
CallPreferences? preferences,
Expand All @@ -172,7 +188,9 @@ class Call {
coordinatorClient: coordinatorClient,
currentUser: currentUser,
setActiveCall: setActiveCall,
getActiveCallCid: getActiveCallCid,
setOutgoingCall: setOutgoingCall,
getActiveCall: getActiveCall,
getOutgoingCall: getOutgoingCall,
preferences: finalCallPreferences,
stateManager: stateManager,
credentials: credentials,
Expand All @@ -185,7 +203,9 @@ class Call {
Call._({
required StateEmitter<User?> currentUser,
required SetActiveCall setActiveCall,
required GetActiveCallCid getActiveCallCid,
required SetOutgoingCall setOutgoingCall,
required GetActiveCall getActiveCall,
required GetOutgoingCall getOutgoingCall,
required CoordinatorClient coordinatorClient,
required CallPreferences preferences,
required CallStateNotifier stateManager,
Expand All @@ -206,7 +226,9 @@ class Call {
.whereNotNull()
.distinct(),
_setActiveCall = setActiveCall,
_getActiveCallCid = getActiveCallCid,
_setOutgoingCall = setOutgoingCall,
_getActiveCall = getActiveCall,
_getOutgoingCall = getOutgoingCall,
_coordinatorClient = coordinatorClient,
_preferences = preferences,
_retryPolicy = retryPolicy,
Expand All @@ -226,7 +248,9 @@ class Call {
final GetCurrentUserId _getCurrentUserId;
final Stream<String> _currentUserIdUpdates;
final SetActiveCall _setActiveCall;
final GetActiveCallCid _getActiveCallCid;
final SetOutgoingCall _setOutgoingCall;
final GetActiveCall _getActiveCall;
final GetOutgoingCall _getOutgoingCall;
final CoordinatorClient _coordinatorClient;
final RetryPolicy _retryPolicy;
final CallPreferences _preferences;
Expand All @@ -241,6 +265,8 @@ class Call {

StreamCallType get type => state.value.callType;

bool get isActiveCall => _getActiveCall()?.callCid == callCid;

String get id => state.value.callId;

StateEmitter<CallState> get state => _stateManager.callStateStream;
Expand Down Expand Up @@ -380,6 +406,21 @@ class Call {
_logger.w(() => '[acceptCall] rejected (invalid status): $status');
return Result.error('invalid status: $status');
}

final outgoingCall = _getOutgoingCall();
if (outgoingCall?.callCid != callCid) {
await outgoingCall?.reject(reason: 'cancel');
await outgoingCall?.leave();
await _setOutgoingCall(null);
}

final activeCall = _getActiveCall();
if (activeCall?.callCid != callCid) {
await activeCall?.reject(reason: 'cancel');
await activeCall?.leave();
await _setActiveCall(null);
}

final result = await _coordinatorClient.acceptCall(cid: state.callCid);
if (result is Success<None>) {
_stateManager.lifecycleCallAccepted();
Expand Down Expand Up @@ -448,7 +489,7 @@ class Call {
return const Result.success(none);
}

if (_getActiveCallCid() == callCid) {
if (_getActiveCall()?.callCid == callCid) {
_logger.w(
() => '[join] rejected (a call with the same cid is in progress)',
);
Expand Down Expand Up @@ -997,6 +1038,7 @@ class Call {
await _session?.dispose();
_session = null;
await _setActiveCall(null);
await _setOutgoingCall(null);
_logger.v(() => '[clear] completed');
}

Expand Down Expand Up @@ -1291,6 +1333,10 @@ class Call {
return Result.error('[getOrCreate] failed; no user_id found');
}

if (ringing) {
await _setOutgoingCall(this);
}

final response = await _coordinatorClient.getOrCreateCall(
callCid: callCid,
ringing: ringing,
Expand Down
7 changes: 5 additions & 2 deletions packages/stream_video/lib/src/call/session/call_session.dart
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,8 @@ class CallSession extends Disposable {
Future<Result<None>> setSubscriptions(
List<SubscriptionChange> subscriptionChanges,
) async {
_logger.d(() => '[setSubscriptions] subscriptionChanges: $subscriptionChanges');
_logger.d(
() => '[setSubscriptions] subscriptionChanges: $subscriptionChanges');

final participants = stateManager.callState.callParticipants;
final exclude = {SfuTrackType.video, SfuTrackType.screenShare};
Expand All @@ -792,7 +793,8 @@ class CallSession extends Disposable {
Future<Result<None>> updateSubscription(
SubscriptionChange subscriptionChange,
) async {
_logger.d(() => '[updateSubscription] subscriptionChange: $subscriptionChange');
_logger.d(
() => '[updateSubscription] subscriptionChange: $subscriptionChange');
return _saBuffer.post(subscriptionChange);
}

Expand Down Expand Up @@ -885,6 +887,7 @@ class CallSession extends Disposable {
enabled: enabled,
constraints: constraints,
);

return result.map((_) => none);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ class CoordinatorWebSocket extends StreamWebSocket

bool _refreshToken = false;

@override
SharedEmitter<CoordinatorEvent> get events => _events;
final _events = MutableSharedEmitterImpl<CoordinatorEvent>();

Expand Down
27 changes: 20 additions & 7 deletions packages/stream_video/lib/src/core/client_state.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import '../call/call.dart';
import '../models/call_cid.dart';
import '../models/user.dart';
import '../state_emitter.dart';
import 'connection_state.dart';
Expand All @@ -21,14 +20,18 @@ abstract class ClientState {
StateEmitter<Call?> get activeCall;

/// Emits when a call was created by another user with ringing set as True.
StateEmitter<Call> get incomingCall;
StateEmitter<Call?> get incomingCall;

/// Emits when a call was created by current user with ringing set as True.
StateEmitter<Call?> get outgoingCall;
}

class MutableClientState implements ClientState {
MutableClientState(User user)
: user = MutableStateEmitterImpl(user),
activeCall = MutableStateEmitterImpl(null),
incomingCall = MutableStateEmitterImpl(null),
outgoingCall = MutableStateEmitterImpl(null),
connection = MutableStateEmitterImpl(
ConnectionState.disconnected(user.id),
);
Expand All @@ -40,7 +43,10 @@ class MutableClientState implements ClientState {
final MutableStateEmitter<Call?> activeCall;

@override
final MutableStateEmitter<Call> incomingCall;
final MutableStateEmitter<Call?> incomingCall;

@override
final MutableStateEmitter<Call?> outgoingCall;

@override
final MutableStateEmitter<ConnectionState> connection;
Expand All @@ -50,16 +56,23 @@ class MutableClientState implements ClientState {

Future<void> clear() async {
activeCall.value = null;
outgoingCall.value = null;
connection.value = ConnectionState.disconnected(user.value.id);
}

StreamCallCid? getActiveCallCid() => activeCall.valueOrNull?.callCid;
Call? getActiveCall() => activeCall.valueOrNull;
Call? getOutgoingCall() => outgoingCall.valueOrNull;

Future<void> setActiveCall(Call? call) async {
final ongoingCall = activeCall.valueOrNull;
if (ongoingCall != null && call != null) {
await ongoingCall.leave();
final currentlyActiveCall = activeCall.valueOrNull;
if (currentlyActiveCall != null && call != null) {
await currentlyActiveCall.leave();
}

activeCall.value = call;
}

Future<void> setOutgoingCall(Call? call) async {
outgoingCall.value = call;
}
}
10 changes: 7 additions & 3 deletions packages/stream_video/lib/src/stream_video.dart
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,9 @@ class StreamVideo extends Disposable {
coordinatorClient: _client,
currentUser: _state.user,
setActiveCall: _state.setActiveCall,
getActiveCallCid: _state.getActiveCallCid,
setOutgoingCall: _state.setOutgoingCall,
getActiveCall: _state.getActiveCall,
getOutgoingCall: _state.getOutgoingCall,
retryPolicy: _options.retryPolicy,
sdpPolicy: _options.sdpPolicy,
preferences: preferences,
Expand All @@ -509,7 +511,9 @@ class StreamVideo extends Disposable {
coordinatorClient: _client,
currentUser: _state.user,
setActiveCall: _state.setActiveCall,
getActiveCallCid: _state.getActiveCallCid,
setOutgoingCall: _state.setOutgoingCall,
getActiveCall: _state.getActiveCall,
getOutgoingCall: _state.getOutgoingCall,
retryPolicy: _options.retryPolicy,
sdpPolicy: _options.sdpPolicy,
preferences: preferences,
Expand Down Expand Up @@ -721,7 +725,7 @@ class StreamVideo extends Disposable {
}

if (_state.incomingCall.valueOrNull?.callCid.value == cid) {
return Result.success(_state.incomingCall.value);
return Result.success(_state.incomingCall.value!);
}

final callCid = StreamCallCid(cid: cid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@ class _HomeScreenState extends State<HomeScreen> {
final StreamVideo _streamVideo = StreamVideo.instance;
late final currentUser = _streamVideo.currentUser;

StreamSubscription<Call>? _onIncomingCallSubscription;
StreamSubscription<Call?>? _onIncomingCallSubscription;

@override
void initState() {
super.initState();
_onIncomingCallSubscription?.cancel();
_onIncomingCallSubscription = _streamVideo.state.incomingCall.listen(
_onNavigateToCall,
);
_onIncomingCallSubscription =
_streamVideo.state.incomingCall.listen((call) {
if (call != null) {
_onNavigateToCall(call);
}
});
}

@override
Expand Down

0 comments on commit 0a3965c

Please sign in to comment.