|
@@ -4,6 +4,7 @@ var VideoLayout = (function (my) {
|
4
|
4
|
var localLastNCount = config.channelLastN;
|
5
|
5
|
var localLastNSet = [];
|
6
|
6
|
var lastNEndpointsCache = [];
|
|
7
|
+ var lastNPickupJid = null;
|
7
|
8
|
var largeVideoState = {
|
8
|
9
|
updateInProgress: false,
|
9
|
10
|
newSrc: ''
|
|
@@ -238,7 +239,7 @@ var VideoLayout = (function (my) {
|
238
|
239
|
}
|
239
|
240
|
};
|
240
|
241
|
|
241
|
|
- my.handleVideoThumbClicked = function(videoSrc) {
|
|
242
|
+ my.handleVideoThumbClicked = function(videoSrc, noPinnedEndpointChangedEvent) {
|
242
|
243
|
// Restore style for previously focused video
|
243
|
244
|
var focusJid = getJidFromVideoSrc(focusedVideoSrc);
|
244
|
245
|
var oldContainer = getParticipantContainer(focusJid);
|
|
@@ -263,7 +264,9 @@ var VideoLayout = (function (my) {
|
263
|
264
|
}
|
264
|
265
|
}
|
265
|
266
|
|
266
|
|
- $(document).trigger("pinnedendpointchanged");
|
|
267
|
+ if (!noPinnedEndpointChangedEvent) {
|
|
268
|
+ $(document).trigger("pinnedendpointchanged");
|
|
269
|
+ }
|
267
|
270
|
return;
|
268
|
271
|
}
|
269
|
272
|
|
|
@@ -277,7 +280,13 @@ var VideoLayout = (function (my) {
|
277
|
280
|
var container = getParticipantContainer(userJid);
|
278
|
281
|
container.addClass("videoContainerFocused");
|
279
|
282
|
|
280
|
|
- $(document).trigger("pinnedendpointchanged", [userJid]);
|
|
283
|
+ if (!noPinnedEndpointChangedEvent) {
|
|
284
|
+ $(document).trigger("pinnedendpointchanged", [userJid]);
|
|
285
|
+ }
|
|
286
|
+ }
|
|
287
|
+
|
|
288
|
+ if ($('#largeVideo').attr('src') == videoSrc) {
|
|
289
|
+ return;
|
281
|
290
|
}
|
282
|
291
|
|
283
|
292
|
// Triggers a "video.selected" event. The "false" parameter indicates
|
|
@@ -599,7 +608,9 @@ var VideoLayout = (function (my) {
|
599
|
608
|
VideoLayout.resizeThumbnails();
|
600
|
609
|
}
|
601
|
610
|
|
602
|
|
- ContactList.setClickable(resourceJid, !isHide);
|
|
611
|
+ // We want to be able to pin a participant from the contact list, even
|
|
612
|
+ // if he's not in the lastN set!
|
|
613
|
+ // ContactList.setClickable(resourceJid, !isHide);
|
603
|
614
|
|
604
|
615
|
};
|
605
|
616
|
|
|
@@ -1271,6 +1282,48 @@ var VideoLayout = (function (my) {
|
1271
|
1282
|
popupmenuElement.appendChild(paddingSpan);
|
1272
|
1283
|
}
|
1273
|
1284
|
|
|
1285
|
+ /**
|
|
1286
|
+ * On contact list item clicked.
|
|
1287
|
+ */
|
|
1288
|
+ $(ContactList).bind('contactclicked', function(event, jid) {
|
|
1289
|
+ if (!jid) {
|
|
1290
|
+ return;
|
|
1291
|
+ }
|
|
1292
|
+
|
|
1293
|
+ var resource = Strophe.getResourceFromJid(jid);
|
|
1294
|
+ var videoContainer = $("#participant_" + resource);
|
|
1295
|
+ if (videoContainer.length > 0) {
|
|
1296
|
+ var videoThumb = $('video', videoContainer).get(0);
|
|
1297
|
+ // It is not always the case that a videoThumb exists (if there is
|
|
1298
|
+ // no actual video).
|
|
1299
|
+ if (videoThumb) {
|
|
1300
|
+ if (videoThumb.src && videoThumb.src != '') {
|
|
1301
|
+
|
|
1302
|
+ // We have a video src, great! Let's update the large video
|
|
1303
|
+ // now.
|
|
1304
|
+
|
|
1305
|
+ VideoLayout.handleVideoThumbClicked(videoThumb.src);
|
|
1306
|
+ } else {
|
|
1307
|
+
|
|
1308
|
+ // If we don't have a video src for jid, there's absolutely
|
|
1309
|
+ // no point in calling handleVideoThumbClicked; Quite
|
|
1310
|
+ // simply, it won't work because it needs an src to attach
|
|
1311
|
+ // to the large video.
|
|
1312
|
+ //
|
|
1313
|
+ // Instead, we trigger the pinned endpoint changed event to
|
|
1314
|
+ // let the bridge adjust its lastN set for myjid and store
|
|
1315
|
+ // the pinned user in the lastNPickupJid variable to be
|
|
1316
|
+ // picked up later by the lastN changed event handler.
|
|
1317
|
+
|
|
1318
|
+ lastNPickupJid = jid;
|
|
1319
|
+ $(document).trigger("pinnedendpointchanged", [jid]);
|
|
1320
|
+ }
|
|
1321
|
+ } else if (jid == connection.emuc.myroomjid) {
|
|
1322
|
+ $("#localVideoContainer").click();
|
|
1323
|
+ }
|
|
1324
|
+ }
|
|
1325
|
+ });
|
|
1326
|
+
|
1274
|
1327
|
/**
|
1275
|
1328
|
* On audio muted event.
|
1276
|
1329
|
*/
|
|
@@ -1430,6 +1483,8 @@ var VideoLayout = (function (my) {
|
1430
|
1483
|
|
1431
|
1484
|
localLastNSet = nextLocalLastNSet;
|
1432
|
1485
|
|
|
1486
|
+ var updateLargeVideo = false;
|
|
1487
|
+
|
1433
|
1488
|
// Handle LastN/local LastN changes.
|
1434
|
1489
|
$('#remoteVideos>span').each(function( index, element ) {
|
1435
|
1490
|
var resourceJid = VideoLayout.getPeerContainerResourceJid(element);
|
|
@@ -1455,28 +1510,8 @@ var VideoLayout = (function (my) {
|
1455
|
1510
|
// displayed in the large video we have to switch to another
|
1456
|
1511
|
// user.
|
1457
|
1512
|
var largeVideoResource = VideoLayout.getLargeVideoResource();
|
1458
|
|
- if (resourceJid === largeVideoResource) {
|
1459
|
|
- var resource, container, src;
|
1460
|
|
- var myResource
|
1461
|
|
- = Strophe.getResourceFromJid(connection.emuc.myroomjid);
|
1462
|
|
-
|
1463
|
|
- // Find out which endpoint to show in the large video.
|
1464
|
|
- for (var i = 0; i < lastNEndpoints.length; i++) {
|
1465
|
|
- resource = lastNEndpoints[i];
|
1466
|
|
- if (!resource || resource === myResource)
|
1467
|
|
- continue;
|
1468
|
|
-
|
1469
|
|
- container = $("#participant_" + resource);
|
1470
|
|
- if (container.length == 0)
|
1471
|
|
- continue;
|
1472
|
|
-
|
1473
|
|
- src = $('video', container).attr('src');
|
1474
|
|
- if (!src)
|
1475
|
|
- continue;
|
1476
|
|
-
|
1477
|
|
- VideoLayout.updateLargeVideo(src);
|
1478
|
|
- break;
|
1479
|
|
- }
|
|
1513
|
+ if (!updateLargeVideo && resourceJid === largeVideoResource) {
|
|
1514
|
+ updateLargeVideo = true;
|
1480
|
1515
|
}
|
1481
|
1516
|
}
|
1482
|
1517
|
});
|
|
@@ -1501,6 +1536,18 @@ var VideoLayout = (function (my) {
|
1501
|
1536
|
|
1502
|
1537
|
var videoStream = simulcast.getReceivingVideoStream(mediaStream.stream);
|
1503
|
1538
|
RTC.attachMediaStream(sel, videoStream);
|
|
1539
|
+ videoSrcToSsrc[sel.attr('src')] = mediaStream.ssrc;
|
|
1540
|
+ if (lastNPickupJid == mediaStream.peerjid) {
|
|
1541
|
+ // Clean up the lastN pickup jid.
|
|
1542
|
+ lastNPickupJid = null;
|
|
1543
|
+
|
|
1544
|
+ // Don't fire the events again, they've already
|
|
1545
|
+ // been fired in the contact list click handler.
|
|
1546
|
+ VideoLayout.handleVideoThumbClicked($(sel).attr('src'), false);
|
|
1547
|
+
|
|
1548
|
+ updateLargeVideo = false;
|
|
1549
|
+ }
|
|
1550
|
+
|
1504
|
1551
|
waitForRemoteVideo(
|
1505
|
1552
|
sel,
|
1506
|
1553
|
mediaStream.ssrc,
|
|
@@ -1511,6 +1558,37 @@ var VideoLayout = (function (my) {
|
1511
|
1558
|
}
|
1512
|
1559
|
});
|
1513
|
1560
|
}
|
|
1561
|
+
|
|
1562
|
+ // The endpoint that was being shown in the large video has dropped out
|
|
1563
|
+ // of the lastN set and there was no lastN pickup jid. We need to update
|
|
1564
|
+ // the large video now.
|
|
1565
|
+
|
|
1566
|
+ if (updateLargeVideo) {
|
|
1567
|
+
|
|
1568
|
+ var resource, container, src;
|
|
1569
|
+ var myResource
|
|
1570
|
+ = Strophe.getResourceFromJid(connection.emuc.myroomjid);
|
|
1571
|
+
|
|
1572
|
+ // Find out which endpoint to show in the large video.
|
|
1573
|
+ for (var i = 0; i < lastNEndpoints.length; i++) {
|
|
1574
|
+ resource = lastNEndpoints[i];
|
|
1575
|
+ if (!resource || resource === myResource)
|
|
1576
|
+ continue;
|
|
1577
|
+
|
|
1578
|
+ container = $("#participant_" + resource);
|
|
1579
|
+ if (container.length == 0)
|
|
1580
|
+ continue;
|
|
1581
|
+
|
|
1582
|
+ src = $('video', container).attr('src');
|
|
1583
|
+ if (!src)
|
|
1584
|
+ continue;
|
|
1585
|
+
|
|
1586
|
+ // videoSrcToSsrc needs to be update for this call to succeed.
|
|
1587
|
+ VideoLayout.updateLargeVideo(src);
|
|
1588
|
+ break;
|
|
1589
|
+
|
|
1590
|
+ }
|
|
1591
|
+ }
|
1514
|
1592
|
});
|
1515
|
1593
|
|
1516
|
1594
|
$(document).bind('videoactive.jingle', function (event, videoelem) {
|