@webex/web-client-media-engine 1.39.0 → 1.40.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/dist/cjs/index.js +167 -22
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +167 -22
- package/dist/esm/index.js.map +1 -1
- package/dist/types/index.d.ts +6 -0
- package/package.json +2 -2
package/dist/cjs/index.js
CHANGED
|
@@ -978,6 +978,10 @@ exports.LocalTrackEvents = void 0;
|
|
|
978
978
|
* Fires when there has been a change in the underlying track.
|
|
979
979
|
*/
|
|
980
980
|
LocalTrackEvents["UnderlyingTrackChange"] = "underlying-track-change";
|
|
981
|
+
/**
|
|
982
|
+
* Fires when the applyConstraints() has been called for the track.
|
|
983
|
+
*/
|
|
984
|
+
LocalTrackEvents["TrackConstraintsChange"] = "track-constraints-change";
|
|
981
985
|
})(exports.LocalTrackEvents || (exports.LocalTrackEvents = {}));
|
|
982
986
|
// TBD: Fix this once types are published separately
|
|
983
987
|
// export type TrackEffect = BaseMicrophoneEffect | BaseCameraEffect;
|
|
@@ -1151,7 +1155,7 @@ class LocalTrack extends EventEmitter$2 {
|
|
|
1151
1155
|
return effect;
|
|
1152
1156
|
}
|
|
1153
1157
|
/**
|
|
1154
|
-
* Cleanup local microphone track.
|
|
1158
|
+
* Cleanup the local microphone track.
|
|
1155
1159
|
*/
|
|
1156
1160
|
disposeEffects() {
|
|
1157
1161
|
if (this.effects.size > 0) {
|
|
@@ -1161,6 +1165,59 @@ class LocalTrack extends EventEmitter$2 {
|
|
|
1161
1165
|
this.emit(exports.LocalTrackEvents.UnderlyingTrackChange);
|
|
1162
1166
|
}
|
|
1163
1167
|
}
|
|
1168
|
+
/**
|
|
1169
|
+
* Apply constraints to the track.
|
|
1170
|
+
*
|
|
1171
|
+
* @param constraints - The constraints to apply to the track.
|
|
1172
|
+
* @returns A promise which resolves when the constraints have been successfully applied.
|
|
1173
|
+
*/
|
|
1174
|
+
applyConstraints(constraints) {
|
|
1175
|
+
return __awaiter$1(this, void 0, void 0, function* () {
|
|
1176
|
+
logger$3.log(`Applying constraints to local track:`, constraints);
|
|
1177
|
+
const ret = this.underlyingTrack.applyConstraints(constraints).then(() => {
|
|
1178
|
+
this.emit(exports.LocalTrackEvents.TrackConstraintsChange);
|
|
1179
|
+
});
|
|
1180
|
+
return ret;
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Get the current constraints of the track.
|
|
1185
|
+
*
|
|
1186
|
+
* @returns The constraints of the track.
|
|
1187
|
+
*/
|
|
1188
|
+
getConstraints() {
|
|
1189
|
+
return this.underlyingTrack.getConstraints();
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Get the current settings of the track.
|
|
1193
|
+
*
|
|
1194
|
+
* @returns The settings of the track.
|
|
1195
|
+
*/
|
|
1196
|
+
getSettings() {
|
|
1197
|
+
return this.underlyingTrack.getSettings();
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Check the resolution and then return how many layers will be active.
|
|
1201
|
+
*
|
|
1202
|
+
* @returns The active layers count.
|
|
1203
|
+
*/
|
|
1204
|
+
getNumActiveSimulcastLayers() {
|
|
1205
|
+
let activeSimulcastLayersNumber = 0;
|
|
1206
|
+
if (this.trackState.type === 'audio') {
|
|
1207
|
+
return activeSimulcastLayersNumber;
|
|
1208
|
+
}
|
|
1209
|
+
const videoHeight = this.underlyingTrack.getSettings().height;
|
|
1210
|
+
if (videoHeight <= 180) {
|
|
1211
|
+
activeSimulcastLayersNumber = 1;
|
|
1212
|
+
}
|
|
1213
|
+
else if (videoHeight <= 360) {
|
|
1214
|
+
activeSimulcastLayersNumber = 2;
|
|
1215
|
+
}
|
|
1216
|
+
else {
|
|
1217
|
+
activeSimulcastLayersNumber = 3;
|
|
1218
|
+
}
|
|
1219
|
+
return activeSimulcastLayersNumber;
|
|
1220
|
+
}
|
|
1164
1221
|
}
|
|
1165
1222
|
LocalTrack.Events = exports.LocalTrackEvents;
|
|
1166
1223
|
|
|
@@ -1204,7 +1261,10 @@ class WcmeError {
|
|
|
1204
1261
|
}
|
|
1205
1262
|
}
|
|
1206
1263
|
/**
|
|
1207
|
-
* Creates a camera video track.
|
|
1264
|
+
* Creates a camera video track. Please note that the constraint params in second getUserMedia call would NOT take effect when:
|
|
1265
|
+
*
|
|
1266
|
+
* 1. Previous captured video track from the same device is not stopped .
|
|
1267
|
+
* 2. Previous createCameraTrack() call for the same device is in progress.
|
|
1208
1268
|
*
|
|
1209
1269
|
* @param constraints - Video device constraints.
|
|
1210
1270
|
* @returns A LocalTrack object or an error.
|
|
@@ -4995,6 +5055,44 @@ class PeerConnection extends EventEmitter$2 {
|
|
|
4995
5055
|
get iceGatheringState() {
|
|
4996
5056
|
return this.pc.iceGatheringState;
|
|
4997
5057
|
}
|
|
5058
|
+
/**
|
|
5059
|
+
* Returns the type of a connection that has been established.
|
|
5060
|
+
*
|
|
5061
|
+
* @returns The connection type which would be `ConnectionType`.
|
|
5062
|
+
*/
|
|
5063
|
+
getCurrentConnectionType() {
|
|
5064
|
+
var _a;
|
|
5065
|
+
return __awaiter$1(this, void 0, void 0, function* () {
|
|
5066
|
+
// make sure this method only can be called when the ice connection is established;
|
|
5067
|
+
const isIceConnected = this.pc.iceConnectionState === 'connected' || this.pc.iceConnectionState === 'completed';
|
|
5068
|
+
if (!isIceConnected) {
|
|
5069
|
+
throw new Error('Ice connection is not established');
|
|
5070
|
+
}
|
|
5071
|
+
const succeededLocalCandidateIds = new Set();
|
|
5072
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5073
|
+
const localCandidateStatsReports = [];
|
|
5074
|
+
(yield this.pc.getStats()).forEach((report) => {
|
|
5075
|
+
var _a;
|
|
5076
|
+
// collect all local candidate ids from `candidate-pair` stats reports with `succeeded` state.
|
|
5077
|
+
if (report.type === 'candidate-pair' && ((_a = report.state) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'succeeded') {
|
|
5078
|
+
succeededLocalCandidateIds.add(report.localCandidateId);
|
|
5079
|
+
}
|
|
5080
|
+
// collect all `local-candidate` stats.
|
|
5081
|
+
if (report.type === 'local-candidate') {
|
|
5082
|
+
localCandidateStatsReports.push(report);
|
|
5083
|
+
}
|
|
5084
|
+
});
|
|
5085
|
+
// find the `local-candidate` stats which report id contains in `succeededLocalCandidateIds`.
|
|
5086
|
+
const localCandidate = localCandidateStatsReports.find((report) => succeededLocalCandidateIds.has(report.id));
|
|
5087
|
+
if (!localCandidate) {
|
|
5088
|
+
return 'unknown';
|
|
5089
|
+
}
|
|
5090
|
+
if (localCandidate.relayProtocol) {
|
|
5091
|
+
return `TURN-${localCandidate.relayProtocol.toUpperCase()}`;
|
|
5092
|
+
}
|
|
5093
|
+
return (_a = localCandidate.protocol) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
5094
|
+
});
|
|
5095
|
+
}
|
|
4998
5096
|
}
|
|
4999
5097
|
PeerConnection.Events = PeerConnectionEvents;
|
|
5000
5098
|
|
|
@@ -8881,6 +8979,9 @@ function injectJmpAttributes(parsedSdp, csiMap, streamSignalingMode) {
|
|
|
8881
8979
|
mLine.addLine(new JmpStreamIdModeLine(streamSignalingMode));
|
|
8882
8980
|
}
|
|
8883
8981
|
});
|
|
8982
|
+
}
|
|
8983
|
+
function hasSimulcast(av) {
|
|
8984
|
+
return !!av.simulcast || av.ssrcGroups.map((sg) => sg.semantics).some((sem) => sem === 'SIM');
|
|
8884
8985
|
}
|
|
8885
8986
|
|
|
8886
8987
|
class SendOnlyTransceiver extends Transceiver {
|
|
@@ -9604,6 +9705,10 @@ const defaultMultistreamConnectionOptions = {
|
|
|
9604
9705
|
enableMainAudio: true,
|
|
9605
9706
|
enableMainVideo: true,
|
|
9606
9707
|
};
|
|
9708
|
+
const defaultVideoCodecParameters = {
|
|
9709
|
+
'max-mbps': `${defaultMaxVideoEncodeMbps}`,
|
|
9710
|
+
'max-fs': `${defaultMaxVideoEncodeFrameSize}`,
|
|
9711
|
+
};
|
|
9607
9712
|
class MultistreamConnection extends EventEmitter {
|
|
9608
9713
|
constructor(userOptions = {}) {
|
|
9609
9714
|
var _a, _b;
|
|
@@ -9614,6 +9719,7 @@ class MultistreamConnection extends EventEmitter {
|
|
|
9614
9719
|
this.pendingJmpTasks = [];
|
|
9615
9720
|
this.metricsCallback = () => { };
|
|
9616
9721
|
this.overuseUpdateCallback = () => { };
|
|
9722
|
+
this.customCodecParameters = new Map();
|
|
9617
9723
|
this.midMap = new Map();
|
|
9618
9724
|
this.currentMid = 0;
|
|
9619
9725
|
this.options = Object.assign(Object.assign({}, defaultMultistreamConnectionOptions), userOptions);
|
|
@@ -9626,6 +9732,7 @@ class MultistreamConnection extends EventEmitter {
|
|
|
9626
9732
|
const mainSceneId = generateSceneId();
|
|
9627
9733
|
const videoMainEncodingOptions = this.getVideoEncodingOptions(MediaContent.Main);
|
|
9628
9734
|
this.createSendTransceiver(MediaType.VideoMain, mainSceneId, videoMainEncodingOptions);
|
|
9735
|
+
this.setCodecParameters(MediaType.VideoMain, defaultVideoCodecParameters);
|
|
9629
9736
|
this.createSendTransceiver(MediaType.AudioMain, mainSceneId);
|
|
9630
9737
|
(_a = this.sendTransceivers.get(MediaType.VideoMain)) === null || _a === void 0 ? void 0 : _a.setActive(this.options.enableMainVideo);
|
|
9631
9738
|
(_b = this.sendTransceivers.get(MediaType.AudioMain)) === null || _b === void 0 ? void 0 : _b.setActive(this.options.enableMainAudio);
|
|
@@ -9633,6 +9740,7 @@ class MultistreamConnection extends EventEmitter {
|
|
|
9633
9740
|
const videoPresentationEncodingOptions = this.getVideoEncodingOptions(MediaContent.Slides);
|
|
9634
9741
|
const contentSceneId = generateSceneId();
|
|
9635
9742
|
this.createSendTransceiver(MediaType.VideoSlides, contentSceneId, videoPresentationEncodingOptions);
|
|
9743
|
+
this.setCodecParameters(MediaType.VideoSlides, defaultVideoCodecParameters);
|
|
9636
9744
|
this.createSendTransceiver(MediaType.AudioSlides, contentSceneId);
|
|
9637
9745
|
}
|
|
9638
9746
|
}
|
|
@@ -9997,20 +10105,7 @@ class MultistreamConnection extends EventEmitter {
|
|
|
9997
10105
|
return ingressSignaler.getReceiverId();
|
|
9998
10106
|
});
|
|
9999
10107
|
if (this.pc.getRemoteDescription()) {
|
|
10000
|
-
yield this.
|
|
10001
|
-
.createOffer()
|
|
10002
|
-
.then((offer) => {
|
|
10003
|
-
if (!offer.sdp) {
|
|
10004
|
-
throw new Error('No SDP offer');
|
|
10005
|
-
}
|
|
10006
|
-
offer.sdp = this.preProcessLocalOffer(offer.sdp);
|
|
10007
|
-
return this.pc.setLocalDescription(offer);
|
|
10008
|
-
})
|
|
10009
|
-
.then(() => {
|
|
10010
|
-
var _a;
|
|
10011
|
-
const answer = this.preProcessRemoteAnswer((_a = this.pc.getRemoteDescription()) === null || _a === void 0 ? void 0 : _a.sdp);
|
|
10012
|
-
return this.pc.setRemoteDescription({ type: 'answer', sdp: answer });
|
|
10013
|
-
});
|
|
10108
|
+
yield this.doLocalOfferAnswer();
|
|
10014
10109
|
}
|
|
10015
10110
|
this.recvTransceivers.set(mediaType, [
|
|
10016
10111
|
...(this.recvTransceivers.get(mediaType) || []),
|
|
@@ -10076,8 +10171,26 @@ class MultistreamConnection extends EventEmitter {
|
|
|
10076
10171
|
}
|
|
10077
10172
|
setAnswer(answer) {
|
|
10078
10173
|
return __awaiter(this, void 0, void 0, function* () {
|
|
10174
|
+
const isInitialAnswer = !this.pc.getRemoteDescription();
|
|
10079
10175
|
const sdp = this.preProcessRemoteAnswer(answer);
|
|
10080
|
-
return this.pc.setRemoteDescription({ type: 'answer', sdp })
|
|
10176
|
+
return this.pc.setRemoteDescription({ type: 'answer', sdp }).then(() => {
|
|
10177
|
+
if (isInitialAnswer && this.customCodecParameters.size > 0) {
|
|
10178
|
+
this.doLocalOfferAnswer();
|
|
10179
|
+
}
|
|
10180
|
+
});
|
|
10181
|
+
});
|
|
10182
|
+
}
|
|
10183
|
+
doLocalOfferAnswer() {
|
|
10184
|
+
var _a;
|
|
10185
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
10186
|
+
const offer = yield this.pc.createOffer();
|
|
10187
|
+
if (!offer.sdp) {
|
|
10188
|
+
throw new Error('No SDP offer');
|
|
10189
|
+
}
|
|
10190
|
+
offer.sdp = this.preProcessLocalOffer(offer.sdp);
|
|
10191
|
+
yield this.pc.setLocalDescription(offer);
|
|
10192
|
+
const answer = this.preProcessRemoteAnswer((_a = this.pc.getRemoteDescription()) === null || _a === void 0 ? void 0 : _a.sdp);
|
|
10193
|
+
return this.pc.setRemoteDescription({ type: 'answer', sdp: answer });
|
|
10081
10194
|
});
|
|
10082
10195
|
}
|
|
10083
10196
|
enableMultistreamAudio(enabled) {
|
|
@@ -10101,15 +10214,23 @@ class MultistreamConnection extends EventEmitter {
|
|
|
10101
10214
|
.filter((av) => av.direction === 'sendrecv')
|
|
10102
10215
|
.forEach((av) => {
|
|
10103
10216
|
const egressSignaler = this.streamSignalerManager.getOrCreateEgressStreamSignaler(av.mid);
|
|
10104
|
-
const simulcastEnabled =
|
|
10217
|
+
const simulcastEnabled = hasSimulcast(av);
|
|
10105
10218
|
const rtxEnabled = av.type === 'video';
|
|
10106
10219
|
egressSignaler.signalStreams(simulcastEnabled, rtxEnabled, av);
|
|
10107
|
-
|
|
10220
|
+
const mediaType = [...this.sendTransceivers.keys()].find((key) => { var _a; return ((_a = this.sendTransceivers.get(key)) === null || _a === void 0 ? void 0 : _a.mid) === av.mid; });
|
|
10221
|
+
if (mediaType && this.customCodecParameters.has(mediaType)) {
|
|
10108
10222
|
[...av.codecs.values()]
|
|
10109
|
-
.filter((ci) => ci.name === 'H264')
|
|
10223
|
+
.filter((ci) => ci.name === (av.type === 'audio' ? 'opus' : 'H264'))
|
|
10110
10224
|
.forEach((ci) => {
|
|
10111
|
-
|
|
10112
|
-
|
|
10225
|
+
var _a;
|
|
10226
|
+
(_a = this.customCodecParameters.get(mediaType)) === null || _a === void 0 ? void 0 : _a.forEach((value, param) => {
|
|
10227
|
+
if (value === null) {
|
|
10228
|
+
ci.fmtParams.delete(param);
|
|
10229
|
+
}
|
|
10230
|
+
else {
|
|
10231
|
+
ci.fmtParams.set(param, `${value}`);
|
|
10232
|
+
}
|
|
10233
|
+
});
|
|
10113
10234
|
});
|
|
10114
10235
|
}
|
|
10115
10236
|
});
|
|
@@ -10165,6 +10286,30 @@ class MultistreamConnection extends EventEmitter {
|
|
|
10165
10286
|
.map((transceiver) => transceiver.publishedTrack)
|
|
10166
10287
|
.filter(Boolean);
|
|
10167
10288
|
}
|
|
10289
|
+
setCodecParameters(mediaType, parameters) {
|
|
10290
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
10291
|
+
const currentParams = this.customCodecParameters.get(mediaType) || new Map();
|
|
10292
|
+
Object.entries(parameters).forEach(([param, value]) => {
|
|
10293
|
+
currentParams.set(param, value);
|
|
10294
|
+
});
|
|
10295
|
+
this.customCodecParameters.set(mediaType, currentParams);
|
|
10296
|
+
if (this.pc.getRemoteDescription()) {
|
|
10297
|
+
yield this.doLocalOfferAnswer();
|
|
10298
|
+
}
|
|
10299
|
+
});
|
|
10300
|
+
}
|
|
10301
|
+
deleteCodecParameters(mediaType, parameters) {
|
|
10302
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
10303
|
+
const currentParams = this.customCodecParameters.get(mediaType) || new Map();
|
|
10304
|
+
parameters.forEach((param) => {
|
|
10305
|
+
currentParams.set(param, null);
|
|
10306
|
+
});
|
|
10307
|
+
this.customCodecParameters.set(mediaType, currentParams);
|
|
10308
|
+
if (this.pc.getRemoteDescription()) {
|
|
10309
|
+
yield this.doLocalOfferAnswer();
|
|
10310
|
+
}
|
|
10311
|
+
});
|
|
10312
|
+
}
|
|
10168
10313
|
requestMedia(mediaType, mediaRequests) {
|
|
10169
10314
|
var _a;
|
|
10170
10315
|
const task = () => {
|