@stream-io/video-client 1.0.2 → 1.0.4
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 +14 -0
- package/dist/index.browser.es.js +82 -56
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +82 -56
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +82 -56
- package/dist/index.es.js.map +1 -1
- package/dist/src/devices/InputMediaDeviceManager.d.ts +2 -2
- package/dist/src/stats/SfuStatsReporter.d.ts +2 -2
- package/dist/src/stats/stateStoreStatsReporter.d.ts +3 -2
- package/dist/src/stats/utils.d.ts +3 -0
- package/package.json +1 -1
- package/src/Call.ts +16 -6
- package/src/devices/InputMediaDeviceManager.ts +1 -1
- package/src/rtc/Publisher.ts +17 -14
- package/src/rtc/Subscriber.ts +19 -14
- package/src/stats/SfuStatsReporter.ts +6 -15
- package/src/stats/stateStoreStatsReporter.ts +29 -21
- package/src/stats/utils.ts +15 -11
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
### [1.0.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.0.3...@stream-io/video-client-1.0.4) (2024-05-14)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* don't create publisher PC for anonymous users ([#1353](https://github.com/GetStream/stream-video-js/issues/1353)) ([7331767](https://github.com/GetStream/stream-video-js/commit/7331767bd9254082517b1f36895796032b7af149))
|
|
11
|
+
|
|
12
|
+
### [1.0.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.0.2...@stream-io/video-client-1.0.3) (2024-05-13)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* improve error handling across the SDK ([#1350](https://github.com/GetStream/stream-video-js/issues/1350)) ([ac0ae3b](https://github.com/GetStream/stream-video-js/commit/ac0ae3b7d5da91152d0f41a203b73e6c99c42ff9))
|
|
18
|
+
|
|
5
19
|
### [1.0.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.0.1...@stream-io/video-client-1.0.2) (2024-05-13)
|
|
6
20
|
|
|
7
21
|
|
package/dist/index.browser.es.js
CHANGED
|
@@ -8399,15 +8399,19 @@ class Publisher {
|
|
|
8399
8399
|
return getPreferredCodecs('audio', preferredCodec ?? defaultAudioCodec, codecToRemove);
|
|
8400
8400
|
}
|
|
8401
8401
|
};
|
|
8402
|
-
this.onIceCandidate =
|
|
8402
|
+
this.onIceCandidate = (e) => {
|
|
8403
8403
|
const { candidate } = e;
|
|
8404
8404
|
if (!candidate) {
|
|
8405
8405
|
logger$3('debug', 'null ice candidate');
|
|
8406
8406
|
return;
|
|
8407
8407
|
}
|
|
8408
|
-
|
|
8408
|
+
this.sfuClient
|
|
8409
|
+
.iceTrickle({
|
|
8409
8410
|
iceCandidate: getIceCandidate(candidate),
|
|
8410
8411
|
peerType: PeerType.PUBLISHER_UNSPECIFIED,
|
|
8412
|
+
})
|
|
8413
|
+
.catch((err) => {
|
|
8414
|
+
logger$3('warn', `ICETrickle failed`, err);
|
|
8411
8415
|
});
|
|
8412
8416
|
};
|
|
8413
8417
|
/**
|
|
@@ -8448,8 +8452,8 @@ class Publisher {
|
|
|
8448
8452
|
}
|
|
8449
8453
|
await this.negotiate({ iceRestart: true });
|
|
8450
8454
|
};
|
|
8451
|
-
this.onNegotiationNeeded =
|
|
8452
|
-
|
|
8455
|
+
this.onNegotiationNeeded = () => {
|
|
8456
|
+
this.negotiate().catch((err) => logger$3('warn', `Negotiation failed.`, err));
|
|
8453
8457
|
};
|
|
8454
8458
|
/**
|
|
8455
8459
|
* Initiates a new offer/answer exchange with the currently connected SFU.
|
|
@@ -8639,10 +8643,12 @@ class Publisher {
|
|
|
8639
8643
|
this.isDtxEnabled = isDtxEnabled;
|
|
8640
8644
|
this.isRedEnabled = isRedEnabled;
|
|
8641
8645
|
this.iceRestartDelay = iceRestartDelay;
|
|
8642
|
-
this.unsubscribeOnIceRestart = dispatcher.on('iceRestart',
|
|
8646
|
+
this.unsubscribeOnIceRestart = dispatcher.on('iceRestart', (iceRestart) => {
|
|
8643
8647
|
if (iceRestart.peerType !== PeerType.PUBLISHER_UNSPECIFIED)
|
|
8644
8648
|
return;
|
|
8645
|
-
|
|
8649
|
+
this.restartIce().catch((err) => {
|
|
8650
|
+
logger$3('warn', `ICERestart failed`, err);
|
|
8651
|
+
});
|
|
8646
8652
|
});
|
|
8647
8653
|
}
|
|
8648
8654
|
}
|
|
@@ -8836,15 +8842,19 @@ class Subscriber {
|
|
|
8836
8842
|
[streamKindProp]: primaryStream,
|
|
8837
8843
|
});
|
|
8838
8844
|
};
|
|
8839
|
-
this.onIceCandidate =
|
|
8845
|
+
this.onIceCandidate = (e) => {
|
|
8840
8846
|
const { candidate } = e;
|
|
8841
8847
|
if (!candidate) {
|
|
8842
8848
|
logger$2('debug', 'null ice candidate');
|
|
8843
8849
|
return;
|
|
8844
8850
|
}
|
|
8845
|
-
|
|
8851
|
+
this.sfuClient
|
|
8852
|
+
.iceTrickle({
|
|
8846
8853
|
iceCandidate: getIceCandidate(candidate),
|
|
8847
8854
|
peerType: PeerType.SUBSCRIBER,
|
|
8855
|
+
})
|
|
8856
|
+
.catch((err) => {
|
|
8857
|
+
logger$2('warn', `ICETrickle failed`, err);
|
|
8848
8858
|
});
|
|
8849
8859
|
};
|
|
8850
8860
|
this.negotiate = async (subscriberOffer) => {
|
|
@@ -8916,13 +8926,17 @@ class Subscriber {
|
|
|
8916
8926
|
this.state = state;
|
|
8917
8927
|
this.iceRestartDelay = iceRestartDelay;
|
|
8918
8928
|
this.pc = this.createPeerConnection(connectionConfig);
|
|
8919
|
-
this.unregisterOnSubscriberOffer = dispatcher.on('subscriberOffer',
|
|
8920
|
-
|
|
8929
|
+
this.unregisterOnSubscriberOffer = dispatcher.on('subscriberOffer', (subscriberOffer) => {
|
|
8930
|
+
this.negotiate(subscriberOffer).catch((err) => {
|
|
8931
|
+
logger$2('warn', `Negotiation failed.`, err);
|
|
8932
|
+
});
|
|
8921
8933
|
});
|
|
8922
|
-
this.unregisterOnIceRestart = dispatcher.on('iceRestart',
|
|
8934
|
+
this.unregisterOnIceRestart = dispatcher.on('iceRestart', (iceRestart) => {
|
|
8923
8935
|
if (iceRestart.peerType !== PeerType.SUBSCRIBER)
|
|
8924
8936
|
return;
|
|
8925
|
-
|
|
8937
|
+
this.restartIce().catch((err) => {
|
|
8938
|
+
logger$2('warn', `ICERestart failed`, err);
|
|
8939
|
+
});
|
|
8926
8940
|
});
|
|
8927
8941
|
}
|
|
8928
8942
|
}
|
|
@@ -9774,25 +9788,29 @@ const flatten = (report) => {
|
|
|
9774
9788
|
};
|
|
9775
9789
|
const getSdkSignature = (clientDetails) => {
|
|
9776
9790
|
const { sdk, ...platform } = clientDetails;
|
|
9777
|
-
const sdkName = sdk
|
|
9778
|
-
|
|
9779
|
-
: sdk && sdk.type === SdkType.REACT_NATIVE
|
|
9780
|
-
? 'stream-react-native'
|
|
9781
|
-
: 'stream-js';
|
|
9782
|
-
const sdkVersion = sdk
|
|
9783
|
-
? `${sdk.major}.${sdk.minor}.${sdk.patch}`
|
|
9784
|
-
: '0.0.0-development';
|
|
9791
|
+
const sdkName = getSdkName(sdk);
|
|
9792
|
+
const sdkVersion = getSdkVersion(sdk);
|
|
9785
9793
|
return {
|
|
9786
9794
|
sdkName,
|
|
9787
9795
|
sdkVersion,
|
|
9788
9796
|
...platform,
|
|
9789
9797
|
};
|
|
9790
9798
|
};
|
|
9799
|
+
const getSdkName = (sdk) => {
|
|
9800
|
+
return sdk && sdk.type === SdkType.REACT
|
|
9801
|
+
? 'stream-react'
|
|
9802
|
+
: sdk && sdk.type === SdkType.REACT_NATIVE
|
|
9803
|
+
? 'stream-react-native'
|
|
9804
|
+
: 'stream-js';
|
|
9805
|
+
};
|
|
9806
|
+
const getSdkVersion = (sdk) => {
|
|
9807
|
+
return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
|
|
9808
|
+
};
|
|
9791
9809
|
|
|
9792
9810
|
/**
|
|
9793
9811
|
* Creates a new StatsReporter instance that collects metrics about the ongoing call and reports them to the state store
|
|
9794
9812
|
*/
|
|
9795
|
-
const createStatsReporter = ({ subscriber, publisher, state, pollingIntervalInMs = 2000, }) => {
|
|
9813
|
+
const createStatsReporter = ({ subscriber, publisher, state, datacenter, pollingIntervalInMs = 2000, }) => {
|
|
9796
9814
|
const logger = getLogger(['stats']);
|
|
9797
9815
|
const getRawStatsForTrack = async (kind, selector) => {
|
|
9798
9816
|
if (kind === 'subscriber' && subscriber) {
|
|
@@ -9802,12 +9820,13 @@ const createStatsReporter = ({ subscriber, publisher, state, pollingIntervalInMs
|
|
|
9802
9820
|
return publisher.getStats(selector);
|
|
9803
9821
|
}
|
|
9804
9822
|
else {
|
|
9805
|
-
logger('warn', `Can't retrieve RTC stats for ${kind}`);
|
|
9806
9823
|
return undefined;
|
|
9807
9824
|
}
|
|
9808
9825
|
};
|
|
9809
9826
|
const getStatsForStream = async (kind, mediaStream) => {
|
|
9810
9827
|
const pc = kind === 'subscriber' ? subscriber : publisher;
|
|
9828
|
+
if (!pc)
|
|
9829
|
+
return [];
|
|
9811
9830
|
const statsForStream = [];
|
|
9812
9831
|
for (let track of mediaStream.getTracks()) {
|
|
9813
9832
|
const report = await pc.getStats(track);
|
|
@@ -9853,7 +9872,7 @@ const createStatsReporter = ({ subscriber, publisher, state, pollingIntervalInMs
|
|
|
9853
9872
|
});
|
|
9854
9873
|
}
|
|
9855
9874
|
catch (e) {
|
|
9856
|
-
logger('error', `Failed to collect stats for ${kind}
|
|
9875
|
+
logger('error', `Failed to collect stats for ${kind} of ${participant.userId}`, e);
|
|
9857
9876
|
}
|
|
9858
9877
|
}
|
|
9859
9878
|
}
|
|
@@ -9866,19 +9885,21 @@ const createStatsReporter = ({ subscriber, publisher, state, pollingIntervalInMs
|
|
|
9866
9885
|
}))
|
|
9867
9886
|
.then(aggregate),
|
|
9868
9887
|
publisher
|
|
9869
|
-
|
|
9870
|
-
|
|
9871
|
-
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
|
|
9888
|
+
? publisher
|
|
9889
|
+
.getStats()
|
|
9890
|
+
.then((report) => transform(report, {
|
|
9891
|
+
kind: 'publisher',
|
|
9892
|
+
trackKind: 'video',
|
|
9893
|
+
}))
|
|
9894
|
+
.then(aggregate)
|
|
9895
|
+
: getEmptyStats(),
|
|
9875
9896
|
]);
|
|
9876
9897
|
const [subscriberRawStats, publisherRawStats] = await Promise.all([
|
|
9877
9898
|
getRawStatsForTrack('subscriber'),
|
|
9878
|
-
getRawStatsForTrack('publisher'),
|
|
9899
|
+
publisher ? getRawStatsForTrack('publisher') : undefined,
|
|
9879
9900
|
]);
|
|
9880
9901
|
state.setCallStatsReport({
|
|
9881
|
-
datacenter
|
|
9902
|
+
datacenter,
|
|
9882
9903
|
publisherStats,
|
|
9883
9904
|
subscriberStats,
|
|
9884
9905
|
subscriberRawStats,
|
|
@@ -9955,14 +9976,9 @@ const transform = (report, opts) => {
|
|
|
9955
9976
|
timestamp: Date.now(),
|
|
9956
9977
|
};
|
|
9957
9978
|
};
|
|
9958
|
-
|
|
9959
|
-
|
|
9960
|
-
|
|
9961
|
-
* @param stats the stats to aggregate.
|
|
9962
|
-
*/
|
|
9963
|
-
const aggregate = (stats) => {
|
|
9964
|
-
const aggregatedStats = {
|
|
9965
|
-
rawReport: stats,
|
|
9979
|
+
const getEmptyStats = (stats) => {
|
|
9980
|
+
return {
|
|
9981
|
+
rawReport: stats ?? { streams: [], timestamp: Date.now() },
|
|
9966
9982
|
totalBytesSent: 0,
|
|
9967
9983
|
totalBytesReceived: 0,
|
|
9968
9984
|
averageJitterInMs: 0,
|
|
@@ -9973,6 +9989,14 @@ const aggregate = (stats) => {
|
|
|
9973
9989
|
highestFramesPerSecond: 0,
|
|
9974
9990
|
timestamp: Date.now(),
|
|
9975
9991
|
};
|
|
9992
|
+
};
|
|
9993
|
+
/**
|
|
9994
|
+
* Aggregates generic stats.
|
|
9995
|
+
*
|
|
9996
|
+
* @param stats the stats to aggregate.
|
|
9997
|
+
*/
|
|
9998
|
+
const aggregate = (stats) => {
|
|
9999
|
+
const aggregatedStats = getEmptyStats(stats);
|
|
9976
10000
|
let maxArea = -1;
|
|
9977
10001
|
const area = (w, h) => w * h;
|
|
9978
10002
|
const qualityLimitationReasons = new Set();
|
|
@@ -10016,7 +10040,7 @@ class SfuStatsReporter {
|
|
|
10016
10040
|
this.run = async () => {
|
|
10017
10041
|
const [subscriberStats, publisherStats] = await Promise.all([
|
|
10018
10042
|
this.subscriber.getStats().then(flatten).then(JSON.stringify),
|
|
10019
|
-
this.publisher
|
|
10043
|
+
this.publisher?.getStats().then(flatten).then(JSON.stringify) ?? '[]',
|
|
10020
10044
|
]);
|
|
10021
10045
|
await this.sfuClient.sendStats({
|
|
10022
10046
|
sdk: this.sdkName,
|
|
@@ -10045,15 +10069,8 @@ class SfuStatsReporter {
|
|
|
10045
10069
|
this.publisher = publisher;
|
|
10046
10070
|
const webRTCInfo = getWebRTCInfo();
|
|
10047
10071
|
const { sdk, browser } = clientDetails;
|
|
10048
|
-
this.sdkName =
|
|
10049
|
-
|
|
10050
|
-
? 'stream-react'
|
|
10051
|
-
: sdk && sdk.type === SdkType.REACT_NATIVE
|
|
10052
|
-
? 'stream-react-native'
|
|
10053
|
-
: 'stream-js';
|
|
10054
|
-
this.sdkVersion = sdk
|
|
10055
|
-
? `${sdk.major}.${sdk.minor}.${sdk.patch}`
|
|
10056
|
-
: '0.0.0-development';
|
|
10072
|
+
this.sdkName = getSdkName(sdk);
|
|
10073
|
+
this.sdkVersion = getSdkVersion(sdk);
|
|
10057
10074
|
// The WebRTC version if passed from the SDK, it is taken else the browser info is sent.
|
|
10058
10075
|
this.webRTCVersion =
|
|
10059
10076
|
webRTCInfo?.version ||
|
|
@@ -12609,7 +12626,10 @@ class Call {
|
|
|
12609
12626
|
connectionConfig,
|
|
12610
12627
|
});
|
|
12611
12628
|
}
|
|
12612
|
-
|
|
12629
|
+
// anonymous users can't publish anything hence, there is no need
|
|
12630
|
+
// to create Publisher Peer Connection for them
|
|
12631
|
+
const isAnonymous = this.streamClient.user?.type === 'anonymous';
|
|
12632
|
+
if (!this.publisher && !isAnonymous) {
|
|
12613
12633
|
const audioSettings = this.state.settings?.audio;
|
|
12614
12634
|
const isDtxEnabled = !!audioSettings?.opus_dtx_enabled;
|
|
12615
12635
|
const isRedEnabled = !!audioSettings?.redundant_coding_enabled;
|
|
@@ -12627,6 +12647,7 @@ class Call {
|
|
|
12627
12647
|
subscriber: this.subscriber,
|
|
12628
12648
|
publisher: this.publisher,
|
|
12629
12649
|
state: this.state,
|
|
12650
|
+
datacenter: this.sfuClient.edgeName,
|
|
12630
12651
|
});
|
|
12631
12652
|
}
|
|
12632
12653
|
const clientDetails = getClientDetails();
|
|
@@ -12672,15 +12693,18 @@ class Call {
|
|
|
12672
12693
|
}
|
|
12673
12694
|
if (isMigrating) {
|
|
12674
12695
|
await this.subscriber.migrateTo(sfuClient, connectionConfig);
|
|
12675
|
-
await this.publisher
|
|
12696
|
+
await this.publisher?.migrateTo(sfuClient, connectionConfig);
|
|
12676
12697
|
}
|
|
12677
12698
|
else if (isReconnecting) {
|
|
12678
12699
|
if (reconnected) {
|
|
12679
12700
|
// update the SFU client instance on the subscriber and publisher
|
|
12680
12701
|
this.subscriber.setSfuClient(sfuClient);
|
|
12681
|
-
|
|
12682
|
-
|
|
12683
|
-
|
|
12702
|
+
// publisher might not be there (anonymous users)
|
|
12703
|
+
if (this.publisher) {
|
|
12704
|
+
this.publisher.setSfuClient(sfuClient);
|
|
12705
|
+
// and perform a full ICE restart on the publisher
|
|
12706
|
+
await this.publisher.restartIce();
|
|
12707
|
+
}
|
|
12684
12708
|
}
|
|
12685
12709
|
else if (previousSfuClient?.isFastReconnecting) {
|
|
12686
12710
|
// reconnection wasn't possible, so we need to do a full rejoin
|
|
@@ -13488,7 +13512,9 @@ class Call {
|
|
|
13488
13512
|
});
|
|
13489
13513
|
this.leaveCallHooks.add(registerEventHandlers(this, this.state, this.dispatcher));
|
|
13490
13514
|
this.registerEffects();
|
|
13491
|
-
this.leaveCallHooks.add(createSubscription(this.trackSubscriptionsSubject.pipe(debounce((v) => timer(v.type)), map$1((v) => v.data)), (subscriptions) => this.sfuClient?.updateSubscriptions(subscriptions))
|
|
13515
|
+
this.leaveCallHooks.add(createSubscription(this.trackSubscriptionsSubject.pipe(debounce((v) => timer(v.type)), map$1((v) => v.data)), (subscriptions) => this.sfuClient?.updateSubscriptions(subscriptions).catch((err) => {
|
|
13516
|
+
this.logger('debug', `Failed to update track subscriptions`, err);
|
|
13517
|
+
})));
|
|
13492
13518
|
this.camera = new CameraManager(this);
|
|
13493
13519
|
this.microphone = new MicrophoneManager(this);
|
|
13494
13520
|
this.speaker = new SpeakerManager(this);
|
|
@@ -15177,7 +15203,7 @@ class StreamClient {
|
|
|
15177
15203
|
});
|
|
15178
15204
|
};
|
|
15179
15205
|
this.getUserAgent = () => {
|
|
15180
|
-
const version = "1.0.
|
|
15206
|
+
const version = "1.0.4" ;
|
|
15181
15207
|
return (this.userAgent ||
|
|
15182
15208
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
15183
15209
|
};
|