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