Skip to content

Commit e709178

Browse files
authored
rewatch calls after coordinator reconnects (#1029)
1 parent c9a01cf commit e709178

File tree

6 files changed

+79
-0
lines changed

6 files changed

+79
-0
lines changed

packages/stream_video/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* Fixed an issue where toggling camera enabled quickly could cause AVCaptureMultiCamSession to crash.
99
* Fixed an issue where the default camera selection would occasionally be incorrect even when properly configured.
1010
* Fixed an issue where changing the audio input device while muted from the start of a call would not apply the new device when unmuting. The selected device will now be correctly set upon unmuting.
11+
* Fixed an issue where coordinator events were not listened to after a fast reconnect in a Call.
1112
* Fixes an issue with `muteUsers` method when called for all tracks.
1213

1314
## 0.10.0

packages/stream_video/lib/src/call/call.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1945,6 +1945,7 @@ class Call {
19451945
}) async {
19461946
if (watch) {
19471947
_observeEvents();
1948+
_streamVideo.state.setWatchedCall(this);
19481949
}
19491950

19501951
final response = await coordinatorCall();

packages/stream_video/lib/src/coordinator/models/coordinator_events.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ class CoordinatorDisconnectedEvent extends CoordinatorEvent {
5252
List<Object?> get props => [connectionId, userId, closeCode, closeReason];
5353
}
5454

55+
/// Fired when web socket reconnected.
56+
class CoordinatorReconnectedEvent extends CoordinatorEvent {
57+
const CoordinatorReconnectedEvent({
58+
this.connectionId,
59+
this.userId,
60+
});
61+
62+
final String? connectionId;
63+
final String? userId;
64+
65+
@override
66+
List<Object?> get props => [connectionId, userId];
67+
}
68+
5569
/// Sent periodically by the server to keep the connection alive.
5670
class CoordinatorHealthCheckEvent extends CoordinatorEvent {
5771
const CoordinatorHealthCheckEvent({

packages/stream_video/lib/src/coordinator/open_api/coordinator_ws.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,19 @@ class CoordinatorWebSocket extends StreamWebSocket implements HealthListener {
4848
_buildUrl(url, apiKey),
4949
protocols: protocols,
5050
tag: '$_tag-${++_seq}',
51+
) {
52+
onConnectionStateUpdated = (event) {
53+
if (event.oldState == ConnectionState.reconnecting &&
54+
event.newState == ConnectionState.connected) {
55+
_events.emit(
56+
CoordinatorReconnectedEvent(
57+
userId: userId,
58+
connectionId: connectionId,
59+
),
5160
);
61+
}
62+
};
63+
}
5264

5365
late final _logger = taggedLogger(tag: '$_tag-$_seq');
5466

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ abstract class ClientState {
2222
/// Emits a list of active calls.
2323
StateEmitter<List<Call>> get activeCalls;
2424

25+
/// Emits a list of watched calls.
26+
StateEmitter<List<Call>> get watchedCalls;
27+
2528
/// Emits an active call.
2629
/// Will only emit if options.allowMultipleActiveCalls is set to false, use activeCalls otherwise.
2730
StateEmitter<Call?> get activeCall;
@@ -40,6 +43,9 @@ abstract class ClientState {
4043
/// Otherwise the call is added to the list of active calls.
4144
Future<void> setActiveCall(Call? call);
4245

46+
/// Adds the call to the list of watched calls.
47+
void setWatchedCall(Call call);
48+
4349
/// Removes the call from the list of active calls.
4450
/// It won't `leave` the call, just removes it from the list.
4551
Future<void> removeActiveCall(Call call);
@@ -50,6 +56,7 @@ class MutableClientState implements ClientState {
5056
: user = MutableStateEmitterImpl(user),
5157
activeCalls = MutableStateEmitterImpl([]),
5258
activeCall = MutableStateEmitterImpl(null),
59+
watchedCalls = MutableStateEmitterImpl([]),
5360
incomingCall = MutableStateEmitterImpl(null),
5461
outgoingCall = MutableStateEmitterImpl(null),
5562
connection = MutableStateEmitterImpl(
@@ -64,6 +71,9 @@ class MutableClientState implements ClientState {
6471
@override
6572
final MutableStateEmitter<List<Call>> activeCalls;
6673

74+
@override
75+
final MutableStateEmitter<List<Call>> watchedCalls;
76+
6777
@override
6878
final MutableStateEmitter<Call?> activeCall;
6979

@@ -111,6 +121,10 @@ class MutableClientState implements ClientState {
111121
} else if (call != null) {
112122
activeCalls.value = [...activeCalls.value, call];
113123
}
124+
125+
if (call != null) {
126+
setWatchedCall(call);
127+
}
114128
}
115129

116130
@override
@@ -124,6 +138,19 @@ class MutableClientState implements ClientState {
124138
activeCalls.value = [
125139
...activeCalls.value.where((it) => it.callCid != call.callCid),
126140
];
141+
142+
watchedCalls.value = [
143+
...watchedCalls.value.where((it) => it.callCid != call.callCid),
144+
];
145+
}
146+
147+
@override
148+
void setWatchedCall(Call call) {
149+
if (watchedCalls.value.any((it) => it.callCid == call.callCid)) {
150+
return;
151+
}
152+
153+
watchedCalls.value = [...watchedCalls.value, call];
127154
}
128155

129156
@override

packages/stream_video/lib/src/stream_video.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,30 @@ class StreamVideo extends Disposable {
474474
_connectionState = ConnectionState.disconnected(
475475
_state.currentUser.id,
476476
);
477+
} else if (event is CoordinatorReconnectedEvent) {
478+
_logger.i(() => '[onCoordinatorEvent] reconnected ${event.userId}');
479+
if (state.watchedCalls.value.isNotEmpty) {
480+
// Re-watch the previously watched calls.
481+
unawaited(
482+
queryCalls(
483+
watch: true,
484+
filterConditions: {
485+
'cid': {
486+
r'$in': state.watchedCalls.value
487+
.map((call) => call.callCid.value)
488+
.toList(),
489+
},
490+
},
491+
).onError(
492+
(error, stackTrace) {
493+
_logger.e(
494+
() => '[onCoordinatorEvent] re-watching calls failed: $error',
495+
);
496+
return Result.failure(VideoErrors.compose(error, stackTrace));
497+
},
498+
),
499+
);
500+
}
477501
}
478502
}
479503

0 commit comments

Comments
 (0)