/
RealtimeController.ts
239 lines (207 loc) · 8.45 KB
/
RealtimeController.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import DataMessage from '../datamessage/DataMessage';
import TranscriptionController from '../transcript/TranscriptionController';
import RealtimeAttendeePositionInFrame from './RealtimeAttendeePositionInFrame';
import type RealtimeSubscribeToAttendeeIdPresenceCallback from './RealtimeSubscribeToAttendeeIdPresenceCallback';
import type VolumeIndicatorCallback from './VolumeIndicatorCallback';
/**
* [[RealtimeController]] controls aspects meetings concerning realtime UX
* that for performance, privacy, or other reasons should be implemented using
* the most direct path. Callbacks generated by this interface should be
* consumed synchronously and without business logic dependent on the UI state
* where possible. All methods are prefixed with `realtime` to make it easier to
* perform audits of realtime control paths.
*
* For an example involving performance implications, consider that volume
* indicator state is received for each attendee multiple times a second.
* The handler that receives WebSocket messages derives which indicators have
* updated and passes that information synchronously through the
* RealtimeController, which in turn provides the consumer of the volume
* indicator callbacks an opportunity to immediately render the information to
* the UI.
*
* For an example involving privacy implications, consider that a mute button
* must accurately represent the mute state as otherwise a user may think they
* are muted when they are not. Creating a direct path from the mute button
* to the place where the underlying media stream is disabled ensures that
* muting is instantaneous and cannot fail.
*
* When you are done using a `RealtimeController`, you should perform some
* cleanup steps in order to avoid memory leaks:
*
* 1. Unsubscribe from listeners; e.g., presence callbacks via
* {@link RealtimeController.realtimeUnsubscribeToAttendeeIdPresence}.
* 2. Drop your reference to the controller to allow it to be garbage collected.
*/
export default interface RealtimeController {
// Attendee Id
/**
* Sets the attendee id of the current user. This is used to override remote
* mute state with local state when there is an active audio input.
* @internal
*/
realtimeSetLocalAttendeeId(attendeeId: string, externalUserId: string | null): void;
/**
* Updates the presence of an attendee id.
* @internal
*/
realtimeSetAttendeeIdPresence(
attendeeId: string,
present: boolean,
externalUserId: string | null,
dropped: boolean | null,
posInFrame: RealtimeAttendeePositionInFrame | null
): void;
/**
* Subscribes to changes in attendee ids in order to discover attendee ids to
* subscribe and unsubscribe to for volume indicator updates.
*/
realtimeSubscribeToAttendeeIdPresence(
callback: RealtimeSubscribeToAttendeeIdPresenceCallback
): void;
/**
* Unsubscribes to changes in attendee ids.
*/
realtimeUnsubscribeToAttendeeIdPresence(
callback: RealtimeSubscribeToAttendeeIdPresenceCallback
): void;
// Muting
/**
* Sets whether the user will be able to mute and then synchronously fires the
* callbacks if can-mute state changed.
*/
realtimeSetCanUnmuteLocalAudio(canUnmute: boolean): void;
/**
* Subscribes to the changes to the can unmute local audio state.
*/
realtimeSubscribeToSetCanUnmuteLocalAudio(callback: (canUnmute: boolean) => void): void;
/**
* Unsubscribes to the changes to the can unmute local audio state.
*/
realtimeUnsubscribeToSetCanUnmuteLocalAudio(callback: (canUnmute: boolean) => void): void;
/**
* Returns whether the user can unmute.
*/
realtimeCanUnmuteLocalAudio(): boolean;
/**
* Mutes the audio input. If there is an active audio input, then a volume
* indicator update is also sent with the mute status for the current attendee
* id. It then synchronously notifies the callbacks if mute state
* changed. This mute is local and overrides any remote unmuted state received
* for the same attendee id.
*/
realtimeMuteLocalAudio(): void;
/**
* Unmutes the audio input if currently allowed. If there is an active audio
* input, then a volume indicator update is also sent with the mute status for
* the current attendee id. It then synchronously notifies the callbacks
* if mute state changed. This unmute is local and overrides any remote muted
* state received for the same attendee id.
*/
realtimeUnmuteLocalAudio(): boolean;
/**
* Subscribes to local audio mutes and unmutes
*/
realtimeSubscribeToMuteAndUnmuteLocalAudio(callback: (muted: boolean) => void): void;
/**
* Unsubscribes to local audio mutes and unmutes
*/
realtimeUnsubscribeToMuteAndUnmuteLocalAudio(callback: (muted: boolean) => void): void;
/**
* Returns whether the current user is muted.
*/
realtimeIsLocalAudioMuted(): boolean;
// Volume Indicators
/**
* Subscribes to volume indicator changes for a specific attendee id with a
* callback. Volume is between 0.0 (min volume) and 1.0 (max volume).
* Signal strength can be 0 (no signal), 0.5 (weak signal), or 1 (good signal).
* A null value for any field means that it has not changed.
*/
realtimeSubscribeToVolumeIndicator(attendeeId: string, callback: VolumeIndicatorCallback): void;
/**
* Unsubscribes to volume indicator changes for a specific attendee id.
* Optionally, you can pass a callback parameter to unsubscribe from a specific callback.
* Otherwise, all callbacks will be unsubscribed (e.g. activeSpeaker).
*/
realtimeUnsubscribeFromVolumeIndicator(
attendeeId: string,
callback?: VolumeIndicatorCallback
): void;
/**
* Computes the difference to the last state and sends a volume indicator
* change for the attendee if necessary. Volume is between 0.0 (min volume)
* and 1.0 (max volume). Signal strength can be 0 (no signal),
* 0.5 (weak signal), or 1 (good signal). A null value for any field means
* that it has not changed. If muted is non-null, then the volume will be
* overridden to 0.0.
* @internal
*/
realtimeUpdateVolumeIndicator(
attendeeId: string,
volume: number | null,
muted: boolean | null,
signalStrength: number | null,
externalUserId: string | null
): void;
/**
* Subscribes to changes in local signal strength
*/
realtimeSubscribeToLocalSignalStrengthChange(callback: (signalStrength: number) => void): void;
/**
* Unsubscribes to changes in local signal strength
*/
realtimeUnsubscribeToLocalSignalStrengthChange(callback: (signalStrength: number) => void): void;
/**
* Subscribe to local send message event
*/
realtimeSubscribeToSendDataMessage( // eslint-disable-next-line @typescript-eslint/no-explicit-any
callback: (topic: string, data: Uint8Array | string | any, lifetimeMs?: number) => void
): void;
/**
* Unsubscribe from local send message event
*/
realtimeUnsubscribeFromSendDataMessage( // eslint-disable-next-line @typescript-eslint/no-explicit-any
callback: (topic: string, data: Uint8Array | string | any, lifetimeMs?: number) => void
): void;
/**
* Send message via data channel
*/
realtimeSendDataMessage(
topic: string,
data: Uint8Array | string | any, // eslint-disable-line @typescript-eslint/no-explicit-any
lifetimeMs?: number
): void;
/**
* Subscribe to receiving message on a topic
*/
realtimeSubscribeToReceiveDataMessage(
topic: string,
callback: (dataMessage: DataMessage) => void
): void;
/**
* Unsubscribe from a message topic
*/
realtimeUnsubscribeFromReceiveDataMessage(topic: string): void;
/**
* Trigger callbacks when receiving a message from data channel
*/
realtimeReceiveDataMessage(dataMessage: DataMessage): void;
// Error Handling
/**
* Subscribes to receive a callback when a fatal error is generated while
* processing an action. Receiving this callback potentially means that it was
* not possible to successfully mute, and so should be handled by tearing down
* the current connection and starting over.
*/
realtimeSubscribeToFatalError(callback: (error: Error) => void): void;
/**
* Unsubscribes from receiving callbacks when fatal errors occur
*/
realtimeUnsubscribeToFatalError(callback: (error: Error) => void): void;
/**
* Returns the [[TranscriptionController]] for this realtime controller.
*/
readonly transcriptionController?: TranscriptionController;
}