@cloudflare/realtimekit-react-native 0.1.1-staging.1 → 0.1.2-staging.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/ios/RNInCallManager.m +72 -36
- package/lib/LocalMediaHandler.d.ts +10 -3
- package/lib/LocalMediaHandler.js +77 -86
- package/lib/LocalMediaInterfaces.d.ts +1 -0
- package/lib/LocalMediaUtils.d.ts +8 -1
- package/lib/LocalMediaUtils.js +24 -10
- package/lib/ReactContext.d.ts +2 -7
- package/lib/ReactContext.js +5 -11
- package/package.json +4 -4
package/ios/RNInCallManager.m
CHANGED
|
@@ -620,7 +620,11 @@ RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
|
|
|
620
620
|
[self audioSessionSetMode:audioMode
|
|
621
621
|
callerMemo:NSStringFromSelector(_cmd)];
|
|
622
622
|
|
|
623
|
-
|
|
623
|
+
@try {
|
|
624
|
+
[self sendEventWithName:@"onAudioDeviceChanged" body:@{@"devices": audioMode}];
|
|
625
|
+
} @catch (NSException *exception) {
|
|
626
|
+
NSLog(@"Error sending event 'onAudioDeviceChanged': %@", exception.reason);
|
|
627
|
+
}
|
|
624
628
|
// NSLog(@"👨💻 RNInCallManager.updateAudioRoute() audio mode has changed to %@", audioMode);
|
|
625
629
|
return true;
|
|
626
630
|
} else {
|
|
@@ -806,7 +810,11 @@ RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
|
|
|
806
810
|
if (state != self->_proximityIsNear) {
|
|
807
811
|
// NSLog(@"RNInCallManager.UIDeviceProximityStateDidChangeNotification(): isNear: %@", state ? @"YES" : @"NO");
|
|
808
812
|
self->_proximityIsNear = state;
|
|
809
|
-
|
|
813
|
+
@try {
|
|
814
|
+
[self sendEventWithName:@"Proximity" body:@{@"isNear": state ? @YES : @NO}];
|
|
815
|
+
} @catch (NSException *exception) {
|
|
816
|
+
NSLog(@"Error sending event 'Proximity': %@", exception.reason);
|
|
817
|
+
}
|
|
810
818
|
}
|
|
811
819
|
}];
|
|
812
820
|
|
|
@@ -936,62 +944,90 @@ RCT_EXPORT_METHOD(isBluetoothHeadsetConnected: (RCTPromiseResolveBlock) resolve
|
|
|
936
944
|
if ([self checkAudioRoute:@[AVAudioSessionPortHeadsetMic]
|
|
937
945
|
routeType:@"input"]) {
|
|
938
946
|
_forceSpeakerOn = 0;
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
947
|
+
@try {
|
|
948
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
949
|
+
body:@{
|
|
950
|
+
@"availableAudioDeviceList": @"[speaker, earpiece, wired]",
|
|
951
|
+
@"selectedAudioDevice": AVAudioSessionPortHeadsetMic,
|
|
952
|
+
}];
|
|
953
|
+
} @catch (NSException *exception) {
|
|
954
|
+
NSLog(@"Error sending event 'onAudioDeviceChanged' (HeadsetMic): %@", exception.reason);
|
|
955
|
+
}
|
|
944
956
|
} else if ([self checkAudioRoute:@[AVAudioSessionPortHeadphones]
|
|
945
957
|
routeType:@"output"]) {
|
|
946
958
|
_forceSpeakerOn = 0;
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
959
|
+
@try {
|
|
960
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
961
|
+
body:@{
|
|
962
|
+
@"availableAudioDeviceList": @"[speaker, earpiece, wired]",
|
|
963
|
+
@"selectedAudioDevice": AVAudioSessionPortHeadphones,
|
|
964
|
+
}];
|
|
965
|
+
} @catch (NSException *exception) {
|
|
966
|
+
NSLog(@"Error sending event 'onAudioDeviceChanged' (Headphones): %@", exception.reason);
|
|
967
|
+
}
|
|
952
968
|
} else if ([self checkAudioRoute:@[AVAudioSessionPortBluetoothHFP]
|
|
953
969
|
routeType:@"input"]) {
|
|
954
970
|
_forceSpeakerOn = 0;
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
971
|
+
@try {
|
|
972
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
973
|
+
body:@{
|
|
974
|
+
@"availableAudioDeviceList": @"[speaker, earpiece, bluetooth]",
|
|
975
|
+
@"selectedAudioDevice": AVAudioSessionPortBluetoothHFP,
|
|
976
|
+
}];
|
|
977
|
+
} @catch (NSException *exception) {
|
|
978
|
+
NSLog(@"Error sending event 'onAudioDeviceChanged' (BluetoothHFP): %@", exception.reason);
|
|
979
|
+
}
|
|
960
980
|
} else if ([self checkAudioRoute:@[AVAudioSessionPortBluetoothA2DP]
|
|
961
981
|
routeType:@"input"]) {
|
|
962
982
|
_forceSpeakerOn = 0;
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
983
|
+
@try {
|
|
984
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
985
|
+
body:@{
|
|
986
|
+
@"availableAudioDeviceList": @"[speaker, earpiece, bluetooth]",
|
|
987
|
+
@"selectedAudioDevice": AVAudioSessionPortBluetoothA2DP,
|
|
988
|
+
}];
|
|
989
|
+
} @catch (NSException *exception) {
|
|
990
|
+
NSLog(@"Error sending event 'onAudioDeviceChanged' (BluetoothA2DP): %@", exception.reason);
|
|
991
|
+
}
|
|
968
992
|
} else if ([self checkAudioRoute:@[AVAudioSessionPortBluetoothLE]
|
|
969
993
|
routeType:@"input"]) {
|
|
970
994
|
_forceSpeakerOn = 0;
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
995
|
+
@try {
|
|
996
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
997
|
+
body:@{
|
|
998
|
+
@"availableAudioDeviceList": @"[speaker, earpiece, bluetooth]",
|
|
999
|
+
@"selectedAudioDevice": AVAudioSessionPortBluetoothLE,
|
|
1000
|
+
}];
|
|
1001
|
+
} @catch (NSException *exception) {
|
|
1002
|
+
NSLog(@"Error sending event 'onAudioDeviceChanged' (BluetoothLE): %@", exception.reason);
|
|
1003
|
+
}
|
|
976
1004
|
}
|
|
977
1005
|
break;
|
|
978
1006
|
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
|
|
979
|
-
|
|
980
|
-
|
|
1007
|
+
@try {
|
|
1008
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
1009
|
+
body:@{
|
|
981
1010
|
@"availableAudioDeviceList": @"[speaker, earpiece]",
|
|
982
1011
|
@"selectedAudioDevice": @"speaker",
|
|
983
|
-
}];
|
|
1012
|
+
}];
|
|
1013
|
+
} @catch (NSException *exception) {
|
|
1014
|
+
NSLog(@"Error sending event 'onAudioDeviceChanged' (OldDeviceUnavailable): %@", exception.reason);
|
|
1015
|
+
}
|
|
984
1016
|
break;
|
|
985
1017
|
case AVAudioSessionRouteChangeReasonCategoryChange:
|
|
986
1018
|
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: CategoryChange. category=%@ mode=%@", self->_audioSession.category, self->_audioSession.mode);
|
|
987
1019
|
break;
|
|
988
1020
|
case AVAudioSessionRouteChangeReasonOverride:
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1021
|
+
@try {
|
|
1022
|
+
// NSLog(@"🧑💻 RNInCallManager.AudioRouteChange.Reason: Override");
|
|
1023
|
+
[self sendEventWithName:@"onAudioDeviceChanged"
|
|
1024
|
+
body:@{
|
|
1025
|
+
@"availableAudioDeviceList": @"[speaker, earpiece]",
|
|
1026
|
+
@"selectedAudioDevice": @"speaker",
|
|
1027
|
+
}];
|
|
1028
|
+
} @catch (NSException *exception) {
|
|
1029
|
+
NSLog(@"Error sending event 'onAudioDeviceChanged' (Override): %@", exception.reason);
|
|
1030
|
+
}
|
|
995
1031
|
break;
|
|
996
1032
|
case AVAudioSessionRouteChangeReasonWakeFromSleep:
|
|
997
1033
|
// NSLog(@"RNInCallManager.AudioRouteChange.Reason: WakeFromSleep");
|
|
@@ -77,11 +77,11 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
77
77
|
private setVideoTrack;
|
|
78
78
|
private setScreenShareTracks;
|
|
79
79
|
private onScreenShareEnded;
|
|
80
|
-
disableAudio(): void
|
|
80
|
+
disableAudio(): Promise<void>;
|
|
81
81
|
enableAudio(): Promise<void>;
|
|
82
|
+
toggleAudio(): Promise<void>;
|
|
82
83
|
enableVideo(): Promise<void>;
|
|
83
84
|
disableVideo(): Promise<void>;
|
|
84
|
-
toggleAudio(): Promise<void>;
|
|
85
85
|
toggleVideo(): Promise<void>;
|
|
86
86
|
setAudioDevice(device: MediaDeviceInfo): Promise<void>;
|
|
87
87
|
setVideoDevice(device: MediaDeviceInfo): Promise<void>;
|
|
@@ -102,7 +102,14 @@ export default class LocalMediaHandler extends EventEmitter {
|
|
|
102
102
|
getDeviceById(deviceId: string, kind: 'audioinput' | 'audiooutput' | 'videoinput'): MediaDeviceInfo;
|
|
103
103
|
getAudioDevices(): MediaDeviceInfo[];
|
|
104
104
|
getVideoDevices(): MediaDeviceInfo[];
|
|
105
|
-
getSpeakerDevices():
|
|
105
|
+
getSpeakerDevices(): {
|
|
106
|
+
deviceId: string;
|
|
107
|
+
label: string;
|
|
108
|
+
kind: string;
|
|
109
|
+
groupId: string;
|
|
110
|
+
facing: string;
|
|
111
|
+
toJSON(): any;
|
|
112
|
+
}[];
|
|
106
113
|
onDeviceChange(changedDevices: {
|
|
107
114
|
added: MediaDeviceInfo[];
|
|
108
115
|
removed: MediaDeviceInfo[];
|
package/lib/LocalMediaHandler.js
CHANGED
|
@@ -28,6 +28,7 @@ import InCallManger from './NativeAudioManager';
|
|
|
28
28
|
import { setupPermissions } from './PermissionHandler';
|
|
29
29
|
const { DyteHelper, BroadcastEventEmitter } = NativeModules;
|
|
30
30
|
const broadcastEmitter = new NativeEventEmitter(BroadcastEventEmitter);
|
|
31
|
+
// eslint-disable-next-line no-shadow
|
|
31
32
|
export var MediaEvents;
|
|
32
33
|
(function (MediaEvents) {
|
|
33
34
|
MediaEvents[MediaEvents["AUDIO_TRACK_CHANGE"] = 0] = "AUDIO_TRACK_CHANGE";
|
|
@@ -98,8 +99,7 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
98
99
|
video: undefined,
|
|
99
100
|
speaker: undefined,
|
|
100
101
|
};
|
|
101
|
-
//
|
|
102
|
-
//if (Platform.OS === 'android')
|
|
102
|
+
// LocalMediaUtils onDeviceChange with callback from native onAudioDeviceChanged events
|
|
103
103
|
__classPrivateFieldGet(this, _LocalMediaHandler_localMediaUtils, "f").onDeviceChange((changedDevices) => __awaiter(this, void 0, void 0, function* () {
|
|
104
104
|
yield this.onDeviceChange(changedDevices, false);
|
|
105
105
|
}));
|
|
@@ -241,7 +241,13 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
241
241
|
(_b = this.audioTrack) === null || _b === void 0 ? void 0 : _b.stop();
|
|
242
242
|
(_c = this.rawAudioTrack) === null || _c === void 0 ? void 0 : _c.stop();
|
|
243
243
|
}
|
|
244
|
-
|
|
244
|
+
try {
|
|
245
|
+
this.rawAudioTrack = yield LocalMediaUtils.getAudioTrack();
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
console.warn('Failed to acquire audio track: ', err);
|
|
249
|
+
this.rawAudioTrack = undefined;
|
|
250
|
+
}
|
|
245
251
|
this.setAudioTrack(this.rawAudioTrack);
|
|
246
252
|
this.addMediaStreamTrackListeners(this.audioTrack);
|
|
247
253
|
this.setDevice(this.currentDevices.audio);
|
|
@@ -254,11 +260,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
254
260
|
if (this.audioTrack && this.permissions.audio === 'NOT_REQUESTED') {
|
|
255
261
|
yield __classPrivateFieldGet(this, _LocalMediaHandler_localMediaUtils, "f").repopulateAvailableDevices();
|
|
256
262
|
}
|
|
257
|
-
this.permissions.audio = 'ACCEPTED';
|
|
258
|
-
this.emit('MEDIA_PERMISSION_UPDATE', {
|
|
259
|
-
kind: 'audio',
|
|
260
|
-
message: this.permissions.audio,
|
|
261
|
-
});
|
|
262
263
|
this.emit('DEVICE_CHANGE', {
|
|
263
264
|
device: this.currentDevices.audio,
|
|
264
265
|
});
|
|
@@ -294,7 +295,13 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
294
295
|
videoDeviceId,
|
|
295
296
|
});
|
|
296
297
|
if (!this.rawVideoTrack) {
|
|
297
|
-
|
|
298
|
+
try {
|
|
299
|
+
this.rawVideoTrack = yield LocalMediaUtils.getVideoTrack(videoConstraints);
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
console.warn('Failed to acquire video track: ', err);
|
|
303
|
+
this.rawVideoTrack = undefined;
|
|
304
|
+
}
|
|
298
305
|
}
|
|
299
306
|
this.setVideoTrack(this.rawVideoTrack);
|
|
300
307
|
this.addMediaStreamTrackListeners(this.rawVideoTrack);
|
|
@@ -310,11 +317,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
310
317
|
if (this.videoTrack && this.permissions.video === 'NOT_REQUESTED') {
|
|
311
318
|
yield __classPrivateFieldGet(this, _LocalMediaHandler_localMediaUtils, "f").repopulateAvailableDevices();
|
|
312
319
|
}
|
|
313
|
-
this.permissions.video = 'ACCEPTED';
|
|
314
|
-
this.emit('MEDIA_PERMISSION_UPDATE', {
|
|
315
|
-
kind: 'video',
|
|
316
|
-
message: this.permissions.video,
|
|
317
|
-
});
|
|
318
320
|
this.emit('DEVICE_CHANGE', {
|
|
319
321
|
device: this.currentDevices.video,
|
|
320
322
|
});
|
|
@@ -327,23 +329,17 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
327
329
|
if (!speakerDevices.length) {
|
|
328
330
|
return;
|
|
329
331
|
}
|
|
330
|
-
const
|
|
332
|
+
const lastDeviceIndex = speakerDevices.length - 1;
|
|
333
|
+
const speakerDeviceId = deviceId !== null && deviceId !== void 0 ? deviceId : speakerDevices[lastDeviceIndex].deviceId;
|
|
331
334
|
if (((_a = this.currentDevices.speaker) === null || _a === void 0 ? void 0 : _a.deviceId) !== speakerDeviceId) {
|
|
332
|
-
|
|
335
|
+
// Audio Input devices are same as output devices in mobile
|
|
336
|
+
this.currentDevices.audio = __classPrivateFieldGet(this, _LocalMediaHandler_localMediaUtils, "f").getDeviceById(speakerDeviceId, 'audioinput');
|
|
337
|
+
this.currentDevices.speaker = this.currentDevices.audio;
|
|
333
338
|
}
|
|
339
|
+
yield this.setDevice(this.currentDevices.audio);
|
|
334
340
|
this.emit('DEVICE_CHANGE', {
|
|
335
341
|
device: this.currentDevices.speaker,
|
|
336
342
|
});
|
|
337
|
-
/*
|
|
338
|
-
TODO
|
|
339
|
-
const speakerDeviceId = deviceId ?? speakerDevices[0].deviceId;
|
|
340
|
-
if (this.currentDevices.speaker?.deviceId !== speakerDeviceId) {
|
|
341
|
-
this.currentDevices.speaker = this.#localMediaUtils.getDeviceById(
|
|
342
|
-
speakerDeviceId,
|
|
343
|
-
'audiooutput'
|
|
344
|
-
);
|
|
345
|
-
callStats.selectedDevice('SPEAKER', this.currentDevices.speaker);
|
|
346
|
-
} */
|
|
347
343
|
});
|
|
348
344
|
}
|
|
349
345
|
getOperationalWebcamDeviceId() {
|
|
@@ -374,10 +370,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
374
370
|
getOperationalMicDeviceId() {
|
|
375
371
|
return __awaiter(this, void 0, void 0, function* () {
|
|
376
372
|
let audioDevices = __classPrivateFieldGet(this, _LocalMediaHandler_localMediaUtils, "f").getAudioDevices();
|
|
377
|
-
// console.log(
|
|
378
|
-
// 'getOperationalMicDeviceId: ',
|
|
379
|
-
// JSON.stringify(audioDevices, null, 2)
|
|
380
|
-
// );
|
|
381
373
|
if (!audioDevices.length) {
|
|
382
374
|
return { isOperational: false, deviceId: null };
|
|
383
375
|
}
|
|
@@ -387,10 +379,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
387
379
|
We are giving preference to external device
|
|
388
380
|
*/
|
|
389
381
|
audioDevices = [...audioDevices].reverse();
|
|
390
|
-
// console.log(
|
|
391
|
-
// 'getOperationalMicDeviceId Reverse: ',
|
|
392
|
-
// JSON.stringify(audioDevices, null, 2)
|
|
393
|
-
// );
|
|
394
382
|
let operationalDeviceId = null;
|
|
395
383
|
for (let deviceIndex = 0; deviceIndex < audioDevices.length; deviceIndex += 1) {
|
|
396
384
|
try {
|
|
@@ -403,7 +391,9 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
403
391
|
break;
|
|
404
392
|
}
|
|
405
393
|
}
|
|
406
|
-
catch (err) {
|
|
394
|
+
catch (err) {
|
|
395
|
+
console.warn('Failed to acquire audio track: ', err);
|
|
396
|
+
}
|
|
407
397
|
}
|
|
408
398
|
return operationalDeviceId
|
|
409
399
|
? { isOperational: true, deviceId: operationalDeviceId }
|
|
@@ -412,7 +402,7 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
412
402
|
}
|
|
413
403
|
setupStreams(_a) {
|
|
414
404
|
return __awaiter(this, arguments, void 0, function* ({ audio, video, }) {
|
|
415
|
-
var _b, _c
|
|
405
|
+
var _b, _c;
|
|
416
406
|
try {
|
|
417
407
|
const permResult = yield setupPermissions(audio, video);
|
|
418
408
|
this.permissions.video = permResult.camera;
|
|
@@ -422,6 +412,14 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
422
412
|
this.permissions.video = (_b = val.camera) !== null && _b !== void 0 ? _b : false;
|
|
423
413
|
this.permissions.audio = (_c = val.microphone) !== null && _c !== void 0 ? _c : false;
|
|
424
414
|
}
|
|
415
|
+
this.emit('MEDIA_PERMISSION_UPDATE', {
|
|
416
|
+
kind: 'audio',
|
|
417
|
+
message: this.permissions.audio,
|
|
418
|
+
});
|
|
419
|
+
this.emit('MEDIA_PERMISSION_UPDATE', {
|
|
420
|
+
kind: 'video',
|
|
421
|
+
message: this.permissions.video,
|
|
422
|
+
});
|
|
425
423
|
const constraints = {};
|
|
426
424
|
if (!this.currentDevices) {
|
|
427
425
|
this.currentDevices = {
|
|
@@ -450,37 +448,20 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
450
448
|
constraints.video = videoConstraints.video;
|
|
451
449
|
}
|
|
452
450
|
}
|
|
453
|
-
const { audioTrack, videoTrack } = yield LocalMediaUtils.getAudioAndVideoTrack(constraints);
|
|
454
|
-
if (audio && audioTrack) {
|
|
455
|
-
this.rawAudioTrack = audioTrack;
|
|
456
|
-
this.permissions.audio = 'ACCEPTED';
|
|
457
|
-
}
|
|
458
|
-
this.emit('MEDIA_PERMISSION_UPDATE', {
|
|
459
|
-
kind: 'audio',
|
|
460
|
-
message: this.permissions.audio,
|
|
461
|
-
});
|
|
462
|
-
if (video && videoTrack) {
|
|
463
|
-
this.rawVideoTrack = videoTrack;
|
|
464
|
-
this.permissions.video = 'ACCEPTED';
|
|
465
|
-
}
|
|
466
|
-
this.emit('MEDIA_PERMISSION_UPDATE', {
|
|
467
|
-
kind: 'video',
|
|
468
|
-
message: this.permissions.video,
|
|
469
|
-
});
|
|
470
|
-
if (((_d = Object.keys(constraints)) === null || _d === void 0 ? void 0 : _d.length) === 0) {
|
|
471
|
-
this.audioEnabled = false;
|
|
472
|
-
this.videoEnabled = false;
|
|
473
|
-
return;
|
|
474
|
-
}
|
|
475
451
|
if (audio)
|
|
476
452
|
yield this.setupAudioStream();
|
|
477
453
|
if (video)
|
|
478
454
|
yield this.setupVideoStream();
|
|
479
|
-
if (audioTrack)
|
|
455
|
+
if (this.audioTrack)
|
|
480
456
|
this.audioEnabled = true;
|
|
481
|
-
|
|
457
|
+
else
|
|
458
|
+
this.audioEnabled = false;
|
|
459
|
+
if (this.videoTrack)
|
|
482
460
|
this.videoEnabled = true;
|
|
461
|
+
else
|
|
462
|
+
this.videoEnabled = false;
|
|
483
463
|
this.screenShareEnabled = false;
|
|
464
|
+
// Setting default audio output to speaker
|
|
484
465
|
yield this.setupSpeaker();
|
|
485
466
|
// Setup Foreground Service after handling permissions
|
|
486
467
|
if (Platform.OS === 'android') {
|
|
@@ -570,12 +551,16 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
570
551
|
this.emit('SCREENSHARE_ENDED');
|
|
571
552
|
}
|
|
572
553
|
disableAudio() {
|
|
573
|
-
this
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
}
|
|
554
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
555
|
+
yield this.toggleAudio();
|
|
556
|
+
});
|
|
577
557
|
}
|
|
578
558
|
enableAudio() {
|
|
559
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
560
|
+
yield this.toggleAudio();
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
toggleAudio() {
|
|
579
564
|
return __awaiter(this, void 0, void 0, function* () {
|
|
580
565
|
var _a, _b;
|
|
581
566
|
if (this.permissions.audio !== 'ACCEPTED') {
|
|
@@ -591,8 +576,16 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
591
576
|
kind: 'audio',
|
|
592
577
|
message: this.permissions.audio,
|
|
593
578
|
});
|
|
594
|
-
if (this.permissions.audio === 'DENIED'
|
|
579
|
+
if (this.permissions.audio === 'DENIED' ||
|
|
580
|
+
this.permissions.audio === 'NOT_REQUESTED') {
|
|
581
|
+
this.audioEnabled = false;
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (this.audioEnabled) {
|
|
595
585
|
this.audioEnabled = false;
|
|
586
|
+
if (this.audioTrack) {
|
|
587
|
+
this.audioTrack.enabled = this.audioEnabled;
|
|
588
|
+
}
|
|
596
589
|
return;
|
|
597
590
|
}
|
|
598
591
|
try {
|
|
@@ -631,20 +624,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
631
624
|
yield this.toggleVideo();
|
|
632
625
|
});
|
|
633
626
|
}
|
|
634
|
-
toggleAudio() {
|
|
635
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
636
|
-
var _a;
|
|
637
|
-
if (this.permissions.audio === 'DENIED') {
|
|
638
|
-
this.audioEnabled = false;
|
|
639
|
-
return;
|
|
640
|
-
}
|
|
641
|
-
if (!this.audioTrack) {
|
|
642
|
-
yield this.setupAudioStream((_a = this.currentDevices.audio) === null || _a === void 0 ? void 0 : _a.deviceId);
|
|
643
|
-
}
|
|
644
|
-
this.audioEnabled = !this.audioEnabled;
|
|
645
|
-
this.audioTrack.enabled = this.audioEnabled;
|
|
646
|
-
});
|
|
647
|
-
}
|
|
648
627
|
toggleVideo() {
|
|
649
628
|
return __awaiter(this, void 0, void 0, function* () {
|
|
650
629
|
var _a, _b;
|
|
@@ -661,7 +640,8 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
661
640
|
kind: 'video',
|
|
662
641
|
message: this.permissions.video,
|
|
663
642
|
});
|
|
664
|
-
if (this.permissions.video === 'DENIED'
|
|
643
|
+
if (this.permissions.video === 'DENIED' ||
|
|
644
|
+
this.permissions.video === 'NOT_REQUESTED') {
|
|
665
645
|
this.videoEnabled = false;
|
|
666
646
|
return;
|
|
667
647
|
}
|
|
@@ -794,12 +774,16 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
794
774
|
*/
|
|
795
775
|
if (addedDevice) {
|
|
796
776
|
if (addedDevice.kind === 'audioinput') {
|
|
797
|
-
|
|
798
|
-
|
|
777
|
+
if (this.permissions.audio === 'DENIED' ||
|
|
778
|
+
this.permissions.audio === 'NOT_REQUESTED') {
|
|
779
|
+
yield this.setupSpeaker(addedDevice.deviceId);
|
|
780
|
+
}
|
|
781
|
+
else {
|
|
782
|
+
yield this.setupAudioStream(addedDevice.deviceId);
|
|
783
|
+
}
|
|
799
784
|
}
|
|
800
785
|
else if (addedDevice.kind === 'videoinput') {
|
|
801
786
|
yield this.setupVideoStream(addedDevice.deviceId);
|
|
802
|
-
this.emit('DEVICE_CHANGE', this.currentDevices.video);
|
|
803
787
|
}
|
|
804
788
|
else if (addedDevice.kind === 'audiooutput') {
|
|
805
789
|
yield this.setupSpeaker(addedDevice.deviceId);
|
|
@@ -808,7 +792,13 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
808
792
|
}
|
|
809
793
|
if (removedDevice) {
|
|
810
794
|
if (removedDevice.kind === 'audioinput') {
|
|
811
|
-
|
|
795
|
+
if (this.permissions.audio === 'DENIED' ||
|
|
796
|
+
this.permissions.audio === 'NOT_REQUESTED') {
|
|
797
|
+
yield this.setupSpeaker();
|
|
798
|
+
}
|
|
799
|
+
else {
|
|
800
|
+
yield this.setupAudioStream();
|
|
801
|
+
}
|
|
812
802
|
}
|
|
813
803
|
else if (removedDevice.kind === 'videoinput') {
|
|
814
804
|
yield this.setupVideoStream();
|
|
@@ -818,7 +808,9 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
818
808
|
}
|
|
819
809
|
this.emit('AUDIO_TRACK_CHANGE');
|
|
820
810
|
}
|
|
821
|
-
|
|
811
|
+
if (changedDevices.added.length || changedDevices.removed.length) {
|
|
812
|
+
this.emit('DEVICE_LIST_UPDATED', changedDevices);
|
|
813
|
+
}
|
|
822
814
|
});
|
|
823
815
|
}
|
|
824
816
|
cleanUpTracks() {
|
|
@@ -837,7 +829,6 @@ class LocalMediaHandler extends EventEmitter {
|
|
|
837
829
|
}
|
|
838
830
|
static init(_) {
|
|
839
831
|
return __awaiter(this, void 0, void 0, function* () {
|
|
840
|
-
yield setupPermissions(true, true);
|
|
841
832
|
const localMediaUtils = yield LocalMediaUtils.init();
|
|
842
833
|
return new LocalMediaHandler(localMediaUtils);
|
|
843
834
|
});
|
|
@@ -68,6 +68,7 @@ export interface RealtimeKitMediaTrackConstraints extends MediaTrackConstraints
|
|
|
68
68
|
}
|
|
69
69
|
export interface RealtimeKitMediaStreamConstraints extends MediaStreamConstraints {
|
|
70
70
|
audio?: boolean | RealtimeKitMediaTrackConstraints;
|
|
71
|
+
timeout?: number;
|
|
71
72
|
}
|
|
72
73
|
export interface VideoConstraints {
|
|
73
74
|
[key: string]: RealtimeKitMediaTrackConstraints;
|
package/lib/LocalMediaUtils.d.ts
CHANGED
|
@@ -89,5 +89,12 @@ export default class LocalMediaUtils {
|
|
|
89
89
|
/**
|
|
90
90
|
* Returns all audio output devices (speaker devices).
|
|
91
91
|
*/
|
|
92
|
-
getSpeakerDevices():
|
|
92
|
+
getSpeakerDevices(): {
|
|
93
|
+
deviceId: string;
|
|
94
|
+
label: string;
|
|
95
|
+
kind: string;
|
|
96
|
+
groupId: string;
|
|
97
|
+
facing: string;
|
|
98
|
+
toJSON(): any;
|
|
99
|
+
}[];
|
|
93
100
|
}
|
package/lib/LocalMediaUtils.js
CHANGED
|
@@ -143,7 +143,7 @@ class LocalMediaUtils {
|
|
|
143
143
|
return yield mediaDevices.getUserMedia(constraints);
|
|
144
144
|
}
|
|
145
145
|
// NOTE(roerohan): The await is required to catch errors (if any).
|
|
146
|
-
return
|
|
146
|
+
return Promise.race([
|
|
147
147
|
mediaDevices.getUserMedia(constraints),
|
|
148
148
|
new Promise((_resolve, reject) => {
|
|
149
149
|
setTimeout(() => reject(new LocalMediaError('Get user media timed out', 'ERR_GUM_TIMEOUT')), timeout);
|
|
@@ -159,13 +159,14 @@ class LocalMediaUtils {
|
|
|
159
159
|
return __awaiter(this, void 0, void 0, function* () {
|
|
160
160
|
const mediaStream = (yield LocalMediaUtils.getUserMediaWithTimeout({
|
|
161
161
|
audio: true,
|
|
162
|
+
timeout: 5000,
|
|
162
163
|
}));
|
|
163
164
|
return mediaStream.getAudioTracks()[0];
|
|
164
165
|
});
|
|
165
166
|
}
|
|
166
167
|
static getVideoTrack(constraints) {
|
|
167
168
|
return __awaiter(this, void 0, void 0, function* () {
|
|
168
|
-
const mediaStream = (yield LocalMediaUtils.getUserMediaWithTimeout(constraints));
|
|
169
|
+
const mediaStream = (yield LocalMediaUtils.getUserMediaWithTimeout(Object.assign(Object.assign({}, constraints), { timeout: 5000 })));
|
|
169
170
|
return mediaStream.getVideoTracks()[0];
|
|
170
171
|
});
|
|
171
172
|
}
|
|
@@ -186,11 +187,16 @@ class LocalMediaUtils {
|
|
|
186
187
|
}
|
|
187
188
|
static getAudioAndVideoTrack(constraints) {
|
|
188
189
|
return __awaiter(this, void 0, void 0, function* () {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
190
|
+
try {
|
|
191
|
+
const mediaStream = (yield LocalMediaUtils.getUserMediaWithTimeout(Object.assign(Object.assign({}, constraints), { timeout: 5000 })));
|
|
192
|
+
return {
|
|
193
|
+
audioTrack: mediaStream.getAudioTracks()[0],
|
|
194
|
+
videoTrack: mediaStream.getVideoTracks()[0],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
throw err;
|
|
199
|
+
}
|
|
194
200
|
});
|
|
195
201
|
}
|
|
196
202
|
onDeviceChange(callback) {
|
|
@@ -212,7 +218,9 @@ class LocalMediaUtils {
|
|
|
212
218
|
removed: previouslyAvailableDevices.filter((device) => !currentlyAvailableDeviceIds.includes(device.deviceId)),
|
|
213
219
|
};
|
|
214
220
|
this.repopulateAvailableDevices().then(() => {
|
|
215
|
-
|
|
221
|
+
if (changedDevices.added.length || changedDevices.removed.length) {
|
|
222
|
+
callback(changedDevices, false);
|
|
223
|
+
}
|
|
216
224
|
});
|
|
217
225
|
}
|
|
218
226
|
else {
|
|
@@ -224,7 +232,9 @@ class LocalMediaUtils {
|
|
|
224
232
|
removed: previouslyAvailableDevices.filter((device) => !currentlyAvailableDeviceIds.includes(device.deviceId)),
|
|
225
233
|
};
|
|
226
234
|
this.repopulateAvailableDevices().then(() => {
|
|
227
|
-
|
|
235
|
+
if (changedDevices.added.length || changedDevices.removed.length) {
|
|
236
|
+
callback(changedDevices, false);
|
|
237
|
+
}
|
|
228
238
|
});
|
|
229
239
|
}
|
|
230
240
|
});
|
|
@@ -269,7 +279,11 @@ class LocalMediaUtils {
|
|
|
269
279
|
* Returns all audio output devices (speaker devices).
|
|
270
280
|
*/
|
|
271
281
|
getSpeakerDevices() {
|
|
272
|
-
|
|
282
|
+
const speakerDevices = __classPrivateFieldGet(this, _LocalMediaUtils_availableDevices, "f");
|
|
283
|
+
// In Mobile, speaker devices are the same as audio input devices
|
|
284
|
+
return speakerDevices
|
|
285
|
+
.filter((device) => device.kind === 'audioinput')
|
|
286
|
+
.map((device) => (Object.assign(Object.assign({}, device), { deviceId: device.deviceId, label: device.label, kind: 'audiooutput' })));
|
|
273
287
|
}
|
|
274
288
|
}
|
|
275
289
|
_LocalMediaUtils_availableDevices = new WeakMap(), _LocalMediaUtils_nativeEventEmitter = new WeakMap();
|
package/lib/ReactContext.d.ts
CHANGED
|
@@ -22,16 +22,11 @@ export declare const RealtimeKitContext: React.Context<{
|
|
|
22
22
|
* @param renderBeforeLoad The provider will not render children by default
|
|
23
23
|
* until it gets a client object, renderBeforeLoad can be used to override that
|
|
24
24
|
*/
|
|
25
|
-
export declare function RealtimeKitProvider({ value, children,
|
|
25
|
+
export declare function RealtimeKitProvider({ value, children, fallback, }: {
|
|
26
26
|
value: RealtimeKitClient | undefined;
|
|
27
27
|
children: ReactChild | ReactChild[];
|
|
28
|
-
|
|
28
|
+
fallback?: ReactChild | ReactChild[];
|
|
29
29
|
}): JSX.Element;
|
|
30
|
-
export declare namespace RealtimeKitProvider {
|
|
31
|
-
var defaultProps: {
|
|
32
|
-
renderBeforeLoad: boolean;
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
30
|
/**
|
|
36
31
|
* Hook which returns the reference to the DyteClient object
|
|
37
32
|
* @returns meeting instance from `useDyteClient()`
|
package/lib/ReactContext.js
CHANGED
|
@@ -59,31 +59,25 @@ export const RealtimeKitContext = createContext({
|
|
|
59
59
|
* @param renderBeforeLoad The provider will not render children by default
|
|
60
60
|
* until it gets a client object, renderBeforeLoad can be used to override that
|
|
61
61
|
*/
|
|
62
|
-
export function RealtimeKitProvider({ value, children,
|
|
63
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
64
|
-
renderBeforeLoad, }) {
|
|
62
|
+
export function RealtimeKitProvider({ value, children, fallback = null, }) {
|
|
65
63
|
const [updates, setUpdates] = useState();
|
|
66
64
|
const updatesRef = useRef();
|
|
67
65
|
useEffect(() => {
|
|
68
66
|
if (value) {
|
|
69
|
-
|
|
67
|
+
const newUpdate = new RealtimeKitUpdates(value);
|
|
68
|
+
setUpdates(newUpdate);
|
|
69
|
+
updatesRef.current = newUpdate;
|
|
70
70
|
}
|
|
71
71
|
return () => {
|
|
72
72
|
var _a;
|
|
73
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
74
73
|
(_a = updatesRef.current) === null || _a === void 0 ? void 0 : _a.clean();
|
|
75
74
|
};
|
|
76
75
|
}, [value]);
|
|
77
|
-
if (!value)
|
|
78
|
-
return null;
|
|
79
76
|
return (React.createElement(RealtimeKitContext.Provider, { value: {
|
|
80
77
|
meeting: value,
|
|
81
78
|
updates,
|
|
82
|
-
} }, children));
|
|
79
|
+
} }, value ? children : fallback));
|
|
83
80
|
}
|
|
84
|
-
RealtimeKitProvider.defaultProps = {
|
|
85
|
-
renderBeforeLoad: false,
|
|
86
|
-
};
|
|
87
81
|
/**
|
|
88
82
|
* Hook which returns the reference to the DyteClient object
|
|
89
83
|
* @returns meeting instance from `useDyteClient()`
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudflare/realtimekit-react-native",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2-staging.1",
|
|
4
4
|
"description": "Cloudflare RealtimeKit SDK for react native",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
|
-
"author": "
|
|
7
|
-
"homepage": "https://
|
|
6
|
+
"author": "Cloudflare",
|
|
7
|
+
"homepage": "https://realtime.cloudflare.com",
|
|
8
8
|
"types": "lib/index.d.ts",
|
|
9
9
|
"files": [
|
|
10
10
|
"lib",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"!**/__mocks__"
|
|
22
22
|
],
|
|
23
23
|
"bugs": {
|
|
24
|
-
"url": "https://
|
|
24
|
+
"url": "https://realtime.cloudflare.com/issues"
|
|
25
25
|
},
|
|
26
26
|
"private": false,
|
|
27
27
|
"dependencies": {
|