|
@@ -8,12 +8,25 @@ var nickname = null;
|
8
|
8
|
var sharedKey = '';
|
9
|
9
|
var roomUrl = null;
|
10
|
10
|
var ssrc2jid = {};
|
|
11
|
+
|
|
12
|
+/**
|
|
13
|
+ * Indicates whether ssrc is camera video or desktop stream.
|
|
14
|
+ * FIXME: remove those maps
|
|
15
|
+ */
|
|
16
|
+var ssrc2videoType = {};
|
|
17
|
+var videoSrcToSsrc = {};
|
|
18
|
+
|
11
|
19
|
var localVideoSrc = null;
|
12
|
20
|
var flipXLocalVideo = true;
|
13
|
21
|
var isFullScreen = false;
|
14
|
22
|
var toolbarTimeout = null;
|
15
|
23
|
var currentVideoWidth = null;
|
16
|
24
|
var currentVideoHeight = null;
|
|
25
|
+/**
|
|
26
|
+ * Method used to calculate large video size.
|
|
27
|
+ * @type {function()}
|
|
28
|
+ */
|
|
29
|
+var getVideoSize;
|
17
|
30
|
|
18
|
31
|
/* window.onbeforeunload = closePageWarning; */
|
19
|
32
|
|
|
@@ -173,10 +186,6 @@ function change_local_video(stream, flipX) {
|
173
|
186
|
localVideo.volume = 0; // is it required if audio is separated ?
|
174
|
187
|
localVideo.oncontextmenu = function () { return false; };
|
175
|
188
|
|
176
|
|
- localVideo.addEventListener('loadedmetadata', function(e){
|
177
|
|
- positionLarge(this.videoWidth, this.videoHeight);
|
178
|
|
- });
|
179
|
|
-
|
180
|
189
|
var localVideoContainer = document.getElementById('localVideoWrapper');
|
181
|
190
|
localVideoContainer.appendChild(localVideo);
|
182
|
191
|
|
|
@@ -201,25 +210,35 @@ function change_local_video(stream, flipX) {
|
201
|
210
|
}
|
202
|
211
|
|
203
|
212
|
$(document).bind('remotestreamadded.jingle', function (event, data, sid) {
|
204
|
|
- function waitForRemoteVideo(selector, sid) {
|
|
213
|
+ function waitForRemoteVideo(selector, sid, ssrc) {
|
205
|
214
|
if(selector.removed) {
|
206
|
215
|
console.warn("media removed before had started", selector);
|
207
|
216
|
return;
|
208
|
217
|
}
|
209
|
218
|
var sess = connection.jingle.sessions[sid];
|
210
|
219
|
if (data.stream.id === 'mixedmslabel') return;
|
211
|
|
- videoTracks = data.stream.getVideoTracks();
|
|
220
|
+ var videoTracks = data.stream.getVideoTracks();
|
212
|
221
|
console.log("waiting..", videoTracks, selector[0]);
|
213
|
222
|
if (videoTracks.length === 0 || selector[0].currentTime > 0) {
|
214
|
223
|
RTC.attachMediaStream(selector, data.stream); // FIXME: why do i have to do this for FF?
|
|
224
|
+
|
|
225
|
+ // FIXME: add a class that will associate peer Jid, video.src, it's ssrc and video type
|
|
226
|
+ // in order to get rid of too many maps
|
|
227
|
+ if(ssrc) {
|
|
228
|
+ videoSrcToSsrc[sel.attr('src')] = ssrc;
|
|
229
|
+ } else {
|
|
230
|
+ console.warn("No ssrc given for video", sel);
|
|
231
|
+ }
|
|
232
|
+
|
215
|
233
|
$(document).trigger('callactive.jingle', [selector, sid]);
|
216
|
234
|
console.log('waitForremotevideo', sess.peerconnection.iceConnectionState, sess.peerconnection.signalingState);
|
217
|
235
|
} else {
|
218
|
|
- setTimeout(function () { waitForRemoteVideo(selector, sid); }, 250);
|
|
236
|
+ setTimeout(function () { waitForRemoteVideo(selector, sid, ssrc); }, 250);
|
219
|
237
|
}
|
220
|
238
|
}
|
221
|
239
|
var sess = connection.jingle.sessions[sid];
|
222
|
240
|
|
|
241
|
+ var thessrc;
|
223
|
242
|
// look up an associated JID for a stream id
|
224
|
243
|
if (data.stream.id.indexOf('mixedmslabel') === -1) {
|
225
|
244
|
var ssrclines = SDPUtil.find_lines(sess.peerconnection.remoteDescription.sdp, 'a=ssrc');
|
|
@@ -272,15 +291,7 @@ $(document).bind('remotestreamadded.jingle', function (event, data, sid) {
|
272
|
291
|
vid.autoplay = true;
|
273
|
292
|
vid.oncontextmenu = function () { return false; };
|
274
|
293
|
|
275
|
|
- vid.addEventListener('loadedmetadata', function(e){
|
276
|
|
- positionLarge(this.videoWidth, this.videoHeight);
|
277
|
|
- });
|
278
|
|
-
|
279
|
294
|
container.appendChild(vid);
|
280
|
|
- var sel = $('#' + id);
|
281
|
|
- sel.hide();
|
282
|
|
- RTC.attachMediaStream(sel, data.stream);
|
283
|
|
- waitForRemoteVideo(sel, sid);
|
284
|
295
|
|
285
|
296
|
// TODO: make mixedstream display:none via css?
|
286
|
297
|
if (id.indexOf('mixedmslabel') !== -1) {
|
|
@@ -293,7 +304,7 @@ $(document).bind('remotestreamadded.jingle', function (event, data, sid) {
|
293
|
304
|
RTC.attachMediaStream(sel, data.stream);
|
294
|
305
|
|
295
|
306
|
if(isVideo) {
|
296
|
|
- waitForRemoteVideo(sel, sid);
|
|
307
|
+ waitForRemoteVideo(sel, sid, thessrc);
|
297
|
308
|
}
|
298
|
309
|
|
299
|
310
|
data.stream.onended = function () {
|
|
@@ -592,6 +603,7 @@ $(document).bind('entered.muc', function (event, jid, info, pres) {
|
592
|
603
|
|
593
|
604
|
$(pres).find('>media[xmlns="http://estos.de/ns/mjs"]>source').each(function (idx, ssrc) {
|
594
|
605
|
//console.log(jid, 'assoc ssrc', ssrc.getAttribute('type'), ssrc.getAttribute('ssrc'));
|
|
606
|
+ // Fixme: direction and video types are unhandled here(maybe something more)
|
595
|
607
|
ssrc2jid[ssrc.getAttribute('ssrc')] = jid;
|
596
|
608
|
});
|
597
|
609
|
});
|
|
@@ -632,13 +644,19 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
|
632
|
644
|
if(ssrc2jid[ssrc] == jid){
|
633
|
645
|
delete ssrc2jid[ssrc];
|
634
|
646
|
}
|
|
647
|
+ if(ssrc2videoType == jid){
|
|
648
|
+ delete ssrc2videoType[ssrc];
|
|
649
|
+ }
|
635
|
650
|
});
|
636
|
651
|
|
637
|
652
|
$(pres).find('>media[xmlns="http://estos.de/ns/mjs"]>source').each(function (idx, ssrc) {
|
638
|
653
|
//console.log(jid, 'assoc ssrc', ssrc.getAttribute('type'), ssrc.getAttribute('ssrc'));
|
639
|
|
- ssrc2jid[ssrc.getAttribute('ssrc')] = jid;
|
|
654
|
+ var ssrcV = ssrc.getAttribute('ssrc');
|
|
655
|
+ ssrc2jid[ssrcV] = jid;
|
640
|
656
|
|
641
|
657
|
var type = ssrc.getAttribute('type');
|
|
658
|
+ ssrc2videoType[ssrcV] = type;
|
|
659
|
+
|
642
|
660
|
// might need to update the direction if participant just went from sendrecv to recvonly
|
643
|
661
|
if (type === 'video' || type === 'screen') {
|
644
|
662
|
var el = $('#participant_' + Strophe.getResourceFromJid(jid) + '>video');
|
|
@@ -652,14 +670,6 @@ $(document).bind('presence.muc', function (event, jid, info, pres) {
|
652
|
670
|
//checkChangeLargeVideo(el);
|
653
|
671
|
break;
|
654
|
672
|
}
|
655
|
|
- // Camera video or shared screen ?
|
656
|
|
- if (type === 'screen') {
|
657
|
|
- // Shared screen
|
658
|
|
- //console.info("Have screen ssrc from "+jid, ssrc);
|
659
|
|
- } else {
|
660
|
|
- // Camera video
|
661
|
|
- //console.info("Have camera ssrc from "+jid, ssrc);
|
662
|
|
- }
|
663
|
673
|
}
|
664
|
674
|
});
|
665
|
675
|
|
|
@@ -705,11 +715,6 @@ function updateLargeVideo(newSrc, vol) {
|
705
|
715
|
console.log('hover in', newSrc);
|
706
|
716
|
|
707
|
717
|
if ($('#largeVideo').attr('src') != newSrc) {
|
708
|
|
- document.getElementById('largeVideo')
|
709
|
|
- .addEventListener('loadedmetadata', function(e){
|
710
|
|
- currentVideoWidth = this.videoWidth;
|
711
|
|
- currentVideoHeight = this.videoHeight;
|
712
|
|
- });
|
713
|
718
|
|
714
|
719
|
var isVisible = $('#largeVideo').is(':visible');
|
715
|
720
|
|
|
@@ -727,12 +732,45 @@ function updateLargeVideo(newSrc, vol) {
|
727
|
732
|
document.getElementById('largeVideo').style.webkitTransform = "none";
|
728
|
733
|
}
|
729
|
734
|
|
|
735
|
+ // Change the way we'll be measuring large video
|
|
736
|
+ getVideoSize = isVideoSrcDesktop(newSrc) ? getVideoSizeFit : getVideoSizeCover;
|
|
737
|
+
|
730
|
738
|
if (isVisible)
|
731
|
739
|
$(this).fadeIn(300);
|
732
|
740
|
});
|
733
|
741
|
}
|
734
|
742
|
}
|
735
|
743
|
|
|
744
|
+/**
|
|
745
|
+ * Checks if video identified by given src is desktop stream.
|
|
746
|
+ * @param videoSrc eg. blob:https%3A//pawel.jitsi.net/9a46e0bd-131e-4d18-9c14-a9264e8db395
|
|
747
|
+ * @returns {boolean}
|
|
748
|
+ */
|
|
749
|
+function isVideoSrcDesktop(videoSrc){
|
|
750
|
+ // FIXME: fix this mapping mess...
|
|
751
|
+ // figure out if large video is desktop stream or just a camera
|
|
752
|
+ var isDesktop = false;
|
|
753
|
+ if(localVideoSrc === videoSrc) {
|
|
754
|
+ // local video
|
|
755
|
+ isDesktop = isUsingScreenStream;
|
|
756
|
+ } else {
|
|
757
|
+ // Do we have associations...
|
|
758
|
+ var videoSsrc = videoSrcToSsrc[videoSrc];
|
|
759
|
+ if(videoSsrc) {
|
|
760
|
+ var videoType = ssrc2videoType[videoSsrc];
|
|
761
|
+ if(videoType) {
|
|
762
|
+ // Finally there...
|
|
763
|
+ isDesktop = videoType === 'screen';
|
|
764
|
+ } else {
|
|
765
|
+ console.error("No video type for ssrc: " + videoSsrc);
|
|
766
|
+ }
|
|
767
|
+ } else {
|
|
768
|
+ console.error("No ssrc for src: " + videoSrc);
|
|
769
|
+ }
|
|
770
|
+ }
|
|
771
|
+ return isDesktop;
|
|
772
|
+}
|
|
773
|
+
|
736
|
774
|
/**
|
737
|
775
|
* Shows/hides the large video.
|
738
|
776
|
*/
|
|
@@ -799,11 +837,11 @@ var positionLarge = function(videoWidth, videoHeight) {
|
799
|
837
|
videoSpaceWidth,
|
800
|
838
|
videoSpaceHeight);
|
801
|
839
|
|
802
|
|
- var availableWidth = videoSize[0];
|
803
|
|
- var availableHeight = videoSize[1];
|
|
840
|
+ var largeVideoWidth = videoSize[0];
|
|
841
|
+ var largeVideoHeight = videoSize[1];
|
804
|
842
|
|
805
|
|
- var videoPosition = getVideoPosition( availableWidth,
|
806
|
|
- availableHeight,
|
|
843
|
+ var videoPosition = getVideoPosition( largeVideoWidth,
|
|
844
|
+ largeVideoHeight,
|
807
|
845
|
videoSpaceWidth,
|
808
|
846
|
videoSpaceHeight);
|
809
|
847
|
|
|
@@ -811,8 +849,8 @@ var positionLarge = function(videoWidth, videoHeight) {
|
811
|
849
|
var verticalIndent = videoPosition[1];
|
812
|
850
|
|
813
|
851
|
positionVideo( $('#largeVideo'),
|
814
|
|
- availableWidth,
|
815
|
|
- availableHeight,
|
|
852
|
+ largeVideoWidth,
|
|
853
|
+ largeVideoHeight,
|
816
|
854
|
horizontalIndent, verticalIndent);
|
817
|
855
|
};
|
818
|
856
|
|
|
@@ -843,14 +881,15 @@ var getVideoPosition = function ( videoWidth,
|
843
|
881
|
};
|
844
|
882
|
|
845
|
883
|
/**
|
846
|
|
- * Returns an array of the video dimensions, so that if fits the screen.
|
|
884
|
+ * Returns an array of the video dimensions, so that it covers the screen.
|
|
885
|
+ * It leaves no empty areas, but some parts of the video might not be visible.
|
847
|
886
|
*
|
848
|
887
|
* @return an array with 2 elements, the video width and the video height
|
849
|
888
|
*/
|
850
|
|
-var getVideoSize = function(videoWidth,
|
851
|
|
- videoHeight,
|
852
|
|
- videoSpaceWidth,
|
853
|
|
- videoSpaceHeight) {
|
|
889
|
+function getVideoSizeCover(videoWidth,
|
|
890
|
+ videoHeight,
|
|
891
|
+ videoSpaceWidth,
|
|
892
|
+ videoSpaceHeight) {
|
854
|
893
|
if (!videoWidth)
|
855
|
894
|
videoWidth = currentVideoWidth;
|
856
|
895
|
if (!videoHeight)
|
|
@@ -872,7 +911,40 @@ var getVideoSize = function(videoWidth,
|
872
|
911
|
}
|
873
|
912
|
|
874
|
913
|
return [availableWidth, availableHeight];
|
875
|
|
-};
|
|
914
|
+}
|
|
915
|
+
|
|
916
|
+/**
|
|
917
|
+ * Returns an array of the video dimensions, so that it keeps it's aspect ratio and fits available area with it's
|
|
918
|
+ * larger dimension. This method ensures that whole video will be visible and can leave empty areas.
|
|
919
|
+ *
|
|
920
|
+ * @return an array with 2 elements, the video width and the video height
|
|
921
|
+ */
|
|
922
|
+function getVideoSizeFit(videoWidth,
|
|
923
|
+ videoHeight,
|
|
924
|
+ videoSpaceWidth,
|
|
925
|
+ videoSpaceHeight) {
|
|
926
|
+ if (!videoWidth)
|
|
927
|
+ videoWidth = currentVideoWidth;
|
|
928
|
+ if (!videoHeight)
|
|
929
|
+ videoHeight = currentVideoHeight;
|
|
930
|
+
|
|
931
|
+ var aspectRatio = videoWidth / videoHeight;
|
|
932
|
+
|
|
933
|
+ var availableWidth = Math.max(videoWidth, videoSpaceWidth);
|
|
934
|
+ var availableHeight = Math.max(videoHeight, videoSpaceHeight);
|
|
935
|
+
|
|
936
|
+ if (availableWidth / aspectRatio >= videoSpaceHeight) {
|
|
937
|
+ availableHeight = videoSpaceHeight;
|
|
938
|
+ availableWidth = availableHeight*aspectRatio;
|
|
939
|
+ }
|
|
940
|
+
|
|
941
|
+ if (availableHeight*aspectRatio >= videoSpaceWidth) {
|
|
942
|
+ availableWidth = videoSpaceWidth;
|
|
943
|
+ availableHeight = availableWidth / aspectRatio;
|
|
944
|
+ }
|
|
945
|
+
|
|
946
|
+ return [availableWidth, availableHeight];
|
|
947
|
+}
|
876
|
948
|
|
877
|
949
|
/**
|
878
|
950
|
* Sets the size and position of the given video element.
|
|
@@ -945,11 +1017,22 @@ $(document).ready(function () {
|
945
|
1017
|
// Set default desktop sharing method
|
946
|
1018
|
setDesktopSharing(config.desktopSharing);
|
947
|
1019
|
|
|
1020
|
+ // By default we cover the whole screen with video
|
|
1021
|
+ getVideoSize = getVideoSizeCover;
|
|
1022
|
+
|
948
|
1023
|
resizeLargeVideoContainer();
|
949
|
1024
|
$(window).resize(function () {
|
950
|
1025
|
resizeLargeVideoContainer();
|
951
|
1026
|
positionLarge();
|
952
|
1027
|
});
|
|
1028
|
+ // Listen for large video size updates
|
|
1029
|
+ document.getElementById('largeVideo')
|
|
1030
|
+ .addEventListener('loadedmetadata', function(e){
|
|
1031
|
+ currentVideoWidth = this.videoWidth;
|
|
1032
|
+ currentVideoHeight = this.videoHeight;
|
|
1033
|
+ positionLarge(currentVideoWidth, currentVideoHeight);
|
|
1034
|
+ });
|
|
1035
|
+
|
953
|
1036
|
if (!$('#settings').is(':visible')) {
|
954
|
1037
|
console.log('init');
|
955
|
1038
|
init();
|