|
@@ -141,9 +141,9 @@ var VideoLayout = (function (my) {
|
141
|
141
|
var oldSrc = $('#largeVideo').attr('src');
|
142
|
142
|
largeVideoState.oldJid = getJidFromVideoSrc(oldSrc);
|
143
|
143
|
|
144
|
|
- var fade = false;
|
|
144
|
+ var userChanged = false;
|
145
|
145
|
if (largeVideoState.oldJid != largeVideoState.userJid) {
|
146
|
|
- fade = true;
|
|
146
|
+ userChanged = true;
|
147
|
147
|
// we want the notification to trigger even if userJid is undefined,
|
148
|
148
|
// or null.
|
149
|
149
|
$(document).trigger("selectedendpointchanged", [largeVideoState.userJid]);
|
|
@@ -154,7 +154,41 @@ var VideoLayout = (function (my) {
|
154
|
154
|
|
155
|
155
|
var doUpdate = function () {
|
156
|
156
|
|
157
|
|
- $('#largeVideo').attr('src', largeVideoState.newSrc);
|
|
157
|
+ if (!userChanged && largeVideoState.preload
|
|
158
|
+ && largeVideoState.preload != null
|
|
159
|
+ && $(largeVideoState.preload).attr('src') == newSrc) {
|
|
160
|
+
|
|
161
|
+ console.info('Switching to preloaded video');
|
|
162
|
+ var attributes = $('#largeVideo').prop("attributes");
|
|
163
|
+
|
|
164
|
+ // loop through largeVideo attributes and apply them on
|
|
165
|
+ // preload.
|
|
166
|
+ $.each(attributes, function () {
|
|
167
|
+ if (this.name != 'id' && this.name != 'src') {
|
|
168
|
+ largeVideoState.preload.attr(this.name, this.value);
|
|
169
|
+ }
|
|
170
|
+ });
|
|
171
|
+
|
|
172
|
+ largeVideoState.preload.appendTo($('#largeVideoContainer'));
|
|
173
|
+ $('#largeVideo').attr('id', 'previousLargeVideo');
|
|
174
|
+ largeVideoState.preload.attr('id', 'largeVideo');
|
|
175
|
+ $('#previousLargeVideo').remove();
|
|
176
|
+
|
|
177
|
+ largeVideoState.preload.on('loadedmetadata', function (e) {
|
|
178
|
+ currentVideoWidth = this.videoWidth;
|
|
179
|
+ currentVideoHeight = this.videoHeight;
|
|
180
|
+ VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
|
|
181
|
+ });
|
|
182
|
+ largeVideoState.preload = null;
|
|
183
|
+ largeVideoState.preload_ssrc = 0;
|
|
184
|
+ } else {
|
|
185
|
+ if (largeVideoState.preload
|
|
186
|
+ && largeVideoState.preload != null) {
|
|
187
|
+ $(largeVideoState.preload).remove();
|
|
188
|
+ largeVideoState.preload_ssrc = 0;
|
|
189
|
+ }
|
|
190
|
+ $('#largeVideo').attr('src', largeVideoState.newSrc);
|
|
191
|
+ }
|
158
|
192
|
|
159
|
193
|
var videoTransform = document.getElementById('largeVideo')
|
160
|
194
|
.style.webkitTransform;
|
|
@@ -191,7 +225,7 @@ var VideoLayout = (function (my) {
|
191
|
225
|
VideoLayout.enableDominantSpeaker(resourceJid, true);
|
192
|
226
|
}
|
193
|
227
|
|
194
|
|
- if (fade && largeVideoState.isVisible) {
|
|
228
|
+ if (userChanged && largeVideoState.isVisible) {
|
195
|
229
|
// using "this" should be ok because we're called
|
196
|
230
|
// from within the fadeOut event.
|
197
|
231
|
$(this).fadeIn(300);
|
|
@@ -200,7 +234,7 @@ var VideoLayout = (function (my) {
|
200
|
234
|
largeVideoState.updateInProgress = false;
|
201
|
235
|
};
|
202
|
236
|
|
203
|
|
- if (fade) {
|
|
237
|
+ if (userChanged) {
|
204
|
238
|
$('#largeVideo').fadeOut(300, doUpdate);
|
205
|
239
|
} else {
|
206
|
240
|
doUpdate();
|
|
@@ -1388,6 +1422,81 @@ var VideoLayout = (function (my) {
|
1388
|
1422
|
}
|
1389
|
1423
|
});
|
1390
|
1424
|
|
|
1425
|
+ $(document).bind('simulcastlayerschanging', function (event, endpointSimulcastLayers) {
|
|
1426
|
+ endpointSimulcastLayers.forEach(function (esl) {
|
|
1427
|
+ var primarySSRC = esl.simulcastLayer.primarySSRC;
|
|
1428
|
+ var msid = simulcast.getRemoteVideoStreamIdBySSRC(primarySSRC);
|
|
1429
|
+
|
|
1430
|
+ // Get session and stream from msid.
|
|
1431
|
+ var session, electedStream;
|
|
1432
|
+ var i, j, k;
|
|
1433
|
+ if (connection.jingle) {
|
|
1434
|
+ var keys = Object.keys(connection.jingle.sessions);
|
|
1435
|
+ for (i = 0; i < keys.length; i++) {
|
|
1436
|
+ var sid = keys[i];
|
|
1437
|
+
|
|
1438
|
+ if (electedStream) {
|
|
1439
|
+ // stream found, stop.
|
|
1440
|
+ break;
|
|
1441
|
+ }
|
|
1442
|
+
|
|
1443
|
+ session = connection.jingle.sessions[sid];
|
|
1444
|
+ if (session.remoteStreams) {
|
|
1445
|
+ for (j = 0; j < session.remoteStreams.length; j++) {
|
|
1446
|
+ var remoteStream = session.remoteStreams[j];
|
|
1447
|
+
|
|
1448
|
+ if (electedStream) {
|
|
1449
|
+ // stream found, stop.
|
|
1450
|
+ break;
|
|
1451
|
+ }
|
|
1452
|
+ var tracks = remoteStream.getVideoTracks();
|
|
1453
|
+ if (tracks) {
|
|
1454
|
+ for (k = 0; k < tracks.length; k++) {
|
|
1455
|
+ var track = tracks[k];
|
|
1456
|
+
|
|
1457
|
+ if (msid === [remoteStream.id, track.id].join(' ')) {
|
|
1458
|
+ electedStream = new webkitMediaStream([track]);
|
|
1459
|
+ // stream found, stop.
|
|
1460
|
+ break;
|
|
1461
|
+ }
|
|
1462
|
+ }
|
|
1463
|
+ }
|
|
1464
|
+ }
|
|
1465
|
+ }
|
|
1466
|
+ }
|
|
1467
|
+ }
|
|
1468
|
+
|
|
1469
|
+ if (session && electedStream) {
|
|
1470
|
+ console.info('Switching simulcast substream.');
|
|
1471
|
+ console.info([esl, primarySSRC, msid, session, electedStream]);
|
|
1472
|
+
|
|
1473
|
+ var msidParts = msid.split(' ');
|
|
1474
|
+ var selRemoteVideo = $(['#', 'remoteVideo_', session.sid, '_', msidParts[0]].join(''));
|
|
1475
|
+
|
|
1476
|
+ var preload = (ssrc2jid[videoSrcToSsrc[selRemoteVideo.attr('src')]]
|
|
1477
|
+ == ssrc2jid[videoSrcToSsrc[largeVideoState.newSrc]]);
|
|
1478
|
+
|
|
1479
|
+ if (preload) {
|
|
1480
|
+ if (largeVideoState.preload)
|
|
1481
|
+ {
|
|
1482
|
+ $(largeVideoState.preload).remove();
|
|
1483
|
+ }
|
|
1484
|
+ console.info('Preloading remote video');
|
|
1485
|
+ largeVideoState.preload = $('<video autoplay></video>');
|
|
1486
|
+ // ssrcs are unique in an rtp session
|
|
1487
|
+ largeVideoState.preload_ssrc = primarySSRC;
|
|
1488
|
+
|
|
1489
|
+ var electedStreamUrl = webkitURL.createObjectURL(electedStream);
|
|
1490
|
+ largeVideoState.preload
|
|
1491
|
+ .attr('src', electedStreamUrl);
|
|
1492
|
+ }
|
|
1493
|
+
|
|
1494
|
+ } else {
|
|
1495
|
+ console.error('Could not find a stream or a session.', session, electedStream);
|
|
1496
|
+ }
|
|
1497
|
+ });
|
|
1498
|
+ });
|
|
1499
|
+
|
1391
|
1500
|
/**
|
1392
|
1501
|
* On simulcast layers changed event.
|
1393
|
1502
|
*/
|
|
@@ -1447,7 +1556,16 @@ var VideoLayout = (function (my) {
|
1447
|
1556
|
== ssrc2jid[videoSrcToSsrc[largeVideoState.newSrc]]);
|
1448
|
1557
|
var updateFocusedVideoSrc = (selRemoteVideo.attr('src') == focusedVideoSrc);
|
1449
|
1558
|
|
1450
|
|
- var electedStreamUrl = webkitURL.createObjectURL(electedStream);
|
|
1559
|
+ var electedStreamUrl;
|
|
1560
|
+ if (largeVideoState.preload_ssrc == primarySSRC)
|
|
1561
|
+ {
|
|
1562
|
+ electedStreamUrl = $(largeVideoState.preload).attr('src');
|
|
1563
|
+ }
|
|
1564
|
+ else
|
|
1565
|
+ {
|
|
1566
|
+ electedStreamUrl = webkitURL.createObjectURL(electedStream);
|
|
1567
|
+ }
|
|
1568
|
+
|
1451
|
1569
|
selRemoteVideo.attr('src', electedStreamUrl);
|
1452
|
1570
|
videoSrcToSsrc[selRemoteVideo.attr('src')] = primarySSRC;
|
1453
|
1571
|
|