@stream-io/video-client 0.2.3 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/index.browser.es.js +982 -675
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +984 -673
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +982 -675
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +21 -9
- package/dist/src/StreamVideoClient.d.ts +3 -1
- package/dist/src/devices/CameraManager.d.ts +31 -0
- package/dist/src/devices/CameraManagerState.d.ts +28 -0
- package/dist/src/devices/InputMediaDeviceManager.d.ts +47 -0
- package/dist/src/devices/InputMediaDeviceManagerState.d.ts +69 -0
- package/dist/src/devices/MicrophoneManager.d.ts +19 -0
- package/dist/src/devices/MicrophoneManagerState.d.ts +4 -0
- package/dist/src/devices/__tests__/mocks.d.ts +13 -0
- package/dist/src/devices/index.d.ts +4 -0
- package/dist/src/events/call-permissions.d.ts +0 -5
- package/dist/src/events/call.d.ts +0 -6
- package/dist/src/events/index.d.ts +0 -6
- package/dist/src/rtc/Dispatcher.d.ts +2 -2
- package/dist/src/rtc/Publisher.d.ts +0 -1
- package/dist/src/store/CallState.d.ts +164 -89
- package/dist/src/types.d.ts +5 -7
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/Call.ts +130 -44
- package/src/StreamVideoClient.ts +14 -17
- package/src/__tests__/StreamVideoClient.test.ts +3 -0
- package/src/devices/CameraManager.ts +73 -0
- package/src/devices/CameraManagerState.ts +61 -0
- package/src/devices/InputMediaDeviceManager.ts +121 -0
- package/src/devices/InputMediaDeviceManagerState.ts +111 -0
- package/src/devices/MicrophoneManager.ts +45 -0
- package/src/devices/MicrophoneManagerState.ts +9 -0
- package/src/devices/__tests__/CameraManager.test.ts +150 -0
- package/src/devices/__tests__/InputMediaDeviceManager.test.ts +159 -0
- package/src/devices/__tests__/MicrophoneManager.test.ts +103 -0
- package/src/devices/__tests__/mocks.ts +98 -0
- package/src/devices/index.ts +4 -0
- package/src/events/__tests__/call-permissions.test.ts +1 -61
- package/src/events/__tests__/call.test.ts +5 -50
- package/src/events/call-permissions.ts +0 -14
- package/src/events/call.ts +5 -16
- package/src/events/callEventHandlers.ts +2 -57
- package/src/events/index.ts +0 -6
- package/src/rtc/Dispatcher.ts +2 -2
- package/src/rtc/Publisher.ts +4 -6
- package/src/store/CallState.ts +475 -119
- package/src/store/__tests__/CallState.test.ts +447 -1
- package/src/types.ts +4 -8
- package/dist/src/events/__tests__/sessions.test.d.ts +0 -1
- package/dist/src/events/backstage.d.ts +0 -6
- package/dist/src/events/members.d.ts +0 -18
- package/dist/src/events/moderation.d.ts +0 -14
- package/dist/src/events/reactions.d.ts +0 -8
- package/dist/src/events/recording.d.ts +0 -18
- package/dist/src/events/sessions.d.ts +0 -26
- package/src/events/__tests__/backstage.test.ts +0 -15
- package/src/events/__tests__/members.test.ts +0 -135
- package/src/events/__tests__/recording.test.ts +0 -65
- package/src/events/__tests__/sessions.test.ts +0 -135
- package/src/events/backstage.ts +0 -15
- package/src/events/members.ts +0 -62
- package/src/events/moderation.ts +0 -35
- package/src/events/reactions.ts +0 -30
- package/src/events/recording.ts +0 -64
- package/src/events/sessions.ts +0 -102
- /package/dist/src/{events/__tests__/backstage.test.d.ts → devices/__tests__/CameraManager.test.d.ts} +0 -0
- /package/dist/src/{events/__tests__/members.test.d.ts → devices/__tests__/InputMediaDeviceManager.test.d.ts} +0 -0
- /package/dist/src/{events/__tests__/recording.test.d.ts → devices/__tests__/MicrophoneManager.test.d.ts} +0 -0
package/dist/index.cjs.js
CHANGED
|
@@ -6543,8 +6543,8 @@ class Publisher {
|
|
|
6543
6543
|
track.removeEventListener('ended', handleTrackEnded);
|
|
6544
6544
|
});
|
|
6545
6545
|
if (!transceiver) {
|
|
6546
|
-
const
|
|
6547
|
-
const targetResolution =
|
|
6546
|
+
const { settings } = this.state;
|
|
6547
|
+
const targetResolution = settings === null || settings === void 0 ? void 0 : settings.video.target_resolution;
|
|
6548
6548
|
const videoEncodings = trackType === TrackType.VIDEO
|
|
6549
6549
|
? findOptimalVideoLayers(track, targetResolution)
|
|
6550
6550
|
: undefined;
|
|
@@ -6822,8 +6822,8 @@ class Publisher {
|
|
|
6822
6822
|
}
|
|
6823
6823
|
return String(media.mid);
|
|
6824
6824
|
};
|
|
6825
|
-
const
|
|
6826
|
-
const targetResolution =
|
|
6825
|
+
const { settings } = this.state;
|
|
6826
|
+
const targetResolution = settings === null || settings === void 0 ? void 0 : settings.video.target_resolution;
|
|
6827
6827
|
return this.pc
|
|
6828
6828
|
.getTransceivers()
|
|
6829
6829
|
.filter((t) => t.direction === 'sendonly' && t.sender.track)
|
|
@@ -6916,7 +6916,6 @@ class Publisher {
|
|
|
6916
6916
|
this.pc = this.createPeerConnection(connectionConfig);
|
|
6917
6917
|
this.sfuClient = sfuClient;
|
|
6918
6918
|
this.state = state;
|
|
6919
|
-
this.dispatcher = dispatcher;
|
|
6920
6919
|
this.isDtxEnabled = isDtxEnabled;
|
|
6921
6920
|
this.isRedEnabled = isRedEnabled;
|
|
6922
6921
|
this.preferredVideoCodec = preferredVideoCodec;
|
|
@@ -7544,17 +7543,6 @@ const retryable = (rpc, logger) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
7544
7543
|
return rpcCallResult;
|
|
7545
7544
|
});
|
|
7546
7545
|
|
|
7547
|
-
/**
|
|
7548
|
-
* Watches for `call.live_started` events.
|
|
7549
|
-
*/
|
|
7550
|
-
const watchCallLiveStarted = (state) => {
|
|
7551
|
-
return function onCallLiveStarted(event) {
|
|
7552
|
-
if (event.type !== 'call.live_started')
|
|
7553
|
-
return;
|
|
7554
|
-
state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { backstage: false })));
|
|
7555
|
-
};
|
|
7556
|
-
};
|
|
7557
|
-
|
|
7558
7546
|
/**
|
|
7559
7547
|
* Gets the current value of an observable, or undefined if the observable has
|
|
7560
7548
|
* not emitted a value yet.
|
|
@@ -7997,71 +7985,29 @@ class CallState {
|
|
|
7997
7985
|
*
|
|
7998
7986
|
*/
|
|
7999
7987
|
constructor() {
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
this.
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
|
|
8009
|
-
|
|
8010
|
-
|
|
7988
|
+
this.backstageSubject = new rxjs.BehaviorSubject(false);
|
|
7989
|
+
this.blockedUserIdsSubject = new rxjs.BehaviorSubject([]);
|
|
7990
|
+
this.createdAtSubject = new rxjs.BehaviorSubject(new Date());
|
|
7991
|
+
this.endedAtSubject = new rxjs.BehaviorSubject(undefined);
|
|
7992
|
+
this.startsAtSubject = new rxjs.BehaviorSubject(undefined);
|
|
7993
|
+
this.updatedAtSubject = new rxjs.BehaviorSubject(new Date());
|
|
7994
|
+
this.createdBySubject = new rxjs.BehaviorSubject(undefined);
|
|
7995
|
+
this.customSubject = new rxjs.BehaviorSubject({});
|
|
7996
|
+
this.egressSubject = new rxjs.BehaviorSubject(undefined);
|
|
7997
|
+
this.ingressSubject = new rxjs.BehaviorSubject(undefined);
|
|
7998
|
+
this.recordingSubject = new rxjs.BehaviorSubject(false);
|
|
7999
|
+
this.sessionSubject = new rxjs.BehaviorSubject(undefined);
|
|
8000
|
+
this.settingsSubject = new rxjs.BehaviorSubject(undefined);
|
|
8001
|
+
this.transcribingSubject = new rxjs.BehaviorSubject(false);
|
|
8002
|
+
this.endedBySubject = new rxjs.BehaviorSubject(undefined);
|
|
8011
8003
|
this.membersSubject = new rxjs.BehaviorSubject([]);
|
|
8012
|
-
/**
|
|
8013
|
-
* The list of capabilities of the current user.
|
|
8014
|
-
*
|
|
8015
|
-
* @private
|
|
8016
|
-
*/
|
|
8017
8004
|
this.ownCapabilitiesSubject = new rxjs.BehaviorSubject([]);
|
|
8018
|
-
/**
|
|
8019
|
-
* The calling state.
|
|
8020
|
-
*
|
|
8021
|
-
* @internal
|
|
8022
|
-
*/
|
|
8023
8005
|
this.callingStateSubject = new rxjs.BehaviorSubject(exports.CallingState.UNKNOWN);
|
|
8024
|
-
/**
|
|
8025
|
-
* The time the call session actually started.
|
|
8026
|
-
*
|
|
8027
|
-
* @internal
|
|
8028
|
-
*/
|
|
8029
8006
|
this.startedAtSubject = new rxjs.BehaviorSubject(undefined);
|
|
8030
|
-
/**
|
|
8031
|
-
* The server-side counted number of participants connected to the current call.
|
|
8032
|
-
* This number includes the anonymous participants as well.
|
|
8033
|
-
*
|
|
8034
|
-
* @internal
|
|
8035
|
-
*/
|
|
8036
8007
|
this.participantCountSubject = new rxjs.BehaviorSubject(0);
|
|
8037
|
-
/**
|
|
8038
|
-
* The server-side counted number of anonymous participants connected to the current call.
|
|
8039
|
-
* This number excludes the regular participants.
|
|
8040
|
-
*
|
|
8041
|
-
* @internal
|
|
8042
|
-
*/
|
|
8043
8008
|
this.anonymousParticipantCountSubject = new rxjs.BehaviorSubject(0);
|
|
8044
|
-
/**
|
|
8045
|
-
* All participants of the current call (including the logged-in user).
|
|
8046
|
-
*
|
|
8047
|
-
* @internal
|
|
8048
|
-
*/
|
|
8049
8009
|
this.participantsSubject = new rxjs.BehaviorSubject([]);
|
|
8050
|
-
/**
|
|
8051
|
-
* The latest stats report of the current call.
|
|
8052
|
-
* When stats gathering is enabled, this observable will emit a new value
|
|
8053
|
-
* at a regular (configurable) interval.
|
|
8054
|
-
*
|
|
8055
|
-
* Consumers of this observable can implement their own batching logic
|
|
8056
|
-
* in case they want to show historical stat data.
|
|
8057
|
-
*
|
|
8058
|
-
* @internal
|
|
8059
|
-
*/
|
|
8060
8010
|
this.callStatsReportSubject = new rxjs.BehaviorSubject(undefined);
|
|
8061
|
-
/**
|
|
8062
|
-
* Emits a list of details about recordings performed for the current call.
|
|
8063
|
-
*/
|
|
8064
|
-
this.callRecordingListSubject = new rxjs.BehaviorSubject([]);
|
|
8065
8011
|
/**
|
|
8066
8012
|
* A list of comparators that are used to sort the participants.
|
|
8067
8013
|
*
|
|
@@ -8144,15 +8090,6 @@ class CallState {
|
|
|
8144
8090
|
this.setCallingState = (state) => {
|
|
8145
8091
|
return this.setCurrentValue(this.callingStateSubject, state);
|
|
8146
8092
|
};
|
|
8147
|
-
/**
|
|
8148
|
-
* Sets the list of call recordings.
|
|
8149
|
-
*
|
|
8150
|
-
* @internal
|
|
8151
|
-
* @param recordings the list of call recordings.
|
|
8152
|
-
*/
|
|
8153
|
-
this.setCallRecordingsList = (recordings) => {
|
|
8154
|
-
return this.setCurrentValue(this.callRecordingListSubject, recordings);
|
|
8155
|
-
};
|
|
8156
8093
|
/**
|
|
8157
8094
|
* Sets the call stats report.
|
|
8158
8095
|
*
|
|
@@ -8162,16 +8099,6 @@ class CallState {
|
|
|
8162
8099
|
this.setCallStatsReport = (report) => {
|
|
8163
8100
|
return this.setCurrentValue(this.callStatsReportSubject, report);
|
|
8164
8101
|
};
|
|
8165
|
-
/**
|
|
8166
|
-
* Sets the metadata of the current call.
|
|
8167
|
-
*
|
|
8168
|
-
* @internal
|
|
8169
|
-
*
|
|
8170
|
-
* @param metadata the metadata to set.
|
|
8171
|
-
*/
|
|
8172
|
-
this.setMetadata = (metadata) => {
|
|
8173
|
-
return this.setCurrentValue(this.metadataSubject, metadata);
|
|
8174
|
-
};
|
|
8175
8102
|
/**
|
|
8176
8103
|
* Sets the members of the current call.
|
|
8177
8104
|
*
|
|
@@ -8270,6 +8197,19 @@ class CallState {
|
|
|
8270
8197
|
return p;
|
|
8271
8198
|
}));
|
|
8272
8199
|
};
|
|
8200
|
+
/**
|
|
8201
|
+
* Updates the call state with the data received from the server.
|
|
8202
|
+
*
|
|
8203
|
+
* @internal
|
|
8204
|
+
*
|
|
8205
|
+
* @param event the video event that our backend sent us.
|
|
8206
|
+
*/
|
|
8207
|
+
this.updateFromEvent = (event) => {
|
|
8208
|
+
const update = this.eventHandlers[event.type];
|
|
8209
|
+
if (update) {
|
|
8210
|
+
update(event);
|
|
8211
|
+
}
|
|
8212
|
+
};
|
|
8273
8213
|
/**
|
|
8274
8214
|
* Updates the participant pinned state with server side pinning data.
|
|
8275
8215
|
*
|
|
@@ -8298,25 +8238,174 @@ class CallState {
|
|
|
8298
8238
|
return participant;
|
|
8299
8239
|
}));
|
|
8300
8240
|
};
|
|
8301
|
-
|
|
8241
|
+
/**
|
|
8242
|
+
* Updates the call state with the data received from the server.
|
|
8243
|
+
*
|
|
8244
|
+
* @internal
|
|
8245
|
+
*
|
|
8246
|
+
* @param call the call response from the server.
|
|
8247
|
+
*/
|
|
8248
|
+
this.updateFromCallResponse = (call) => {
|
|
8249
|
+
this.setCurrentValue(this.backstageSubject, call.backstage);
|
|
8250
|
+
this.setCurrentValue(this.blockedUserIdsSubject, call.blocked_user_ids);
|
|
8251
|
+
this.setCurrentValue(this.createdAtSubject, new Date(call.created_at));
|
|
8252
|
+
this.setCurrentValue(this.updatedAtSubject, new Date(call.updated_at));
|
|
8253
|
+
this.setCurrentValue(this.startsAtSubject, call.starts_at ? new Date(call.starts_at) : undefined);
|
|
8254
|
+
this.setCurrentValue(this.endedAtSubject, call.ended_at ? new Date(call.ended_at) : undefined);
|
|
8255
|
+
this.setCurrentValue(this.createdBySubject, call.created_by);
|
|
8256
|
+
this.setCurrentValue(this.customSubject, call.custom);
|
|
8257
|
+
this.setCurrentValue(this.egressSubject, call.egress);
|
|
8258
|
+
this.setCurrentValue(this.ingressSubject, call.ingress);
|
|
8259
|
+
this.setCurrentValue(this.recordingSubject, call.recording);
|
|
8260
|
+
this.setCurrentValue(this.sessionSubject, call.session);
|
|
8261
|
+
this.setCurrentValue(this.settingsSubject, call.settings);
|
|
8262
|
+
this.setCurrentValue(this.transcribingSubject, call.transcribing);
|
|
8263
|
+
};
|
|
8264
|
+
this.updateFromMemberRemoved = (event) => {
|
|
8265
|
+
this.setCurrentValue(this.membersSubject, (members) => members.filter((m) => event.members.indexOf(m.user_id) === -1));
|
|
8266
|
+
};
|
|
8267
|
+
this.updateFromMemberAdded = (event) => {
|
|
8268
|
+
this.setCurrentValue(this.membersSubject, (members) => [
|
|
8269
|
+
...members,
|
|
8270
|
+
...event.members,
|
|
8271
|
+
]);
|
|
8272
|
+
};
|
|
8273
|
+
this.updateFromBroadcastStopped = () => {
|
|
8274
|
+
this.setCurrentValue(this.egressSubject, (egress) => (Object.assign(Object.assign({}, egress), { broadcasting: false })));
|
|
8275
|
+
};
|
|
8276
|
+
this.updateFromBroadcastStarted = (event) => {
|
|
8277
|
+
this.setCurrentValue(this.egressSubject, (egress) => (Object.assign(Object.assign({}, egress), { broadcasting: true, hls: Object.assign(Object.assign({}, egress.hls), { playlist_url: event.hls_playlist_url }) })));
|
|
8278
|
+
};
|
|
8279
|
+
this.updateFromSessionParticipantLeft = (event) => {
|
|
8280
|
+
this.setCurrentValue(this.sessionSubject, (session) => {
|
|
8281
|
+
if (!session) {
|
|
8282
|
+
this.logger('warn', `Received call.session_participant_left event but no session is available.`, event);
|
|
8283
|
+
return session;
|
|
8284
|
+
}
|
|
8285
|
+
const { participants, participants_count_by_role } = session;
|
|
8286
|
+
const { user, user_session_id } = event.participant;
|
|
8287
|
+
return Object.assign(Object.assign({}, session), { participants: participants.filter((p) => p.user_session_id !== user_session_id), participants_count_by_role: Object.assign(Object.assign({}, participants_count_by_role), { [user.role]: Math.max(0, (participants_count_by_role[user.role] || 0) - 1) }) });
|
|
8288
|
+
});
|
|
8289
|
+
};
|
|
8290
|
+
this.updateFromSessionParticipantJoined = (event) => {
|
|
8291
|
+
this.setCurrentValue(this.sessionSubject, (session) => {
|
|
8292
|
+
if (!session) {
|
|
8293
|
+
this.logger('warn', `Received call.session_participant_joined event but no session is available.`, event);
|
|
8294
|
+
return session;
|
|
8295
|
+
}
|
|
8296
|
+
const { participants, participants_count_by_role } = session;
|
|
8297
|
+
const { user } = event.participant;
|
|
8298
|
+
return Object.assign(Object.assign({}, session), { participants: [...participants, event.participant], participants_count_by_role: Object.assign(Object.assign({}, participants_count_by_role), { [user.role]: (participants_count_by_role[user.role] || 0) + 1 }) });
|
|
8299
|
+
});
|
|
8300
|
+
};
|
|
8301
|
+
this.updateMembers = (event) => {
|
|
8302
|
+
this.setCurrentValue(this.membersSubject, (members) => members.map((member) => {
|
|
8303
|
+
const memberUpdate = event.members.find((m) => m.user_id === member.user_id);
|
|
8304
|
+
return memberUpdate ? memberUpdate : member;
|
|
8305
|
+
}));
|
|
8306
|
+
};
|
|
8307
|
+
this.updateParticipantReaction = (event) => {
|
|
8308
|
+
const { user, custom, type, emoji_code } = event.reaction;
|
|
8309
|
+
this.setParticipants((participants) => {
|
|
8310
|
+
return participants.map((p) => {
|
|
8311
|
+
// skip if the reaction is not for this participant
|
|
8312
|
+
if (p.userId !== user.id)
|
|
8313
|
+
return p;
|
|
8314
|
+
// update the participant with the new reaction
|
|
8315
|
+
return Object.assign(Object.assign({}, p), { reaction: {
|
|
8316
|
+
type,
|
|
8317
|
+
emoji_code,
|
|
8318
|
+
custom,
|
|
8319
|
+
} });
|
|
8320
|
+
});
|
|
8321
|
+
});
|
|
8322
|
+
};
|
|
8323
|
+
this.unblockUser = (event) => {
|
|
8324
|
+
this.setCurrentValue(this.blockedUserIdsSubject, (current) => {
|
|
8325
|
+
if (!current)
|
|
8326
|
+
return current;
|
|
8327
|
+
return current.filter((id) => id !== event.user.id);
|
|
8328
|
+
});
|
|
8329
|
+
};
|
|
8330
|
+
this.blockUser = (event) => {
|
|
8331
|
+
this.setCurrentValue(this.blockedUserIdsSubject, (current) => [
|
|
8332
|
+
...(current || []),
|
|
8333
|
+
event.user.id,
|
|
8334
|
+
]);
|
|
8335
|
+
};
|
|
8336
|
+
this.updateOwnCapabilities = (event) => {
|
|
8337
|
+
var _a;
|
|
8338
|
+
if (event.user.id === ((_a = this.localParticipant) === null || _a === void 0 ? void 0 : _a.userId)) {
|
|
8339
|
+
this.setCurrentValue(this.ownCapabilitiesSubject, event.own_capabilities);
|
|
8340
|
+
}
|
|
8341
|
+
};
|
|
8342
|
+
this.logger = getLogger(['CallState']);
|
|
8302
8343
|
this.participants$ = this.participantsSubject.pipe(operators.map((ps) => ps.sort(this.sortParticipantsBy)));
|
|
8303
8344
|
this.localParticipant$ = this.participants$.pipe(operators.map((participants) => participants.find(isStreamVideoLocalParticipant)));
|
|
8304
8345
|
this.remoteParticipants$ = this.participants$.pipe(operators.map((participants) => participants.filter((p) => !p.isLocalParticipant)));
|
|
8305
8346
|
this.pinnedParticipants$ = this.participants$.pipe(operators.map((participants) => participants.filter((p) => !!p.pin)));
|
|
8306
8347
|
this.dominantSpeaker$ = this.participants$.pipe(operators.map((participants) => participants.find((p) => p.isDominantSpeaker)));
|
|
8307
|
-
this.hasOngoingScreenShare$ = this.participants$.pipe(operators.map((participants) =>
|
|
8308
|
-
return participants.some((p) => p.publishedTracks.includes(TrackType.SCREEN_SHARE));
|
|
8309
|
-
}), operators.distinctUntilChanged());
|
|
8348
|
+
this.hasOngoingScreenShare$ = this.participants$.pipe(operators.map((participants) => participants.some((p) => p.publishedTracks.includes(TrackType.SCREEN_SHARE))), operators.distinctUntilChanged());
|
|
8310
8349
|
this.startedAt$ = this.startedAtSubject.asObservable();
|
|
8311
8350
|
this.participantCount$ = this.participantCountSubject.asObservable();
|
|
8312
8351
|
this.anonymousParticipantCount$ =
|
|
8313
8352
|
this.anonymousParticipantCountSubject.asObservable();
|
|
8314
8353
|
this.callStatsReport$ = this.callStatsReportSubject.asObservable();
|
|
8315
|
-
this.callRecordingList$ = this.callRecordingListSubject.asObservable();
|
|
8316
|
-
this.metadata$ = this.metadataSubject.asObservable();
|
|
8317
8354
|
this.members$ = this.membersSubject.asObservable();
|
|
8318
8355
|
this.ownCapabilities$ = this.ownCapabilitiesSubject.asObservable();
|
|
8319
8356
|
this.callingState$ = this.callingStateSubject.asObservable();
|
|
8357
|
+
this.backstage$ = this.backstageSubject.asObservable();
|
|
8358
|
+
this.blockedUserIds$ = this.blockedUserIdsSubject.asObservable();
|
|
8359
|
+
this.createdAt$ = this.createdAtSubject.asObservable();
|
|
8360
|
+
this.endedAt$ = this.endedAtSubject.asObservable();
|
|
8361
|
+
this.startsAt$ = this.startsAtSubject.asObservable();
|
|
8362
|
+
this.updatedAt$ = this.updatedAtSubject.asObservable();
|
|
8363
|
+
this.createdBy$ = this.createdBySubject.asObservable();
|
|
8364
|
+
this.custom$ = this.customSubject.asObservable();
|
|
8365
|
+
this.egress$ = this.egressSubject.asObservable();
|
|
8366
|
+
this.ingress$ = this.ingressSubject.asObservable();
|
|
8367
|
+
this.recording$ = this.recordingSubject.asObservable();
|
|
8368
|
+
this.session$ = this.sessionSubject.asObservable();
|
|
8369
|
+
this.settings$ = this.settingsSubject.asObservable();
|
|
8370
|
+
this.transcribing$ = this.transcribingSubject.asObservable();
|
|
8371
|
+
this.endedBy$ = this.endedBySubject.asObservable();
|
|
8372
|
+
this.eventHandlers = {
|
|
8373
|
+
// these events are not updating the call state:
|
|
8374
|
+
'call.permission_request': undefined,
|
|
8375
|
+
'call.user_muted': undefined,
|
|
8376
|
+
'connection.error': undefined,
|
|
8377
|
+
'connection.ok': undefined,
|
|
8378
|
+
'health.check': undefined,
|
|
8379
|
+
custom: undefined,
|
|
8380
|
+
// events that update call state:
|
|
8381
|
+
'call.accepted': (e) => this.updateFromCallResponse(e.call),
|
|
8382
|
+
'call.created': (e) => this.updateFromCallResponse(e.call),
|
|
8383
|
+
'call.notification': (e) => this.updateFromCallResponse(e.call),
|
|
8384
|
+
'call.rejected': (e) => this.updateFromCallResponse(e.call),
|
|
8385
|
+
'call.ring': (e) => this.updateFromCallResponse(e.call),
|
|
8386
|
+
'call.live_started': (e) => this.updateFromCallResponse(e.call),
|
|
8387
|
+
'call.updated': (e) => this.updateFromCallResponse(e.call),
|
|
8388
|
+
'call.session_started': (e) => this.updateFromCallResponse(e.call),
|
|
8389
|
+
'call.session_ended': (e) => this.updateFromCallResponse(e.call),
|
|
8390
|
+
'call.ended': (e) => {
|
|
8391
|
+
this.updateFromCallResponse(e.call);
|
|
8392
|
+
this.setCurrentValue(this.endedBySubject, e.user);
|
|
8393
|
+
},
|
|
8394
|
+
'call.recording_started': () => this.setCurrentValue(this.recordingSubject, true),
|
|
8395
|
+
'call.recording_stopped': () => this.setCurrentValue(this.recordingSubject, false),
|
|
8396
|
+
'call.broadcasting_started': this.updateFromBroadcastStarted,
|
|
8397
|
+
'call.broadcasting_stopped': this.updateFromBroadcastStopped,
|
|
8398
|
+
'call.session_participant_joined': this.updateFromSessionParticipantJoined,
|
|
8399
|
+
'call.session_participant_left': this.updateFromSessionParticipantLeft,
|
|
8400
|
+
'call.blocked_user': this.blockUser,
|
|
8401
|
+
'call.unblocked_user': this.unblockUser,
|
|
8402
|
+
'call.permissions_updated': this.updateOwnCapabilities,
|
|
8403
|
+
'call.member_added': this.updateFromMemberAdded,
|
|
8404
|
+
'call.member_removed': this.updateFromMemberRemoved,
|
|
8405
|
+
'call.member_updated': this.updateMembers,
|
|
8406
|
+
'call.member_updated_permission': this.updateMembers,
|
|
8407
|
+
'call.reaction_new': this.updateParticipantReaction,
|
|
8408
|
+
};
|
|
8320
8409
|
}
|
|
8321
8410
|
/**
|
|
8322
8411
|
* The server-side counted number of participants connected to the current call.
|
|
@@ -8381,24 +8470,12 @@ class CallState {
|
|
|
8381
8470
|
get callingState() {
|
|
8382
8471
|
return this.getCurrentValue(this.callingState$);
|
|
8383
8472
|
}
|
|
8384
|
-
/**
|
|
8385
|
-
* The list of call recordings.
|
|
8386
|
-
*/
|
|
8387
|
-
get callRecordingsList() {
|
|
8388
|
-
return this.getCurrentValue(this.callRecordingList$);
|
|
8389
|
-
}
|
|
8390
8473
|
/**
|
|
8391
8474
|
* The call stats report.
|
|
8392
8475
|
*/
|
|
8393
8476
|
get callStatsReport() {
|
|
8394
8477
|
return this.getCurrentValue(this.callStatsReport$);
|
|
8395
8478
|
}
|
|
8396
|
-
/**
|
|
8397
|
-
* The metadata of the current call.
|
|
8398
|
-
*/
|
|
8399
|
-
get metadata() {
|
|
8400
|
-
return this.getCurrentValue(this.metadata$);
|
|
8401
|
-
}
|
|
8402
8479
|
/**
|
|
8403
8480
|
* The members of the current call.
|
|
8404
8481
|
*/
|
|
@@ -8411,6 +8488,96 @@ class CallState {
|
|
|
8411
8488
|
get ownCapabilities() {
|
|
8412
8489
|
return this.getCurrentValue(this.ownCapabilities$);
|
|
8413
8490
|
}
|
|
8491
|
+
/**
|
|
8492
|
+
* The backstage state.
|
|
8493
|
+
*/
|
|
8494
|
+
get backstage() {
|
|
8495
|
+
return this.getCurrentValue(this.backstage$);
|
|
8496
|
+
}
|
|
8497
|
+
/**
|
|
8498
|
+
* Will provide the list of blocked user IDs.
|
|
8499
|
+
*/
|
|
8500
|
+
get blockedUserIds() {
|
|
8501
|
+
return this.getCurrentValue(this.blockedUserIds$);
|
|
8502
|
+
}
|
|
8503
|
+
/**
|
|
8504
|
+
* Will provide the time when this call has been created.
|
|
8505
|
+
*/
|
|
8506
|
+
get createdAt() {
|
|
8507
|
+
return this.getCurrentValue(this.createdAt$);
|
|
8508
|
+
}
|
|
8509
|
+
/**
|
|
8510
|
+
* Will provide the time when this call has been ended.
|
|
8511
|
+
*/
|
|
8512
|
+
get endedAt() {
|
|
8513
|
+
return this.getCurrentValue(this.endedAt$);
|
|
8514
|
+
}
|
|
8515
|
+
/**
|
|
8516
|
+
* Will provide the time when this call has been scheduled to start.
|
|
8517
|
+
*/
|
|
8518
|
+
get startsAt() {
|
|
8519
|
+
return this.getCurrentValue(this.startsAt$);
|
|
8520
|
+
}
|
|
8521
|
+
/**
|
|
8522
|
+
* Will provide the time when this call has been updated.
|
|
8523
|
+
*/
|
|
8524
|
+
get updatedAt() {
|
|
8525
|
+
return this.getCurrentValue(this.updatedAt$);
|
|
8526
|
+
}
|
|
8527
|
+
/**
|
|
8528
|
+
* Will provide the user who created this call.
|
|
8529
|
+
*/
|
|
8530
|
+
get createdBy() {
|
|
8531
|
+
return this.getCurrentValue(this.createdBy$);
|
|
8532
|
+
}
|
|
8533
|
+
/**
|
|
8534
|
+
* Will provide the custom data of this call.
|
|
8535
|
+
*/
|
|
8536
|
+
get custom() {
|
|
8537
|
+
return this.getCurrentValue(this.custom$);
|
|
8538
|
+
}
|
|
8539
|
+
/**
|
|
8540
|
+
* Will provide the egress data of this call.
|
|
8541
|
+
*/
|
|
8542
|
+
get egress() {
|
|
8543
|
+
return this.getCurrentValue(this.egress$);
|
|
8544
|
+
}
|
|
8545
|
+
/**
|
|
8546
|
+
* Will provide the ingress data of this call.
|
|
8547
|
+
*/
|
|
8548
|
+
get ingress() {
|
|
8549
|
+
return this.getCurrentValue(this.ingress$);
|
|
8550
|
+
}
|
|
8551
|
+
/**
|
|
8552
|
+
* Will provide the recording state of this call.
|
|
8553
|
+
*/
|
|
8554
|
+
get recording() {
|
|
8555
|
+
return this.getCurrentValue(this.recording$);
|
|
8556
|
+
}
|
|
8557
|
+
/**
|
|
8558
|
+
* Will provide the session data of this call.
|
|
8559
|
+
*/
|
|
8560
|
+
get session() {
|
|
8561
|
+
return this.getCurrentValue(this.session$);
|
|
8562
|
+
}
|
|
8563
|
+
/**
|
|
8564
|
+
* Will provide the settings of this call.
|
|
8565
|
+
*/
|
|
8566
|
+
get settings() {
|
|
8567
|
+
return this.getCurrentValue(this.settings$);
|
|
8568
|
+
}
|
|
8569
|
+
/**
|
|
8570
|
+
* Will provide the transcribing state of this call.
|
|
8571
|
+
*/
|
|
8572
|
+
get transcribing() {
|
|
8573
|
+
return this.getCurrentValue(this.transcribing$);
|
|
8574
|
+
}
|
|
8575
|
+
/**
|
|
8576
|
+
* Will provide the user who ended this call.
|
|
8577
|
+
*/
|
|
8578
|
+
get endedBy() {
|
|
8579
|
+
return this.getCurrentValue(this.endedBy$);
|
|
8580
|
+
}
|
|
8414
8581
|
}
|
|
8415
8582
|
|
|
8416
8583
|
/**
|
|
@@ -8482,40 +8649,16 @@ const watchCallEnded = (call) => {
|
|
|
8482
8649
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8483
8650
|
if (event.type !== 'call.ended')
|
|
8484
8651
|
return;
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8652
|
+
const { callingState } = call.state;
|
|
8653
|
+
if (callingState === exports.CallingState.RINGING ||
|
|
8654
|
+
callingState === exports.CallingState.JOINED ||
|
|
8655
|
+
callingState === exports.CallingState.JOINING) {
|
|
8489
8656
|
yield call.leave();
|
|
8490
8657
|
}
|
|
8491
8658
|
});
|
|
8492
8659
|
};
|
|
8493
8660
|
};
|
|
8494
|
-
/**
|
|
8495
|
-
* An event handler which listens to `call.updated` events
|
|
8496
|
-
* and updates the given call state accordingly.
|
|
8497
|
-
*/
|
|
8498
|
-
const watchCallUpdated = (state) => {
|
|
8499
|
-
return function onCallUpdated(event) {
|
|
8500
|
-
if (event.type !== 'call.updated')
|
|
8501
|
-
return;
|
|
8502
|
-
state.setMetadata(event.call);
|
|
8503
|
-
};
|
|
8504
|
-
};
|
|
8505
8661
|
|
|
8506
|
-
/**
|
|
8507
|
-
* Event handler that watches for `call.permissions_updated` events
|
|
8508
|
-
*/
|
|
8509
|
-
const watchCallPermissionsUpdated = (state) => {
|
|
8510
|
-
return function onCallPermissionsUpdated(event) {
|
|
8511
|
-
if (event.type !== 'call.permissions_updated')
|
|
8512
|
-
return;
|
|
8513
|
-
const { localParticipant } = state;
|
|
8514
|
-
if (event.user.id === (localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.userId)) {
|
|
8515
|
-
state.setOwnCapabilities(event.own_capabilities);
|
|
8516
|
-
}
|
|
8517
|
-
};
|
|
8518
|
-
};
|
|
8519
8662
|
/**
|
|
8520
8663
|
* Event handler that watches for `callGrantsUpdated` events.
|
|
8521
8664
|
*
|
|
@@ -8629,57 +8772,6 @@ const watchPinsUpdated = (state) => {
|
|
|
8629
8772
|
};
|
|
8630
8773
|
};
|
|
8631
8774
|
|
|
8632
|
-
/**
|
|
8633
|
-
* Watches for `call.member_added` events.
|
|
8634
|
-
*/
|
|
8635
|
-
const watchCallMemberAdded = (state) => {
|
|
8636
|
-
return function onCallMemberAdded(event) {
|
|
8637
|
-
if (event.type !== 'call.member_added')
|
|
8638
|
-
return;
|
|
8639
|
-
state.setMembers((members) => [...members, ...event.members]);
|
|
8640
|
-
};
|
|
8641
|
-
};
|
|
8642
|
-
/**
|
|
8643
|
-
* Watches for `call.member_removed` events.
|
|
8644
|
-
*/
|
|
8645
|
-
const watchCallMemberRemoved = (state) => {
|
|
8646
|
-
return function onCallMemberRemoved(event) {
|
|
8647
|
-
if (event.type !== 'call.member_removed')
|
|
8648
|
-
return;
|
|
8649
|
-
state.setMembers((members) => members.filter((m) => event.members.indexOf(m.user_id) === -1));
|
|
8650
|
-
};
|
|
8651
|
-
};
|
|
8652
|
-
/**
|
|
8653
|
-
* Watches for `call.member_updated_permission` events.
|
|
8654
|
-
*/
|
|
8655
|
-
const watchCallMemberUpdatedPermission = (state) => {
|
|
8656
|
-
return function onCallMemberUpdated(event) {
|
|
8657
|
-
if (event.type !== 'call.member_updated_permission')
|
|
8658
|
-
return;
|
|
8659
|
-
state.setMembers((members) => members.map((member) => {
|
|
8660
|
-
const memberUpdate = event.members.find((m) => m.user_id === member.user_id);
|
|
8661
|
-
if (memberUpdate) {
|
|
8662
|
-
member.user.role = memberUpdate.role;
|
|
8663
|
-
member = Object.assign({}, member);
|
|
8664
|
-
}
|
|
8665
|
-
return member;
|
|
8666
|
-
}));
|
|
8667
|
-
};
|
|
8668
|
-
};
|
|
8669
|
-
/**
|
|
8670
|
-
* Watches for `call.member_updated` events.
|
|
8671
|
-
*/
|
|
8672
|
-
const watchCallMemberUpdated = (state) => {
|
|
8673
|
-
return function onCallMemberUpdated(event) {
|
|
8674
|
-
if (event.type !== 'call.member_updated')
|
|
8675
|
-
return;
|
|
8676
|
-
state.setMembers((members) => members.map((member) => {
|
|
8677
|
-
const memberUpdate = event.members.find((m) => m.user_id === member.user_id);
|
|
8678
|
-
return memberUpdate ? memberUpdate : member;
|
|
8679
|
-
}));
|
|
8680
|
-
};
|
|
8681
|
-
};
|
|
8682
|
-
|
|
8683
8775
|
/**
|
|
8684
8776
|
* An event responder which handles the `participantJoined` event.
|
|
8685
8777
|
*/
|
|
@@ -8761,74 +8853,6 @@ const watchTrackUnpublished = (state) => {
|
|
|
8761
8853
|
};
|
|
8762
8854
|
const unique = (v, i, arr) => arr.indexOf(v) === i;
|
|
8763
8855
|
|
|
8764
|
-
/**
|
|
8765
|
-
* Watches the delivery of CallReactionEvent.
|
|
8766
|
-
*
|
|
8767
|
-
* @param state the state store to update.
|
|
8768
|
-
*/
|
|
8769
|
-
const watchNewReactions = (state) => {
|
|
8770
|
-
return function onNewReactions(event) {
|
|
8771
|
-
if (event.type !== 'call.reaction_new')
|
|
8772
|
-
return;
|
|
8773
|
-
const { reaction } = event;
|
|
8774
|
-
const { user, custom, type, emoji_code } = reaction;
|
|
8775
|
-
state.setParticipants((participants) => {
|
|
8776
|
-
return participants.map((p) => {
|
|
8777
|
-
// skip if the reaction is not for this participant
|
|
8778
|
-
if (p.userId !== user.id)
|
|
8779
|
-
return p;
|
|
8780
|
-
// update the participant with the new reaction
|
|
8781
|
-
return Object.assign(Object.assign({}, p), { reaction: {
|
|
8782
|
-
type,
|
|
8783
|
-
emoji_code,
|
|
8784
|
-
custom,
|
|
8785
|
-
} });
|
|
8786
|
-
});
|
|
8787
|
-
});
|
|
8788
|
-
};
|
|
8789
|
-
};
|
|
8790
|
-
|
|
8791
|
-
/**
|
|
8792
|
-
* Watches for `call.recording_started` events.
|
|
8793
|
-
*/
|
|
8794
|
-
const watchCallRecordingStarted = (state) => {
|
|
8795
|
-
return function onCallRecordingStarted(event) {
|
|
8796
|
-
if (event.type !== 'call.recording_started')
|
|
8797
|
-
return;
|
|
8798
|
-
state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { recording: true })));
|
|
8799
|
-
};
|
|
8800
|
-
};
|
|
8801
|
-
/**
|
|
8802
|
-
* Watches for `call.recording_stopped` events.
|
|
8803
|
-
*/
|
|
8804
|
-
const watchCallRecordingStopped = (state) => {
|
|
8805
|
-
return function onCallRecordingStopped(event) {
|
|
8806
|
-
if (event.type !== 'call.recording_stopped')
|
|
8807
|
-
return;
|
|
8808
|
-
state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { recording: false })));
|
|
8809
|
-
};
|
|
8810
|
-
};
|
|
8811
|
-
/**
|
|
8812
|
-
* Watches for `call.broadcasting_started` events.
|
|
8813
|
-
*/
|
|
8814
|
-
const watchCallBroadcastingStarted = (state) => {
|
|
8815
|
-
return function onCallBroadcastingStarted(event) {
|
|
8816
|
-
if (event.type !== 'call.broadcasting_started')
|
|
8817
|
-
return;
|
|
8818
|
-
state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { egress: Object.assign(Object.assign({}, metadata.egress), { broadcasting: true, hls: Object.assign(Object.assign({}, metadata.egress.hls), { playlist_url: event.hls_playlist_url }) }) })));
|
|
8819
|
-
};
|
|
8820
|
-
};
|
|
8821
|
-
/**
|
|
8822
|
-
* Watches for `call.broadcasting_stopped` events.
|
|
8823
|
-
*/
|
|
8824
|
-
const watchCallBroadcastingStopped = (state) => {
|
|
8825
|
-
return function onCallBroadcastingStopped(event) {
|
|
8826
|
-
if (event.type !== 'call.broadcasting_stopped')
|
|
8827
|
-
return;
|
|
8828
|
-
state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { egress: Object.assign(Object.assign({}, metadata.egress), { broadcasting: false }) })));
|
|
8829
|
-
};
|
|
8830
|
-
};
|
|
8831
|
-
|
|
8832
8856
|
/**
|
|
8833
8857
|
* Watches for `dominantSpeakerChanged` events.
|
|
8834
8858
|
*/
|
|
@@ -8871,98 +8895,6 @@ const watchAudioLevelChanged = (dispatcher, state) => {
|
|
|
8871
8895
|
});
|
|
8872
8896
|
};
|
|
8873
8897
|
|
|
8874
|
-
/**
|
|
8875
|
-
* Watch for call.session_started events and update the call metadata.
|
|
8876
|
-
*
|
|
8877
|
-
* @param state the call state.
|
|
8878
|
-
*/
|
|
8879
|
-
const watchCallSessionStarted = (state) => {
|
|
8880
|
-
return function onCallSessionStarted(event) {
|
|
8881
|
-
if (event.type !== 'call.session_started')
|
|
8882
|
-
return;
|
|
8883
|
-
state.setMetadata(event.call);
|
|
8884
|
-
};
|
|
8885
|
-
};
|
|
8886
|
-
/**
|
|
8887
|
-
* Watch for call.session_ended events and update the call metadata.
|
|
8888
|
-
*
|
|
8889
|
-
* @param state the call state.
|
|
8890
|
-
*/
|
|
8891
|
-
const watchCallSessionEnded = (state) => {
|
|
8892
|
-
return function onCallSessionEnded(event) {
|
|
8893
|
-
if (event.type !== 'call.session_ended')
|
|
8894
|
-
return;
|
|
8895
|
-
state.setMetadata(event.call);
|
|
8896
|
-
};
|
|
8897
|
-
};
|
|
8898
|
-
/**
|
|
8899
|
-
* Watch for call.session_participant_joined events and update the call metadata.
|
|
8900
|
-
*
|
|
8901
|
-
* @param state the call state.
|
|
8902
|
-
*/
|
|
8903
|
-
const watchCallSessionParticipantJoined = (state) => {
|
|
8904
|
-
return function onCallParticipantJoined(event) {
|
|
8905
|
-
if (event.type !== 'call.session_participant_joined')
|
|
8906
|
-
return;
|
|
8907
|
-
const { participant } = event;
|
|
8908
|
-
state.setMetadata((metadata) => {
|
|
8909
|
-
if (!metadata || !metadata.session) {
|
|
8910
|
-
state.logger('warn', `Received call.session_participant_joined event but the metadata structure is invalid.`, event);
|
|
8911
|
-
return metadata;
|
|
8912
|
-
}
|
|
8913
|
-
const { session } = metadata;
|
|
8914
|
-
const { participants, participants_count_by_role } = session;
|
|
8915
|
-
const { user } = participant;
|
|
8916
|
-
return Object.assign(Object.assign({}, metadata), { session: Object.assign(Object.assign({}, session), { participants: [...participants, participant], participants_count_by_role: Object.assign(Object.assign({}, participants_count_by_role), { [user.role]: (participants_count_by_role[user.role] || 0) + 1 }) }) });
|
|
8917
|
-
});
|
|
8918
|
-
};
|
|
8919
|
-
};
|
|
8920
|
-
/**
|
|
8921
|
-
* Watch for call.session_participant_left events and update the call metadata.
|
|
8922
|
-
*
|
|
8923
|
-
* @param state the call state.
|
|
8924
|
-
*/
|
|
8925
|
-
const watchCallSessionParticipantLeft = (state) => {
|
|
8926
|
-
return function onCallParticipantLeft(event) {
|
|
8927
|
-
if (event.type !== 'call.session_participant_left')
|
|
8928
|
-
return;
|
|
8929
|
-
const { user, user_session_id } = event.participant;
|
|
8930
|
-
state.setMetadata((metadata) => {
|
|
8931
|
-
if (!metadata || !metadata.session) {
|
|
8932
|
-
state.logger('warn', `Received call.session_participant_left event but the metadata structure is invalid.`, event);
|
|
8933
|
-
return metadata;
|
|
8934
|
-
}
|
|
8935
|
-
const { session } = metadata;
|
|
8936
|
-
const { participants, participants_count_by_role } = session;
|
|
8937
|
-
return Object.assign(Object.assign({}, metadata), { session: Object.assign(Object.assign({}, session), { participants: participants.filter((p) => p.user_session_id !== user_session_id), participants_count_by_role: Object.assign(Object.assign({}, participants_count_by_role), { [user.role]: Math.max(0, (participants_count_by_role[user.role] || 0) - 1) }) }) });
|
|
8938
|
-
});
|
|
8939
|
-
};
|
|
8940
|
-
};
|
|
8941
|
-
|
|
8942
|
-
/**
|
|
8943
|
-
* Event handler that watches for `call.blocked_user` events,
|
|
8944
|
-
* updates the call store `blocked_user_ids` property by adding
|
|
8945
|
-
* `event.user_id` to the list
|
|
8946
|
-
*/
|
|
8947
|
-
const watchBlockedUser = (state) => (event) => {
|
|
8948
|
-
if (event.type !== 'call.blocked_user')
|
|
8949
|
-
return;
|
|
8950
|
-
state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { blocked_user_ids: [...((metadata === null || metadata === void 0 ? void 0 : metadata.blocked_user_ids) || []), event.user.id] })));
|
|
8951
|
-
};
|
|
8952
|
-
/**
|
|
8953
|
-
* Event handler that watches for `call.unblocked_user` events,
|
|
8954
|
-
* updates the call store `blocked_user_ids` property by
|
|
8955
|
-
* removing `event.user_id` from the list
|
|
8956
|
-
*/
|
|
8957
|
-
const watchUnblockedUser = (state) => (event) => {
|
|
8958
|
-
if (event.type !== 'call.unblocked_user')
|
|
8959
|
-
return;
|
|
8960
|
-
state.setMetadata((metadata) => {
|
|
8961
|
-
const blocked_user_ids = ((metadata === null || metadata === void 0 ? void 0 : metadata.blocked_user_ids) || []).filter((userId) => event.user.id !== userId);
|
|
8962
|
-
return Object.assign(Object.assign({}, metadata), { blocked_user_ids });
|
|
8963
|
-
});
|
|
8964
|
-
};
|
|
8965
|
-
|
|
8966
8898
|
/**
|
|
8967
8899
|
* Registers the default event handlers for a call during its lifecycle.
|
|
8968
8900
|
*
|
|
@@ -8971,29 +8903,8 @@ const watchUnblockedUser = (state) => (event) => {
|
|
|
8971
8903
|
* @param dispatcher the dispatcher.
|
|
8972
8904
|
*/
|
|
8973
8905
|
const registerEventHandlers = (call, state, dispatcher) => {
|
|
8974
|
-
const coordinatorEvents = {
|
|
8975
|
-
'call.blocked_user': watchBlockedUser(state),
|
|
8976
|
-
'call.broadcasting_started': watchCallBroadcastingStarted(state),
|
|
8977
|
-
'call.broadcasting_stopped': watchCallBroadcastingStopped(state),
|
|
8978
|
-
'call.ended': watchCallEnded(call),
|
|
8979
|
-
'call.live_started': watchCallLiveStarted(state),
|
|
8980
|
-
'call.member_added': watchCallMemberAdded(state),
|
|
8981
|
-
'call.member_removed': watchCallMemberRemoved(state),
|
|
8982
|
-
'call.member_updated': watchCallMemberUpdated(state),
|
|
8983
|
-
'call.member_updated_permission': watchCallMemberUpdatedPermission(state),
|
|
8984
|
-
'call.permissions_updated': watchCallPermissionsUpdated(state),
|
|
8985
|
-
'call.reaction_new': watchNewReactions(state),
|
|
8986
|
-
'call.recording_started': watchCallRecordingStarted(state),
|
|
8987
|
-
'call.recording_stopped': watchCallRecordingStopped(state),
|
|
8988
|
-
'call.session_started': watchCallSessionStarted(state),
|
|
8989
|
-
'call.session_ended': watchCallSessionEnded(state),
|
|
8990
|
-
'call.session_participant_joined': watchCallSessionParticipantJoined(state),
|
|
8991
|
-
'call.session_participant_left': watchCallSessionParticipantLeft(state),
|
|
8992
|
-
'call.unblocked_user': watchUnblockedUser(state),
|
|
8993
|
-
'call.updated': watchCallUpdated(state),
|
|
8994
|
-
'call.user_muted': () => console.log('call.user_muted received'),
|
|
8995
|
-
};
|
|
8996
8906
|
const eventHandlers = [
|
|
8907
|
+
call.on('call.ended', watchCallEnded(call)),
|
|
8997
8908
|
watchLiveEnded(dispatcher, call),
|
|
8998
8909
|
watchSfuErrorReports(dispatcher),
|
|
8999
8910
|
watchChangePublishQuality(dispatcher, call),
|
|
@@ -9008,10 +8919,6 @@ const registerEventHandlers = (call, state, dispatcher) => {
|
|
|
9008
8919
|
call.on('callGrantsUpdated', watchCallGrantsUpdated(state)),
|
|
9009
8920
|
call.on('pinsUpdated', watchPinsUpdated(state)),
|
|
9010
8921
|
];
|
|
9011
|
-
Object.keys(coordinatorEvents).forEach((event) => {
|
|
9012
|
-
const eventName = event;
|
|
9013
|
-
eventHandlers.push(call.on(eventName, coordinatorEvents[eventName]));
|
|
9014
|
-
});
|
|
9015
8922
|
if (call.ringing) {
|
|
9016
8923
|
// these events are only relevant when the call is ringing
|
|
9017
8924
|
eventHandlers.push(registerRingingCallEventHandlers(call));
|
|
@@ -9630,7 +9537,592 @@ const getClientDetails = () => {
|
|
|
9630
9537
|
};
|
|
9631
9538
|
};
|
|
9632
9539
|
|
|
9633
|
-
|
|
9540
|
+
class InputMediaDeviceManagerState {
|
|
9541
|
+
constructor() {
|
|
9542
|
+
this.statusSubject = new rxjs.BehaviorSubject(undefined);
|
|
9543
|
+
this.mediaStreamSubject = new rxjs.BehaviorSubject(undefined);
|
|
9544
|
+
this.selectedDeviceSubject = new rxjs.BehaviorSubject(undefined);
|
|
9545
|
+
/**
|
|
9546
|
+
* Gets the current value of an observable, or undefined if the observable has
|
|
9547
|
+
* not emitted a value yet.
|
|
9548
|
+
*
|
|
9549
|
+
* @param observable$ the observable to get the value from.
|
|
9550
|
+
*/
|
|
9551
|
+
this.getCurrentValue = getCurrentValue;
|
|
9552
|
+
/**
|
|
9553
|
+
* Updates the value of the provided Subject.
|
|
9554
|
+
* An `update` can either be a new value or a function which takes
|
|
9555
|
+
* the current value and returns a new value.
|
|
9556
|
+
*
|
|
9557
|
+
* @internal
|
|
9558
|
+
*
|
|
9559
|
+
* @param subject the subject to update.
|
|
9560
|
+
* @param update the update to apply to the subject.
|
|
9561
|
+
* @return the updated value.
|
|
9562
|
+
*/
|
|
9563
|
+
this.setCurrentValue = setCurrentValue;
|
|
9564
|
+
this.mediaStream$ = this.mediaStreamSubject.asObservable();
|
|
9565
|
+
this.selectedDevice$ = this.selectedDeviceSubject
|
|
9566
|
+
.asObservable()
|
|
9567
|
+
.pipe(rxjs.distinctUntilChanged());
|
|
9568
|
+
this.status$ = this.statusSubject.asObservable();
|
|
9569
|
+
}
|
|
9570
|
+
/**
|
|
9571
|
+
* The device status
|
|
9572
|
+
*/
|
|
9573
|
+
get status() {
|
|
9574
|
+
return this.getCurrentValue(this.status$);
|
|
9575
|
+
}
|
|
9576
|
+
/**
|
|
9577
|
+
* The currently selected device
|
|
9578
|
+
*/
|
|
9579
|
+
get selectedDevice() {
|
|
9580
|
+
return this.getCurrentValue(this.selectedDevice$);
|
|
9581
|
+
}
|
|
9582
|
+
/**
|
|
9583
|
+
* The current media stream, or `undefined` if the device is currently disabled.
|
|
9584
|
+
*/
|
|
9585
|
+
get mediaStream() {
|
|
9586
|
+
return this.getCurrentValue(this.mediaStream$);
|
|
9587
|
+
}
|
|
9588
|
+
/**
|
|
9589
|
+
* @internal
|
|
9590
|
+
* @param status
|
|
9591
|
+
*/
|
|
9592
|
+
setStatus(status) {
|
|
9593
|
+
this.setCurrentValue(this.statusSubject, status);
|
|
9594
|
+
}
|
|
9595
|
+
/**
|
|
9596
|
+
* @internal
|
|
9597
|
+
* @param stream
|
|
9598
|
+
*/
|
|
9599
|
+
setMediaStream(stream) {
|
|
9600
|
+
this.setCurrentValue(this.mediaStreamSubject, stream);
|
|
9601
|
+
if (stream) {
|
|
9602
|
+
this.setDevice(this.getDeviceIdFromStream(stream));
|
|
9603
|
+
}
|
|
9604
|
+
}
|
|
9605
|
+
/**
|
|
9606
|
+
* @internal
|
|
9607
|
+
* @param stream
|
|
9608
|
+
*/
|
|
9609
|
+
setDevice(deviceId) {
|
|
9610
|
+
this.setCurrentValue(this.selectedDeviceSubject, deviceId);
|
|
9611
|
+
}
|
|
9612
|
+
}
|
|
9613
|
+
|
|
9614
|
+
class CameraManagerState extends InputMediaDeviceManagerState {
|
|
9615
|
+
constructor() {
|
|
9616
|
+
super();
|
|
9617
|
+
this.directionSubject = new rxjs.BehaviorSubject(undefined);
|
|
9618
|
+
this.direction$ = this.directionSubject
|
|
9619
|
+
.asObservable()
|
|
9620
|
+
.pipe(rxjs.distinctUntilChanged());
|
|
9621
|
+
}
|
|
9622
|
+
/**
|
|
9623
|
+
* The preferred camera direction
|
|
9624
|
+
* front - means the camera facing the user
|
|
9625
|
+
* back - means the camera facing the environment
|
|
9626
|
+
*/
|
|
9627
|
+
get direction() {
|
|
9628
|
+
return this.getCurrentValue(this.direction$);
|
|
9629
|
+
}
|
|
9630
|
+
/**
|
|
9631
|
+
* @internal
|
|
9632
|
+
*/
|
|
9633
|
+
setDirection(direction) {
|
|
9634
|
+
this.setCurrentValue(this.directionSubject, direction);
|
|
9635
|
+
}
|
|
9636
|
+
/**
|
|
9637
|
+
* @internal
|
|
9638
|
+
*/
|
|
9639
|
+
setMediaStream(stream) {
|
|
9640
|
+
var _a;
|
|
9641
|
+
super.setMediaStream(stream);
|
|
9642
|
+
if (stream) {
|
|
9643
|
+
// RN getSettings() doesn't return facingMode, so we don't verify camera direction
|
|
9644
|
+
const direction = isReactNative()
|
|
9645
|
+
? this.direction
|
|
9646
|
+
: ((_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().facingMode) === 'environment'
|
|
9647
|
+
? 'back'
|
|
9648
|
+
: 'front';
|
|
9649
|
+
this.setDirection(direction);
|
|
9650
|
+
}
|
|
9651
|
+
}
|
|
9652
|
+
getDeviceIdFromStream(stream) {
|
|
9653
|
+
var _a;
|
|
9654
|
+
return (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
|
|
9655
|
+
}
|
|
9656
|
+
}
|
|
9657
|
+
|
|
9658
|
+
const getDevices = (constraints) => {
|
|
9659
|
+
return new rxjs.Observable((subscriber) => {
|
|
9660
|
+
navigator.mediaDevices
|
|
9661
|
+
.getUserMedia(constraints)
|
|
9662
|
+
.then((media) => {
|
|
9663
|
+
// in Firefox, devices can be enumerated after userMedia is requested
|
|
9664
|
+
// and permissions granted. Otherwise, device labels are empty
|
|
9665
|
+
navigator.mediaDevices.enumerateDevices().then((devices) => {
|
|
9666
|
+
subscriber.next(devices);
|
|
9667
|
+
// If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
|
|
9668
|
+
disposeOfMediaStream(media);
|
|
9669
|
+
subscriber.complete();
|
|
9670
|
+
});
|
|
9671
|
+
})
|
|
9672
|
+
.catch((error) => {
|
|
9673
|
+
getLogger(['devices'])('error', 'Failed to get devices', error);
|
|
9674
|
+
subscriber.error(error);
|
|
9675
|
+
});
|
|
9676
|
+
});
|
|
9677
|
+
};
|
|
9678
|
+
/**
|
|
9679
|
+
* [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
|
|
9680
|
+
*
|
|
9681
|
+
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
9682
|
+
*/
|
|
9683
|
+
const checkIfAudioOutputChangeSupported = () => {
|
|
9684
|
+
if (typeof document === 'undefined')
|
|
9685
|
+
return false;
|
|
9686
|
+
const element = document.createElement('audio');
|
|
9687
|
+
return element.sinkId !== undefined;
|
|
9688
|
+
};
|
|
9689
|
+
/**
|
|
9690
|
+
* The default constraints used to request audio devices.
|
|
9691
|
+
*/
|
|
9692
|
+
const audioDeviceConstraints = {
|
|
9693
|
+
audio: {
|
|
9694
|
+
autoGainControl: true,
|
|
9695
|
+
noiseSuppression: true,
|
|
9696
|
+
echoCancellation: true,
|
|
9697
|
+
},
|
|
9698
|
+
};
|
|
9699
|
+
/**
|
|
9700
|
+
* The default constraints used to request video devices.
|
|
9701
|
+
*/
|
|
9702
|
+
const videoDeviceConstraints = {
|
|
9703
|
+
video: {
|
|
9704
|
+
width: 1280,
|
|
9705
|
+
height: 720,
|
|
9706
|
+
},
|
|
9707
|
+
};
|
|
9708
|
+
// Audio and video devices are requested in two separate requests: that way users will be presented with two separate prompts -> they can give access to just camera, or just microphone
|
|
9709
|
+
const deviceChange$ = new rxjs.Observable((subscriber) => {
|
|
9710
|
+
var _a, _b;
|
|
9711
|
+
const deviceChangeHandler = () => subscriber.next();
|
|
9712
|
+
(_b = (_a = navigator.mediaDevices).addEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
|
|
9713
|
+
return () => {
|
|
9714
|
+
var _a, _b;
|
|
9715
|
+
return (_b = (_a = navigator.mediaDevices).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
|
|
9716
|
+
};
|
|
9717
|
+
}).pipe(rxjs.debounceTime(500), rxjs.concatMap(() => rxjs.from(navigator.mediaDevices.enumerateDevices())), rxjs.shareReplay(1));
|
|
9718
|
+
const audioDevices$ = rxjs.merge(getDevices(audioDeviceConstraints), deviceChange$).pipe(rxjs.shareReplay(1));
|
|
9719
|
+
const videoDevices$ = rxjs.merge(getDevices(videoDeviceConstraints), deviceChange$).pipe(rxjs.shareReplay(1));
|
|
9720
|
+
/**
|
|
9721
|
+
* Prompts the user for a permission to use audio devices (if not already granted) and lists the available 'audioinput' devices, if devices are added/removed the list is updated.
|
|
9722
|
+
*
|
|
9723
|
+
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
9724
|
+
* @returns
|
|
9725
|
+
*/
|
|
9726
|
+
const getAudioDevices = () => audioDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'audioinput')));
|
|
9727
|
+
/**
|
|
9728
|
+
* Prompts the user for a permission to use video devices (if not already granted) and lists the available 'videoinput' devices, if devices are added/removed the list is updated.
|
|
9729
|
+
*
|
|
9730
|
+
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
9731
|
+
* @returns
|
|
9732
|
+
*/
|
|
9733
|
+
const getVideoDevices = () => videoDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'videoinput' && d.deviceId.length)));
|
|
9734
|
+
/**
|
|
9735
|
+
* Prompts the user for a permission to use audio devices (if not already granted) and lists the available 'audiooutput' devices, if devices are added/removed the list is updated. Selecting 'audiooutput' device only makes sense if [the browser has support for changing audio output on 'audio' elements](#checkifaudiooutputchangesupported)
|
|
9736
|
+
*
|
|
9737
|
+
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
9738
|
+
* @returns
|
|
9739
|
+
*/
|
|
9740
|
+
const getAudioOutputDevices = () => {
|
|
9741
|
+
return audioDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'audiooutput')));
|
|
9742
|
+
};
|
|
9743
|
+
const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
9744
|
+
try {
|
|
9745
|
+
return yield navigator.mediaDevices.getUserMedia(constraints);
|
|
9746
|
+
}
|
|
9747
|
+
catch (e) {
|
|
9748
|
+
getLogger(['devices'])('error', `Failed get user media`, {
|
|
9749
|
+
error: e,
|
|
9750
|
+
constraints: constraints,
|
|
9751
|
+
});
|
|
9752
|
+
throw e;
|
|
9753
|
+
}
|
|
9754
|
+
});
|
|
9755
|
+
/**
|
|
9756
|
+
* Returns an audio media stream that fulfills the given constraints.
|
|
9757
|
+
* If no constraints are provided, it uses the browser's default ones.
|
|
9758
|
+
*
|
|
9759
|
+
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
9760
|
+
* @param trackConstraints the constraints to use when requesting the stream.
|
|
9761
|
+
* @returns the new `MediaStream` fulfilling the given constraints.
|
|
9762
|
+
*/
|
|
9763
|
+
const getAudioStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
9764
|
+
const constraints = {
|
|
9765
|
+
audio: Object.assign(Object.assign({}, audioDeviceConstraints.audio), trackConstraints),
|
|
9766
|
+
};
|
|
9767
|
+
return getStream(constraints);
|
|
9768
|
+
});
|
|
9769
|
+
/**
|
|
9770
|
+
* Returns a video media stream that fulfills the given constraints.
|
|
9771
|
+
* If no constraints are provided, it uses the browser's default ones.
|
|
9772
|
+
*
|
|
9773
|
+
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
9774
|
+
* @param trackConstraints the constraints to use when requesting the stream.
|
|
9775
|
+
* @returns a new `MediaStream` fulfilling the given constraints.
|
|
9776
|
+
*/
|
|
9777
|
+
const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
9778
|
+
const constraints = {
|
|
9779
|
+
video: Object.assign(Object.assign({}, videoDeviceConstraints.video), trackConstraints),
|
|
9780
|
+
};
|
|
9781
|
+
return getStream(constraints);
|
|
9782
|
+
});
|
|
9783
|
+
/**
|
|
9784
|
+
* Prompts the user for a permission to share a screen.
|
|
9785
|
+
* If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
|
|
9786
|
+
*
|
|
9787
|
+
* The callers of this API are responsible to handle the possible errors.
|
|
9788
|
+
*
|
|
9789
|
+
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
9790
|
+
*
|
|
9791
|
+
* @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
|
|
9792
|
+
*/
|
|
9793
|
+
const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
9794
|
+
try {
|
|
9795
|
+
return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
|
|
9796
|
+
}
|
|
9797
|
+
catch (e) {
|
|
9798
|
+
getLogger(['devices'])('error', 'Failed to get screen share stream', e);
|
|
9799
|
+
throw e;
|
|
9800
|
+
}
|
|
9801
|
+
});
|
|
9802
|
+
const watchForDisconnectedDevice = (kind, deviceId$) => {
|
|
9803
|
+
let devices$;
|
|
9804
|
+
switch (kind) {
|
|
9805
|
+
case 'audioinput':
|
|
9806
|
+
devices$ = getAudioDevices();
|
|
9807
|
+
break;
|
|
9808
|
+
case 'videoinput':
|
|
9809
|
+
devices$ = getVideoDevices();
|
|
9810
|
+
break;
|
|
9811
|
+
case 'audiooutput':
|
|
9812
|
+
devices$ = getAudioOutputDevices();
|
|
9813
|
+
break;
|
|
9814
|
+
}
|
|
9815
|
+
return rxjs.combineLatest([devices$, deviceId$]).pipe(rxjs.filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), rxjs.map(() => true));
|
|
9816
|
+
};
|
|
9817
|
+
/**
|
|
9818
|
+
* Notifies the subscriber if a given 'audioinput' device is disconnected
|
|
9819
|
+
*
|
|
9820
|
+
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
9821
|
+
* @param deviceId$ an Observable that specifies which device to watch for
|
|
9822
|
+
* @returns
|
|
9823
|
+
*/
|
|
9824
|
+
const watchForDisconnectedAudioDevice = (deviceId$) => {
|
|
9825
|
+
return watchForDisconnectedDevice('audioinput', deviceId$);
|
|
9826
|
+
};
|
|
9827
|
+
/**
|
|
9828
|
+
* Notifies the subscriber if a given 'videoinput' device is disconnected
|
|
9829
|
+
*
|
|
9830
|
+
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
9831
|
+
* @param deviceId$ an Observable that specifies which device to watch for
|
|
9832
|
+
* @returns
|
|
9833
|
+
*/
|
|
9834
|
+
const watchForDisconnectedVideoDevice = (deviceId$) => {
|
|
9835
|
+
return watchForDisconnectedDevice('videoinput', deviceId$);
|
|
9836
|
+
};
|
|
9837
|
+
/**
|
|
9838
|
+
* Notifies the subscriber if a given 'audiooutput' device is disconnected
|
|
9839
|
+
*
|
|
9840
|
+
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
9841
|
+
* @param deviceId$ an Observable that specifies which device to watch for
|
|
9842
|
+
* @returns
|
|
9843
|
+
*/
|
|
9844
|
+
const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
|
|
9845
|
+
return watchForDisconnectedDevice('audiooutput', deviceId$);
|
|
9846
|
+
};
|
|
9847
|
+
const watchForAddedDefaultDevice = (kind) => {
|
|
9848
|
+
let devices$;
|
|
9849
|
+
switch (kind) {
|
|
9850
|
+
case 'audioinput':
|
|
9851
|
+
devices$ = getAudioDevices();
|
|
9852
|
+
break;
|
|
9853
|
+
case 'videoinput':
|
|
9854
|
+
devices$ = getVideoDevices();
|
|
9855
|
+
break;
|
|
9856
|
+
case 'audiooutput':
|
|
9857
|
+
devices$ = getAudioOutputDevices();
|
|
9858
|
+
break;
|
|
9859
|
+
default:
|
|
9860
|
+
throw new Error('Unknown MediaDeviceKind', kind);
|
|
9861
|
+
}
|
|
9862
|
+
return devices$.pipe(rxjs.pairwise(), rxjs.filter(([prev, current]) => {
|
|
9863
|
+
const prevDefault = prev.find((device) => device.deviceId === 'default');
|
|
9864
|
+
const currentDefault = current.find((device) => device.deviceId === 'default');
|
|
9865
|
+
return !!(current.length > prev.length &&
|
|
9866
|
+
prevDefault &&
|
|
9867
|
+
currentDefault &&
|
|
9868
|
+
prevDefault.groupId !== currentDefault.groupId);
|
|
9869
|
+
}), rxjs.map(() => true));
|
|
9870
|
+
};
|
|
9871
|
+
/**
|
|
9872
|
+
* Notifies the subscriber about newly added default audio input device.
|
|
9873
|
+
* @returns Observable<boolean>
|
|
9874
|
+
*/
|
|
9875
|
+
const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
|
|
9876
|
+
/**
|
|
9877
|
+
* Notifies the subscriber about newly added default audio output device.
|
|
9878
|
+
* @returns Observable<boolean>
|
|
9879
|
+
*/
|
|
9880
|
+
const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
|
|
9881
|
+
/**
|
|
9882
|
+
* Notifies the subscriber about newly added default video input device.
|
|
9883
|
+
* @returns Observable<boolean>
|
|
9884
|
+
*/
|
|
9885
|
+
const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
|
|
9886
|
+
/**
|
|
9887
|
+
* Deactivates MediaStream (stops and removes tracks) to be later garbage collected
|
|
9888
|
+
*
|
|
9889
|
+
* @param stream MediaStream
|
|
9890
|
+
* @returns void
|
|
9891
|
+
*/
|
|
9892
|
+
const disposeOfMediaStream = (stream) => {
|
|
9893
|
+
if (!stream.active)
|
|
9894
|
+
return;
|
|
9895
|
+
stream.getTracks().forEach((track) => {
|
|
9896
|
+
track.stop();
|
|
9897
|
+
stream.removeTrack(track);
|
|
9898
|
+
});
|
|
9899
|
+
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
|
|
9900
|
+
if (typeof stream.release === 'function') {
|
|
9901
|
+
// @ts-expect-error
|
|
9902
|
+
stream.release();
|
|
9903
|
+
}
|
|
9904
|
+
};
|
|
9905
|
+
|
|
9906
|
+
class InputMediaDeviceManager {
|
|
9907
|
+
constructor(call, state) {
|
|
9908
|
+
this.call = call;
|
|
9909
|
+
this.state = state;
|
|
9910
|
+
}
|
|
9911
|
+
/**
|
|
9912
|
+
* Lists the available audio/video devices
|
|
9913
|
+
*
|
|
9914
|
+
* Note: It prompts the user for a permission to use devices (if not already granted)
|
|
9915
|
+
*
|
|
9916
|
+
* @returns an Observable that will be updated if a device is connected or disconnected
|
|
9917
|
+
*/
|
|
9918
|
+
listDevices() {
|
|
9919
|
+
return this.getDevices();
|
|
9920
|
+
}
|
|
9921
|
+
/**
|
|
9922
|
+
* Starts camera/microphone
|
|
9923
|
+
*/
|
|
9924
|
+
enable() {
|
|
9925
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9926
|
+
if (this.state.status === 'enabled') {
|
|
9927
|
+
return;
|
|
9928
|
+
}
|
|
9929
|
+
yield this.startStream();
|
|
9930
|
+
this.state.setStatus('enabled');
|
|
9931
|
+
});
|
|
9932
|
+
}
|
|
9933
|
+
/**
|
|
9934
|
+
* Stops camera/microphone
|
|
9935
|
+
* @returns
|
|
9936
|
+
*/
|
|
9937
|
+
disable() {
|
|
9938
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9939
|
+
if (this.state.status === 'disabled') {
|
|
9940
|
+
return;
|
|
9941
|
+
}
|
|
9942
|
+
yield this.stopStream();
|
|
9943
|
+
this.state.setStatus('disabled');
|
|
9944
|
+
});
|
|
9945
|
+
}
|
|
9946
|
+
/**
|
|
9947
|
+
* If current device statis is disabled, it will enable the device, else it will disable it.
|
|
9948
|
+
* @returns
|
|
9949
|
+
*/
|
|
9950
|
+
toggle() {
|
|
9951
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9952
|
+
if (this.state.status === 'enabled') {
|
|
9953
|
+
return this.disable();
|
|
9954
|
+
}
|
|
9955
|
+
else {
|
|
9956
|
+
return this.enable();
|
|
9957
|
+
}
|
|
9958
|
+
});
|
|
9959
|
+
}
|
|
9960
|
+
/**
|
|
9961
|
+
* Select device
|
|
9962
|
+
*
|
|
9963
|
+
* Note: this method is not supported in React Native
|
|
9964
|
+
*
|
|
9965
|
+
* @param deviceId
|
|
9966
|
+
*/
|
|
9967
|
+
select(deviceId) {
|
|
9968
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9969
|
+
if (isReactNative()) {
|
|
9970
|
+
throw new Error('This method is not supported in React Native');
|
|
9971
|
+
}
|
|
9972
|
+
if (deviceId === this.state.selectedDevice) {
|
|
9973
|
+
return;
|
|
9974
|
+
}
|
|
9975
|
+
this.state.setDevice(deviceId);
|
|
9976
|
+
yield this.applySettingsToStream();
|
|
9977
|
+
});
|
|
9978
|
+
}
|
|
9979
|
+
applySettingsToStream() {
|
|
9980
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9981
|
+
if (this.state.status === 'enabled') {
|
|
9982
|
+
yield this.stopStream();
|
|
9983
|
+
yield this.startStream();
|
|
9984
|
+
}
|
|
9985
|
+
});
|
|
9986
|
+
}
|
|
9987
|
+
stopStream() {
|
|
9988
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9989
|
+
if (!this.state.mediaStream) {
|
|
9990
|
+
return;
|
|
9991
|
+
}
|
|
9992
|
+
if (this.call.state.callingState === exports.CallingState.JOINED) {
|
|
9993
|
+
yield this.stopPublishStream();
|
|
9994
|
+
}
|
|
9995
|
+
else if (this.state.mediaStream) {
|
|
9996
|
+
disposeOfMediaStream(this.state.mediaStream);
|
|
9997
|
+
}
|
|
9998
|
+
this.state.setMediaStream(undefined);
|
|
9999
|
+
});
|
|
10000
|
+
}
|
|
10001
|
+
startStream() {
|
|
10002
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
10003
|
+
if (this.state.mediaStream) {
|
|
10004
|
+
return;
|
|
10005
|
+
}
|
|
10006
|
+
const constraints = { deviceId: this.state.selectedDevice };
|
|
10007
|
+
const stream = yield this.getStream(constraints);
|
|
10008
|
+
if (this.call.state.callingState === exports.CallingState.JOINED) {
|
|
10009
|
+
yield this.publishStream(stream);
|
|
10010
|
+
}
|
|
10011
|
+
this.state.setMediaStream(stream);
|
|
10012
|
+
});
|
|
10013
|
+
}
|
|
10014
|
+
}
|
|
10015
|
+
|
|
10016
|
+
class CameraManager extends InputMediaDeviceManager {
|
|
10017
|
+
constructor(call) {
|
|
10018
|
+
super(call, new CameraManagerState());
|
|
10019
|
+
}
|
|
10020
|
+
/**
|
|
10021
|
+
* Select the camera direaction
|
|
10022
|
+
* @param direction
|
|
10023
|
+
*/
|
|
10024
|
+
selectDirection(direction) {
|
|
10025
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
10026
|
+
this.state.setDirection(direction);
|
|
10027
|
+
// Providing both device id and direction doesn't work, so we deselect the device
|
|
10028
|
+
this.state.setDevice(undefined);
|
|
10029
|
+
yield this.applySettingsToStream();
|
|
10030
|
+
});
|
|
10031
|
+
}
|
|
10032
|
+
/**
|
|
10033
|
+
* Flips the camera direction: if it's front it will change to back, if it's back, it will change to front.
|
|
10034
|
+
*
|
|
10035
|
+
* Note: if there is no available camera with the desired direction, this method will do nothing.
|
|
10036
|
+
* @returns
|
|
10037
|
+
*/
|
|
10038
|
+
flip() {
|
|
10039
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
10040
|
+
const newDirection = this.state.direction === 'front' ? 'back' : 'front';
|
|
10041
|
+
this.selectDirection(newDirection);
|
|
10042
|
+
});
|
|
10043
|
+
}
|
|
10044
|
+
getDevices() {
|
|
10045
|
+
return getVideoDevices();
|
|
10046
|
+
}
|
|
10047
|
+
getStream(constraints) {
|
|
10048
|
+
// We can't set both device id and facing mode
|
|
10049
|
+
// Device id has higher priority
|
|
10050
|
+
if (!constraints.deviceId && this.state.direction) {
|
|
10051
|
+
constraints.facingMode =
|
|
10052
|
+
this.state.direction === 'front' ? 'user' : 'environment';
|
|
10053
|
+
}
|
|
10054
|
+
return getVideoStream(constraints);
|
|
10055
|
+
}
|
|
10056
|
+
publishStream(stream) {
|
|
10057
|
+
return this.call.publishVideoStream(stream);
|
|
10058
|
+
}
|
|
10059
|
+
stopPublishStream() {
|
|
10060
|
+
return this.call.stopPublish(TrackType.VIDEO);
|
|
10061
|
+
}
|
|
10062
|
+
/**
|
|
10063
|
+
* Disables the video tracks of the camera
|
|
10064
|
+
*/
|
|
10065
|
+
pause() {
|
|
10066
|
+
var _a;
|
|
10067
|
+
(_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
|
|
10068
|
+
track.enabled = false;
|
|
10069
|
+
});
|
|
10070
|
+
}
|
|
10071
|
+
/**
|
|
10072
|
+
* (Re)enables the video tracks of the camera
|
|
10073
|
+
*/
|
|
10074
|
+
resume() {
|
|
10075
|
+
var _a;
|
|
10076
|
+
(_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
|
|
10077
|
+
track.enabled = true;
|
|
10078
|
+
});
|
|
10079
|
+
}
|
|
10080
|
+
}
|
|
10081
|
+
|
|
10082
|
+
class MicrophoneManagerState extends InputMediaDeviceManagerState {
|
|
10083
|
+
getDeviceIdFromStream(stream) {
|
|
10084
|
+
var _a;
|
|
10085
|
+
return (_a = stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
|
|
10086
|
+
}
|
|
10087
|
+
}
|
|
10088
|
+
|
|
10089
|
+
class MicrophoneManager extends InputMediaDeviceManager {
|
|
10090
|
+
constructor(call) {
|
|
10091
|
+
super(call, new MicrophoneManagerState());
|
|
10092
|
+
}
|
|
10093
|
+
getDevices() {
|
|
10094
|
+
return getAudioDevices();
|
|
10095
|
+
}
|
|
10096
|
+
getStream(constraints) {
|
|
10097
|
+
return getAudioStream(constraints);
|
|
10098
|
+
}
|
|
10099
|
+
publishStream(stream) {
|
|
10100
|
+
return this.call.publishAudioStream(stream);
|
|
10101
|
+
}
|
|
10102
|
+
stopPublishStream() {
|
|
10103
|
+
return this.call.stopPublish(TrackType.AUDIO);
|
|
10104
|
+
}
|
|
10105
|
+
/**
|
|
10106
|
+
* Disables the audio tracks of the microphone
|
|
10107
|
+
*/
|
|
10108
|
+
pause() {
|
|
10109
|
+
var _a;
|
|
10110
|
+
(_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
|
|
10111
|
+
track.enabled = false;
|
|
10112
|
+
});
|
|
10113
|
+
}
|
|
10114
|
+
/**
|
|
10115
|
+
* (Re)enables the audio tracks of the microphone
|
|
10116
|
+
*/
|
|
10117
|
+
resume() {
|
|
10118
|
+
var _a;
|
|
10119
|
+
(_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
|
|
10120
|
+
track.enabled = true;
|
|
10121
|
+
});
|
|
10122
|
+
}
|
|
10123
|
+
}
|
|
10124
|
+
|
|
10125
|
+
/**
|
|
9634
10126
|
* An object representation of a `Call`.
|
|
9635
10127
|
*/
|
|
9636
10128
|
class Call {
|
|
@@ -9641,7 +10133,7 @@ class Call {
|
|
|
9641
10133
|
* Use the [`StreamVideoClient.call`](./StreamVideoClient.md/#call)
|
|
9642
10134
|
* method to construct a `Call` instance.
|
|
9643
10135
|
*/
|
|
9644
|
-
constructor({ type, id, streamClient,
|
|
10136
|
+
constructor({ type, id, streamClient, members, ownCapabilities, sortParticipantsBy, clientStore, ringing = false, watching = false, }) {
|
|
9645
10137
|
/**
|
|
9646
10138
|
* ViewportTracker instance
|
|
9647
10139
|
*/
|
|
@@ -9720,7 +10212,7 @@ class Call {
|
|
|
9720
10212
|
if ((params === null || params === void 0 ? void 0 : params.ring) && !this.ringing) {
|
|
9721
10213
|
this.ringingSubject.next(true);
|
|
9722
10214
|
}
|
|
9723
|
-
this.state.
|
|
10215
|
+
this.state.updateFromCallResponse(response.call);
|
|
9724
10216
|
this.state.setMembers(response.members);
|
|
9725
10217
|
this.state.setOwnCapabilities(response.own_capabilities);
|
|
9726
10218
|
if (this.streamClient._hasConnectionID()) {
|
|
@@ -9739,7 +10231,7 @@ class Call {
|
|
|
9739
10231
|
if ((data === null || data === void 0 ? void 0 : data.ring) && !this.ringing) {
|
|
9740
10232
|
this.ringingSubject.next(true);
|
|
9741
10233
|
}
|
|
9742
|
-
this.state.
|
|
10234
|
+
this.state.updateFromCallResponse(response.call);
|
|
9743
10235
|
this.state.setMembers(response.members);
|
|
9744
10236
|
this.state.setOwnCapabilities(response.own_capabilities);
|
|
9745
10237
|
if (this.streamClient._hasConnectionID()) {
|
|
@@ -9796,7 +10288,7 @@ class Call {
|
|
|
9796
10288
|
* @returns a promise which resolves once the call join-flow has finished.
|
|
9797
10289
|
*/
|
|
9798
10290
|
this.join = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
9799
|
-
var _e, _f, _g;
|
|
10291
|
+
var _e, _f, _g, _h;
|
|
9800
10292
|
const callingState = this.state.callingState;
|
|
9801
10293
|
if ([exports.CallingState.JOINED, exports.CallingState.JOINING].includes(callingState)) {
|
|
9802
10294
|
this.logger('warn', 'Join method called twice, you should only call this once');
|
|
@@ -9820,7 +10312,7 @@ class Call {
|
|
|
9820
10312
|
let connectionConfig;
|
|
9821
10313
|
try {
|
|
9822
10314
|
const call = yield join(this.streamClient, this.type, this.id, data);
|
|
9823
|
-
this.state.
|
|
10315
|
+
this.state.updateFromCallResponse(call.metadata);
|
|
9824
10316
|
this.state.setMembers(call.members);
|
|
9825
10317
|
this.state.setOwnCapabilities(call.ownCapabilities);
|
|
9826
10318
|
connectionConfig = call.connectionConfig;
|
|
@@ -9985,7 +10477,7 @@ class Call {
|
|
|
9985
10477
|
connectionConfig,
|
|
9986
10478
|
});
|
|
9987
10479
|
}
|
|
9988
|
-
const audioSettings = (_f = this.
|
|
10480
|
+
const audioSettings = (_f = this.state.settings) === null || _f === void 0 ? void 0 : _f.audio;
|
|
9989
10481
|
const isDtxEnabled = !!(audioSettings === null || audioSettings === void 0 ? void 0 : audioSettings.opus_dtx_enabled);
|
|
9990
10482
|
const isRedEnabled = !!(audioSettings === null || audioSettings === void 0 ? void 0 : audioSettings.redundant_coding_enabled);
|
|
9991
10483
|
if (!this.publisher) {
|
|
@@ -10065,6 +10557,11 @@ class Call {
|
|
|
10065
10557
|
this.state.setServerSidePins(pins);
|
|
10066
10558
|
this.reconnectAttempts = 0; // reset the reconnect attempts counter
|
|
10067
10559
|
this.state.setCallingState(exports.CallingState.JOINED);
|
|
10560
|
+
// React uses a different device management for now
|
|
10561
|
+
if (((_h = getSdkInfo()) === null || _h === void 0 ? void 0 : _h.type) !== SdkType.REACT) {
|
|
10562
|
+
this.initCamera();
|
|
10563
|
+
this.initMic();
|
|
10564
|
+
}
|
|
10068
10565
|
// 3. once we have the "joinResponse", and possibly reconciled the local state
|
|
10069
10566
|
// we schedule a fast subscription update for all remote participants
|
|
10070
10567
|
// that were visible before we reconnected or migrated to a new SFU.
|
|
@@ -10187,9 +10684,9 @@ class Call {
|
|
|
10187
10684
|
* @param trackType the track type to stop publishing.
|
|
10188
10685
|
*/
|
|
10189
10686
|
this.stopPublish = (trackType) => __awaiter(this, void 0, void 0, function* () {
|
|
10190
|
-
var
|
|
10687
|
+
var _j;
|
|
10191
10688
|
this.logger('info', `stopPublish ${TrackType[trackType]}`);
|
|
10192
|
-
yield ((
|
|
10689
|
+
yield ((_j = this.publisher) === null || _j === void 0 ? void 0 : _j.unpublishStream(trackType));
|
|
10193
10690
|
});
|
|
10194
10691
|
/**
|
|
10195
10692
|
* Update track subscription configuration for one or more participants.
|
|
@@ -10290,6 +10787,8 @@ class Call {
|
|
|
10290
10787
|
*
|
|
10291
10788
|
*
|
|
10292
10789
|
* @param deviceId the selected device, pass `undefined` to clear the device selection
|
|
10790
|
+
*
|
|
10791
|
+
* @deprecated use call.microphone.select
|
|
10293
10792
|
*/
|
|
10294
10793
|
this.setAudioDevice = (deviceId) => {
|
|
10295
10794
|
if (!this.sfuClient)
|
|
@@ -10304,6 +10803,8 @@ class Call {
|
|
|
10304
10803
|
* This method only stores the selection, if you want to start publishing a media stream call the [`publishVideoStream` method](#publishvideostream) that will set `videoDeviceId` as well.
|
|
10305
10804
|
*
|
|
10306
10805
|
* @param deviceId the selected device, pass `undefined` to clear the device selection
|
|
10806
|
+
*
|
|
10807
|
+
* @deprecated use call.camera.select
|
|
10307
10808
|
*/
|
|
10308
10809
|
this.setVideoDevice = (deviceId) => {
|
|
10309
10810
|
if (!this.sfuClient)
|
|
@@ -10336,8 +10837,8 @@ class Call {
|
|
|
10336
10837
|
* @returns
|
|
10337
10838
|
*/
|
|
10338
10839
|
this.updatePublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
|
|
10339
|
-
var
|
|
10340
|
-
return (
|
|
10840
|
+
var _k;
|
|
10841
|
+
return (_k = this.publisher) === null || _k === void 0 ? void 0 : _k.updateVideoPublishQuality(enabledRids);
|
|
10341
10842
|
});
|
|
10342
10843
|
this.assertCallJoined = () => {
|
|
10343
10844
|
return new Promise((resolve) => {
|
|
@@ -10532,7 +11033,7 @@ class Call {
|
|
|
10532
11033
|
this.update = (updates) => __awaiter(this, void 0, void 0, function* () {
|
|
10533
11034
|
const response = yield this.streamClient.patch(`${this.streamClientBasePath}`, updates);
|
|
10534
11035
|
const { call, members, own_capabilities } = response;
|
|
10535
|
-
this.state.
|
|
11036
|
+
this.state.updateFromCallResponse(call);
|
|
10536
11037
|
this.state.setMembers(members);
|
|
10537
11038
|
this.state.setOwnCapabilities(own_capabilities);
|
|
10538
11039
|
return response;
|
|
@@ -10605,19 +11106,20 @@ class Call {
|
|
|
10605
11106
|
this.scheduleAutoDrop = () => {
|
|
10606
11107
|
if (this.dropTimeout)
|
|
10607
11108
|
clearTimeout(this.dropTimeout);
|
|
10608
|
-
const subscription = this.state.
|
|
10609
|
-
.pipe(rxjs.pairwise(), rxjs.tap(([
|
|
10610
|
-
|
|
11109
|
+
const subscription = this.state.settings$
|
|
11110
|
+
.pipe(rxjs.pairwise(), rxjs.tap(([prevSettings, currentSettings]) => {
|
|
11111
|
+
var _a;
|
|
11112
|
+
if (!currentSettings || !this.clientStore.connectedUser)
|
|
10611
11113
|
return;
|
|
10612
|
-
const isOutgoingCall = this.currentUserId ===
|
|
11114
|
+
const isOutgoingCall = this.currentUserId === ((_a = this.state.createdBy) === null || _a === void 0 ? void 0 : _a.id);
|
|
10613
11115
|
const [prevTimeoutMs, timeoutMs] = isOutgoingCall
|
|
10614
11116
|
? [
|
|
10615
|
-
|
|
10616
|
-
|
|
11117
|
+
prevSettings === null || prevSettings === void 0 ? void 0 : prevSettings.ring.auto_cancel_timeout_ms,
|
|
11118
|
+
currentSettings.ring.auto_cancel_timeout_ms,
|
|
10617
11119
|
]
|
|
10618
11120
|
: [
|
|
10619
|
-
|
|
10620
|
-
|
|
11121
|
+
prevSettings === null || prevSettings === void 0 ? void 0 : prevSettings.ring.incoming_call_timeout_ms,
|
|
11122
|
+
currentSettings.ring.incoming_call_timeout_ms,
|
|
10621
11123
|
];
|
|
10622
11124
|
if (typeof timeoutMs === 'undefined' ||
|
|
10623
11125
|
timeoutMs === prevTimeoutMs ||
|
|
@@ -10634,7 +11136,6 @@ class Call {
|
|
|
10634
11136
|
};
|
|
10635
11137
|
/**
|
|
10636
11138
|
* Retrieves the list of recordings for the current call or call session.
|
|
10637
|
-
* Updates the call state with the returned array of CallRecording objects.
|
|
10638
11139
|
*
|
|
10639
11140
|
* If `callSessionId` is provided, it will return the recordings for that call session.
|
|
10640
11141
|
* Otherwise, all recordings for the current call will be returned.
|
|
@@ -10646,9 +11147,7 @@ class Call {
|
|
|
10646
11147
|
if (callSessionId) {
|
|
10647
11148
|
endpoint = `${endpoint}/${callSessionId}`;
|
|
10648
11149
|
}
|
|
10649
|
-
|
|
10650
|
-
this.state.setCallRecordingsList(response.recordings);
|
|
10651
|
-
return response;
|
|
11150
|
+
return this.streamClient.get(`${endpoint}/recordings`);
|
|
10652
11151
|
});
|
|
10653
11152
|
/**
|
|
10654
11153
|
* Sends a custom event to all call participants.
|
|
@@ -10672,21 +11171,26 @@ class Call {
|
|
|
10672
11171
|
if (participantSorter) {
|
|
10673
11172
|
this.state.setSortParticipantsBy(participantSorter);
|
|
10674
11173
|
}
|
|
10675
|
-
this.state.setMetadata(metadata);
|
|
10676
11174
|
this.state.setMembers(members || []);
|
|
10677
11175
|
this.state.setOwnCapabilities(ownCapabilities || []);
|
|
10678
11176
|
this.state.setCallingState(ringing ? exports.CallingState.RINGING : exports.CallingState.IDLE);
|
|
11177
|
+
this.on('all', (event) => {
|
|
11178
|
+
// update state with the latest event data
|
|
11179
|
+
this.state.updateFromEvent(event);
|
|
11180
|
+
});
|
|
10679
11181
|
this.leaveCallHooks.push(registerEventHandlers(this, this.state, this.dispatcher));
|
|
10680
11182
|
this.registerEffects();
|
|
10681
11183
|
this.leaveCallHooks.push(createSubscription(this.trackSubscriptionsSubject.pipe(rxjs.debounce((v) => rxjs.timer(v.type)), rxjs.map((v) => v.data)), (subscriptions) => { var _a; return (_a = this.sfuClient) === null || _a === void 0 ? void 0 : _a.updateSubscriptions(subscriptions); }));
|
|
11184
|
+
this.camera = new CameraManager(this);
|
|
11185
|
+
this.microphone = new MicrophoneManager(this);
|
|
10682
11186
|
}
|
|
10683
11187
|
registerEffects() {
|
|
10684
11188
|
this.leaveCallHooks.push(
|
|
10685
|
-
// handles updating the permissions context when the
|
|
10686
|
-
createSubscription(this.state.
|
|
10687
|
-
if (!
|
|
11189
|
+
// handles updating the permissions context when the settings change.
|
|
11190
|
+
createSubscription(this.state.settings$, (settings) => {
|
|
11191
|
+
if (!settings)
|
|
10688
11192
|
return;
|
|
10689
|
-
this.permissionsContext.setCallSettings(
|
|
11193
|
+
this.permissionsContext.setCallSettings(settings);
|
|
10690
11194
|
}),
|
|
10691
11195
|
// handle the case when the user permissions are modified.
|
|
10692
11196
|
createSubscription(this.state.ownCapabilities$, (ownCapabilities) => {
|
|
@@ -10710,12 +11214,11 @@ class Call {
|
|
|
10710
11214
|
}
|
|
10711
11215
|
}),
|
|
10712
11216
|
// handles the case when the user is blocked by the call owner.
|
|
10713
|
-
createSubscription(this.state.
|
|
10714
|
-
if (!
|
|
11217
|
+
createSubscription(this.state.blockedUserIds$, (blockedUserIds) => __awaiter(this, void 0, void 0, function* () {
|
|
11218
|
+
if (!blockedUserIds)
|
|
10715
11219
|
return;
|
|
10716
11220
|
const currentUserId = this.currentUserId;
|
|
10717
|
-
if (currentUserId &&
|
|
10718
|
-
metadata.blocked_user_ids.includes(currentUserId)) {
|
|
11221
|
+
if (currentUserId && blockedUserIds.includes(currentUserId)) {
|
|
10719
11222
|
this.logger('info', 'Leaving call because of being blocked');
|
|
10720
11223
|
yield this.leave();
|
|
10721
11224
|
}
|
|
@@ -10767,12 +11270,6 @@ class Call {
|
|
|
10767
11270
|
}
|
|
10768
11271
|
}
|
|
10769
11272
|
}
|
|
10770
|
-
/**
|
|
10771
|
-
* A getter for the call metadata.
|
|
10772
|
-
*/
|
|
10773
|
-
get data() {
|
|
10774
|
-
return this.state.metadata;
|
|
10775
|
-
}
|
|
10776
11273
|
/**
|
|
10777
11274
|
* A flag indicating whether the call is "ringing" type of call.
|
|
10778
11275
|
*/
|
|
@@ -10791,7 +11288,65 @@ class Call {
|
|
|
10791
11288
|
*/
|
|
10792
11289
|
get isCreatedByMe() {
|
|
10793
11290
|
var _a;
|
|
10794
|
-
return ((_a = this.state.
|
|
11291
|
+
return ((_a = this.state.createdBy) === null || _a === void 0 ? void 0 : _a.id) === this.currentUserId;
|
|
11292
|
+
}
|
|
11293
|
+
initCamera() {
|
|
11294
|
+
var _a, _b, _c;
|
|
11295
|
+
if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream) ||
|
|
11296
|
+
!this.permissionsContext.hasPermission('send-video')) {
|
|
11297
|
+
return;
|
|
11298
|
+
}
|
|
11299
|
+
// Set camera direction if it's not yet set
|
|
11300
|
+
// This will also start publishing if camera is enabled
|
|
11301
|
+
if (!this.camera.state.direction && !this.camera.state.selectedDevice) {
|
|
11302
|
+
let defaultDirection = 'front';
|
|
11303
|
+
const backendSetting = (_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.video.camera_facing;
|
|
11304
|
+
if (backendSetting) {
|
|
11305
|
+
defaultDirection = backendSetting === 'front' ? 'front' : 'back';
|
|
11306
|
+
}
|
|
11307
|
+
this.camera.selectDirection(defaultDirection);
|
|
11308
|
+
}
|
|
11309
|
+
else if (this.camera.state.status === 'enabled') {
|
|
11310
|
+
// Publish already started media streams (this is the case if there is a lobby screen before join)
|
|
11311
|
+
// Wait for media stream
|
|
11312
|
+
this.camera.state.mediaStream$
|
|
11313
|
+
.pipe(rxjs.takeWhile((s) => s === undefined, true))
|
|
11314
|
+
.subscribe((stream) => {
|
|
11315
|
+
var _a;
|
|
11316
|
+
if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream)) {
|
|
11317
|
+
this.publishVideoStream(stream);
|
|
11318
|
+
}
|
|
11319
|
+
});
|
|
11320
|
+
}
|
|
11321
|
+
// Apply backend config (this is the case if there is no lobby screen before join)
|
|
11322
|
+
if (this.camera.state.status === undefined &&
|
|
11323
|
+
((_c = this.state.settings) === null || _c === void 0 ? void 0 : _c.video.camera_default_on)) {
|
|
11324
|
+
void this.camera.enable();
|
|
11325
|
+
}
|
|
11326
|
+
}
|
|
11327
|
+
initMic() {
|
|
11328
|
+
var _a, _b;
|
|
11329
|
+
if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream) ||
|
|
11330
|
+
!this.permissionsContext.hasPermission('send-audio')) {
|
|
11331
|
+
return;
|
|
11332
|
+
}
|
|
11333
|
+
// Publish already started media streams (this is the case if there is a lobby screen before join)
|
|
11334
|
+
if (this.microphone.state.status === 'enabled') {
|
|
11335
|
+
// Wait for media stream
|
|
11336
|
+
this.microphone.state.mediaStream$
|
|
11337
|
+
.pipe(rxjs.takeWhile((s) => s === undefined, true))
|
|
11338
|
+
.subscribe((stream) => {
|
|
11339
|
+
var _a;
|
|
11340
|
+
if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream)) {
|
|
11341
|
+
this.publishAudioStream(stream);
|
|
11342
|
+
}
|
|
11343
|
+
});
|
|
11344
|
+
}
|
|
11345
|
+
// Apply backend config (this is the case if there is no lobby screen before join)
|
|
11346
|
+
if (this.microphone.state.status === undefined &&
|
|
11347
|
+
((_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.audio.mic_default_on)) {
|
|
11348
|
+
void this.microphone.enable();
|
|
11349
|
+
}
|
|
10795
11350
|
}
|
|
10796
11351
|
}
|
|
10797
11352
|
|
|
@@ -11904,7 +12459,7 @@ class WSConnectionFallback {
|
|
|
11904
12459
|
}
|
|
11905
12460
|
}
|
|
11906
12461
|
|
|
11907
|
-
const version = '0.
|
|
12462
|
+
const version = '0.3.1';
|
|
11908
12463
|
|
|
11909
12464
|
const logger = getLogger(['location']);
|
|
11910
12465
|
const HINT_URL = `https://hint.stream-io-video.com/`;
|
|
@@ -12598,12 +13153,12 @@ class StreamVideoClient {
|
|
|
12598
13153
|
streamClient: this.streamClient,
|
|
12599
13154
|
id: c.call.id,
|
|
12600
13155
|
type: c.call.type,
|
|
12601
|
-
metadata: c.call,
|
|
12602
13156
|
members: c.members,
|
|
12603
13157
|
ownCapabilities: c.own_capabilities,
|
|
12604
13158
|
watching: data.watch,
|
|
12605
13159
|
clientStore: this.writeableStateStore,
|
|
12606
13160
|
});
|
|
13161
|
+
call.state.updateFromCallResponse(c.call);
|
|
12607
13162
|
if (data.watch) {
|
|
12608
13163
|
this.writeableStateStore.registerCall(call);
|
|
12609
13164
|
}
|
|
@@ -12611,9 +13166,9 @@ class StreamVideoClient {
|
|
|
12611
13166
|
});
|
|
12612
13167
|
return Object.assign(Object.assign({}, response), { calls: calls });
|
|
12613
13168
|
});
|
|
12614
|
-
|
|
12615
|
-
|
|
12616
|
-
|
|
13169
|
+
/**
|
|
13170
|
+
* Returns a list of available data centers available for hosting calls.
|
|
13171
|
+
*/
|
|
12617
13172
|
this.edges = () => __awaiter(this, void 0, void 0, function* () {
|
|
12618
13173
|
return this.streamClient.get(`/edges`);
|
|
12619
13174
|
});
|
|
@@ -12788,14 +13343,15 @@ class StreamVideoClient {
|
|
|
12788
13343
|
return;
|
|
12789
13344
|
}
|
|
12790
13345
|
this.logger('info', `New call created and registered: ${call.cid}`);
|
|
12791
|
-
|
|
13346
|
+
const newCall = new Call({
|
|
12792
13347
|
streamClient: this.streamClient,
|
|
12793
13348
|
type: call.type,
|
|
12794
13349
|
id: call.id,
|
|
12795
|
-
metadata: call,
|
|
12796
13350
|
members,
|
|
12797
13351
|
clientStore: this.writeableStateStore,
|
|
12798
|
-
})
|
|
13352
|
+
});
|
|
13353
|
+
newCall.state.updateFromCallResponse(call);
|
|
13354
|
+
this.writeableStateStore.registerCall(newCall);
|
|
12799
13355
|
}));
|
|
12800
13356
|
this.eventHandlersToUnregister.push(this.on('call.ring', (event) => __awaiter(this, void 0, void 0, function* () {
|
|
12801
13357
|
if (event.type !== 'call.ring')
|
|
@@ -12809,7 +13365,6 @@ class StreamVideoClient {
|
|
|
12809
13365
|
// if `call.created` was received before `call.ring`.
|
|
12810
13366
|
// In that case, we cleanup the already tracked call.
|
|
12811
13367
|
const prevCall = this.writeableStateStore.findCall(call.type, call.id);
|
|
12812
|
-
const prevMetadata = prevCall === null || prevCall === void 0 ? void 0 : prevCall.state.metadata;
|
|
12813
13368
|
yield (prevCall === null || prevCall === void 0 ? void 0 : prevCall.leave());
|
|
12814
13369
|
// we create a new call
|
|
12815
13370
|
const theCall = new Call({
|
|
@@ -12819,8 +13374,8 @@ class StreamVideoClient {
|
|
|
12819
13374
|
members,
|
|
12820
13375
|
clientStore: this.writeableStateStore,
|
|
12821
13376
|
ringing: true,
|
|
12822
|
-
metadata: prevMetadata,
|
|
12823
13377
|
});
|
|
13378
|
+
theCall.state.updateFromCallResponse(call);
|
|
12824
13379
|
// we fetch the latest metadata for the call from the server
|
|
12825
13380
|
yield theCall.get();
|
|
12826
13381
|
this.writeableStateStore.registerCall(theCall);
|
|
@@ -12878,254 +13433,6 @@ class StreamVideoServerClient extends StreamVideoClient {
|
|
|
12878
13433
|
}
|
|
12879
13434
|
}
|
|
12880
13435
|
|
|
12881
|
-
const getDevices = (constraints) => {
|
|
12882
|
-
return new rxjs.Observable((subscriber) => {
|
|
12883
|
-
navigator.mediaDevices
|
|
12884
|
-
.getUserMedia(constraints)
|
|
12885
|
-
.then((media) => {
|
|
12886
|
-
// in Firefox, devices can be enumerated after userMedia is requested
|
|
12887
|
-
// and permissions granted. Otherwise, device labels are empty
|
|
12888
|
-
navigator.mediaDevices.enumerateDevices().then((devices) => {
|
|
12889
|
-
subscriber.next(devices);
|
|
12890
|
-
// If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
|
|
12891
|
-
disposeOfMediaStream(media);
|
|
12892
|
-
subscriber.complete();
|
|
12893
|
-
});
|
|
12894
|
-
})
|
|
12895
|
-
.catch((error) => {
|
|
12896
|
-
getLogger(['devices'])('error', 'Failed to get devices', error);
|
|
12897
|
-
subscriber.error(error);
|
|
12898
|
-
});
|
|
12899
|
-
});
|
|
12900
|
-
};
|
|
12901
|
-
/**
|
|
12902
|
-
* [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
|
|
12903
|
-
*
|
|
12904
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
12905
|
-
*/
|
|
12906
|
-
const checkIfAudioOutputChangeSupported = () => {
|
|
12907
|
-
if (typeof document === 'undefined')
|
|
12908
|
-
return false;
|
|
12909
|
-
const element = document.createElement('audio');
|
|
12910
|
-
return element.sinkId !== undefined;
|
|
12911
|
-
};
|
|
12912
|
-
/**
|
|
12913
|
-
* The default constraints used to request audio devices.
|
|
12914
|
-
*/
|
|
12915
|
-
const audioDeviceConstraints = {
|
|
12916
|
-
audio: {
|
|
12917
|
-
autoGainControl: true,
|
|
12918
|
-
noiseSuppression: true,
|
|
12919
|
-
echoCancellation: true,
|
|
12920
|
-
},
|
|
12921
|
-
};
|
|
12922
|
-
/**
|
|
12923
|
-
* The default constraints used to request video devices.
|
|
12924
|
-
*/
|
|
12925
|
-
const videoDeviceConstraints = {
|
|
12926
|
-
video: {
|
|
12927
|
-
width: 1280,
|
|
12928
|
-
height: 720,
|
|
12929
|
-
},
|
|
12930
|
-
};
|
|
12931
|
-
// Audio and video devices are requested in two separate requests: that way users will be presented with two separate prompts -> they can give access to just camera, or just microphone
|
|
12932
|
-
const deviceChange$ = new rxjs.Observable((subscriber) => {
|
|
12933
|
-
var _a, _b;
|
|
12934
|
-
const deviceChangeHandler = () => subscriber.next();
|
|
12935
|
-
(_b = (_a = navigator.mediaDevices).addEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
|
|
12936
|
-
return () => {
|
|
12937
|
-
var _a, _b;
|
|
12938
|
-
return (_b = (_a = navigator.mediaDevices).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
|
|
12939
|
-
};
|
|
12940
|
-
}).pipe(rxjs.debounceTime(500), rxjs.concatMap(() => rxjs.from(navigator.mediaDevices.enumerateDevices())), rxjs.shareReplay(1));
|
|
12941
|
-
const audioDevices$ = rxjs.merge(getDevices(audioDeviceConstraints), deviceChange$).pipe(rxjs.shareReplay(1));
|
|
12942
|
-
const videoDevices$ = rxjs.merge(getDevices(videoDeviceConstraints), deviceChange$).pipe(rxjs.shareReplay(1));
|
|
12943
|
-
/**
|
|
12944
|
-
* Prompts the user for a permission to use audio devices (if not already granted) and lists the available 'audioinput' devices, if devices are added/removed the list is updated.
|
|
12945
|
-
*
|
|
12946
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
12947
|
-
* @returns
|
|
12948
|
-
*/
|
|
12949
|
-
const getAudioDevices = () => audioDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'audioinput')));
|
|
12950
|
-
/**
|
|
12951
|
-
* Prompts the user for a permission to use video devices (if not already granted) and lists the available 'videoinput' devices, if devices are added/removed the list is updated.
|
|
12952
|
-
*
|
|
12953
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
12954
|
-
* @returns
|
|
12955
|
-
*/
|
|
12956
|
-
const getVideoDevices = () => videoDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'videoinput' && d.deviceId.length)));
|
|
12957
|
-
/**
|
|
12958
|
-
* Prompts the user for a permission to use audio devices (if not already granted) and lists the available 'audiooutput' devices, if devices are added/removed the list is updated. Selecting 'audiooutput' device only makes sense if [the browser has support for changing audio output on 'audio' elements](#checkifaudiooutputchangesupported)
|
|
12959
|
-
*
|
|
12960
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
12961
|
-
* @returns
|
|
12962
|
-
*/
|
|
12963
|
-
const getAudioOutputDevices = () => {
|
|
12964
|
-
return audioDevices$.pipe(rxjs.map((values) => values.filter((d) => d.kind === 'audiooutput')));
|
|
12965
|
-
};
|
|
12966
|
-
const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
12967
|
-
try {
|
|
12968
|
-
return yield navigator.mediaDevices.getUserMedia(constraints);
|
|
12969
|
-
}
|
|
12970
|
-
catch (e) {
|
|
12971
|
-
getLogger(['devices'])('error', `Failed get user media`, {
|
|
12972
|
-
error: e,
|
|
12973
|
-
constraints: constraints,
|
|
12974
|
-
});
|
|
12975
|
-
throw e;
|
|
12976
|
-
}
|
|
12977
|
-
});
|
|
12978
|
-
/**
|
|
12979
|
-
* Returns an audio media stream that fulfills the given constraints.
|
|
12980
|
-
* If no constraints are provided, it uses the browser's default ones.
|
|
12981
|
-
*
|
|
12982
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
12983
|
-
* @param trackConstraints the constraints to use when requesting the stream.
|
|
12984
|
-
* @returns the new `MediaStream` fulfilling the given constraints.
|
|
12985
|
-
*/
|
|
12986
|
-
const getAudioStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
12987
|
-
const constraints = {
|
|
12988
|
-
audio: Object.assign(Object.assign({}, audioDeviceConstraints.audio), trackConstraints),
|
|
12989
|
-
};
|
|
12990
|
-
return getStream(constraints);
|
|
12991
|
-
});
|
|
12992
|
-
/**
|
|
12993
|
-
* Returns a video media stream that fulfills the given constraints.
|
|
12994
|
-
* If no constraints are provided, it uses the browser's default ones.
|
|
12995
|
-
*
|
|
12996
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
12997
|
-
* @param trackConstraints the constraints to use when requesting the stream.
|
|
12998
|
-
* @returns a new `MediaStream` fulfilling the given constraints.
|
|
12999
|
-
*/
|
|
13000
|
-
const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
13001
|
-
const constraints = {
|
|
13002
|
-
video: Object.assign(Object.assign({}, videoDeviceConstraints.video), trackConstraints),
|
|
13003
|
-
};
|
|
13004
|
-
return getStream(constraints);
|
|
13005
|
-
});
|
|
13006
|
-
/**
|
|
13007
|
-
* Prompts the user for a permission to share a screen.
|
|
13008
|
-
* If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
|
|
13009
|
-
*
|
|
13010
|
-
* The callers of this API are responsible to handle the possible errors.
|
|
13011
|
-
*
|
|
13012
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
13013
|
-
*
|
|
13014
|
-
* @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
|
|
13015
|
-
*/
|
|
13016
|
-
const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
13017
|
-
try {
|
|
13018
|
-
return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
|
|
13019
|
-
}
|
|
13020
|
-
catch (e) {
|
|
13021
|
-
getLogger(['devices'])('error', 'Failed to get screen share stream', e);
|
|
13022
|
-
throw e;
|
|
13023
|
-
}
|
|
13024
|
-
});
|
|
13025
|
-
const watchForDisconnectedDevice = (kind, deviceId$) => {
|
|
13026
|
-
let devices$;
|
|
13027
|
-
switch (kind) {
|
|
13028
|
-
case 'audioinput':
|
|
13029
|
-
devices$ = getAudioDevices();
|
|
13030
|
-
break;
|
|
13031
|
-
case 'videoinput':
|
|
13032
|
-
devices$ = getVideoDevices();
|
|
13033
|
-
break;
|
|
13034
|
-
case 'audiooutput':
|
|
13035
|
-
devices$ = getAudioOutputDevices();
|
|
13036
|
-
break;
|
|
13037
|
-
}
|
|
13038
|
-
return rxjs.combineLatest([devices$, deviceId$]).pipe(rxjs.filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), rxjs.map(() => true));
|
|
13039
|
-
};
|
|
13040
|
-
/**
|
|
13041
|
-
* Notifies the subscriber if a given 'audioinput' device is disconnected
|
|
13042
|
-
*
|
|
13043
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
13044
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
13045
|
-
* @returns
|
|
13046
|
-
*/
|
|
13047
|
-
const watchForDisconnectedAudioDevice = (deviceId$) => {
|
|
13048
|
-
return watchForDisconnectedDevice('audioinput', deviceId$);
|
|
13049
|
-
};
|
|
13050
|
-
/**
|
|
13051
|
-
* Notifies the subscriber if a given 'videoinput' device is disconnected
|
|
13052
|
-
*
|
|
13053
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
13054
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
13055
|
-
* @returns
|
|
13056
|
-
*/
|
|
13057
|
-
const watchForDisconnectedVideoDevice = (deviceId$) => {
|
|
13058
|
-
return watchForDisconnectedDevice('videoinput', deviceId$);
|
|
13059
|
-
};
|
|
13060
|
-
/**
|
|
13061
|
-
* Notifies the subscriber if a given 'audiooutput' device is disconnected
|
|
13062
|
-
*
|
|
13063
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
13064
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
13065
|
-
* @returns
|
|
13066
|
-
*/
|
|
13067
|
-
const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
|
|
13068
|
-
return watchForDisconnectedDevice('audiooutput', deviceId$);
|
|
13069
|
-
};
|
|
13070
|
-
const watchForAddedDefaultDevice = (kind) => {
|
|
13071
|
-
let devices$;
|
|
13072
|
-
switch (kind) {
|
|
13073
|
-
case 'audioinput':
|
|
13074
|
-
devices$ = getAudioDevices();
|
|
13075
|
-
break;
|
|
13076
|
-
case 'videoinput':
|
|
13077
|
-
devices$ = getVideoDevices();
|
|
13078
|
-
break;
|
|
13079
|
-
case 'audiooutput':
|
|
13080
|
-
devices$ = getAudioOutputDevices();
|
|
13081
|
-
break;
|
|
13082
|
-
default:
|
|
13083
|
-
throw new Error('Unknown MediaDeviceKind', kind);
|
|
13084
|
-
}
|
|
13085
|
-
return devices$.pipe(rxjs.pairwise(), rxjs.filter(([prev, current]) => {
|
|
13086
|
-
const prevDefault = prev.find((device) => device.deviceId === 'default');
|
|
13087
|
-
const currentDefault = current.find((device) => device.deviceId === 'default');
|
|
13088
|
-
return !!(current.length > prev.length &&
|
|
13089
|
-
prevDefault &&
|
|
13090
|
-
currentDefault &&
|
|
13091
|
-
prevDefault.groupId !== currentDefault.groupId);
|
|
13092
|
-
}), rxjs.map(() => true));
|
|
13093
|
-
};
|
|
13094
|
-
/**
|
|
13095
|
-
* Notifies the subscriber about newly added default audio input device.
|
|
13096
|
-
* @returns Observable<boolean>
|
|
13097
|
-
*/
|
|
13098
|
-
const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
|
|
13099
|
-
/**
|
|
13100
|
-
* Notifies the subscriber about newly added default audio output device.
|
|
13101
|
-
* @returns Observable<boolean>
|
|
13102
|
-
*/
|
|
13103
|
-
const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
|
|
13104
|
-
/**
|
|
13105
|
-
* Notifies the subscriber about newly added default video input device.
|
|
13106
|
-
* @returns Observable<boolean>
|
|
13107
|
-
*/
|
|
13108
|
-
const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
|
|
13109
|
-
/**
|
|
13110
|
-
* Deactivates MediaStream (stops and removes tracks) to be later garbage collected
|
|
13111
|
-
*
|
|
13112
|
-
* @param stream MediaStream
|
|
13113
|
-
* @returns void
|
|
13114
|
-
*/
|
|
13115
|
-
const disposeOfMediaStream = (stream) => {
|
|
13116
|
-
if (!stream.active)
|
|
13117
|
-
return;
|
|
13118
|
-
stream.getTracks().forEach((track) => {
|
|
13119
|
-
track.stop();
|
|
13120
|
-
stream.removeTrack(track);
|
|
13121
|
-
});
|
|
13122
|
-
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
|
|
13123
|
-
if (typeof stream.release === 'function') {
|
|
13124
|
-
// @ts-expect-error
|
|
13125
|
-
stream.release();
|
|
13126
|
-
}
|
|
13127
|
-
};
|
|
13128
|
-
|
|
13129
13436
|
const DETECTION_FREQUENCY_IN_MS = 500;
|
|
13130
13437
|
const AUDIO_LEVEL_THRESHOLD = 150;
|
|
13131
13438
|
const FFT_SIZE = 128;
|
|
@@ -13217,8 +13524,12 @@ exports.Call = Call;
|
|
|
13217
13524
|
exports.CallState = CallState;
|
|
13218
13525
|
exports.CallType = CallType;
|
|
13219
13526
|
exports.CallTypes = CallTypes;
|
|
13527
|
+
exports.CameraManager = CameraManager;
|
|
13220
13528
|
exports.CreateDeviceRequestPushProviderEnum = CreateDeviceRequestPushProviderEnum;
|
|
13221
13529
|
exports.ErrorFromResponse = ErrorFromResponse;
|
|
13530
|
+
exports.InputMediaDeviceManager = InputMediaDeviceManager;
|
|
13531
|
+
exports.InputMediaDeviceManagerState = InputMediaDeviceManagerState;
|
|
13532
|
+
exports.MicrophoneManager = MicrophoneManager;
|
|
13222
13533
|
exports.OwnCapability = OwnCapability;
|
|
13223
13534
|
exports.RecordSettingsModeEnum = RecordSettingsModeEnum;
|
|
13224
13535
|
exports.RecordSettingsQualityEnum = RecordSettingsQualityEnum;
|