@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.browser.es.js
CHANGED
|
@@ -4,7 +4,7 @@ import { ServiceType, stackIntercept } from '@protobuf-ts/runtime-rpc';
|
|
|
4
4
|
import axios, { AxiosHeaders } from 'axios';
|
|
5
5
|
export { AxiosError } from 'axios';
|
|
6
6
|
import { TwirpFetchTransport } from '@protobuf-ts/twirp-transport';
|
|
7
|
-
import { ReplaySubject, BehaviorSubject,
|
|
7
|
+
import { ReplaySubject, BehaviorSubject, distinctUntilChanged as distinctUntilChanged$1, Observable, debounceTime, concatMap, from, shareReplay, merge, map as map$2, combineLatest, filter, pairwise, takeWhile, tap, debounce, timer } from 'rxjs';
|
|
8
8
|
import * as SDP from 'sdp-transform';
|
|
9
9
|
import WebSocket from 'isomorphic-ws';
|
|
10
10
|
import { take, map as map$1, distinctUntilChanged } from 'rxjs/operators';
|
|
@@ -6520,8 +6520,8 @@ class Publisher {
|
|
|
6520
6520
|
track.removeEventListener('ended', handleTrackEnded);
|
|
6521
6521
|
});
|
|
6522
6522
|
if (!transceiver) {
|
|
6523
|
-
const
|
|
6524
|
-
const targetResolution =
|
|
6523
|
+
const { settings } = this.state;
|
|
6524
|
+
const targetResolution = settings === null || settings === void 0 ? void 0 : settings.video.target_resolution;
|
|
6525
6525
|
const videoEncodings = trackType === TrackType.VIDEO
|
|
6526
6526
|
? findOptimalVideoLayers(track, targetResolution)
|
|
6527
6527
|
: undefined;
|
|
@@ -6799,8 +6799,8 @@ class Publisher {
|
|
|
6799
6799
|
}
|
|
6800
6800
|
return String(media.mid);
|
|
6801
6801
|
};
|
|
6802
|
-
const
|
|
6803
|
-
const targetResolution =
|
|
6802
|
+
const { settings } = this.state;
|
|
6803
|
+
const targetResolution = settings === null || settings === void 0 ? void 0 : settings.video.target_resolution;
|
|
6804
6804
|
return this.pc
|
|
6805
6805
|
.getTransceivers()
|
|
6806
6806
|
.filter((t) => t.direction === 'sendonly' && t.sender.track)
|
|
@@ -6893,7 +6893,6 @@ class Publisher {
|
|
|
6893
6893
|
this.pc = this.createPeerConnection(connectionConfig);
|
|
6894
6894
|
this.sfuClient = sfuClient;
|
|
6895
6895
|
this.state = state;
|
|
6896
|
-
this.dispatcher = dispatcher;
|
|
6897
6896
|
this.isDtxEnabled = isDtxEnabled;
|
|
6898
6897
|
this.isRedEnabled = isRedEnabled;
|
|
6899
6898
|
this.preferredVideoCodec = preferredVideoCodec;
|
|
@@ -7521,17 +7520,6 @@ const retryable = (rpc, logger) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
7521
7520
|
return rpcCallResult;
|
|
7522
7521
|
});
|
|
7523
7522
|
|
|
7524
|
-
/**
|
|
7525
|
-
* Watches for `call.live_started` events.
|
|
7526
|
-
*/
|
|
7527
|
-
const watchCallLiveStarted = (state) => {
|
|
7528
|
-
return function onCallLiveStarted(event) {
|
|
7529
|
-
if (event.type !== 'call.live_started')
|
|
7530
|
-
return;
|
|
7531
|
-
state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { backstage: false })));
|
|
7532
|
-
};
|
|
7533
|
-
};
|
|
7534
|
-
|
|
7535
7523
|
/**
|
|
7536
7524
|
* Gets the current value of an observable, or undefined if the observable has
|
|
7537
7525
|
* not emitted a value yet.
|
|
@@ -7974,71 +7962,29 @@ class CallState {
|
|
|
7974
7962
|
*
|
|
7975
7963
|
*/
|
|
7976
7964
|
constructor() {
|
|
7977
|
-
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
this.
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7965
|
+
this.backstageSubject = new BehaviorSubject(false);
|
|
7966
|
+
this.blockedUserIdsSubject = new BehaviorSubject([]);
|
|
7967
|
+
this.createdAtSubject = new BehaviorSubject(new Date());
|
|
7968
|
+
this.endedAtSubject = new BehaviorSubject(undefined);
|
|
7969
|
+
this.startsAtSubject = new BehaviorSubject(undefined);
|
|
7970
|
+
this.updatedAtSubject = new BehaviorSubject(new Date());
|
|
7971
|
+
this.createdBySubject = new BehaviorSubject(undefined);
|
|
7972
|
+
this.customSubject = new BehaviorSubject({});
|
|
7973
|
+
this.egressSubject = new BehaviorSubject(undefined);
|
|
7974
|
+
this.ingressSubject = new BehaviorSubject(undefined);
|
|
7975
|
+
this.recordingSubject = new BehaviorSubject(false);
|
|
7976
|
+
this.sessionSubject = new BehaviorSubject(undefined);
|
|
7977
|
+
this.settingsSubject = new BehaviorSubject(undefined);
|
|
7978
|
+
this.transcribingSubject = new BehaviorSubject(false);
|
|
7979
|
+
this.endedBySubject = new BehaviorSubject(undefined);
|
|
7988
7980
|
this.membersSubject = new BehaviorSubject([]);
|
|
7989
|
-
/**
|
|
7990
|
-
* The list of capabilities of the current user.
|
|
7991
|
-
*
|
|
7992
|
-
* @private
|
|
7993
|
-
*/
|
|
7994
7981
|
this.ownCapabilitiesSubject = new BehaviorSubject([]);
|
|
7995
|
-
/**
|
|
7996
|
-
* The calling state.
|
|
7997
|
-
*
|
|
7998
|
-
* @internal
|
|
7999
|
-
*/
|
|
8000
7982
|
this.callingStateSubject = new BehaviorSubject(CallingState.UNKNOWN);
|
|
8001
|
-
/**
|
|
8002
|
-
* The time the call session actually started.
|
|
8003
|
-
*
|
|
8004
|
-
* @internal
|
|
8005
|
-
*/
|
|
8006
7983
|
this.startedAtSubject = new BehaviorSubject(undefined);
|
|
8007
|
-
/**
|
|
8008
|
-
* The server-side counted number of participants connected to the current call.
|
|
8009
|
-
* This number includes the anonymous participants as well.
|
|
8010
|
-
*
|
|
8011
|
-
* @internal
|
|
8012
|
-
*/
|
|
8013
7984
|
this.participantCountSubject = new BehaviorSubject(0);
|
|
8014
|
-
/**
|
|
8015
|
-
* The server-side counted number of anonymous participants connected to the current call.
|
|
8016
|
-
* This number excludes the regular participants.
|
|
8017
|
-
*
|
|
8018
|
-
* @internal
|
|
8019
|
-
*/
|
|
8020
7985
|
this.anonymousParticipantCountSubject = new BehaviorSubject(0);
|
|
8021
|
-
/**
|
|
8022
|
-
* All participants of the current call (including the logged-in user).
|
|
8023
|
-
*
|
|
8024
|
-
* @internal
|
|
8025
|
-
*/
|
|
8026
7986
|
this.participantsSubject = new BehaviorSubject([]);
|
|
8027
|
-
/**
|
|
8028
|
-
* The latest stats report of the current call.
|
|
8029
|
-
* When stats gathering is enabled, this observable will emit a new value
|
|
8030
|
-
* at a regular (configurable) interval.
|
|
8031
|
-
*
|
|
8032
|
-
* Consumers of this observable can implement their own batching logic
|
|
8033
|
-
* in case they want to show historical stat data.
|
|
8034
|
-
*
|
|
8035
|
-
* @internal
|
|
8036
|
-
*/
|
|
8037
7987
|
this.callStatsReportSubject = new BehaviorSubject(undefined);
|
|
8038
|
-
/**
|
|
8039
|
-
* Emits a list of details about recordings performed for the current call.
|
|
8040
|
-
*/
|
|
8041
|
-
this.callRecordingListSubject = new BehaviorSubject([]);
|
|
8042
7988
|
/**
|
|
8043
7989
|
* A list of comparators that are used to sort the participants.
|
|
8044
7990
|
*
|
|
@@ -8121,15 +8067,6 @@ class CallState {
|
|
|
8121
8067
|
this.setCallingState = (state) => {
|
|
8122
8068
|
return this.setCurrentValue(this.callingStateSubject, state);
|
|
8123
8069
|
};
|
|
8124
|
-
/**
|
|
8125
|
-
* Sets the list of call recordings.
|
|
8126
|
-
*
|
|
8127
|
-
* @internal
|
|
8128
|
-
* @param recordings the list of call recordings.
|
|
8129
|
-
*/
|
|
8130
|
-
this.setCallRecordingsList = (recordings) => {
|
|
8131
|
-
return this.setCurrentValue(this.callRecordingListSubject, recordings);
|
|
8132
|
-
};
|
|
8133
8070
|
/**
|
|
8134
8071
|
* Sets the call stats report.
|
|
8135
8072
|
*
|
|
@@ -8139,16 +8076,6 @@ class CallState {
|
|
|
8139
8076
|
this.setCallStatsReport = (report) => {
|
|
8140
8077
|
return this.setCurrentValue(this.callStatsReportSubject, report);
|
|
8141
8078
|
};
|
|
8142
|
-
/**
|
|
8143
|
-
* Sets the metadata of the current call.
|
|
8144
|
-
*
|
|
8145
|
-
* @internal
|
|
8146
|
-
*
|
|
8147
|
-
* @param metadata the metadata to set.
|
|
8148
|
-
*/
|
|
8149
|
-
this.setMetadata = (metadata) => {
|
|
8150
|
-
return this.setCurrentValue(this.metadataSubject, metadata);
|
|
8151
|
-
};
|
|
8152
8079
|
/**
|
|
8153
8080
|
* Sets the members of the current call.
|
|
8154
8081
|
*
|
|
@@ -8247,6 +8174,19 @@ class CallState {
|
|
|
8247
8174
|
return p;
|
|
8248
8175
|
}));
|
|
8249
8176
|
};
|
|
8177
|
+
/**
|
|
8178
|
+
* Updates the call state with the data received from the server.
|
|
8179
|
+
*
|
|
8180
|
+
* @internal
|
|
8181
|
+
*
|
|
8182
|
+
* @param event the video event that our backend sent us.
|
|
8183
|
+
*/
|
|
8184
|
+
this.updateFromEvent = (event) => {
|
|
8185
|
+
const update = this.eventHandlers[event.type];
|
|
8186
|
+
if (update) {
|
|
8187
|
+
update(event);
|
|
8188
|
+
}
|
|
8189
|
+
};
|
|
8250
8190
|
/**
|
|
8251
8191
|
* Updates the participant pinned state with server side pinning data.
|
|
8252
8192
|
*
|
|
@@ -8275,25 +8215,174 @@ class CallState {
|
|
|
8275
8215
|
return participant;
|
|
8276
8216
|
}));
|
|
8277
8217
|
};
|
|
8278
|
-
|
|
8218
|
+
/**
|
|
8219
|
+
* Updates the call state with the data received from the server.
|
|
8220
|
+
*
|
|
8221
|
+
* @internal
|
|
8222
|
+
*
|
|
8223
|
+
* @param call the call response from the server.
|
|
8224
|
+
*/
|
|
8225
|
+
this.updateFromCallResponse = (call) => {
|
|
8226
|
+
this.setCurrentValue(this.backstageSubject, call.backstage);
|
|
8227
|
+
this.setCurrentValue(this.blockedUserIdsSubject, call.blocked_user_ids);
|
|
8228
|
+
this.setCurrentValue(this.createdAtSubject, new Date(call.created_at));
|
|
8229
|
+
this.setCurrentValue(this.updatedAtSubject, new Date(call.updated_at));
|
|
8230
|
+
this.setCurrentValue(this.startsAtSubject, call.starts_at ? new Date(call.starts_at) : undefined);
|
|
8231
|
+
this.setCurrentValue(this.endedAtSubject, call.ended_at ? new Date(call.ended_at) : undefined);
|
|
8232
|
+
this.setCurrentValue(this.createdBySubject, call.created_by);
|
|
8233
|
+
this.setCurrentValue(this.customSubject, call.custom);
|
|
8234
|
+
this.setCurrentValue(this.egressSubject, call.egress);
|
|
8235
|
+
this.setCurrentValue(this.ingressSubject, call.ingress);
|
|
8236
|
+
this.setCurrentValue(this.recordingSubject, call.recording);
|
|
8237
|
+
this.setCurrentValue(this.sessionSubject, call.session);
|
|
8238
|
+
this.setCurrentValue(this.settingsSubject, call.settings);
|
|
8239
|
+
this.setCurrentValue(this.transcribingSubject, call.transcribing);
|
|
8240
|
+
};
|
|
8241
|
+
this.updateFromMemberRemoved = (event) => {
|
|
8242
|
+
this.setCurrentValue(this.membersSubject, (members) => members.filter((m) => event.members.indexOf(m.user_id) === -1));
|
|
8243
|
+
};
|
|
8244
|
+
this.updateFromMemberAdded = (event) => {
|
|
8245
|
+
this.setCurrentValue(this.membersSubject, (members) => [
|
|
8246
|
+
...members,
|
|
8247
|
+
...event.members,
|
|
8248
|
+
]);
|
|
8249
|
+
};
|
|
8250
|
+
this.updateFromBroadcastStopped = () => {
|
|
8251
|
+
this.setCurrentValue(this.egressSubject, (egress) => (Object.assign(Object.assign({}, egress), { broadcasting: false })));
|
|
8252
|
+
};
|
|
8253
|
+
this.updateFromBroadcastStarted = (event) => {
|
|
8254
|
+
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 }) })));
|
|
8255
|
+
};
|
|
8256
|
+
this.updateFromSessionParticipantLeft = (event) => {
|
|
8257
|
+
this.setCurrentValue(this.sessionSubject, (session) => {
|
|
8258
|
+
if (!session) {
|
|
8259
|
+
this.logger('warn', `Received call.session_participant_left event but no session is available.`, event);
|
|
8260
|
+
return session;
|
|
8261
|
+
}
|
|
8262
|
+
const { participants, participants_count_by_role } = session;
|
|
8263
|
+
const { user, user_session_id } = event.participant;
|
|
8264
|
+
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) }) });
|
|
8265
|
+
});
|
|
8266
|
+
};
|
|
8267
|
+
this.updateFromSessionParticipantJoined = (event) => {
|
|
8268
|
+
this.setCurrentValue(this.sessionSubject, (session) => {
|
|
8269
|
+
if (!session) {
|
|
8270
|
+
this.logger('warn', `Received call.session_participant_joined event but no session is available.`, event);
|
|
8271
|
+
return session;
|
|
8272
|
+
}
|
|
8273
|
+
const { participants, participants_count_by_role } = session;
|
|
8274
|
+
const { user } = event.participant;
|
|
8275
|
+
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 }) });
|
|
8276
|
+
});
|
|
8277
|
+
};
|
|
8278
|
+
this.updateMembers = (event) => {
|
|
8279
|
+
this.setCurrentValue(this.membersSubject, (members) => members.map((member) => {
|
|
8280
|
+
const memberUpdate = event.members.find((m) => m.user_id === member.user_id);
|
|
8281
|
+
return memberUpdate ? memberUpdate : member;
|
|
8282
|
+
}));
|
|
8283
|
+
};
|
|
8284
|
+
this.updateParticipantReaction = (event) => {
|
|
8285
|
+
const { user, custom, type, emoji_code } = event.reaction;
|
|
8286
|
+
this.setParticipants((participants) => {
|
|
8287
|
+
return participants.map((p) => {
|
|
8288
|
+
// skip if the reaction is not for this participant
|
|
8289
|
+
if (p.userId !== user.id)
|
|
8290
|
+
return p;
|
|
8291
|
+
// update the participant with the new reaction
|
|
8292
|
+
return Object.assign(Object.assign({}, p), { reaction: {
|
|
8293
|
+
type,
|
|
8294
|
+
emoji_code,
|
|
8295
|
+
custom,
|
|
8296
|
+
} });
|
|
8297
|
+
});
|
|
8298
|
+
});
|
|
8299
|
+
};
|
|
8300
|
+
this.unblockUser = (event) => {
|
|
8301
|
+
this.setCurrentValue(this.blockedUserIdsSubject, (current) => {
|
|
8302
|
+
if (!current)
|
|
8303
|
+
return current;
|
|
8304
|
+
return current.filter((id) => id !== event.user.id);
|
|
8305
|
+
});
|
|
8306
|
+
};
|
|
8307
|
+
this.blockUser = (event) => {
|
|
8308
|
+
this.setCurrentValue(this.blockedUserIdsSubject, (current) => [
|
|
8309
|
+
...(current || []),
|
|
8310
|
+
event.user.id,
|
|
8311
|
+
]);
|
|
8312
|
+
};
|
|
8313
|
+
this.updateOwnCapabilities = (event) => {
|
|
8314
|
+
var _a;
|
|
8315
|
+
if (event.user.id === ((_a = this.localParticipant) === null || _a === void 0 ? void 0 : _a.userId)) {
|
|
8316
|
+
this.setCurrentValue(this.ownCapabilitiesSubject, event.own_capabilities);
|
|
8317
|
+
}
|
|
8318
|
+
};
|
|
8319
|
+
this.logger = getLogger(['CallState']);
|
|
8279
8320
|
this.participants$ = this.participantsSubject.pipe(map$1((ps) => ps.sort(this.sortParticipantsBy)));
|
|
8280
8321
|
this.localParticipant$ = this.participants$.pipe(map$1((participants) => participants.find(isStreamVideoLocalParticipant)));
|
|
8281
8322
|
this.remoteParticipants$ = this.participants$.pipe(map$1((participants) => participants.filter((p) => !p.isLocalParticipant)));
|
|
8282
8323
|
this.pinnedParticipants$ = this.participants$.pipe(map$1((participants) => participants.filter((p) => !!p.pin)));
|
|
8283
8324
|
this.dominantSpeaker$ = this.participants$.pipe(map$1((participants) => participants.find((p) => p.isDominantSpeaker)));
|
|
8284
|
-
this.hasOngoingScreenShare$ = this.participants$.pipe(map$1((participants) =>
|
|
8285
|
-
return participants.some((p) => p.publishedTracks.includes(TrackType.SCREEN_SHARE));
|
|
8286
|
-
}), distinctUntilChanged());
|
|
8325
|
+
this.hasOngoingScreenShare$ = this.participants$.pipe(map$1((participants) => participants.some((p) => p.publishedTracks.includes(TrackType.SCREEN_SHARE))), distinctUntilChanged());
|
|
8287
8326
|
this.startedAt$ = this.startedAtSubject.asObservable();
|
|
8288
8327
|
this.participantCount$ = this.participantCountSubject.asObservable();
|
|
8289
8328
|
this.anonymousParticipantCount$ =
|
|
8290
8329
|
this.anonymousParticipantCountSubject.asObservable();
|
|
8291
8330
|
this.callStatsReport$ = this.callStatsReportSubject.asObservable();
|
|
8292
|
-
this.callRecordingList$ = this.callRecordingListSubject.asObservable();
|
|
8293
|
-
this.metadata$ = this.metadataSubject.asObservable();
|
|
8294
8331
|
this.members$ = this.membersSubject.asObservable();
|
|
8295
8332
|
this.ownCapabilities$ = this.ownCapabilitiesSubject.asObservable();
|
|
8296
8333
|
this.callingState$ = this.callingStateSubject.asObservable();
|
|
8334
|
+
this.backstage$ = this.backstageSubject.asObservable();
|
|
8335
|
+
this.blockedUserIds$ = this.blockedUserIdsSubject.asObservable();
|
|
8336
|
+
this.createdAt$ = this.createdAtSubject.asObservable();
|
|
8337
|
+
this.endedAt$ = this.endedAtSubject.asObservable();
|
|
8338
|
+
this.startsAt$ = this.startsAtSubject.asObservable();
|
|
8339
|
+
this.updatedAt$ = this.updatedAtSubject.asObservable();
|
|
8340
|
+
this.createdBy$ = this.createdBySubject.asObservable();
|
|
8341
|
+
this.custom$ = this.customSubject.asObservable();
|
|
8342
|
+
this.egress$ = this.egressSubject.asObservable();
|
|
8343
|
+
this.ingress$ = this.ingressSubject.asObservable();
|
|
8344
|
+
this.recording$ = this.recordingSubject.asObservable();
|
|
8345
|
+
this.session$ = this.sessionSubject.asObservable();
|
|
8346
|
+
this.settings$ = this.settingsSubject.asObservable();
|
|
8347
|
+
this.transcribing$ = this.transcribingSubject.asObservable();
|
|
8348
|
+
this.endedBy$ = this.endedBySubject.asObservable();
|
|
8349
|
+
this.eventHandlers = {
|
|
8350
|
+
// these events are not updating the call state:
|
|
8351
|
+
'call.permission_request': undefined,
|
|
8352
|
+
'call.user_muted': undefined,
|
|
8353
|
+
'connection.error': undefined,
|
|
8354
|
+
'connection.ok': undefined,
|
|
8355
|
+
'health.check': undefined,
|
|
8356
|
+
custom: undefined,
|
|
8357
|
+
// events that update call state:
|
|
8358
|
+
'call.accepted': (e) => this.updateFromCallResponse(e.call),
|
|
8359
|
+
'call.created': (e) => this.updateFromCallResponse(e.call),
|
|
8360
|
+
'call.notification': (e) => this.updateFromCallResponse(e.call),
|
|
8361
|
+
'call.rejected': (e) => this.updateFromCallResponse(e.call),
|
|
8362
|
+
'call.ring': (e) => this.updateFromCallResponse(e.call),
|
|
8363
|
+
'call.live_started': (e) => this.updateFromCallResponse(e.call),
|
|
8364
|
+
'call.updated': (e) => this.updateFromCallResponse(e.call),
|
|
8365
|
+
'call.session_started': (e) => this.updateFromCallResponse(e.call),
|
|
8366
|
+
'call.session_ended': (e) => this.updateFromCallResponse(e.call),
|
|
8367
|
+
'call.ended': (e) => {
|
|
8368
|
+
this.updateFromCallResponse(e.call);
|
|
8369
|
+
this.setCurrentValue(this.endedBySubject, e.user);
|
|
8370
|
+
},
|
|
8371
|
+
'call.recording_started': () => this.setCurrentValue(this.recordingSubject, true),
|
|
8372
|
+
'call.recording_stopped': () => this.setCurrentValue(this.recordingSubject, false),
|
|
8373
|
+
'call.broadcasting_started': this.updateFromBroadcastStarted,
|
|
8374
|
+
'call.broadcasting_stopped': this.updateFromBroadcastStopped,
|
|
8375
|
+
'call.session_participant_joined': this.updateFromSessionParticipantJoined,
|
|
8376
|
+
'call.session_participant_left': this.updateFromSessionParticipantLeft,
|
|
8377
|
+
'call.blocked_user': this.blockUser,
|
|
8378
|
+
'call.unblocked_user': this.unblockUser,
|
|
8379
|
+
'call.permissions_updated': this.updateOwnCapabilities,
|
|
8380
|
+
'call.member_added': this.updateFromMemberAdded,
|
|
8381
|
+
'call.member_removed': this.updateFromMemberRemoved,
|
|
8382
|
+
'call.member_updated': this.updateMembers,
|
|
8383
|
+
'call.member_updated_permission': this.updateMembers,
|
|
8384
|
+
'call.reaction_new': this.updateParticipantReaction,
|
|
8385
|
+
};
|
|
8297
8386
|
}
|
|
8298
8387
|
/**
|
|
8299
8388
|
* The server-side counted number of participants connected to the current call.
|
|
@@ -8358,24 +8447,12 @@ class CallState {
|
|
|
8358
8447
|
get callingState() {
|
|
8359
8448
|
return this.getCurrentValue(this.callingState$);
|
|
8360
8449
|
}
|
|
8361
|
-
/**
|
|
8362
|
-
* The list of call recordings.
|
|
8363
|
-
*/
|
|
8364
|
-
get callRecordingsList() {
|
|
8365
|
-
return this.getCurrentValue(this.callRecordingList$);
|
|
8366
|
-
}
|
|
8367
8450
|
/**
|
|
8368
8451
|
* The call stats report.
|
|
8369
8452
|
*/
|
|
8370
8453
|
get callStatsReport() {
|
|
8371
8454
|
return this.getCurrentValue(this.callStatsReport$);
|
|
8372
8455
|
}
|
|
8373
|
-
/**
|
|
8374
|
-
* The metadata of the current call.
|
|
8375
|
-
*/
|
|
8376
|
-
get metadata() {
|
|
8377
|
-
return this.getCurrentValue(this.metadata$);
|
|
8378
|
-
}
|
|
8379
8456
|
/**
|
|
8380
8457
|
* The members of the current call.
|
|
8381
8458
|
*/
|
|
@@ -8388,6 +8465,96 @@ class CallState {
|
|
|
8388
8465
|
get ownCapabilities() {
|
|
8389
8466
|
return this.getCurrentValue(this.ownCapabilities$);
|
|
8390
8467
|
}
|
|
8468
|
+
/**
|
|
8469
|
+
* The backstage state.
|
|
8470
|
+
*/
|
|
8471
|
+
get backstage() {
|
|
8472
|
+
return this.getCurrentValue(this.backstage$);
|
|
8473
|
+
}
|
|
8474
|
+
/**
|
|
8475
|
+
* Will provide the list of blocked user IDs.
|
|
8476
|
+
*/
|
|
8477
|
+
get blockedUserIds() {
|
|
8478
|
+
return this.getCurrentValue(this.blockedUserIds$);
|
|
8479
|
+
}
|
|
8480
|
+
/**
|
|
8481
|
+
* Will provide the time when this call has been created.
|
|
8482
|
+
*/
|
|
8483
|
+
get createdAt() {
|
|
8484
|
+
return this.getCurrentValue(this.createdAt$);
|
|
8485
|
+
}
|
|
8486
|
+
/**
|
|
8487
|
+
* Will provide the time when this call has been ended.
|
|
8488
|
+
*/
|
|
8489
|
+
get endedAt() {
|
|
8490
|
+
return this.getCurrentValue(this.endedAt$);
|
|
8491
|
+
}
|
|
8492
|
+
/**
|
|
8493
|
+
* Will provide the time when this call has been scheduled to start.
|
|
8494
|
+
*/
|
|
8495
|
+
get startsAt() {
|
|
8496
|
+
return this.getCurrentValue(this.startsAt$);
|
|
8497
|
+
}
|
|
8498
|
+
/**
|
|
8499
|
+
* Will provide the time when this call has been updated.
|
|
8500
|
+
*/
|
|
8501
|
+
get updatedAt() {
|
|
8502
|
+
return this.getCurrentValue(this.updatedAt$);
|
|
8503
|
+
}
|
|
8504
|
+
/**
|
|
8505
|
+
* Will provide the user who created this call.
|
|
8506
|
+
*/
|
|
8507
|
+
get createdBy() {
|
|
8508
|
+
return this.getCurrentValue(this.createdBy$);
|
|
8509
|
+
}
|
|
8510
|
+
/**
|
|
8511
|
+
* Will provide the custom data of this call.
|
|
8512
|
+
*/
|
|
8513
|
+
get custom() {
|
|
8514
|
+
return this.getCurrentValue(this.custom$);
|
|
8515
|
+
}
|
|
8516
|
+
/**
|
|
8517
|
+
* Will provide the egress data of this call.
|
|
8518
|
+
*/
|
|
8519
|
+
get egress() {
|
|
8520
|
+
return this.getCurrentValue(this.egress$);
|
|
8521
|
+
}
|
|
8522
|
+
/**
|
|
8523
|
+
* Will provide the ingress data of this call.
|
|
8524
|
+
*/
|
|
8525
|
+
get ingress() {
|
|
8526
|
+
return this.getCurrentValue(this.ingress$);
|
|
8527
|
+
}
|
|
8528
|
+
/**
|
|
8529
|
+
* Will provide the recording state of this call.
|
|
8530
|
+
*/
|
|
8531
|
+
get recording() {
|
|
8532
|
+
return this.getCurrentValue(this.recording$);
|
|
8533
|
+
}
|
|
8534
|
+
/**
|
|
8535
|
+
* Will provide the session data of this call.
|
|
8536
|
+
*/
|
|
8537
|
+
get session() {
|
|
8538
|
+
return this.getCurrentValue(this.session$);
|
|
8539
|
+
}
|
|
8540
|
+
/**
|
|
8541
|
+
* Will provide the settings of this call.
|
|
8542
|
+
*/
|
|
8543
|
+
get settings() {
|
|
8544
|
+
return this.getCurrentValue(this.settings$);
|
|
8545
|
+
}
|
|
8546
|
+
/**
|
|
8547
|
+
* Will provide the transcribing state of this call.
|
|
8548
|
+
*/
|
|
8549
|
+
get transcribing() {
|
|
8550
|
+
return this.getCurrentValue(this.transcribing$);
|
|
8551
|
+
}
|
|
8552
|
+
/**
|
|
8553
|
+
* Will provide the user who ended this call.
|
|
8554
|
+
*/
|
|
8555
|
+
get endedBy() {
|
|
8556
|
+
return this.getCurrentValue(this.endedBy$);
|
|
8557
|
+
}
|
|
8391
8558
|
}
|
|
8392
8559
|
|
|
8393
8560
|
/**
|
|
@@ -8459,40 +8626,16 @@ const watchCallEnded = (call) => {
|
|
|
8459
8626
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8460
8627
|
if (event.type !== 'call.ended')
|
|
8461
8628
|
return;
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8629
|
+
const { callingState } = call.state;
|
|
8630
|
+
if (callingState === CallingState.RINGING ||
|
|
8631
|
+
callingState === CallingState.JOINED ||
|
|
8632
|
+
callingState === CallingState.JOINING) {
|
|
8466
8633
|
yield call.leave();
|
|
8467
8634
|
}
|
|
8468
8635
|
});
|
|
8469
8636
|
};
|
|
8470
8637
|
};
|
|
8471
|
-
/**
|
|
8472
|
-
* An event handler which listens to `call.updated` events
|
|
8473
|
-
* and updates the given call state accordingly.
|
|
8474
|
-
*/
|
|
8475
|
-
const watchCallUpdated = (state) => {
|
|
8476
|
-
return function onCallUpdated(event) {
|
|
8477
|
-
if (event.type !== 'call.updated')
|
|
8478
|
-
return;
|
|
8479
|
-
state.setMetadata(event.call);
|
|
8480
|
-
};
|
|
8481
|
-
};
|
|
8482
8638
|
|
|
8483
|
-
/**
|
|
8484
|
-
* Event handler that watches for `call.permissions_updated` events
|
|
8485
|
-
*/
|
|
8486
|
-
const watchCallPermissionsUpdated = (state) => {
|
|
8487
|
-
return function onCallPermissionsUpdated(event) {
|
|
8488
|
-
if (event.type !== 'call.permissions_updated')
|
|
8489
|
-
return;
|
|
8490
|
-
const { localParticipant } = state;
|
|
8491
|
-
if (event.user.id === (localParticipant === null || localParticipant === void 0 ? void 0 : localParticipant.userId)) {
|
|
8492
|
-
state.setOwnCapabilities(event.own_capabilities);
|
|
8493
|
-
}
|
|
8494
|
-
};
|
|
8495
|
-
};
|
|
8496
8639
|
/**
|
|
8497
8640
|
* Event handler that watches for `callGrantsUpdated` events.
|
|
8498
8641
|
*
|
|
@@ -8606,57 +8749,6 @@ const watchPinsUpdated = (state) => {
|
|
|
8606
8749
|
};
|
|
8607
8750
|
};
|
|
8608
8751
|
|
|
8609
|
-
/**
|
|
8610
|
-
* Watches for `call.member_added` events.
|
|
8611
|
-
*/
|
|
8612
|
-
const watchCallMemberAdded = (state) => {
|
|
8613
|
-
return function onCallMemberAdded(event) {
|
|
8614
|
-
if (event.type !== 'call.member_added')
|
|
8615
|
-
return;
|
|
8616
|
-
state.setMembers((members) => [...members, ...event.members]);
|
|
8617
|
-
};
|
|
8618
|
-
};
|
|
8619
|
-
/**
|
|
8620
|
-
* Watches for `call.member_removed` events.
|
|
8621
|
-
*/
|
|
8622
|
-
const watchCallMemberRemoved = (state) => {
|
|
8623
|
-
return function onCallMemberRemoved(event) {
|
|
8624
|
-
if (event.type !== 'call.member_removed')
|
|
8625
|
-
return;
|
|
8626
|
-
state.setMembers((members) => members.filter((m) => event.members.indexOf(m.user_id) === -1));
|
|
8627
|
-
};
|
|
8628
|
-
};
|
|
8629
|
-
/**
|
|
8630
|
-
* Watches for `call.member_updated_permission` events.
|
|
8631
|
-
*/
|
|
8632
|
-
const watchCallMemberUpdatedPermission = (state) => {
|
|
8633
|
-
return function onCallMemberUpdated(event) {
|
|
8634
|
-
if (event.type !== 'call.member_updated_permission')
|
|
8635
|
-
return;
|
|
8636
|
-
state.setMembers((members) => members.map((member) => {
|
|
8637
|
-
const memberUpdate = event.members.find((m) => m.user_id === member.user_id);
|
|
8638
|
-
if (memberUpdate) {
|
|
8639
|
-
member.user.role = memberUpdate.role;
|
|
8640
|
-
member = Object.assign({}, member);
|
|
8641
|
-
}
|
|
8642
|
-
return member;
|
|
8643
|
-
}));
|
|
8644
|
-
};
|
|
8645
|
-
};
|
|
8646
|
-
/**
|
|
8647
|
-
* Watches for `call.member_updated` events.
|
|
8648
|
-
*/
|
|
8649
|
-
const watchCallMemberUpdated = (state) => {
|
|
8650
|
-
return function onCallMemberUpdated(event) {
|
|
8651
|
-
if (event.type !== 'call.member_updated')
|
|
8652
|
-
return;
|
|
8653
|
-
state.setMembers((members) => members.map((member) => {
|
|
8654
|
-
const memberUpdate = event.members.find((m) => m.user_id === member.user_id);
|
|
8655
|
-
return memberUpdate ? memberUpdate : member;
|
|
8656
|
-
}));
|
|
8657
|
-
};
|
|
8658
|
-
};
|
|
8659
|
-
|
|
8660
8752
|
/**
|
|
8661
8753
|
* An event responder which handles the `participantJoined` event.
|
|
8662
8754
|
*/
|
|
@@ -8738,74 +8830,6 @@ const watchTrackUnpublished = (state) => {
|
|
|
8738
8830
|
};
|
|
8739
8831
|
const unique = (v, i, arr) => arr.indexOf(v) === i;
|
|
8740
8832
|
|
|
8741
|
-
/**
|
|
8742
|
-
* Watches the delivery of CallReactionEvent.
|
|
8743
|
-
*
|
|
8744
|
-
* @param state the state store to update.
|
|
8745
|
-
*/
|
|
8746
|
-
const watchNewReactions = (state) => {
|
|
8747
|
-
return function onNewReactions(event) {
|
|
8748
|
-
if (event.type !== 'call.reaction_new')
|
|
8749
|
-
return;
|
|
8750
|
-
const { reaction } = event;
|
|
8751
|
-
const { user, custom, type, emoji_code } = reaction;
|
|
8752
|
-
state.setParticipants((participants) => {
|
|
8753
|
-
return participants.map((p) => {
|
|
8754
|
-
// skip if the reaction is not for this participant
|
|
8755
|
-
if (p.userId !== user.id)
|
|
8756
|
-
return p;
|
|
8757
|
-
// update the participant with the new reaction
|
|
8758
|
-
return Object.assign(Object.assign({}, p), { reaction: {
|
|
8759
|
-
type,
|
|
8760
|
-
emoji_code,
|
|
8761
|
-
custom,
|
|
8762
|
-
} });
|
|
8763
|
-
});
|
|
8764
|
-
});
|
|
8765
|
-
};
|
|
8766
|
-
};
|
|
8767
|
-
|
|
8768
|
-
/**
|
|
8769
|
-
* Watches for `call.recording_started` events.
|
|
8770
|
-
*/
|
|
8771
|
-
const watchCallRecordingStarted = (state) => {
|
|
8772
|
-
return function onCallRecordingStarted(event) {
|
|
8773
|
-
if (event.type !== 'call.recording_started')
|
|
8774
|
-
return;
|
|
8775
|
-
state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { recording: true })));
|
|
8776
|
-
};
|
|
8777
|
-
};
|
|
8778
|
-
/**
|
|
8779
|
-
* Watches for `call.recording_stopped` events.
|
|
8780
|
-
*/
|
|
8781
|
-
const watchCallRecordingStopped = (state) => {
|
|
8782
|
-
return function onCallRecordingStopped(event) {
|
|
8783
|
-
if (event.type !== 'call.recording_stopped')
|
|
8784
|
-
return;
|
|
8785
|
-
state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { recording: false })));
|
|
8786
|
-
};
|
|
8787
|
-
};
|
|
8788
|
-
/**
|
|
8789
|
-
* Watches for `call.broadcasting_started` events.
|
|
8790
|
-
*/
|
|
8791
|
-
const watchCallBroadcastingStarted = (state) => {
|
|
8792
|
-
return function onCallBroadcastingStarted(event) {
|
|
8793
|
-
if (event.type !== 'call.broadcasting_started')
|
|
8794
|
-
return;
|
|
8795
|
-
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 }) }) })));
|
|
8796
|
-
};
|
|
8797
|
-
};
|
|
8798
|
-
/**
|
|
8799
|
-
* Watches for `call.broadcasting_stopped` events.
|
|
8800
|
-
*/
|
|
8801
|
-
const watchCallBroadcastingStopped = (state) => {
|
|
8802
|
-
return function onCallBroadcastingStopped(event) {
|
|
8803
|
-
if (event.type !== 'call.broadcasting_stopped')
|
|
8804
|
-
return;
|
|
8805
|
-
state.setMetadata((metadata) => (Object.assign(Object.assign({}, metadata), { egress: Object.assign(Object.assign({}, metadata.egress), { broadcasting: false }) })));
|
|
8806
|
-
};
|
|
8807
|
-
};
|
|
8808
|
-
|
|
8809
8833
|
/**
|
|
8810
8834
|
* Watches for `dominantSpeakerChanged` events.
|
|
8811
8835
|
*/
|
|
@@ -8848,98 +8872,6 @@ const watchAudioLevelChanged = (dispatcher, state) => {
|
|
|
8848
8872
|
});
|
|
8849
8873
|
};
|
|
8850
8874
|
|
|
8851
|
-
/**
|
|
8852
|
-
* Watch for call.session_started events and update the call metadata.
|
|
8853
|
-
*
|
|
8854
|
-
* @param state the call state.
|
|
8855
|
-
*/
|
|
8856
|
-
const watchCallSessionStarted = (state) => {
|
|
8857
|
-
return function onCallSessionStarted(event) {
|
|
8858
|
-
if (event.type !== 'call.session_started')
|
|
8859
|
-
return;
|
|
8860
|
-
state.setMetadata(event.call);
|
|
8861
|
-
};
|
|
8862
|
-
};
|
|
8863
|
-
/**
|
|
8864
|
-
* Watch for call.session_ended events and update the call metadata.
|
|
8865
|
-
*
|
|
8866
|
-
* @param state the call state.
|
|
8867
|
-
*/
|
|
8868
|
-
const watchCallSessionEnded = (state) => {
|
|
8869
|
-
return function onCallSessionEnded(event) {
|
|
8870
|
-
if (event.type !== 'call.session_ended')
|
|
8871
|
-
return;
|
|
8872
|
-
state.setMetadata(event.call);
|
|
8873
|
-
};
|
|
8874
|
-
};
|
|
8875
|
-
/**
|
|
8876
|
-
* Watch for call.session_participant_joined events and update the call metadata.
|
|
8877
|
-
*
|
|
8878
|
-
* @param state the call state.
|
|
8879
|
-
*/
|
|
8880
|
-
const watchCallSessionParticipantJoined = (state) => {
|
|
8881
|
-
return function onCallParticipantJoined(event) {
|
|
8882
|
-
if (event.type !== 'call.session_participant_joined')
|
|
8883
|
-
return;
|
|
8884
|
-
const { participant } = event;
|
|
8885
|
-
state.setMetadata((metadata) => {
|
|
8886
|
-
if (!metadata || !metadata.session) {
|
|
8887
|
-
state.logger('warn', `Received call.session_participant_joined event but the metadata structure is invalid.`, event);
|
|
8888
|
-
return metadata;
|
|
8889
|
-
}
|
|
8890
|
-
const { session } = metadata;
|
|
8891
|
-
const { participants, participants_count_by_role } = session;
|
|
8892
|
-
const { user } = participant;
|
|
8893
|
-
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 }) }) });
|
|
8894
|
-
});
|
|
8895
|
-
};
|
|
8896
|
-
};
|
|
8897
|
-
/**
|
|
8898
|
-
* Watch for call.session_participant_left events and update the call metadata.
|
|
8899
|
-
*
|
|
8900
|
-
* @param state the call state.
|
|
8901
|
-
*/
|
|
8902
|
-
const watchCallSessionParticipantLeft = (state) => {
|
|
8903
|
-
return function onCallParticipantLeft(event) {
|
|
8904
|
-
if (event.type !== 'call.session_participant_left')
|
|
8905
|
-
return;
|
|
8906
|
-
const { user, user_session_id } = event.participant;
|
|
8907
|
-
state.setMetadata((metadata) => {
|
|
8908
|
-
if (!metadata || !metadata.session) {
|
|
8909
|
-
state.logger('warn', `Received call.session_participant_left event but the metadata structure is invalid.`, event);
|
|
8910
|
-
return metadata;
|
|
8911
|
-
}
|
|
8912
|
-
const { session } = metadata;
|
|
8913
|
-
const { participants, participants_count_by_role } = session;
|
|
8914
|
-
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) }) }) });
|
|
8915
|
-
});
|
|
8916
|
-
};
|
|
8917
|
-
};
|
|
8918
|
-
|
|
8919
|
-
/**
|
|
8920
|
-
* Event handler that watches for `call.blocked_user` events,
|
|
8921
|
-
* updates the call store `blocked_user_ids` property by adding
|
|
8922
|
-
* `event.user_id` to the list
|
|
8923
|
-
*/
|
|
8924
|
-
const watchBlockedUser = (state) => (event) => {
|
|
8925
|
-
if (event.type !== 'call.blocked_user')
|
|
8926
|
-
return;
|
|
8927
|
-
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] })));
|
|
8928
|
-
};
|
|
8929
|
-
/**
|
|
8930
|
-
* Event handler that watches for `call.unblocked_user` events,
|
|
8931
|
-
* updates the call store `blocked_user_ids` property by
|
|
8932
|
-
* removing `event.user_id` from the list
|
|
8933
|
-
*/
|
|
8934
|
-
const watchUnblockedUser = (state) => (event) => {
|
|
8935
|
-
if (event.type !== 'call.unblocked_user')
|
|
8936
|
-
return;
|
|
8937
|
-
state.setMetadata((metadata) => {
|
|
8938
|
-
const blocked_user_ids = ((metadata === null || metadata === void 0 ? void 0 : metadata.blocked_user_ids) || []).filter((userId) => event.user.id !== userId);
|
|
8939
|
-
return Object.assign(Object.assign({}, metadata), { blocked_user_ids });
|
|
8940
|
-
});
|
|
8941
|
-
};
|
|
8942
|
-
|
|
8943
8875
|
/**
|
|
8944
8876
|
* Registers the default event handlers for a call during its lifecycle.
|
|
8945
8877
|
*
|
|
@@ -8948,29 +8880,8 @@ const watchUnblockedUser = (state) => (event) => {
|
|
|
8948
8880
|
* @param dispatcher the dispatcher.
|
|
8949
8881
|
*/
|
|
8950
8882
|
const registerEventHandlers = (call, state, dispatcher) => {
|
|
8951
|
-
const coordinatorEvents = {
|
|
8952
|
-
'call.blocked_user': watchBlockedUser(state),
|
|
8953
|
-
'call.broadcasting_started': watchCallBroadcastingStarted(state),
|
|
8954
|
-
'call.broadcasting_stopped': watchCallBroadcastingStopped(state),
|
|
8955
|
-
'call.ended': watchCallEnded(call),
|
|
8956
|
-
'call.live_started': watchCallLiveStarted(state),
|
|
8957
|
-
'call.member_added': watchCallMemberAdded(state),
|
|
8958
|
-
'call.member_removed': watchCallMemberRemoved(state),
|
|
8959
|
-
'call.member_updated': watchCallMemberUpdated(state),
|
|
8960
|
-
'call.member_updated_permission': watchCallMemberUpdatedPermission(state),
|
|
8961
|
-
'call.permissions_updated': watchCallPermissionsUpdated(state),
|
|
8962
|
-
'call.reaction_new': watchNewReactions(state),
|
|
8963
|
-
'call.recording_started': watchCallRecordingStarted(state),
|
|
8964
|
-
'call.recording_stopped': watchCallRecordingStopped(state),
|
|
8965
|
-
'call.session_started': watchCallSessionStarted(state),
|
|
8966
|
-
'call.session_ended': watchCallSessionEnded(state),
|
|
8967
|
-
'call.session_participant_joined': watchCallSessionParticipantJoined(state),
|
|
8968
|
-
'call.session_participant_left': watchCallSessionParticipantLeft(state),
|
|
8969
|
-
'call.unblocked_user': watchUnblockedUser(state),
|
|
8970
|
-
'call.updated': watchCallUpdated(state),
|
|
8971
|
-
'call.user_muted': () => console.log('call.user_muted received'),
|
|
8972
|
-
};
|
|
8973
8883
|
const eventHandlers = [
|
|
8884
|
+
call.on('call.ended', watchCallEnded(call)),
|
|
8974
8885
|
watchLiveEnded(dispatcher, call),
|
|
8975
8886
|
watchSfuErrorReports(dispatcher),
|
|
8976
8887
|
watchChangePublishQuality(dispatcher, call),
|
|
@@ -8985,10 +8896,6 @@ const registerEventHandlers = (call, state, dispatcher) => {
|
|
|
8985
8896
|
call.on('callGrantsUpdated', watchCallGrantsUpdated(state)),
|
|
8986
8897
|
call.on('pinsUpdated', watchPinsUpdated(state)),
|
|
8987
8898
|
];
|
|
8988
|
-
Object.keys(coordinatorEvents).forEach((event) => {
|
|
8989
|
-
const eventName = event;
|
|
8990
|
-
eventHandlers.push(call.on(eventName, coordinatorEvents[eventName]));
|
|
8991
|
-
});
|
|
8992
8899
|
if (call.ringing) {
|
|
8993
8900
|
// these events are only relevant when the call is ringing
|
|
8994
8901
|
eventHandlers.push(registerRingingCallEventHandlers(call));
|
|
@@ -9607,7 +9514,592 @@ const getClientDetails = () => {
|
|
|
9607
9514
|
};
|
|
9608
9515
|
};
|
|
9609
9516
|
|
|
9610
|
-
|
|
9517
|
+
class InputMediaDeviceManagerState {
|
|
9518
|
+
constructor() {
|
|
9519
|
+
this.statusSubject = new BehaviorSubject(undefined);
|
|
9520
|
+
this.mediaStreamSubject = new BehaviorSubject(undefined);
|
|
9521
|
+
this.selectedDeviceSubject = new BehaviorSubject(undefined);
|
|
9522
|
+
/**
|
|
9523
|
+
* Gets the current value of an observable, or undefined if the observable has
|
|
9524
|
+
* not emitted a value yet.
|
|
9525
|
+
*
|
|
9526
|
+
* @param observable$ the observable to get the value from.
|
|
9527
|
+
*/
|
|
9528
|
+
this.getCurrentValue = getCurrentValue;
|
|
9529
|
+
/**
|
|
9530
|
+
* Updates the value of the provided Subject.
|
|
9531
|
+
* An `update` can either be a new value or a function which takes
|
|
9532
|
+
* the current value and returns a new value.
|
|
9533
|
+
*
|
|
9534
|
+
* @internal
|
|
9535
|
+
*
|
|
9536
|
+
* @param subject the subject to update.
|
|
9537
|
+
* @param update the update to apply to the subject.
|
|
9538
|
+
* @return the updated value.
|
|
9539
|
+
*/
|
|
9540
|
+
this.setCurrentValue = setCurrentValue;
|
|
9541
|
+
this.mediaStream$ = this.mediaStreamSubject.asObservable();
|
|
9542
|
+
this.selectedDevice$ = this.selectedDeviceSubject
|
|
9543
|
+
.asObservable()
|
|
9544
|
+
.pipe(distinctUntilChanged$1());
|
|
9545
|
+
this.status$ = this.statusSubject.asObservable();
|
|
9546
|
+
}
|
|
9547
|
+
/**
|
|
9548
|
+
* The device status
|
|
9549
|
+
*/
|
|
9550
|
+
get status() {
|
|
9551
|
+
return this.getCurrentValue(this.status$);
|
|
9552
|
+
}
|
|
9553
|
+
/**
|
|
9554
|
+
* The currently selected device
|
|
9555
|
+
*/
|
|
9556
|
+
get selectedDevice() {
|
|
9557
|
+
return this.getCurrentValue(this.selectedDevice$);
|
|
9558
|
+
}
|
|
9559
|
+
/**
|
|
9560
|
+
* The current media stream, or `undefined` if the device is currently disabled.
|
|
9561
|
+
*/
|
|
9562
|
+
get mediaStream() {
|
|
9563
|
+
return this.getCurrentValue(this.mediaStream$);
|
|
9564
|
+
}
|
|
9565
|
+
/**
|
|
9566
|
+
* @internal
|
|
9567
|
+
* @param status
|
|
9568
|
+
*/
|
|
9569
|
+
setStatus(status) {
|
|
9570
|
+
this.setCurrentValue(this.statusSubject, status);
|
|
9571
|
+
}
|
|
9572
|
+
/**
|
|
9573
|
+
* @internal
|
|
9574
|
+
* @param stream
|
|
9575
|
+
*/
|
|
9576
|
+
setMediaStream(stream) {
|
|
9577
|
+
this.setCurrentValue(this.mediaStreamSubject, stream);
|
|
9578
|
+
if (stream) {
|
|
9579
|
+
this.setDevice(this.getDeviceIdFromStream(stream));
|
|
9580
|
+
}
|
|
9581
|
+
}
|
|
9582
|
+
/**
|
|
9583
|
+
* @internal
|
|
9584
|
+
* @param stream
|
|
9585
|
+
*/
|
|
9586
|
+
setDevice(deviceId) {
|
|
9587
|
+
this.setCurrentValue(this.selectedDeviceSubject, deviceId);
|
|
9588
|
+
}
|
|
9589
|
+
}
|
|
9590
|
+
|
|
9591
|
+
class CameraManagerState extends InputMediaDeviceManagerState {
|
|
9592
|
+
constructor() {
|
|
9593
|
+
super();
|
|
9594
|
+
this.directionSubject = new BehaviorSubject(undefined);
|
|
9595
|
+
this.direction$ = this.directionSubject
|
|
9596
|
+
.asObservable()
|
|
9597
|
+
.pipe(distinctUntilChanged$1());
|
|
9598
|
+
}
|
|
9599
|
+
/**
|
|
9600
|
+
* The preferred camera direction
|
|
9601
|
+
* front - means the camera facing the user
|
|
9602
|
+
* back - means the camera facing the environment
|
|
9603
|
+
*/
|
|
9604
|
+
get direction() {
|
|
9605
|
+
return this.getCurrentValue(this.direction$);
|
|
9606
|
+
}
|
|
9607
|
+
/**
|
|
9608
|
+
* @internal
|
|
9609
|
+
*/
|
|
9610
|
+
setDirection(direction) {
|
|
9611
|
+
this.setCurrentValue(this.directionSubject, direction);
|
|
9612
|
+
}
|
|
9613
|
+
/**
|
|
9614
|
+
* @internal
|
|
9615
|
+
*/
|
|
9616
|
+
setMediaStream(stream) {
|
|
9617
|
+
var _a;
|
|
9618
|
+
super.setMediaStream(stream);
|
|
9619
|
+
if (stream) {
|
|
9620
|
+
// RN getSettings() doesn't return facingMode, so we don't verify camera direction
|
|
9621
|
+
const direction = isReactNative()
|
|
9622
|
+
? this.direction
|
|
9623
|
+
: ((_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().facingMode) === 'environment'
|
|
9624
|
+
? 'back'
|
|
9625
|
+
: 'front';
|
|
9626
|
+
this.setDirection(direction);
|
|
9627
|
+
}
|
|
9628
|
+
}
|
|
9629
|
+
getDeviceIdFromStream(stream) {
|
|
9630
|
+
var _a;
|
|
9631
|
+
return (_a = stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
|
|
9632
|
+
}
|
|
9633
|
+
}
|
|
9634
|
+
|
|
9635
|
+
const getDevices = (constraints) => {
|
|
9636
|
+
return new Observable((subscriber) => {
|
|
9637
|
+
navigator.mediaDevices
|
|
9638
|
+
.getUserMedia(constraints)
|
|
9639
|
+
.then((media) => {
|
|
9640
|
+
// in Firefox, devices can be enumerated after userMedia is requested
|
|
9641
|
+
// and permissions granted. Otherwise, device labels are empty
|
|
9642
|
+
navigator.mediaDevices.enumerateDevices().then((devices) => {
|
|
9643
|
+
subscriber.next(devices);
|
|
9644
|
+
// If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
|
|
9645
|
+
disposeOfMediaStream(media);
|
|
9646
|
+
subscriber.complete();
|
|
9647
|
+
});
|
|
9648
|
+
})
|
|
9649
|
+
.catch((error) => {
|
|
9650
|
+
getLogger(['devices'])('error', 'Failed to get devices', error);
|
|
9651
|
+
subscriber.error(error);
|
|
9652
|
+
});
|
|
9653
|
+
});
|
|
9654
|
+
};
|
|
9655
|
+
/**
|
|
9656
|
+
* [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
|
|
9657
|
+
*
|
|
9658
|
+
* @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.
|
|
9659
|
+
*/
|
|
9660
|
+
const checkIfAudioOutputChangeSupported = () => {
|
|
9661
|
+
if (typeof document === 'undefined')
|
|
9662
|
+
return false;
|
|
9663
|
+
const element = document.createElement('audio');
|
|
9664
|
+
return element.sinkId !== undefined;
|
|
9665
|
+
};
|
|
9666
|
+
/**
|
|
9667
|
+
* The default constraints used to request audio devices.
|
|
9668
|
+
*/
|
|
9669
|
+
const audioDeviceConstraints = {
|
|
9670
|
+
audio: {
|
|
9671
|
+
autoGainControl: true,
|
|
9672
|
+
noiseSuppression: true,
|
|
9673
|
+
echoCancellation: true,
|
|
9674
|
+
},
|
|
9675
|
+
};
|
|
9676
|
+
/**
|
|
9677
|
+
* The default constraints used to request video devices.
|
|
9678
|
+
*/
|
|
9679
|
+
const videoDeviceConstraints = {
|
|
9680
|
+
video: {
|
|
9681
|
+
width: 1280,
|
|
9682
|
+
height: 720,
|
|
9683
|
+
},
|
|
9684
|
+
};
|
|
9685
|
+
// 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
|
|
9686
|
+
const deviceChange$ = new Observable((subscriber) => {
|
|
9687
|
+
var _a, _b;
|
|
9688
|
+
const deviceChangeHandler = () => subscriber.next();
|
|
9689
|
+
(_b = (_a = navigator.mediaDevices).addEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
|
|
9690
|
+
return () => {
|
|
9691
|
+
var _a, _b;
|
|
9692
|
+
return (_b = (_a = navigator.mediaDevices).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
|
|
9693
|
+
};
|
|
9694
|
+
}).pipe(debounceTime(500), concatMap(() => from(navigator.mediaDevices.enumerateDevices())), shareReplay(1));
|
|
9695
|
+
const audioDevices$ = merge(getDevices(audioDeviceConstraints), deviceChange$).pipe(shareReplay(1));
|
|
9696
|
+
const videoDevices$ = merge(getDevices(videoDeviceConstraints), deviceChange$).pipe(shareReplay(1));
|
|
9697
|
+
/**
|
|
9698
|
+
* 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.
|
|
9699
|
+
*
|
|
9700
|
+
* @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.
|
|
9701
|
+
* @returns
|
|
9702
|
+
*/
|
|
9703
|
+
const getAudioDevices = () => audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audioinput')));
|
|
9704
|
+
/**
|
|
9705
|
+
* 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.
|
|
9706
|
+
*
|
|
9707
|
+
* @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.
|
|
9708
|
+
* @returns
|
|
9709
|
+
*/
|
|
9710
|
+
const getVideoDevices = () => videoDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'videoinput' && d.deviceId.length)));
|
|
9711
|
+
/**
|
|
9712
|
+
* 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)
|
|
9713
|
+
*
|
|
9714
|
+
* @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.
|
|
9715
|
+
* @returns
|
|
9716
|
+
*/
|
|
9717
|
+
const getAudioOutputDevices = () => {
|
|
9718
|
+
return audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audiooutput')));
|
|
9719
|
+
};
|
|
9720
|
+
const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
9721
|
+
try {
|
|
9722
|
+
return yield navigator.mediaDevices.getUserMedia(constraints);
|
|
9723
|
+
}
|
|
9724
|
+
catch (e) {
|
|
9725
|
+
getLogger(['devices'])('error', `Failed get user media`, {
|
|
9726
|
+
error: e,
|
|
9727
|
+
constraints: constraints,
|
|
9728
|
+
});
|
|
9729
|
+
throw e;
|
|
9730
|
+
}
|
|
9731
|
+
});
|
|
9732
|
+
/**
|
|
9733
|
+
* Returns an audio media stream that fulfills the given constraints.
|
|
9734
|
+
* If no constraints are provided, it uses the browser's default ones.
|
|
9735
|
+
*
|
|
9736
|
+
* @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.
|
|
9737
|
+
* @param trackConstraints the constraints to use when requesting the stream.
|
|
9738
|
+
* @returns the new `MediaStream` fulfilling the given constraints.
|
|
9739
|
+
*/
|
|
9740
|
+
const getAudioStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
9741
|
+
const constraints = {
|
|
9742
|
+
audio: Object.assign(Object.assign({}, audioDeviceConstraints.audio), trackConstraints),
|
|
9743
|
+
};
|
|
9744
|
+
return getStream(constraints);
|
|
9745
|
+
});
|
|
9746
|
+
/**
|
|
9747
|
+
* Returns a video media stream that fulfills the given constraints.
|
|
9748
|
+
* If no constraints are provided, it uses the browser's default ones.
|
|
9749
|
+
*
|
|
9750
|
+
* @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.
|
|
9751
|
+
* @param trackConstraints the constraints to use when requesting the stream.
|
|
9752
|
+
* @returns a new `MediaStream` fulfilling the given constraints.
|
|
9753
|
+
*/
|
|
9754
|
+
const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
9755
|
+
const constraints = {
|
|
9756
|
+
video: Object.assign(Object.assign({}, videoDeviceConstraints.video), trackConstraints),
|
|
9757
|
+
};
|
|
9758
|
+
return getStream(constraints);
|
|
9759
|
+
});
|
|
9760
|
+
/**
|
|
9761
|
+
* Prompts the user for a permission to share a screen.
|
|
9762
|
+
* If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
|
|
9763
|
+
*
|
|
9764
|
+
* The callers of this API are responsible to handle the possible errors.
|
|
9765
|
+
*
|
|
9766
|
+
* @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.
|
|
9767
|
+
*
|
|
9768
|
+
* @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
|
|
9769
|
+
*/
|
|
9770
|
+
const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
9771
|
+
try {
|
|
9772
|
+
return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
|
|
9773
|
+
}
|
|
9774
|
+
catch (e) {
|
|
9775
|
+
getLogger(['devices'])('error', 'Failed to get screen share stream', e);
|
|
9776
|
+
throw e;
|
|
9777
|
+
}
|
|
9778
|
+
});
|
|
9779
|
+
const watchForDisconnectedDevice = (kind, deviceId$) => {
|
|
9780
|
+
let devices$;
|
|
9781
|
+
switch (kind) {
|
|
9782
|
+
case 'audioinput':
|
|
9783
|
+
devices$ = getAudioDevices();
|
|
9784
|
+
break;
|
|
9785
|
+
case 'videoinput':
|
|
9786
|
+
devices$ = getVideoDevices();
|
|
9787
|
+
break;
|
|
9788
|
+
case 'audiooutput':
|
|
9789
|
+
devices$ = getAudioOutputDevices();
|
|
9790
|
+
break;
|
|
9791
|
+
}
|
|
9792
|
+
return combineLatest([devices$, deviceId$]).pipe(filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), map$2(() => true));
|
|
9793
|
+
};
|
|
9794
|
+
/**
|
|
9795
|
+
* Notifies the subscriber if a given 'audioinput' device is disconnected
|
|
9796
|
+
*
|
|
9797
|
+
* @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.
|
|
9798
|
+
* @param deviceId$ an Observable that specifies which device to watch for
|
|
9799
|
+
* @returns
|
|
9800
|
+
*/
|
|
9801
|
+
const watchForDisconnectedAudioDevice = (deviceId$) => {
|
|
9802
|
+
return watchForDisconnectedDevice('audioinput', deviceId$);
|
|
9803
|
+
};
|
|
9804
|
+
/**
|
|
9805
|
+
* Notifies the subscriber if a given 'videoinput' device is disconnected
|
|
9806
|
+
*
|
|
9807
|
+
* @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.
|
|
9808
|
+
* @param deviceId$ an Observable that specifies which device to watch for
|
|
9809
|
+
* @returns
|
|
9810
|
+
*/
|
|
9811
|
+
const watchForDisconnectedVideoDevice = (deviceId$) => {
|
|
9812
|
+
return watchForDisconnectedDevice('videoinput', deviceId$);
|
|
9813
|
+
};
|
|
9814
|
+
/**
|
|
9815
|
+
* Notifies the subscriber if a given 'audiooutput' device is disconnected
|
|
9816
|
+
*
|
|
9817
|
+
* @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.
|
|
9818
|
+
* @param deviceId$ an Observable that specifies which device to watch for
|
|
9819
|
+
* @returns
|
|
9820
|
+
*/
|
|
9821
|
+
const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
|
|
9822
|
+
return watchForDisconnectedDevice('audiooutput', deviceId$);
|
|
9823
|
+
};
|
|
9824
|
+
const watchForAddedDefaultDevice = (kind) => {
|
|
9825
|
+
let devices$;
|
|
9826
|
+
switch (kind) {
|
|
9827
|
+
case 'audioinput':
|
|
9828
|
+
devices$ = getAudioDevices();
|
|
9829
|
+
break;
|
|
9830
|
+
case 'videoinput':
|
|
9831
|
+
devices$ = getVideoDevices();
|
|
9832
|
+
break;
|
|
9833
|
+
case 'audiooutput':
|
|
9834
|
+
devices$ = getAudioOutputDevices();
|
|
9835
|
+
break;
|
|
9836
|
+
default:
|
|
9837
|
+
throw new Error('Unknown MediaDeviceKind', kind);
|
|
9838
|
+
}
|
|
9839
|
+
return devices$.pipe(pairwise(), filter(([prev, current]) => {
|
|
9840
|
+
const prevDefault = prev.find((device) => device.deviceId === 'default');
|
|
9841
|
+
const currentDefault = current.find((device) => device.deviceId === 'default');
|
|
9842
|
+
return !!(current.length > prev.length &&
|
|
9843
|
+
prevDefault &&
|
|
9844
|
+
currentDefault &&
|
|
9845
|
+
prevDefault.groupId !== currentDefault.groupId);
|
|
9846
|
+
}), map$2(() => true));
|
|
9847
|
+
};
|
|
9848
|
+
/**
|
|
9849
|
+
* Notifies the subscriber about newly added default audio input device.
|
|
9850
|
+
* @returns Observable<boolean>
|
|
9851
|
+
*/
|
|
9852
|
+
const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
|
|
9853
|
+
/**
|
|
9854
|
+
* Notifies the subscriber about newly added default audio output device.
|
|
9855
|
+
* @returns Observable<boolean>
|
|
9856
|
+
*/
|
|
9857
|
+
const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
|
|
9858
|
+
/**
|
|
9859
|
+
* Notifies the subscriber about newly added default video input device.
|
|
9860
|
+
* @returns Observable<boolean>
|
|
9861
|
+
*/
|
|
9862
|
+
const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
|
|
9863
|
+
/**
|
|
9864
|
+
* Deactivates MediaStream (stops and removes tracks) to be later garbage collected
|
|
9865
|
+
*
|
|
9866
|
+
* @param stream MediaStream
|
|
9867
|
+
* @returns void
|
|
9868
|
+
*/
|
|
9869
|
+
const disposeOfMediaStream = (stream) => {
|
|
9870
|
+
if (!stream.active)
|
|
9871
|
+
return;
|
|
9872
|
+
stream.getTracks().forEach((track) => {
|
|
9873
|
+
track.stop();
|
|
9874
|
+
stream.removeTrack(track);
|
|
9875
|
+
});
|
|
9876
|
+
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
|
|
9877
|
+
if (typeof stream.release === 'function') {
|
|
9878
|
+
// @ts-expect-error
|
|
9879
|
+
stream.release();
|
|
9880
|
+
}
|
|
9881
|
+
};
|
|
9882
|
+
|
|
9883
|
+
class InputMediaDeviceManager {
|
|
9884
|
+
constructor(call, state) {
|
|
9885
|
+
this.call = call;
|
|
9886
|
+
this.state = state;
|
|
9887
|
+
}
|
|
9888
|
+
/**
|
|
9889
|
+
* Lists the available audio/video devices
|
|
9890
|
+
*
|
|
9891
|
+
* Note: It prompts the user for a permission to use devices (if not already granted)
|
|
9892
|
+
*
|
|
9893
|
+
* @returns an Observable that will be updated if a device is connected or disconnected
|
|
9894
|
+
*/
|
|
9895
|
+
listDevices() {
|
|
9896
|
+
return this.getDevices();
|
|
9897
|
+
}
|
|
9898
|
+
/**
|
|
9899
|
+
* Starts camera/microphone
|
|
9900
|
+
*/
|
|
9901
|
+
enable() {
|
|
9902
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9903
|
+
if (this.state.status === 'enabled') {
|
|
9904
|
+
return;
|
|
9905
|
+
}
|
|
9906
|
+
yield this.startStream();
|
|
9907
|
+
this.state.setStatus('enabled');
|
|
9908
|
+
});
|
|
9909
|
+
}
|
|
9910
|
+
/**
|
|
9911
|
+
* Stops camera/microphone
|
|
9912
|
+
* @returns
|
|
9913
|
+
*/
|
|
9914
|
+
disable() {
|
|
9915
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9916
|
+
if (this.state.status === 'disabled') {
|
|
9917
|
+
return;
|
|
9918
|
+
}
|
|
9919
|
+
yield this.stopStream();
|
|
9920
|
+
this.state.setStatus('disabled');
|
|
9921
|
+
});
|
|
9922
|
+
}
|
|
9923
|
+
/**
|
|
9924
|
+
* If current device statis is disabled, it will enable the device, else it will disable it.
|
|
9925
|
+
* @returns
|
|
9926
|
+
*/
|
|
9927
|
+
toggle() {
|
|
9928
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9929
|
+
if (this.state.status === 'enabled') {
|
|
9930
|
+
return this.disable();
|
|
9931
|
+
}
|
|
9932
|
+
else {
|
|
9933
|
+
return this.enable();
|
|
9934
|
+
}
|
|
9935
|
+
});
|
|
9936
|
+
}
|
|
9937
|
+
/**
|
|
9938
|
+
* Select device
|
|
9939
|
+
*
|
|
9940
|
+
* Note: this method is not supported in React Native
|
|
9941
|
+
*
|
|
9942
|
+
* @param deviceId
|
|
9943
|
+
*/
|
|
9944
|
+
select(deviceId) {
|
|
9945
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9946
|
+
if (isReactNative()) {
|
|
9947
|
+
throw new Error('This method is not supported in React Native');
|
|
9948
|
+
}
|
|
9949
|
+
if (deviceId === this.state.selectedDevice) {
|
|
9950
|
+
return;
|
|
9951
|
+
}
|
|
9952
|
+
this.state.setDevice(deviceId);
|
|
9953
|
+
yield this.applySettingsToStream();
|
|
9954
|
+
});
|
|
9955
|
+
}
|
|
9956
|
+
applySettingsToStream() {
|
|
9957
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9958
|
+
if (this.state.status === 'enabled') {
|
|
9959
|
+
yield this.stopStream();
|
|
9960
|
+
yield this.startStream();
|
|
9961
|
+
}
|
|
9962
|
+
});
|
|
9963
|
+
}
|
|
9964
|
+
stopStream() {
|
|
9965
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9966
|
+
if (!this.state.mediaStream) {
|
|
9967
|
+
return;
|
|
9968
|
+
}
|
|
9969
|
+
if (this.call.state.callingState === CallingState.JOINED) {
|
|
9970
|
+
yield this.stopPublishStream();
|
|
9971
|
+
}
|
|
9972
|
+
else if (this.state.mediaStream) {
|
|
9973
|
+
disposeOfMediaStream(this.state.mediaStream);
|
|
9974
|
+
}
|
|
9975
|
+
this.state.setMediaStream(undefined);
|
|
9976
|
+
});
|
|
9977
|
+
}
|
|
9978
|
+
startStream() {
|
|
9979
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9980
|
+
if (this.state.mediaStream) {
|
|
9981
|
+
return;
|
|
9982
|
+
}
|
|
9983
|
+
const constraints = { deviceId: this.state.selectedDevice };
|
|
9984
|
+
const stream = yield this.getStream(constraints);
|
|
9985
|
+
if (this.call.state.callingState === CallingState.JOINED) {
|
|
9986
|
+
yield this.publishStream(stream);
|
|
9987
|
+
}
|
|
9988
|
+
this.state.setMediaStream(stream);
|
|
9989
|
+
});
|
|
9990
|
+
}
|
|
9991
|
+
}
|
|
9992
|
+
|
|
9993
|
+
class CameraManager extends InputMediaDeviceManager {
|
|
9994
|
+
constructor(call) {
|
|
9995
|
+
super(call, new CameraManagerState());
|
|
9996
|
+
}
|
|
9997
|
+
/**
|
|
9998
|
+
* Select the camera direaction
|
|
9999
|
+
* @param direction
|
|
10000
|
+
*/
|
|
10001
|
+
selectDirection(direction) {
|
|
10002
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
10003
|
+
this.state.setDirection(direction);
|
|
10004
|
+
// Providing both device id and direction doesn't work, so we deselect the device
|
|
10005
|
+
this.state.setDevice(undefined);
|
|
10006
|
+
yield this.applySettingsToStream();
|
|
10007
|
+
});
|
|
10008
|
+
}
|
|
10009
|
+
/**
|
|
10010
|
+
* Flips the camera direction: if it's front it will change to back, if it's back, it will change to front.
|
|
10011
|
+
*
|
|
10012
|
+
* Note: if there is no available camera with the desired direction, this method will do nothing.
|
|
10013
|
+
* @returns
|
|
10014
|
+
*/
|
|
10015
|
+
flip() {
|
|
10016
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
10017
|
+
const newDirection = this.state.direction === 'front' ? 'back' : 'front';
|
|
10018
|
+
this.selectDirection(newDirection);
|
|
10019
|
+
});
|
|
10020
|
+
}
|
|
10021
|
+
getDevices() {
|
|
10022
|
+
return getVideoDevices();
|
|
10023
|
+
}
|
|
10024
|
+
getStream(constraints) {
|
|
10025
|
+
// We can't set both device id and facing mode
|
|
10026
|
+
// Device id has higher priority
|
|
10027
|
+
if (!constraints.deviceId && this.state.direction) {
|
|
10028
|
+
constraints.facingMode =
|
|
10029
|
+
this.state.direction === 'front' ? 'user' : 'environment';
|
|
10030
|
+
}
|
|
10031
|
+
return getVideoStream(constraints);
|
|
10032
|
+
}
|
|
10033
|
+
publishStream(stream) {
|
|
10034
|
+
return this.call.publishVideoStream(stream);
|
|
10035
|
+
}
|
|
10036
|
+
stopPublishStream() {
|
|
10037
|
+
return this.call.stopPublish(TrackType.VIDEO);
|
|
10038
|
+
}
|
|
10039
|
+
/**
|
|
10040
|
+
* Disables the video tracks of the camera
|
|
10041
|
+
*/
|
|
10042
|
+
pause() {
|
|
10043
|
+
var _a;
|
|
10044
|
+
(_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
|
|
10045
|
+
track.enabled = false;
|
|
10046
|
+
});
|
|
10047
|
+
}
|
|
10048
|
+
/**
|
|
10049
|
+
* (Re)enables the video tracks of the camera
|
|
10050
|
+
*/
|
|
10051
|
+
resume() {
|
|
10052
|
+
var _a;
|
|
10053
|
+
(_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((track) => {
|
|
10054
|
+
track.enabled = true;
|
|
10055
|
+
});
|
|
10056
|
+
}
|
|
10057
|
+
}
|
|
10058
|
+
|
|
10059
|
+
class MicrophoneManagerState extends InputMediaDeviceManagerState {
|
|
10060
|
+
getDeviceIdFromStream(stream) {
|
|
10061
|
+
var _a;
|
|
10062
|
+
return (_a = stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
|
|
10063
|
+
}
|
|
10064
|
+
}
|
|
10065
|
+
|
|
10066
|
+
class MicrophoneManager extends InputMediaDeviceManager {
|
|
10067
|
+
constructor(call) {
|
|
10068
|
+
super(call, new MicrophoneManagerState());
|
|
10069
|
+
}
|
|
10070
|
+
getDevices() {
|
|
10071
|
+
return getAudioDevices();
|
|
10072
|
+
}
|
|
10073
|
+
getStream(constraints) {
|
|
10074
|
+
return getAudioStream(constraints);
|
|
10075
|
+
}
|
|
10076
|
+
publishStream(stream) {
|
|
10077
|
+
return this.call.publishAudioStream(stream);
|
|
10078
|
+
}
|
|
10079
|
+
stopPublishStream() {
|
|
10080
|
+
return this.call.stopPublish(TrackType.AUDIO);
|
|
10081
|
+
}
|
|
10082
|
+
/**
|
|
10083
|
+
* Disables the audio tracks of the microphone
|
|
10084
|
+
*/
|
|
10085
|
+
pause() {
|
|
10086
|
+
var _a;
|
|
10087
|
+
(_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
|
|
10088
|
+
track.enabled = false;
|
|
10089
|
+
});
|
|
10090
|
+
}
|
|
10091
|
+
/**
|
|
10092
|
+
* (Re)enables the audio tracks of the microphone
|
|
10093
|
+
*/
|
|
10094
|
+
resume() {
|
|
10095
|
+
var _a;
|
|
10096
|
+
(_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((track) => {
|
|
10097
|
+
track.enabled = true;
|
|
10098
|
+
});
|
|
10099
|
+
}
|
|
10100
|
+
}
|
|
10101
|
+
|
|
10102
|
+
/**
|
|
9611
10103
|
* An object representation of a `Call`.
|
|
9612
10104
|
*/
|
|
9613
10105
|
class Call {
|
|
@@ -9618,7 +10110,7 @@ class Call {
|
|
|
9618
10110
|
* Use the [`StreamVideoClient.call`](./StreamVideoClient.md/#call)
|
|
9619
10111
|
* method to construct a `Call` instance.
|
|
9620
10112
|
*/
|
|
9621
|
-
constructor({ type, id, streamClient,
|
|
10113
|
+
constructor({ type, id, streamClient, members, ownCapabilities, sortParticipantsBy, clientStore, ringing = false, watching = false, }) {
|
|
9622
10114
|
/**
|
|
9623
10115
|
* ViewportTracker instance
|
|
9624
10116
|
*/
|
|
@@ -9697,7 +10189,7 @@ class Call {
|
|
|
9697
10189
|
if ((params === null || params === void 0 ? void 0 : params.ring) && !this.ringing) {
|
|
9698
10190
|
this.ringingSubject.next(true);
|
|
9699
10191
|
}
|
|
9700
|
-
this.state.
|
|
10192
|
+
this.state.updateFromCallResponse(response.call);
|
|
9701
10193
|
this.state.setMembers(response.members);
|
|
9702
10194
|
this.state.setOwnCapabilities(response.own_capabilities);
|
|
9703
10195
|
if (this.streamClient._hasConnectionID()) {
|
|
@@ -9716,7 +10208,7 @@ class Call {
|
|
|
9716
10208
|
if ((data === null || data === void 0 ? void 0 : data.ring) && !this.ringing) {
|
|
9717
10209
|
this.ringingSubject.next(true);
|
|
9718
10210
|
}
|
|
9719
|
-
this.state.
|
|
10211
|
+
this.state.updateFromCallResponse(response.call);
|
|
9720
10212
|
this.state.setMembers(response.members);
|
|
9721
10213
|
this.state.setOwnCapabilities(response.own_capabilities);
|
|
9722
10214
|
if (this.streamClient._hasConnectionID()) {
|
|
@@ -9773,7 +10265,7 @@ class Call {
|
|
|
9773
10265
|
* @returns a promise which resolves once the call join-flow has finished.
|
|
9774
10266
|
*/
|
|
9775
10267
|
this.join = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
9776
|
-
var _e, _f, _g;
|
|
10268
|
+
var _e, _f, _g, _h;
|
|
9777
10269
|
const callingState = this.state.callingState;
|
|
9778
10270
|
if ([CallingState.JOINED, CallingState.JOINING].includes(callingState)) {
|
|
9779
10271
|
this.logger('warn', 'Join method called twice, you should only call this once');
|
|
@@ -9797,7 +10289,7 @@ class Call {
|
|
|
9797
10289
|
let connectionConfig;
|
|
9798
10290
|
try {
|
|
9799
10291
|
const call = yield join(this.streamClient, this.type, this.id, data);
|
|
9800
|
-
this.state.
|
|
10292
|
+
this.state.updateFromCallResponse(call.metadata);
|
|
9801
10293
|
this.state.setMembers(call.members);
|
|
9802
10294
|
this.state.setOwnCapabilities(call.ownCapabilities);
|
|
9803
10295
|
connectionConfig = call.connectionConfig;
|
|
@@ -9962,7 +10454,7 @@ class Call {
|
|
|
9962
10454
|
connectionConfig,
|
|
9963
10455
|
});
|
|
9964
10456
|
}
|
|
9965
|
-
const audioSettings = (_f = this.
|
|
10457
|
+
const audioSettings = (_f = this.state.settings) === null || _f === void 0 ? void 0 : _f.audio;
|
|
9966
10458
|
const isDtxEnabled = !!(audioSettings === null || audioSettings === void 0 ? void 0 : audioSettings.opus_dtx_enabled);
|
|
9967
10459
|
const isRedEnabled = !!(audioSettings === null || audioSettings === void 0 ? void 0 : audioSettings.redundant_coding_enabled);
|
|
9968
10460
|
if (!this.publisher) {
|
|
@@ -10042,6 +10534,11 @@ class Call {
|
|
|
10042
10534
|
this.state.setServerSidePins(pins);
|
|
10043
10535
|
this.reconnectAttempts = 0; // reset the reconnect attempts counter
|
|
10044
10536
|
this.state.setCallingState(CallingState.JOINED);
|
|
10537
|
+
// React uses a different device management for now
|
|
10538
|
+
if (((_h = getSdkInfo()) === null || _h === void 0 ? void 0 : _h.type) !== SdkType.REACT) {
|
|
10539
|
+
this.initCamera();
|
|
10540
|
+
this.initMic();
|
|
10541
|
+
}
|
|
10045
10542
|
// 3. once we have the "joinResponse", and possibly reconciled the local state
|
|
10046
10543
|
// we schedule a fast subscription update for all remote participants
|
|
10047
10544
|
// that were visible before we reconnected or migrated to a new SFU.
|
|
@@ -10164,9 +10661,9 @@ class Call {
|
|
|
10164
10661
|
* @param trackType the track type to stop publishing.
|
|
10165
10662
|
*/
|
|
10166
10663
|
this.stopPublish = (trackType) => __awaiter(this, void 0, void 0, function* () {
|
|
10167
|
-
var
|
|
10664
|
+
var _j;
|
|
10168
10665
|
this.logger('info', `stopPublish ${TrackType[trackType]}`);
|
|
10169
|
-
yield ((
|
|
10666
|
+
yield ((_j = this.publisher) === null || _j === void 0 ? void 0 : _j.unpublishStream(trackType));
|
|
10170
10667
|
});
|
|
10171
10668
|
/**
|
|
10172
10669
|
* Update track subscription configuration for one or more participants.
|
|
@@ -10267,6 +10764,8 @@ class Call {
|
|
|
10267
10764
|
*
|
|
10268
10765
|
*
|
|
10269
10766
|
* @param deviceId the selected device, pass `undefined` to clear the device selection
|
|
10767
|
+
*
|
|
10768
|
+
* @deprecated use call.microphone.select
|
|
10270
10769
|
*/
|
|
10271
10770
|
this.setAudioDevice = (deviceId) => {
|
|
10272
10771
|
if (!this.sfuClient)
|
|
@@ -10281,6 +10780,8 @@ class Call {
|
|
|
10281
10780
|
* 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.
|
|
10282
10781
|
*
|
|
10283
10782
|
* @param deviceId the selected device, pass `undefined` to clear the device selection
|
|
10783
|
+
*
|
|
10784
|
+
* @deprecated use call.camera.select
|
|
10284
10785
|
*/
|
|
10285
10786
|
this.setVideoDevice = (deviceId) => {
|
|
10286
10787
|
if (!this.sfuClient)
|
|
@@ -10313,8 +10814,8 @@ class Call {
|
|
|
10313
10814
|
* @returns
|
|
10314
10815
|
*/
|
|
10315
10816
|
this.updatePublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
|
|
10316
|
-
var
|
|
10317
|
-
return (
|
|
10817
|
+
var _k;
|
|
10818
|
+
return (_k = this.publisher) === null || _k === void 0 ? void 0 : _k.updateVideoPublishQuality(enabledRids);
|
|
10318
10819
|
});
|
|
10319
10820
|
this.assertCallJoined = () => {
|
|
10320
10821
|
return new Promise((resolve) => {
|
|
@@ -10509,7 +11010,7 @@ class Call {
|
|
|
10509
11010
|
this.update = (updates) => __awaiter(this, void 0, void 0, function* () {
|
|
10510
11011
|
const response = yield this.streamClient.patch(`${this.streamClientBasePath}`, updates);
|
|
10511
11012
|
const { call, members, own_capabilities } = response;
|
|
10512
|
-
this.state.
|
|
11013
|
+
this.state.updateFromCallResponse(call);
|
|
10513
11014
|
this.state.setMembers(members);
|
|
10514
11015
|
this.state.setOwnCapabilities(own_capabilities);
|
|
10515
11016
|
return response;
|
|
@@ -10582,19 +11083,20 @@ class Call {
|
|
|
10582
11083
|
this.scheduleAutoDrop = () => {
|
|
10583
11084
|
if (this.dropTimeout)
|
|
10584
11085
|
clearTimeout(this.dropTimeout);
|
|
10585
|
-
const subscription = this.state.
|
|
10586
|
-
.pipe(pairwise(), tap(([
|
|
10587
|
-
|
|
11086
|
+
const subscription = this.state.settings$
|
|
11087
|
+
.pipe(pairwise(), tap(([prevSettings, currentSettings]) => {
|
|
11088
|
+
var _a;
|
|
11089
|
+
if (!currentSettings || !this.clientStore.connectedUser)
|
|
10588
11090
|
return;
|
|
10589
|
-
const isOutgoingCall = this.currentUserId ===
|
|
11091
|
+
const isOutgoingCall = this.currentUserId === ((_a = this.state.createdBy) === null || _a === void 0 ? void 0 : _a.id);
|
|
10590
11092
|
const [prevTimeoutMs, timeoutMs] = isOutgoingCall
|
|
10591
11093
|
? [
|
|
10592
|
-
|
|
10593
|
-
|
|
11094
|
+
prevSettings === null || prevSettings === void 0 ? void 0 : prevSettings.ring.auto_cancel_timeout_ms,
|
|
11095
|
+
currentSettings.ring.auto_cancel_timeout_ms,
|
|
10594
11096
|
]
|
|
10595
11097
|
: [
|
|
10596
|
-
|
|
10597
|
-
|
|
11098
|
+
prevSettings === null || prevSettings === void 0 ? void 0 : prevSettings.ring.incoming_call_timeout_ms,
|
|
11099
|
+
currentSettings.ring.incoming_call_timeout_ms,
|
|
10598
11100
|
];
|
|
10599
11101
|
if (typeof timeoutMs === 'undefined' ||
|
|
10600
11102
|
timeoutMs === prevTimeoutMs ||
|
|
@@ -10611,7 +11113,6 @@ class Call {
|
|
|
10611
11113
|
};
|
|
10612
11114
|
/**
|
|
10613
11115
|
* Retrieves the list of recordings for the current call or call session.
|
|
10614
|
-
* Updates the call state with the returned array of CallRecording objects.
|
|
10615
11116
|
*
|
|
10616
11117
|
* If `callSessionId` is provided, it will return the recordings for that call session.
|
|
10617
11118
|
* Otherwise, all recordings for the current call will be returned.
|
|
@@ -10623,9 +11124,7 @@ class Call {
|
|
|
10623
11124
|
if (callSessionId) {
|
|
10624
11125
|
endpoint = `${endpoint}/${callSessionId}`;
|
|
10625
11126
|
}
|
|
10626
|
-
|
|
10627
|
-
this.state.setCallRecordingsList(response.recordings);
|
|
10628
|
-
return response;
|
|
11127
|
+
return this.streamClient.get(`${endpoint}/recordings`);
|
|
10629
11128
|
});
|
|
10630
11129
|
/**
|
|
10631
11130
|
* Sends a custom event to all call participants.
|
|
@@ -10649,21 +11148,26 @@ class Call {
|
|
|
10649
11148
|
if (participantSorter) {
|
|
10650
11149
|
this.state.setSortParticipantsBy(participantSorter);
|
|
10651
11150
|
}
|
|
10652
|
-
this.state.setMetadata(metadata);
|
|
10653
11151
|
this.state.setMembers(members || []);
|
|
10654
11152
|
this.state.setOwnCapabilities(ownCapabilities || []);
|
|
10655
11153
|
this.state.setCallingState(ringing ? CallingState.RINGING : CallingState.IDLE);
|
|
11154
|
+
this.on('all', (event) => {
|
|
11155
|
+
// update state with the latest event data
|
|
11156
|
+
this.state.updateFromEvent(event);
|
|
11157
|
+
});
|
|
10656
11158
|
this.leaveCallHooks.push(registerEventHandlers(this, this.state, this.dispatcher));
|
|
10657
11159
|
this.registerEffects();
|
|
10658
11160
|
this.leaveCallHooks.push(createSubscription(this.trackSubscriptionsSubject.pipe(debounce((v) => timer(v.type)), map$2((v) => v.data)), (subscriptions) => { var _a; return (_a = this.sfuClient) === null || _a === void 0 ? void 0 : _a.updateSubscriptions(subscriptions); }));
|
|
11161
|
+
this.camera = new CameraManager(this);
|
|
11162
|
+
this.microphone = new MicrophoneManager(this);
|
|
10659
11163
|
}
|
|
10660
11164
|
registerEffects() {
|
|
10661
11165
|
this.leaveCallHooks.push(
|
|
10662
|
-
// handles updating the permissions context when the
|
|
10663
|
-
createSubscription(this.state.
|
|
10664
|
-
if (!
|
|
11166
|
+
// handles updating the permissions context when the settings change.
|
|
11167
|
+
createSubscription(this.state.settings$, (settings) => {
|
|
11168
|
+
if (!settings)
|
|
10665
11169
|
return;
|
|
10666
|
-
this.permissionsContext.setCallSettings(
|
|
11170
|
+
this.permissionsContext.setCallSettings(settings);
|
|
10667
11171
|
}),
|
|
10668
11172
|
// handle the case when the user permissions are modified.
|
|
10669
11173
|
createSubscription(this.state.ownCapabilities$, (ownCapabilities) => {
|
|
@@ -10687,12 +11191,11 @@ class Call {
|
|
|
10687
11191
|
}
|
|
10688
11192
|
}),
|
|
10689
11193
|
// handles the case when the user is blocked by the call owner.
|
|
10690
|
-
createSubscription(this.state.
|
|
10691
|
-
if (!
|
|
11194
|
+
createSubscription(this.state.blockedUserIds$, (blockedUserIds) => __awaiter(this, void 0, void 0, function* () {
|
|
11195
|
+
if (!blockedUserIds)
|
|
10692
11196
|
return;
|
|
10693
11197
|
const currentUserId = this.currentUserId;
|
|
10694
|
-
if (currentUserId &&
|
|
10695
|
-
metadata.blocked_user_ids.includes(currentUserId)) {
|
|
11198
|
+
if (currentUserId && blockedUserIds.includes(currentUserId)) {
|
|
10696
11199
|
this.logger('info', 'Leaving call because of being blocked');
|
|
10697
11200
|
yield this.leave();
|
|
10698
11201
|
}
|
|
@@ -10744,12 +11247,6 @@ class Call {
|
|
|
10744
11247
|
}
|
|
10745
11248
|
}
|
|
10746
11249
|
}
|
|
10747
|
-
/**
|
|
10748
|
-
* A getter for the call metadata.
|
|
10749
|
-
*/
|
|
10750
|
-
get data() {
|
|
10751
|
-
return this.state.metadata;
|
|
10752
|
-
}
|
|
10753
11250
|
/**
|
|
10754
11251
|
* A flag indicating whether the call is "ringing" type of call.
|
|
10755
11252
|
*/
|
|
@@ -10768,7 +11265,65 @@ class Call {
|
|
|
10768
11265
|
*/
|
|
10769
11266
|
get isCreatedByMe() {
|
|
10770
11267
|
var _a;
|
|
10771
|
-
return ((_a = this.state.
|
|
11268
|
+
return ((_a = this.state.createdBy) === null || _a === void 0 ? void 0 : _a.id) === this.currentUserId;
|
|
11269
|
+
}
|
|
11270
|
+
initCamera() {
|
|
11271
|
+
var _a, _b, _c;
|
|
11272
|
+
if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream) ||
|
|
11273
|
+
!this.permissionsContext.hasPermission('send-video')) {
|
|
11274
|
+
return;
|
|
11275
|
+
}
|
|
11276
|
+
// Set camera direction if it's not yet set
|
|
11277
|
+
// This will also start publishing if camera is enabled
|
|
11278
|
+
if (!this.camera.state.direction && !this.camera.state.selectedDevice) {
|
|
11279
|
+
let defaultDirection = 'front';
|
|
11280
|
+
const backendSetting = (_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.video.camera_facing;
|
|
11281
|
+
if (backendSetting) {
|
|
11282
|
+
defaultDirection = backendSetting === 'front' ? 'front' : 'back';
|
|
11283
|
+
}
|
|
11284
|
+
this.camera.selectDirection(defaultDirection);
|
|
11285
|
+
}
|
|
11286
|
+
else if (this.camera.state.status === 'enabled') {
|
|
11287
|
+
// Publish already started media streams (this is the case if there is a lobby screen before join)
|
|
11288
|
+
// Wait for media stream
|
|
11289
|
+
this.camera.state.mediaStream$
|
|
11290
|
+
.pipe(takeWhile((s) => s === undefined, true))
|
|
11291
|
+
.subscribe((stream) => {
|
|
11292
|
+
var _a;
|
|
11293
|
+
if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.videoStream)) {
|
|
11294
|
+
this.publishVideoStream(stream);
|
|
11295
|
+
}
|
|
11296
|
+
});
|
|
11297
|
+
}
|
|
11298
|
+
// Apply backend config (this is the case if there is no lobby screen before join)
|
|
11299
|
+
if (this.camera.state.status === undefined &&
|
|
11300
|
+
((_c = this.state.settings) === null || _c === void 0 ? void 0 : _c.video.camera_default_on)) {
|
|
11301
|
+
void this.camera.enable();
|
|
11302
|
+
}
|
|
11303
|
+
}
|
|
11304
|
+
initMic() {
|
|
11305
|
+
var _a, _b;
|
|
11306
|
+
if (((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream) ||
|
|
11307
|
+
!this.permissionsContext.hasPermission('send-audio')) {
|
|
11308
|
+
return;
|
|
11309
|
+
}
|
|
11310
|
+
// Publish already started media streams (this is the case if there is a lobby screen before join)
|
|
11311
|
+
if (this.microphone.state.status === 'enabled') {
|
|
11312
|
+
// Wait for media stream
|
|
11313
|
+
this.microphone.state.mediaStream$
|
|
11314
|
+
.pipe(takeWhile((s) => s === undefined, true))
|
|
11315
|
+
.subscribe((stream) => {
|
|
11316
|
+
var _a;
|
|
11317
|
+
if (!((_a = this.state.localParticipant) === null || _a === void 0 ? void 0 : _a.audioStream)) {
|
|
11318
|
+
this.publishAudioStream(stream);
|
|
11319
|
+
}
|
|
11320
|
+
});
|
|
11321
|
+
}
|
|
11322
|
+
// Apply backend config (this is the case if there is no lobby screen before join)
|
|
11323
|
+
if (this.microphone.state.status === undefined &&
|
|
11324
|
+
((_b = this.state.settings) === null || _b === void 0 ? void 0 : _b.audio.mic_default_on)) {
|
|
11325
|
+
void this.microphone.enable();
|
|
11326
|
+
}
|
|
10772
11327
|
}
|
|
10773
11328
|
}
|
|
10774
11329
|
|
|
@@ -11880,7 +12435,7 @@ class WSConnectionFallback {
|
|
|
11880
12435
|
}
|
|
11881
12436
|
}
|
|
11882
12437
|
|
|
11883
|
-
const version = '0.
|
|
12438
|
+
const version = '0.3.1';
|
|
11884
12439
|
|
|
11885
12440
|
const logger = getLogger(['location']);
|
|
11886
12441
|
const HINT_URL = `https://hint.stream-io-video.com/`;
|
|
@@ -12574,12 +13129,12 @@ class StreamVideoClient {
|
|
|
12574
13129
|
streamClient: this.streamClient,
|
|
12575
13130
|
id: c.call.id,
|
|
12576
13131
|
type: c.call.type,
|
|
12577
|
-
metadata: c.call,
|
|
12578
13132
|
members: c.members,
|
|
12579
13133
|
ownCapabilities: c.own_capabilities,
|
|
12580
13134
|
watching: data.watch,
|
|
12581
13135
|
clientStore: this.writeableStateStore,
|
|
12582
13136
|
});
|
|
13137
|
+
call.state.updateFromCallResponse(c.call);
|
|
12583
13138
|
if (data.watch) {
|
|
12584
13139
|
this.writeableStateStore.registerCall(call);
|
|
12585
13140
|
}
|
|
@@ -12587,9 +13142,9 @@ class StreamVideoClient {
|
|
|
12587
13142
|
});
|
|
12588
13143
|
return Object.assign(Object.assign({}, response), { calls: calls });
|
|
12589
13144
|
});
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
|
|
13145
|
+
/**
|
|
13146
|
+
* Returns a list of available data centers available for hosting calls.
|
|
13147
|
+
*/
|
|
12593
13148
|
this.edges = () => __awaiter(this, void 0, void 0, function* () {
|
|
12594
13149
|
return this.streamClient.get(`/edges`);
|
|
12595
13150
|
});
|
|
@@ -12764,14 +13319,15 @@ class StreamVideoClient {
|
|
|
12764
13319
|
return;
|
|
12765
13320
|
}
|
|
12766
13321
|
this.logger('info', `New call created and registered: ${call.cid}`);
|
|
12767
|
-
|
|
13322
|
+
const newCall = new Call({
|
|
12768
13323
|
streamClient: this.streamClient,
|
|
12769
13324
|
type: call.type,
|
|
12770
13325
|
id: call.id,
|
|
12771
|
-
metadata: call,
|
|
12772
13326
|
members,
|
|
12773
13327
|
clientStore: this.writeableStateStore,
|
|
12774
|
-
})
|
|
13328
|
+
});
|
|
13329
|
+
newCall.state.updateFromCallResponse(call);
|
|
13330
|
+
this.writeableStateStore.registerCall(newCall);
|
|
12775
13331
|
}));
|
|
12776
13332
|
this.eventHandlersToUnregister.push(this.on('call.ring', (event) => __awaiter(this, void 0, void 0, function* () {
|
|
12777
13333
|
if (event.type !== 'call.ring')
|
|
@@ -12785,7 +13341,6 @@ class StreamVideoClient {
|
|
|
12785
13341
|
// if `call.created` was received before `call.ring`.
|
|
12786
13342
|
// In that case, we cleanup the already tracked call.
|
|
12787
13343
|
const prevCall = this.writeableStateStore.findCall(call.type, call.id);
|
|
12788
|
-
const prevMetadata = prevCall === null || prevCall === void 0 ? void 0 : prevCall.state.metadata;
|
|
12789
13344
|
yield (prevCall === null || prevCall === void 0 ? void 0 : prevCall.leave());
|
|
12790
13345
|
// we create a new call
|
|
12791
13346
|
const theCall = new Call({
|
|
@@ -12795,8 +13350,8 @@ class StreamVideoClient {
|
|
|
12795
13350
|
members,
|
|
12796
13351
|
clientStore: this.writeableStateStore,
|
|
12797
13352
|
ringing: true,
|
|
12798
|
-
metadata: prevMetadata,
|
|
12799
13353
|
});
|
|
13354
|
+
theCall.state.updateFromCallResponse(call);
|
|
12800
13355
|
// we fetch the latest metadata for the call from the server
|
|
12801
13356
|
yield theCall.get();
|
|
12802
13357
|
this.writeableStateStore.registerCall(theCall);
|
|
@@ -12854,254 +13409,6 @@ class StreamVideoServerClient extends StreamVideoClient {
|
|
|
12854
13409
|
}
|
|
12855
13410
|
}
|
|
12856
13411
|
|
|
12857
|
-
const getDevices = (constraints) => {
|
|
12858
|
-
return new Observable((subscriber) => {
|
|
12859
|
-
navigator.mediaDevices
|
|
12860
|
-
.getUserMedia(constraints)
|
|
12861
|
-
.then((media) => {
|
|
12862
|
-
// in Firefox, devices can be enumerated after userMedia is requested
|
|
12863
|
-
// and permissions granted. Otherwise, device labels are empty
|
|
12864
|
-
navigator.mediaDevices.enumerateDevices().then((devices) => {
|
|
12865
|
-
subscriber.next(devices);
|
|
12866
|
-
// If we stop the tracks before enumerateDevices -> the labels won't show up in Firefox
|
|
12867
|
-
disposeOfMediaStream(media);
|
|
12868
|
-
subscriber.complete();
|
|
12869
|
-
});
|
|
12870
|
-
})
|
|
12871
|
-
.catch((error) => {
|
|
12872
|
-
getLogger(['devices'])('error', 'Failed to get devices', error);
|
|
12873
|
-
subscriber.error(error);
|
|
12874
|
-
});
|
|
12875
|
-
});
|
|
12876
|
-
};
|
|
12877
|
-
/**
|
|
12878
|
-
* [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
|
|
12879
|
-
*
|
|
12880
|
-
* @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.
|
|
12881
|
-
*/
|
|
12882
|
-
const checkIfAudioOutputChangeSupported = () => {
|
|
12883
|
-
if (typeof document === 'undefined')
|
|
12884
|
-
return false;
|
|
12885
|
-
const element = document.createElement('audio');
|
|
12886
|
-
return element.sinkId !== undefined;
|
|
12887
|
-
};
|
|
12888
|
-
/**
|
|
12889
|
-
* The default constraints used to request audio devices.
|
|
12890
|
-
*/
|
|
12891
|
-
const audioDeviceConstraints = {
|
|
12892
|
-
audio: {
|
|
12893
|
-
autoGainControl: true,
|
|
12894
|
-
noiseSuppression: true,
|
|
12895
|
-
echoCancellation: true,
|
|
12896
|
-
},
|
|
12897
|
-
};
|
|
12898
|
-
/**
|
|
12899
|
-
* The default constraints used to request video devices.
|
|
12900
|
-
*/
|
|
12901
|
-
const videoDeviceConstraints = {
|
|
12902
|
-
video: {
|
|
12903
|
-
width: 1280,
|
|
12904
|
-
height: 720,
|
|
12905
|
-
},
|
|
12906
|
-
};
|
|
12907
|
-
// 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
|
|
12908
|
-
const deviceChange$ = new Observable((subscriber) => {
|
|
12909
|
-
var _a, _b;
|
|
12910
|
-
const deviceChangeHandler = () => subscriber.next();
|
|
12911
|
-
(_b = (_a = navigator.mediaDevices).addEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
|
|
12912
|
-
return () => {
|
|
12913
|
-
var _a, _b;
|
|
12914
|
-
return (_b = (_a = navigator.mediaDevices).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, 'devicechange', deviceChangeHandler);
|
|
12915
|
-
};
|
|
12916
|
-
}).pipe(debounceTime(500), concatMap(() => from(navigator.mediaDevices.enumerateDevices())), shareReplay(1));
|
|
12917
|
-
const audioDevices$ = merge(getDevices(audioDeviceConstraints), deviceChange$).pipe(shareReplay(1));
|
|
12918
|
-
const videoDevices$ = merge(getDevices(videoDeviceConstraints), deviceChange$).pipe(shareReplay(1));
|
|
12919
|
-
/**
|
|
12920
|
-
* 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.
|
|
12921
|
-
*
|
|
12922
|
-
* @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.
|
|
12923
|
-
* @returns
|
|
12924
|
-
*/
|
|
12925
|
-
const getAudioDevices = () => audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audioinput')));
|
|
12926
|
-
/**
|
|
12927
|
-
* 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.
|
|
12928
|
-
*
|
|
12929
|
-
* @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.
|
|
12930
|
-
* @returns
|
|
12931
|
-
*/
|
|
12932
|
-
const getVideoDevices = () => videoDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'videoinput' && d.deviceId.length)));
|
|
12933
|
-
/**
|
|
12934
|
-
* 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)
|
|
12935
|
-
*
|
|
12936
|
-
* @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.
|
|
12937
|
-
* @returns
|
|
12938
|
-
*/
|
|
12939
|
-
const getAudioOutputDevices = () => {
|
|
12940
|
-
return audioDevices$.pipe(map$2((values) => values.filter((d) => d.kind === 'audiooutput')));
|
|
12941
|
-
};
|
|
12942
|
-
const getStream = (constraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
12943
|
-
try {
|
|
12944
|
-
return yield navigator.mediaDevices.getUserMedia(constraints);
|
|
12945
|
-
}
|
|
12946
|
-
catch (e) {
|
|
12947
|
-
getLogger(['devices'])('error', `Failed get user media`, {
|
|
12948
|
-
error: e,
|
|
12949
|
-
constraints: constraints,
|
|
12950
|
-
});
|
|
12951
|
-
throw e;
|
|
12952
|
-
}
|
|
12953
|
-
});
|
|
12954
|
-
/**
|
|
12955
|
-
* Returns an audio media stream that fulfills the given constraints.
|
|
12956
|
-
* If no constraints are provided, it uses the browser's default ones.
|
|
12957
|
-
*
|
|
12958
|
-
* @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.
|
|
12959
|
-
* @param trackConstraints the constraints to use when requesting the stream.
|
|
12960
|
-
* @returns the new `MediaStream` fulfilling the given constraints.
|
|
12961
|
-
*/
|
|
12962
|
-
const getAudioStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
12963
|
-
const constraints = {
|
|
12964
|
-
audio: Object.assign(Object.assign({}, audioDeviceConstraints.audio), trackConstraints),
|
|
12965
|
-
};
|
|
12966
|
-
return getStream(constraints);
|
|
12967
|
-
});
|
|
12968
|
-
/**
|
|
12969
|
-
* Returns a video media stream that fulfills the given constraints.
|
|
12970
|
-
* If no constraints are provided, it uses the browser's default ones.
|
|
12971
|
-
*
|
|
12972
|
-
* @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.
|
|
12973
|
-
* @param trackConstraints the constraints to use when requesting the stream.
|
|
12974
|
-
* @returns a new `MediaStream` fulfilling the given constraints.
|
|
12975
|
-
*/
|
|
12976
|
-
const getVideoStream = (trackConstraints) => __awaiter(void 0, void 0, void 0, function* () {
|
|
12977
|
-
const constraints = {
|
|
12978
|
-
video: Object.assign(Object.assign({}, videoDeviceConstraints.video), trackConstraints),
|
|
12979
|
-
};
|
|
12980
|
-
return getStream(constraints);
|
|
12981
|
-
});
|
|
12982
|
-
/**
|
|
12983
|
-
* Prompts the user for a permission to share a screen.
|
|
12984
|
-
* If the user grants the permission, a screen sharing stream is returned. Throws otherwise.
|
|
12985
|
-
*
|
|
12986
|
-
* The callers of this API are responsible to handle the possible errors.
|
|
12987
|
-
*
|
|
12988
|
-
* @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.
|
|
12989
|
-
*
|
|
12990
|
-
* @param options any additional options to pass to the [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) API.
|
|
12991
|
-
*/
|
|
12992
|
-
const getScreenShareStream = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
12993
|
-
try {
|
|
12994
|
-
return yield navigator.mediaDevices.getDisplayMedia(Object.assign({ video: true, audio: false }, options));
|
|
12995
|
-
}
|
|
12996
|
-
catch (e) {
|
|
12997
|
-
getLogger(['devices'])('error', 'Failed to get screen share stream', e);
|
|
12998
|
-
throw e;
|
|
12999
|
-
}
|
|
13000
|
-
});
|
|
13001
|
-
const watchForDisconnectedDevice = (kind, deviceId$) => {
|
|
13002
|
-
let devices$;
|
|
13003
|
-
switch (kind) {
|
|
13004
|
-
case 'audioinput':
|
|
13005
|
-
devices$ = getAudioDevices();
|
|
13006
|
-
break;
|
|
13007
|
-
case 'videoinput':
|
|
13008
|
-
devices$ = getVideoDevices();
|
|
13009
|
-
break;
|
|
13010
|
-
case 'audiooutput':
|
|
13011
|
-
devices$ = getAudioOutputDevices();
|
|
13012
|
-
break;
|
|
13013
|
-
}
|
|
13014
|
-
return combineLatest([devices$, deviceId$]).pipe(filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), map$2(() => true));
|
|
13015
|
-
};
|
|
13016
|
-
/**
|
|
13017
|
-
* Notifies the subscriber if a given 'audioinput' device is disconnected
|
|
13018
|
-
*
|
|
13019
|
-
* @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.
|
|
13020
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
13021
|
-
* @returns
|
|
13022
|
-
*/
|
|
13023
|
-
const watchForDisconnectedAudioDevice = (deviceId$) => {
|
|
13024
|
-
return watchForDisconnectedDevice('audioinput', deviceId$);
|
|
13025
|
-
};
|
|
13026
|
-
/**
|
|
13027
|
-
* Notifies the subscriber if a given 'videoinput' device is disconnected
|
|
13028
|
-
*
|
|
13029
|
-
* @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.
|
|
13030
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
13031
|
-
* @returns
|
|
13032
|
-
*/
|
|
13033
|
-
const watchForDisconnectedVideoDevice = (deviceId$) => {
|
|
13034
|
-
return watchForDisconnectedDevice('videoinput', deviceId$);
|
|
13035
|
-
};
|
|
13036
|
-
/**
|
|
13037
|
-
* Notifies the subscriber if a given 'audiooutput' device is disconnected
|
|
13038
|
-
*
|
|
13039
|
-
* @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.
|
|
13040
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
13041
|
-
* @returns
|
|
13042
|
-
*/
|
|
13043
|
-
const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
|
|
13044
|
-
return watchForDisconnectedDevice('audiooutput', deviceId$);
|
|
13045
|
-
};
|
|
13046
|
-
const watchForAddedDefaultDevice = (kind) => {
|
|
13047
|
-
let devices$;
|
|
13048
|
-
switch (kind) {
|
|
13049
|
-
case 'audioinput':
|
|
13050
|
-
devices$ = getAudioDevices();
|
|
13051
|
-
break;
|
|
13052
|
-
case 'videoinput':
|
|
13053
|
-
devices$ = getVideoDevices();
|
|
13054
|
-
break;
|
|
13055
|
-
case 'audiooutput':
|
|
13056
|
-
devices$ = getAudioOutputDevices();
|
|
13057
|
-
break;
|
|
13058
|
-
default:
|
|
13059
|
-
throw new Error('Unknown MediaDeviceKind', kind);
|
|
13060
|
-
}
|
|
13061
|
-
return devices$.pipe(pairwise(), filter(([prev, current]) => {
|
|
13062
|
-
const prevDefault = prev.find((device) => device.deviceId === 'default');
|
|
13063
|
-
const currentDefault = current.find((device) => device.deviceId === 'default');
|
|
13064
|
-
return !!(current.length > prev.length &&
|
|
13065
|
-
prevDefault &&
|
|
13066
|
-
currentDefault &&
|
|
13067
|
-
prevDefault.groupId !== currentDefault.groupId);
|
|
13068
|
-
}), map$2(() => true));
|
|
13069
|
-
};
|
|
13070
|
-
/**
|
|
13071
|
-
* Notifies the subscriber about newly added default audio input device.
|
|
13072
|
-
* @returns Observable<boolean>
|
|
13073
|
-
*/
|
|
13074
|
-
const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
|
|
13075
|
-
/**
|
|
13076
|
-
* Notifies the subscriber about newly added default audio output device.
|
|
13077
|
-
* @returns Observable<boolean>
|
|
13078
|
-
*/
|
|
13079
|
-
const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
|
|
13080
|
-
/**
|
|
13081
|
-
* Notifies the subscriber about newly added default video input device.
|
|
13082
|
-
* @returns Observable<boolean>
|
|
13083
|
-
*/
|
|
13084
|
-
const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
|
|
13085
|
-
/**
|
|
13086
|
-
* Deactivates MediaStream (stops and removes tracks) to be later garbage collected
|
|
13087
|
-
*
|
|
13088
|
-
* @param stream MediaStream
|
|
13089
|
-
* @returns void
|
|
13090
|
-
*/
|
|
13091
|
-
const disposeOfMediaStream = (stream) => {
|
|
13092
|
-
if (!stream.active)
|
|
13093
|
-
return;
|
|
13094
|
-
stream.getTracks().forEach((track) => {
|
|
13095
|
-
track.stop();
|
|
13096
|
-
stream.removeTrack(track);
|
|
13097
|
-
});
|
|
13098
|
-
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
|
|
13099
|
-
if (typeof stream.release === 'function') {
|
|
13100
|
-
// @ts-expect-error
|
|
13101
|
-
stream.release();
|
|
13102
|
-
}
|
|
13103
|
-
};
|
|
13104
|
-
|
|
13105
13412
|
const DETECTION_FREQUENCY_IN_MS = 500;
|
|
13106
13413
|
const AUDIO_LEVEL_THRESHOLD = 150;
|
|
13107
13414
|
const FFT_SIZE = 128;
|
|
@@ -13182,5 +13489,5 @@ var browsers = /*#__PURE__*/Object.freeze({
|
|
|
13182
13489
|
isSafari: isSafari
|
|
13183
13490
|
});
|
|
13184
13491
|
|
|
13185
|
-
export { AudioSettingsDefaultDeviceEnum, AudioSettingsRequestDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CreateDeviceRequestPushProviderEnum, DebounceType, ErrorFromResponse, OwnCapability, RecordSettingsModeEnum, RecordSettingsQualityEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, events as SfuEvents, models as SfuModels, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoServerClient, StreamVideoWriteableStateStore, TranscriptionSettingsModeEnum, TranscriptionSettingsRequestModeEnum, VideoSettingsCameraFacingEnum, VideoSettingsRequestCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, isStreamVideoLocalParticipant, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setSdkInfo, speakerLayoutSortPreset, speaking, watchForAddedDefaultAudioDevice, watchForAddedDefaultAudioOutputDevice, watchForAddedDefaultVideoDevice, watchForDisconnectedAudioDevice, watchForDisconnectedAudioOutputDevice, watchForDisconnectedVideoDevice };
|
|
13492
|
+
export { AudioSettingsDefaultDeviceEnum, AudioSettingsRequestDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CreateDeviceRequestPushProviderEnum, DebounceType, ErrorFromResponse, InputMediaDeviceManager, InputMediaDeviceManagerState, MicrophoneManager, OwnCapability, RecordSettingsModeEnum, RecordSettingsQualityEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, events as SfuEvents, models as SfuModels, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoServerClient, StreamVideoWriteableStateStore, TranscriptionSettingsModeEnum, TranscriptionSettingsRequestModeEnum, VideoSettingsCameraFacingEnum, VideoSettingsRequestCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, isStreamVideoLocalParticipant, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setSdkInfo, speakerLayoutSortPreset, speaking, watchForAddedDefaultAudioDevice, watchForAddedDefaultAudioOutputDevice, watchForAddedDefaultVideoDevice, watchForDisconnectedAudioDevice, watchForDisconnectedAudioOutputDevice, watchForDisconnectedVideoDevice };
|
|
13186
13493
|
//# sourceMappingURL=index.browser.es.js.map
|