|
|
@@ -122,6 +122,34 @@ export default class JingleSessionPC extends JingleSession {
|
|
122
|
122
|
return maxFrameHeightSel.length ? Number(maxFrameHeightSel.text()) : null;
|
|
123
|
123
|
}
|
|
124
|
124
|
|
|
|
125
|
+ /**
|
|
|
126
|
+ * Parses the source-name and max frame height value of the 'content-modify' IQ when source-name signaling
|
|
|
127
|
+ * is enabled.
|
|
|
128
|
+ *
|
|
|
129
|
+ * @param {jQuery} jingleContents - A jQuery selector pointing to the '>jingle' element.
|
|
|
130
|
+ * @returns {Object|null}
|
|
|
131
|
+ */
|
|
|
132
|
+ static parseSourceMaxFrameHeight(jingleContents) {
|
|
|
133
|
+ const receiverConstraints = [];
|
|
|
134
|
+ const sourceFrameHeightSel = jingleContents.find('>content[name="video"]>source-frame-height');
|
|
|
135
|
+ let maxHeight, sourceName;
|
|
|
136
|
+
|
|
|
137
|
+ if (sourceFrameHeightSel.length) {
|
|
|
138
|
+ sourceFrameHeightSel.each((_, source) => {
|
|
|
139
|
+ sourceName = source.getAttribute('sourceName');
|
|
|
140
|
+ maxHeight = source.getAttribute('maxHeight');
|
|
|
141
|
+ receiverConstraints.push({
|
|
|
142
|
+ maxHeight,
|
|
|
143
|
+ sourceName
|
|
|
144
|
+ });
|
|
|
145
|
+ });
|
|
|
146
|
+
|
|
|
147
|
+ return receiverConstraints;
|
|
|
148
|
+ }
|
|
|
149
|
+
|
|
|
150
|
+ return null;
|
|
|
151
|
+ }
|
|
|
152
|
+
|
|
125
|
153
|
/* eslint-disable max-params */
|
|
126
|
154
|
|
|
127
|
155
|
/**
|
|
|
@@ -208,6 +236,14 @@ export default class JingleSessionPC extends JingleSession {
|
|
208
|
236
|
*/
|
|
209
|
237
|
this.localRecvMaxFrameHeight = undefined;
|
|
210
|
238
|
|
|
|
239
|
+ /**
|
|
|
240
|
+ * Receiver constraints (max height) set by the application per remote source. Will be used for p2p connection
|
|
|
241
|
+ * in lieu of localRecvMaxFrameHeight when source-name signaling is enabled.
|
|
|
242
|
+ *
|
|
|
243
|
+ * @type {Map<string, number>}
|
|
|
244
|
+ */
|
|
|
245
|
+ this._sourceReceiverConstraints = undefined;
|
|
|
246
|
+
|
|
211
|
247
|
/**
|
|
212
|
248
|
* Indicates whether or not this session is willing to send/receive
|
|
213
|
249
|
* video media. When set to <tt>false</tt> the underlying peer
|
|
|
@@ -263,6 +299,13 @@ export default class JingleSessionPC extends JingleSession {
|
|
263
|
299
|
*/
|
|
264
|
300
|
this.remoteRecvMaxFrameHeight = undefined;
|
|
265
|
301
|
|
|
|
302
|
+ /**
|
|
|
303
|
+ * Remote preference for the receive video max frame heights when source-name signaling is enabled.
|
|
|
304
|
+ *
|
|
|
305
|
+ * @type {Map<string, number>|undefined}
|
|
|
306
|
+ */
|
|
|
307
|
+ this.remoteSourceMaxFrameHeights = undefined;
|
|
|
308
|
+
|
|
266
|
309
|
/**
|
|
267
|
310
|
* The queue used to serialize operations done on the peerconnection.
|
|
268
|
311
|
*
|
|
|
@@ -640,6 +683,19 @@ export default class JingleSessionPC extends JingleSession {
|
|
640
|
683
|
return undefined;
|
|
641
|
684
|
}
|
|
642
|
685
|
|
|
|
686
|
+ /**
|
|
|
687
|
+ * Remote preference for receive video max frame heights when source-name signaling is enabled.
|
|
|
688
|
+ *
|
|
|
689
|
+ * @returns {Map<string, number>|undefined}
|
|
|
690
|
+ */
|
|
|
691
|
+ getRemoteSourcesRecvMaxFrameHeight() {
|
|
|
692
|
+ if (this.isP2P) {
|
|
|
693
|
+ return this.remoteSourceMaxFrameHeights;
|
|
|
694
|
+ }
|
|
|
695
|
+
|
|
|
696
|
+ return undefined;
|
|
|
697
|
+ }
|
|
|
698
|
+
|
|
643
|
699
|
/**
|
|
644
|
700
|
* Sends given candidate in Jingle 'transport-info' message.
|
|
645
|
701
|
* @param {RTCIceCandidate} candidate the WebRTC ICE candidate instance
|
|
|
@@ -1168,7 +1224,9 @@ export default class JingleSessionPC extends JingleSession {
|
|
1168
|
1224
|
// up our SDP translation chain (simulcast, video mute, RTX etc.)
|
|
1169
|
1225
|
// #2 Sends the max frame height if it was set, before the session-initiate/accept
|
|
1170
|
1226
|
if (this.isP2P
|
|
1171
|
|
- && (!this._localVideoActive || this.localRecvMaxFrameHeight)) {
|
|
|
1227
|
+ && (!this._localVideoActive
|
|
|
1228
|
+ || this.localRecvMaxFrameHeight
|
|
|
1229
|
+ || this._sourceReceiverConstraints)) {
|
|
1172
|
1230
|
this.sendContentModify();
|
|
1173
|
1231
|
}
|
|
1174
|
1232
|
}
|
|
|
@@ -1407,9 +1465,24 @@ export default class JingleSessionPC extends JingleSession {
|
|
1407
|
1465
|
sessionModify = sessionModify
|
|
1408
|
1466
|
.c('max-frame-height', { xmlns: 'http://jitsi.org/jitmeet/video' })
|
|
1409
|
1467
|
.t(maxFrameHeight);
|
|
|
1468
|
+ logger.info(`${this} sending content-modify, video senders: ${senders},`
|
|
|
1469
|
+ + ` max frame height: ${maxFrameHeight}`);
|
|
|
1470
|
+ }
|
|
|
1471
|
+
|
|
|
1472
|
+ if (typeof this._sourceReceiverConstraints !== 'undefined') {
|
|
|
1473
|
+ this._sourceReceiverConstraints.forEach((maxHeight, sourceName) => {
|
|
|
1474
|
+ sessionModify
|
|
|
1475
|
+ .c('source-frame-height', { xmlns: 'http://jitsi.org/jitmeet/video' })
|
|
|
1476
|
+ .attrs({
|
|
|
1477
|
+ sourceName,
|
|
|
1478
|
+ maxHeight
|
|
|
1479
|
+ });
|
|
|
1480
|
+
|
|
|
1481
|
+ sessionModify.up();
|
|
|
1482
|
+ logger.info(`${this} sending content-modify for source-name: ${sourceName}, maxHeight: ${maxHeight}`);
|
|
|
1483
|
+ });
|
|
1410
|
1484
|
}
|
|
1411
|
1485
|
|
|
1412
|
|
- logger.info(`${this} sending content-modify, video senders: ${senders}, max frame height: ${maxFrameHeight}`);
|
|
1413
|
1486
|
logger.debug(sessionModify.tree());
|
|
1414
|
1487
|
|
|
1415
|
1488
|
this.connection.sendIQ(
|
|
|
@@ -1424,11 +1497,17 @@ export default class JingleSessionPC extends JingleSession {
|
|
1424
|
1497
|
* the remote party.
|
|
1425
|
1498
|
*
|
|
1426
|
1499
|
* @param {Number} maxFrameHeight - the new value to set.
|
|
|
1500
|
+ * @param {Map<string, number>} sourceReceiverConstraints - The receiver constraints per source.
|
|
1427
|
1501
|
*/
|
|
1428
|
|
- setReceiverVideoConstraint(maxFrameHeight) {
|
|
1429
|
|
- logger.info(`${this} setReceiverVideoConstraint - max frame height: ${maxFrameHeight}`);
|
|
|
1502
|
+ setReceiverVideoConstraint(maxFrameHeight, sourceReceiverConstraints) {
|
|
|
1503
|
+ logger.info(`${this} setReceiverVideoConstraint - max frame height: ${maxFrameHeight}`
|
|
|
1504
|
+ + ` sourceReceiverConstraints: ${sourceReceiverConstraints}`);
|
|
1430
|
1505
|
|
|
1431
|
|
- this.localRecvMaxFrameHeight = maxFrameHeight;
|
|
|
1506
|
+ if (FeatureFlags.isSourceNameSignalingEnabled()) {
|
|
|
1507
|
+ this._sourceReceiverConstraints = sourceReceiverConstraints;
|
|
|
1508
|
+ } else {
|
|
|
1509
|
+ this.localRecvMaxFrameHeight = maxFrameHeight;
|
|
|
1510
|
+ }
|
|
1432
|
1511
|
|
|
1433
|
1512
|
if (this.isP2P) {
|
|
1434
|
1513
|
// Tell the remote peer about our receive constraint. If Jingle session is not yet active the state will
|
|
|
@@ -1436,8 +1515,6 @@ export default class JingleSessionPC extends JingleSession {
|
|
1436
|
1515
|
if (this.state === JingleSessionState.ACTIVE) {
|
|
1437
|
1516
|
this.sendContentModify();
|
|
1438
|
1517
|
}
|
|
1439
|
|
- } else {
|
|
1440
|
|
- this.rtc.setReceiverVideoConstraint(maxFrameHeight);
|
|
1441
|
1518
|
}
|
|
1442
|
1519
|
}
|
|
1443
|
1520
|
|
|
|
@@ -2524,32 +2601,31 @@ export default class JingleSessionPC extends JingleSession {
|
|
2524
|
2601
|
* @see {@link _localVideoActive}
|
|
2525
|
2602
|
*/
|
|
2526
|
2603
|
modifyContents(jingleContents) {
|
|
2527
|
|
- const newVideoSenders
|
|
2528
|
|
- = JingleSessionPC.parseVideoSenders(jingleContents);
|
|
2529
|
|
- const newMaxFrameHeight
|
|
2530
|
|
- = JingleSessionPC.parseMaxFrameHeight(jingleContents);
|
|
|
2604
|
+ const newVideoSenders = JingleSessionPC.parseVideoSenders(jingleContents);
|
|
|
2605
|
+ const newMaxFrameHeight = JingleSessionPC.parseMaxFrameHeight(jingleContents);
|
|
|
2606
|
+ const sourceMaxFrameHeights = JingleSessionPC.parseSourceMaxFrameHeight(jingleContents);
|
|
2531
|
2607
|
|
|
2532
|
2608
|
// frame height is optional in our content-modify protocol
|
|
2533
|
2609
|
if (newMaxFrameHeight) {
|
|
2534
|
2610
|
logger.info(`${this} received remote max frame height: ${newMaxFrameHeight}`);
|
|
2535
|
2611
|
this.remoteRecvMaxFrameHeight = newMaxFrameHeight;
|
|
2536
|
|
- this.eventEmitter.emit(
|
|
2537
|
|
- MediaSessionEvents.REMOTE_VIDEO_CONSTRAINTS_CHANGED, this);
|
|
|
2612
|
+ this.eventEmitter.emit(MediaSessionEvents.REMOTE_VIDEO_CONSTRAINTS_CHANGED, this);
|
|
|
2613
|
+ }
|
|
|
2614
|
+
|
|
|
2615
|
+ if (sourceMaxFrameHeights) {
|
|
|
2616
|
+ this.remoteSourceMaxFrameHeights = sourceMaxFrameHeights;
|
|
|
2617
|
+ this.eventEmitter.emit(MediaSessionEvents.REMOTE_SOURCE_CONSTRAINTS_CHANGED, this, sourceMaxFrameHeights);
|
|
2538
|
2618
|
}
|
|
2539
|
2619
|
|
|
2540
|
2620
|
if (newVideoSenders === null) {
|
|
2541
|
|
- logger.error(
|
|
2542
|
|
- `${this} - failed to parse video "senders" attribute in`
|
|
2543
|
|
- + '"content-modify" action');
|
|
|
2621
|
+ logger.error(`${this} - failed to parse video "senders" attribute in "content-modify" action`);
|
|
2544
|
2622
|
|
|
2545
|
2623
|
return;
|
|
2546
|
2624
|
}
|
|
2547
|
2625
|
|
|
2548
|
2626
|
const workFunction = finishedCallback => {
|
|
2549
|
|
- if (this._assertNotEnded('content-modify')
|
|
2550
|
|
- && this._modifyRemoteVideoActive(newVideoSenders)) {
|
|
2551
|
|
- // Will do the sRD/sLD cycle to update SDPs and adjust
|
|
2552
|
|
- // the media direction
|
|
|
2627
|
+ if (this._assertNotEnded() && this._modifyRemoteVideoActive(newVideoSenders)) {
|
|
|
2628
|
+ // Will do the sRD/sLD cycle to update SDPs and adjust the media direction.
|
|
2553
|
2629
|
this._renegotiate()
|
|
2554
|
2630
|
.then(finishedCallback, finishedCallback /* (error) */);
|
|
2555
|
2631
|
} else {
|
|
|
@@ -2591,8 +2667,7 @@ export default class JingleSessionPC extends JingleSession {
|
|
2591
|
2667
|
this._remoteVideoActive = isRemoteVideoActive;
|
|
2592
|
2668
|
}
|
|
2593
|
2669
|
|
|
2594
|
|
- return this.peerconnection.setVideoTransferActive(
|
|
2595
|
|
- this._localVideoActive && this._remoteVideoActive);
|
|
|
2670
|
+ return this.peerconnection.setVideoTransferActive(this._localVideoActive && this._remoteVideoActive);
|
|
2596
|
2671
|
}
|
|
2597
|
2672
|
|
|
2598
|
2673
|
/**
|