Explorar el Código

Nukes colibri.*.js and restores original file structure of strophe.jingle.

master
George Politis hace 11 años
padre
commit
dc5d5f8436

+ 2
- 6
index.html Ver fichero

@@ -17,13 +17,9 @@
17 17
     <script src="libs/strophe/strophe.disco.min.js?v=1"></script>
18 18
     <script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script>
19 19
     <script src="libs/strophe/strophe.jingle.js?v=2"></script>
20
-    <script src="libs/strophe/strophe.jingle.sdp.js?v=2"></script>
21
-    <script src="libs/strophe/strophe.jingle.sdp.util.js?v=1"></script>
22
-    <script src="libs/strophe/strophe.jingle.sessionbase.js?v=1"></script>
23
-    <script src="libs/strophe/strophe.jingle.session.js?v=2"></script>
20
+    <script src="libs/strophe/strophe.jingle.sdp.js?v=3"></script>
21
+    <script src="libs/strophe/strophe.jingle.session.js?v=3"></script>
24 22
     <script src="libs/strophe/strophe.util.js"></script>
25
-    <script src="libs/colibri/colibri.focus.js?v=12"></script><!-- colibri focus implementation -->
26
-    <script src="libs/colibri/colibri.session.js?v=1"></script>
27 23
     <script src="libs/jquery-ui.js"></script>
28 24
     <script src="libs/rayo.js?v=1"></script>
29 25
     <script src="libs/tooltip.js?v=1"></script><!-- bootstrap tooltip lib -->

+ 0
- 1638
libs/colibri/colibri.focus.js
La diferencia del archivo ha sido suprimido porque es demasiado grande
Ver fichero


+ 0
- 94
libs/colibri/colibri.session.js Ver fichero

@@ -1,94 +0,0 @@
1
-/* colibri.js -- a COLIBRI focus 
2
- * The colibri spec has been submitted to the XMPP Standards Foundation
3
- * for publications as a XMPP extensions:
4
- * http://xmpp.org/extensions/inbox/colibri.html
5
- *
6
- * colibri.js is a participating focus, i.e. the focus participates
7
- * in the conference. The conference itself can be ad-hoc, through a
8
- * MUC, through PubSub, etc.
9
- *
10
- * colibri.js relies heavily on the strophe.jingle library available 
11
- * from https://github.com/ESTOS/strophe.jingle
12
- * and interoperates with the Jitsi videobridge available from
13
- * https://jitsi.org/Projects/JitsiVideobridge
14
- */
15
-/*
16
-Copyright (c) 2013 ESTOS GmbH
17
-
18
-Permission is hereby granted, free of charge, to any person obtaining a copy
19
-of this software and associated documentation files (the "Software"), to deal
20
-in the Software without restriction, including without limitation the rights
21
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
-copies of the Software, and to permit persons to whom the Software is
23
-furnished to do so, subject to the following conditions:
24
-
25
-The above copyright notice and this permission notice shall be included in
26
-all copies or substantial portions of the Software.
27
-
28
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
34
-THE SOFTWARE.
35
-*/
36
-// A colibri session is similar to a jingle session, it just implements some things differently
37
-// FIXME: inherit jinglesession, see https://github.com/legastero/Jingle-RTCPeerConnection/blob/master/index.js
38
-function ColibriSession(me, sid, connection) {
39
-    this.me = me;
40
-    this.sid = sid;
41
-    this.connection = connection;
42
-    //this.peerconnection = null;
43
-    //this.mychannel = null;
44
-    //this.channels = null;
45
-    this.peerjid = null;
46
-
47
-    this.colibri = null;
48
-}
49
-
50
-// implementation of JingleSession interface
51
-ColibriSession.prototype.initiate = function (peerjid, isInitiator) {
52
-    this.peerjid = peerjid;
53
-};
54
-
55
-ColibriSession.prototype.sendOffer = function (offer) {
56
-    console.log('ColibriSession.sendOffer');
57
-};
58
-
59
-
60
-ColibriSession.prototype.accept = function () {
61
-    console.log('ColibriSession.accept');
62
-};
63
-
64
-ColibriSession.prototype.addSource = function (elem, fromJid) {
65
-    this.colibri.addSource(elem, fromJid);
66
-};
67
-
68
-ColibriSession.prototype.removeSource = function (elem, fromJid) {
69
-    this.colibri.removeSource(elem, fromJid);
70
-};
71
-
72
-ColibriSession.prototype.terminate = function (reason) {
73
-    this.colibri.terminate(this, reason);
74
-};
75
-
76
-ColibriSession.prototype.active = function () {
77
-    console.log('ColibriSession.active');
78
-};
79
-
80
-ColibriSession.prototype.setRemoteDescription = function (elem, desctype) {
81
-    this.colibri.setRemoteDescription(this, elem, desctype);
82
-};
83
-
84
-ColibriSession.prototype.addIceCandidate = function (elem) {
85
-    this.colibri.addIceCandidate(this, elem);
86
-};
87
-
88
-ColibriSession.prototype.sendAnswer = function (sdp, provisional) {
89
-    console.log('ColibriSession.sendAnswer');
90
-};
91
-
92
-ColibriSession.prototype.sendTerminate = function (reason, text) {
93
-    this.colibri.sendTerminate(this, reason, text);
94
-};

+ 406
- 0
libs/strophe/strophe.jingle.sdp.js Ver fichero

@@ -683,3 +683,409 @@ SDP.prototype.jingle2media = function (content) {
683 683
 
684 684
     return media;
685 685
 };
686
+/**
687
+ * Contains utility classes used in SDP class.
688
+ *
689
+ */
690
+
691
+/**
692
+ * Class holds a=ssrc lines and media type a=mid
693
+ * @param ssrc synchronization source identifier number(a=ssrc lines from SDP)
694
+ * @param type media type eg. "audio" or "video"(a=mid frm SDP)
695
+ * @constructor
696
+ */
697
+function ChannelSsrc(ssrc, type) {
698
+    this.ssrc = ssrc;
699
+    this.type = type;
700
+    this.lines = [];
701
+}
702
+
703
+/**
704
+ * Class holds a=ssrc-group: lines
705
+ * @param semantics
706
+ * @param ssrcs
707
+ * @constructor
708
+ */
709
+function ChannelSsrcGroup(semantics, ssrcs, line) {
710
+    this.semantics = semantics;
711
+    this.ssrcs = ssrcs;
712
+}
713
+
714
+/**
715
+ * Helper class represents media channel. Is a container for ChannelSsrc, holds channel idx and media type.
716
+ * @param channelNumber channel idx in SDP media array.
717
+ * @param mediaType media type(a=mid)
718
+ * @constructor
719
+ */
720
+function MediaChannel(channelNumber, mediaType) {
721
+    /**
722
+     * SDP channel number
723
+     * @type {*}
724
+     */
725
+    this.chNumber = channelNumber;
726
+    /**
727
+     * Channel media type(a=mid)
728
+     * @type {*}
729
+     */
730
+    this.mediaType = mediaType;
731
+    /**
732
+     * The maps of ssrc numbers to ChannelSsrc objects.
733
+     */
734
+    this.ssrcs = {};
735
+
736
+    /**
737
+     * The array of ChannelSsrcGroup objects.
738
+     * @type {Array}
739
+     */
740
+    this.ssrcGroups = [];
741
+}
742
+
743
+SDPUtil = {
744
+    iceparams: function (mediadesc, sessiondesc) {
745
+        var data = null;
746
+        if (SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc) &&
747
+            SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc)) {
748
+            data = {
749
+                ufrag: SDPUtil.parse_iceufrag(SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc)),
750
+                pwd: SDPUtil.parse_icepwd(SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc))
751
+            };
752
+        }
753
+        return data;
754
+    },
755
+    parse_iceufrag: function (line) {
756
+        return line.substring(12);
757
+    },
758
+    build_iceufrag: function (frag) {
759
+        return 'a=ice-ufrag:' + frag;
760
+    },
761
+    parse_icepwd: function (line) {
762
+        return line.substring(10);
763
+    },
764
+    build_icepwd: function (pwd) {
765
+        return 'a=ice-pwd:' + pwd;
766
+    },
767
+    parse_mid: function (line) {
768
+        return line.substring(6);
769
+    },
770
+    parse_mline: function (line) {
771
+        var parts = line.substring(2).split(' '),
772
+            data = {};
773
+        data.media = parts.shift();
774
+        data.port = parts.shift();
775
+        data.proto = parts.shift();
776
+        if (parts[parts.length - 1] === '') { // trailing whitespace
777
+            parts.pop();
778
+        }
779
+        data.fmt = parts;
780
+        return data;
781
+    },
782
+    build_mline: function (mline) {
783
+        return 'm=' + mline.media + ' ' + mline.port + ' ' + mline.proto + ' ' + mline.fmt.join(' ');
784
+    },
785
+    parse_rtpmap: function (line) {
786
+        var parts = line.substring(9).split(' '),
787
+            data = {};
788
+        data.id = parts.shift();
789
+        parts = parts[0].split('/');
790
+        data.name = parts.shift();
791
+        data.clockrate = parts.shift();
792
+        data.channels = parts.length ? parts.shift() : '1';
793
+        return data;
794
+    },
795
+    /**
796
+     * Parses SDP line "a=sctpmap:..." and extracts SCTP port from it.
797
+     * @param line eg. "a=sctpmap:5000 webrtc-datachannel"
798
+     * @returns [SCTP port number, protocol, streams]
799
+     */
800
+    parse_sctpmap: function (line)
801
+    {
802
+        var parts = line.substring(10).split(' ');
803
+        var sctpPort = parts[0];
804
+        var protocol = parts[1];
805
+        // Stream count is optional
806
+        var streamCount = parts.length > 2 ? parts[2] : null;
807
+        return [sctpPort, protocol, streamCount];// SCTP port
808
+    },
809
+    build_rtpmap: function (el) {
810
+        var line = 'a=rtpmap:' + el.getAttribute('id') + ' ' + el.getAttribute('name') + '/' + el.getAttribute('clockrate');
811
+        if (el.getAttribute('channels') && el.getAttribute('channels') != '1') {
812
+            line += '/' + el.getAttribute('channels');
813
+        }
814
+        return line;
815
+    },
816
+    parse_crypto: function (line) {
817
+        var parts = line.substring(9).split(' '),
818
+            data = {};
819
+        data.tag = parts.shift();
820
+        data['crypto-suite'] = parts.shift();
821
+        data['key-params'] = parts.shift();
822
+        if (parts.length) {
823
+            data['session-params'] = parts.join(' ');
824
+        }
825
+        return data;
826
+    },
827
+    parse_fingerprint: function (line) { // RFC 4572
828
+        var parts = line.substring(14).split(' '),
829
+            data = {};
830
+        data.hash = parts.shift();
831
+        data.fingerprint = parts.shift();
832
+        // TODO assert that fingerprint satisfies 2UHEX *(":" 2UHEX) ?
833
+        return data;
834
+    },
835
+    parse_fmtp: function (line) {
836
+        var parts = line.split(' '),
837
+            i, key, value,
838
+            data = [];
839
+        parts.shift();
840
+        parts = parts.join(' ').split(';');
841
+        for (i = 0; i < parts.length; i++) {
842
+            key = parts[i].split('=')[0];
843
+            while (key.length && key[0] == ' ') {
844
+                key = key.substring(1);
845
+            }
846
+            value = parts[i].split('=')[1];
847
+            if (key && value) {
848
+                data.push({name: key, value: value});
849
+            } else if (key) {
850
+                // rfc 4733 (DTMF) style stuff
851
+                data.push({name: '', value: key});
852
+            }
853
+        }
854
+        return data;
855
+    },
856
+    parse_icecandidate: function (line) {
857
+        var candidate = {},
858
+            elems = line.split(' ');
859
+        candidate.foundation = elems[0].substring(12);
860
+        candidate.component = elems[1];
861
+        candidate.protocol = elems[2].toLowerCase();
862
+        candidate.priority = elems[3];
863
+        candidate.ip = elems[4];
864
+        candidate.port = elems[5];
865
+        // elems[6] => "typ"
866
+        candidate.type = elems[7];
867
+        candidate.generation = 0; // default value, may be overwritten below
868
+        for (var i = 8; i < elems.length; i += 2) {
869
+            switch (elems[i]) {
870
+                case 'raddr':
871
+                    candidate['rel-addr'] = elems[i + 1];
872
+                    break;
873
+                case 'rport':
874
+                    candidate['rel-port'] = elems[i + 1];
875
+                    break;
876
+                case 'generation':
877
+                    candidate.generation = elems[i + 1];
878
+                    break;
879
+                case 'tcptype':
880
+                    candidate.tcptype = elems[i + 1];
881
+                    break;
882
+                default: // TODO
883
+                    console.log('parse_icecandidate not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
884
+            }
885
+        }
886
+        candidate.network = '1';
887
+        candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
888
+        return candidate;
889
+    },
890
+    build_icecandidate: function (cand) {
891
+        var line = ['a=candidate:' + cand.foundation, cand.component, cand.protocol, cand.priority, cand.ip, cand.port, 'typ', cand.type].join(' ');
892
+        line += ' ';
893
+        switch (cand.type) {
894
+            case 'srflx':
895
+            case 'prflx':
896
+            case 'relay':
897
+                if (cand.hasOwnAttribute('rel-addr') && cand.hasOwnAttribute('rel-port')) {
898
+                    line += 'raddr';
899
+                    line += ' ';
900
+                    line += cand['rel-addr'];
901
+                    line += ' ';
902
+                    line += 'rport';
903
+                    line += ' ';
904
+                    line += cand['rel-port'];
905
+                    line += ' ';
906
+                }
907
+                break;
908
+        }
909
+        if (cand.hasOwnAttribute('tcptype')) {
910
+            line += 'tcptype';
911
+            line += ' ';
912
+            line += cand.tcptype;
913
+            line += ' ';
914
+        }
915
+        line += 'generation';
916
+        line += ' ';
917
+        line += cand.hasOwnAttribute('generation') ? cand.generation : '0';
918
+        return line;
919
+    },
920
+    parse_ssrc: function (desc) {
921
+        // proprietary mapping of a=ssrc lines
922
+        // TODO: see "Jingle RTP Source Description" by Juberti and P. Thatcher on google docs
923
+        // and parse according to that
924
+        var lines = desc.split('\r\n'),
925
+            data = {};
926
+        for (var i = 0; i < lines.length; i++) {
927
+            if (lines[i].substring(0, 7) == 'a=ssrc:') {
928
+                var idx = lines[i].indexOf(' ');
929
+                data[lines[i].substr(idx + 1).split(':', 2)[0]] = lines[i].substr(idx + 1).split(':', 2)[1];
930
+            }
931
+        }
932
+        return data;
933
+    },
934
+    parse_rtcpfb: function (line) {
935
+        var parts = line.substr(10).split(' ');
936
+        var data = {};
937
+        data.pt = parts.shift();
938
+        data.type = parts.shift();
939
+        data.params = parts;
940
+        return data;
941
+    },
942
+    parse_extmap: function (line) {
943
+        var parts = line.substr(9).split(' ');
944
+        var data = {};
945
+        data.value = parts.shift();
946
+        if (data.value.indexOf('/') != -1) {
947
+            data.direction = data.value.substr(data.value.indexOf('/') + 1);
948
+            data.value = data.value.substr(0, data.value.indexOf('/'));
949
+        } else {
950
+            data.direction = 'both';
951
+        }
952
+        data.uri = parts.shift();
953
+        data.params = parts;
954
+        return data;
955
+    },
956
+    find_line: function (haystack, needle, sessionpart) {
957
+        var lines = haystack.split('\r\n');
958
+        for (var i = 0; i < lines.length; i++) {
959
+            if (lines[i].substring(0, needle.length) == needle) {
960
+                return lines[i];
961
+            }
962
+        }
963
+        if (!sessionpart) {
964
+            return false;
965
+        }
966
+        // search session part
967
+        lines = sessionpart.split('\r\n');
968
+        for (var j = 0; j < lines.length; j++) {
969
+            if (lines[j].substring(0, needle.length) == needle) {
970
+                return lines[j];
971
+            }
972
+        }
973
+        return false;
974
+    },
975
+    find_lines: function (haystack, needle, sessionpart) {
976
+        var lines = haystack.split('\r\n'),
977
+            needles = [];
978
+        for (var i = 0; i < lines.length; i++) {
979
+            if (lines[i].substring(0, needle.length) == needle)
980
+                needles.push(lines[i]);
981
+        }
982
+        if (needles.length || !sessionpart) {
983
+            return needles;
984
+        }
985
+        // search session part
986
+        lines = sessionpart.split('\r\n');
987
+        for (var j = 0; j < lines.length; j++) {
988
+            if (lines[j].substring(0, needle.length) == needle) {
989
+                needles.push(lines[j]);
990
+            }
991
+        }
992
+        return needles;
993
+    },
994
+    candidateToJingle: function (line) {
995
+        // a=candidate:2979166662 1 udp 2113937151 192.168.2.100 57698 typ host generation 0
996
+        //      <candidate component=... foundation=... generation=... id=... ip=... network=... port=... priority=... protocol=... type=.../>
997
+        if (line.indexOf('candidate:') === 0) {
998
+            line = 'a=' + line;
999
+        } else if (line.substring(0, 12) != 'a=candidate:') {
1000
+            console.log('parseCandidate called with a line that is not a candidate line');
1001
+            console.log(line);
1002
+            return null;
1003
+        }
1004
+        if (line.substring(line.length - 2) == '\r\n') // chomp it
1005
+            line = line.substring(0, line.length - 2);
1006
+        var candidate = {},
1007
+            elems = line.split(' '),
1008
+            i;
1009
+        if (elems[6] != 'typ') {
1010
+            console.log('did not find typ in the right place');
1011
+            console.log(line);
1012
+            return null;
1013
+        }
1014
+        candidate.foundation = elems[0].substring(12);
1015
+        candidate.component = elems[1];
1016
+        candidate.protocol = elems[2].toLowerCase();
1017
+        candidate.priority = elems[3];
1018
+        candidate.ip = elems[4];
1019
+        candidate.port = elems[5];
1020
+        // elems[6] => "typ"
1021
+        candidate.type = elems[7];
1022
+
1023
+        candidate.generation = '0'; // default, may be overwritten below
1024
+        for (i = 8; i < elems.length; i += 2) {
1025
+            switch (elems[i]) {
1026
+                case 'raddr':
1027
+                    candidate['rel-addr'] = elems[i + 1];
1028
+                    break;
1029
+                case 'rport':
1030
+                    candidate['rel-port'] = elems[i + 1];
1031
+                    break;
1032
+                case 'generation':
1033
+                    candidate.generation = elems[i + 1];
1034
+                    break;
1035
+                case 'tcptype':
1036
+                    candidate.tcptype = elems[i + 1];
1037
+                    break;
1038
+                default: // TODO
1039
+                    console.log('not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
1040
+            }
1041
+        }
1042
+        candidate.network = '1';
1043
+        candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
1044
+        return candidate;
1045
+    },
1046
+    candidateFromJingle: function (cand) {
1047
+        var line = 'a=candidate:';
1048
+        line += cand.getAttribute('foundation');
1049
+        line += ' ';
1050
+        line += cand.getAttribute('component');
1051
+        line += ' ';
1052
+        line += cand.getAttribute('protocol'); //.toUpperCase(); // chrome M23 doesn't like this
1053
+        line += ' ';
1054
+        line += cand.getAttribute('priority');
1055
+        line += ' ';
1056
+        line += cand.getAttribute('ip');
1057
+        line += ' ';
1058
+        line += cand.getAttribute('port');
1059
+        line += ' ';
1060
+        line += 'typ';
1061
+        line += ' ' + cand.getAttribute('type');
1062
+        line += ' ';
1063
+        switch (cand.getAttribute('type')) {
1064
+            case 'srflx':
1065
+            case 'prflx':
1066
+            case 'relay':
1067
+                if (cand.getAttribute('rel-addr') && cand.getAttribute('rel-port')) {
1068
+                    line += 'raddr';
1069
+                    line += ' ';
1070
+                    line += cand.getAttribute('rel-addr');
1071
+                    line += ' ';
1072
+                    line += 'rport';
1073
+                    line += ' ';
1074
+                    line += cand.getAttribute('rel-port');
1075
+                    line += ' ';
1076
+                }
1077
+                break;
1078
+        }
1079
+        if (cand.getAttribute('protocol').toLowerCase() == 'tcp') {
1080
+            line += 'tcptype';
1081
+            line += ' ';
1082
+            line += cand.getAttribute('tcptype');
1083
+            line += ' ';
1084
+        }
1085
+        line += 'generation';
1086
+        line += ' ';
1087
+        line += cand.getAttribute('generation') || '0';
1088
+        return line + '\r\n';
1089
+    }
1090
+};
1091
+

+ 0
- 406
libs/strophe/strophe.jingle.sdp.util.js Ver fichero

@@ -1,406 +0,0 @@
1
-/**
2
- * Contains utility classes used in SDP class.
3
- *
4
- */
5
-
6
-/**
7
- * Class holds a=ssrc lines and media type a=mid
8
- * @param ssrc synchronization source identifier number(a=ssrc lines from SDP)
9
- * @param type media type eg. "audio" or "video"(a=mid frm SDP)
10
- * @constructor
11
- */
12
-function ChannelSsrc(ssrc, type) {
13
-    this.ssrc = ssrc;
14
-    this.type = type;
15
-    this.lines = [];
16
-}
17
-
18
-/**
19
- * Class holds a=ssrc-group: lines
20
- * @param semantics
21
- * @param ssrcs
22
- * @constructor
23
- */
24
-function ChannelSsrcGroup(semantics, ssrcs, line) {
25
-    this.semantics = semantics;
26
-    this.ssrcs = ssrcs;
27
-}
28
-
29
-/**
30
- * Helper class represents media channel. Is a container for ChannelSsrc, holds channel idx and media type.
31
- * @param channelNumber channel idx in SDP media array.
32
- * @param mediaType media type(a=mid)
33
- * @constructor
34
- */
35
-function MediaChannel(channelNumber, mediaType) {
36
-    /**
37
-     * SDP channel number
38
-     * @type {*}
39
-     */
40
-    this.chNumber = channelNumber;
41
-    /**
42
-     * Channel media type(a=mid)
43
-     * @type {*}
44
-     */
45
-    this.mediaType = mediaType;
46
-    /**
47
-     * The maps of ssrc numbers to ChannelSsrc objects.
48
-     */
49
-    this.ssrcs = {};
50
-
51
-    /**
52
-     * The array of ChannelSsrcGroup objects.
53
-     * @type {Array}
54
-     */
55
-    this.ssrcGroups = [];
56
-}
57
-
58
-SDPUtil = {
59
-    iceparams: function (mediadesc, sessiondesc) {
60
-        var data = null;
61
-        if (SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc) &&
62
-            SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc)) {
63
-            data = {
64
-                ufrag: SDPUtil.parse_iceufrag(SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc)),
65
-                pwd: SDPUtil.parse_icepwd(SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc))
66
-            };
67
-        }
68
-        return data;
69
-    },
70
-    parse_iceufrag: function (line) {
71
-        return line.substring(12);
72
-    },
73
-    build_iceufrag: function (frag) {
74
-        return 'a=ice-ufrag:' + frag;
75
-    },
76
-    parse_icepwd: function (line) {
77
-        return line.substring(10);
78
-    },
79
-    build_icepwd: function (pwd) {
80
-        return 'a=ice-pwd:' + pwd;
81
-    },
82
-    parse_mid: function (line) {
83
-        return line.substring(6);
84
-    },
85
-    parse_mline: function (line) {
86
-        var parts = line.substring(2).split(' '),
87
-            data = {};
88
-        data.media = parts.shift();
89
-        data.port = parts.shift();
90
-        data.proto = parts.shift();
91
-        if (parts[parts.length - 1] === '') { // trailing whitespace
92
-            parts.pop();
93
-        }
94
-        data.fmt = parts;
95
-        return data;
96
-    },
97
-    build_mline: function (mline) {
98
-        return 'm=' + mline.media + ' ' + mline.port + ' ' + mline.proto + ' ' + mline.fmt.join(' ');
99
-    },
100
-    parse_rtpmap: function (line) {
101
-        var parts = line.substring(9).split(' '),
102
-            data = {};
103
-        data.id = parts.shift();
104
-        parts = parts[0].split('/');
105
-        data.name = parts.shift();
106
-        data.clockrate = parts.shift();
107
-        data.channels = parts.length ? parts.shift() : '1';
108
-        return data;
109
-    },
110
-    /**
111
-     * Parses SDP line "a=sctpmap:..." and extracts SCTP port from it.
112
-     * @param line eg. "a=sctpmap:5000 webrtc-datachannel"
113
-     * @returns [SCTP port number, protocol, streams]
114
-     */
115
-    parse_sctpmap: function (line)
116
-    {
117
-        var parts = line.substring(10).split(' ');
118
-        var sctpPort = parts[0];
119
-        var protocol = parts[1];
120
-        // Stream count is optional
121
-        var streamCount = parts.length > 2 ? parts[2] : null;
122
-        return [sctpPort, protocol, streamCount];// SCTP port
123
-    },
124
-    build_rtpmap: function (el) {
125
-        var line = 'a=rtpmap:' + el.getAttribute('id') + ' ' + el.getAttribute('name') + '/' + el.getAttribute('clockrate');
126
-        if (el.getAttribute('channels') && el.getAttribute('channels') != '1') {
127
-            line += '/' + el.getAttribute('channels');
128
-        }
129
-        return line;
130
-    },
131
-    parse_crypto: function (line) {
132
-        var parts = line.substring(9).split(' '),
133
-            data = {};
134
-        data.tag = parts.shift();
135
-        data['crypto-suite'] = parts.shift();
136
-        data['key-params'] = parts.shift();
137
-        if (parts.length) {
138
-            data['session-params'] = parts.join(' ');
139
-        }
140
-        return data;
141
-    },
142
-    parse_fingerprint: function (line) { // RFC 4572
143
-        var parts = line.substring(14).split(' '),
144
-            data = {};
145
-        data.hash = parts.shift();
146
-        data.fingerprint = parts.shift();
147
-        // TODO assert that fingerprint satisfies 2UHEX *(":" 2UHEX) ?
148
-        return data;
149
-    },
150
-    parse_fmtp: function (line) {
151
-        var parts = line.split(' '),
152
-            i, key, value,
153
-            data = [];
154
-        parts.shift();
155
-        parts = parts.join(' ').split(';');
156
-        for (i = 0; i < parts.length; i++) {
157
-            key = parts[i].split('=')[0];
158
-            while (key.length && key[0] == ' ') {
159
-                key = key.substring(1);
160
-            }
161
-            value = parts[i].split('=')[1];
162
-            if (key && value) {
163
-                data.push({name: key, value: value});
164
-            } else if (key) {
165
-                // rfc 4733 (DTMF) style stuff
166
-                data.push({name: '', value: key});
167
-            }
168
-        }
169
-        return data;
170
-    },
171
-    parse_icecandidate: function (line) {
172
-        var candidate = {},
173
-            elems = line.split(' ');
174
-        candidate.foundation = elems[0].substring(12);
175
-        candidate.component = elems[1];
176
-        candidate.protocol = elems[2].toLowerCase();
177
-        candidate.priority = elems[3];
178
-        candidate.ip = elems[4];
179
-        candidate.port = elems[5];
180
-        // elems[6] => "typ"
181
-        candidate.type = elems[7];
182
-        candidate.generation = 0; // default value, may be overwritten below
183
-        for (var i = 8; i < elems.length; i += 2) {
184
-            switch (elems[i]) {
185
-                case 'raddr':
186
-                    candidate['rel-addr'] = elems[i + 1];
187
-                    break;
188
-                case 'rport':
189
-                    candidate['rel-port'] = elems[i + 1];
190
-                    break;
191
-                case 'generation':
192
-                    candidate.generation = elems[i + 1];
193
-                    break;
194
-                case 'tcptype':
195
-                    candidate.tcptype = elems[i + 1];
196
-                    break;
197
-                default: // TODO
198
-                    console.log('parse_icecandidate not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
199
-            }
200
-        }
201
-        candidate.network = '1';
202
-        candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
203
-        return candidate;
204
-    },
205
-    build_icecandidate: function (cand) {
206
-        var line = ['a=candidate:' + cand.foundation, cand.component, cand.protocol, cand.priority, cand.ip, cand.port, 'typ', cand.type].join(' ');
207
-        line += ' ';
208
-        switch (cand.type) {
209
-            case 'srflx':
210
-            case 'prflx':
211
-            case 'relay':
212
-                if (cand.hasOwnAttribute('rel-addr') && cand.hasOwnAttribute('rel-port')) {
213
-                    line += 'raddr';
214
-                    line += ' ';
215
-                    line += cand['rel-addr'];
216
-                    line += ' ';
217
-                    line += 'rport';
218
-                    line += ' ';
219
-                    line += cand['rel-port'];
220
-                    line += ' ';
221
-                }
222
-                break;
223
-        }
224
-        if (cand.hasOwnAttribute('tcptype')) {
225
-            line += 'tcptype';
226
-            line += ' ';
227
-            line += cand.tcptype;
228
-            line += ' ';
229
-        }
230
-        line += 'generation';
231
-        line += ' ';
232
-        line += cand.hasOwnAttribute('generation') ? cand.generation : '0';
233
-        return line;
234
-    },
235
-    parse_ssrc: function (desc) {
236
-        // proprietary mapping of a=ssrc lines
237
-        // TODO: see "Jingle RTP Source Description" by Juberti and P. Thatcher on google docs
238
-        // and parse according to that
239
-        var lines = desc.split('\r\n'),
240
-            data = {};
241
-        for (var i = 0; i < lines.length; i++) {
242
-            if (lines[i].substring(0, 7) == 'a=ssrc:') {
243
-                var idx = lines[i].indexOf(' ');
244
-                data[lines[i].substr(idx + 1).split(':', 2)[0]] = lines[i].substr(idx + 1).split(':', 2)[1];
245
-            }
246
-        }
247
-        return data;
248
-    },
249
-    parse_rtcpfb: function (line) {
250
-        var parts = line.substr(10).split(' ');
251
-        var data = {};
252
-        data.pt = parts.shift();
253
-        data.type = parts.shift();
254
-        data.params = parts;
255
-        return data;
256
-    },
257
-    parse_extmap: function (line) {
258
-        var parts = line.substr(9).split(' ');
259
-        var data = {};
260
-        data.value = parts.shift();
261
-        if (data.value.indexOf('/') != -1) {
262
-            data.direction = data.value.substr(data.value.indexOf('/') + 1);
263
-            data.value = data.value.substr(0, data.value.indexOf('/'));
264
-        } else {
265
-            data.direction = 'both';
266
-        }
267
-        data.uri = parts.shift();
268
-        data.params = parts;
269
-        return data;
270
-    },
271
-    find_line: function (haystack, needle, sessionpart) {
272
-        var lines = haystack.split('\r\n');
273
-        for (var i = 0; i < lines.length; i++) {
274
-            if (lines[i].substring(0, needle.length) == needle) {
275
-                return lines[i];
276
-            }
277
-        }
278
-        if (!sessionpart) {
279
-            return false;
280
-        }
281
-        // search session part
282
-        lines = sessionpart.split('\r\n');
283
-        for (var j = 0; j < lines.length; j++) {
284
-            if (lines[j].substring(0, needle.length) == needle) {
285
-                return lines[j];
286
-            }
287
-        }
288
-        return false;
289
-    },
290
-    find_lines: function (haystack, needle, sessionpart) {
291
-        var lines = haystack.split('\r\n'),
292
-            needles = [];
293
-        for (var i = 0; i < lines.length; i++) {
294
-            if (lines[i].substring(0, needle.length) == needle)
295
-                needles.push(lines[i]);
296
-        }
297
-        if (needles.length || !sessionpart) {
298
-            return needles;
299
-        }
300
-        // search session part
301
-        lines = sessionpart.split('\r\n');
302
-        for (var j = 0; j < lines.length; j++) {
303
-            if (lines[j].substring(0, needle.length) == needle) {
304
-                needles.push(lines[j]);
305
-            }
306
-        }
307
-        return needles;
308
-    },
309
-    candidateToJingle: function (line) {
310
-        // a=candidate:2979166662 1 udp 2113937151 192.168.2.100 57698 typ host generation 0
311
-        //      <candidate component=... foundation=... generation=... id=... ip=... network=... port=... priority=... protocol=... type=.../>
312
-        if (line.indexOf('candidate:') === 0) {
313
-            line = 'a=' + line;
314
-        } else if (line.substring(0, 12) != 'a=candidate:') {
315
-            console.log('parseCandidate called with a line that is not a candidate line');
316
-            console.log(line);
317
-            return null;
318
-        }
319
-        if (line.substring(line.length - 2) == '\r\n') // chomp it
320
-            line = line.substring(0, line.length - 2);
321
-        var candidate = {},
322
-            elems = line.split(' '),
323
-            i;
324
-        if (elems[6] != 'typ') {
325
-            console.log('did not find typ in the right place');
326
-            console.log(line);
327
-            return null;
328
-        }
329
-        candidate.foundation = elems[0].substring(12);
330
-        candidate.component = elems[1];
331
-        candidate.protocol = elems[2].toLowerCase();
332
-        candidate.priority = elems[3];
333
-        candidate.ip = elems[4];
334
-        candidate.port = elems[5];
335
-        // elems[6] => "typ"
336
-        candidate.type = elems[7];
337
-
338
-        candidate.generation = '0'; // default, may be overwritten below
339
-        for (i = 8; i < elems.length; i += 2) {
340
-            switch (elems[i]) {
341
-                case 'raddr':
342
-                    candidate['rel-addr'] = elems[i + 1];
343
-                    break;
344
-                case 'rport':
345
-                    candidate['rel-port'] = elems[i + 1];
346
-                    break;
347
-                case 'generation':
348
-                    candidate.generation = elems[i + 1];
349
-                    break;
350
-                case 'tcptype':
351
-                    candidate.tcptype = elems[i + 1];
352
-                    break;
353
-                default: // TODO
354
-                    console.log('not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
355
-            }
356
-        }
357
-        candidate.network = '1';
358
-        candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
359
-        return candidate;
360
-    },
361
-    candidateFromJingle: function (cand) {
362
-        var line = 'a=candidate:';
363
-        line += cand.getAttribute('foundation');
364
-        line += ' ';
365
-        line += cand.getAttribute('component');
366
-        line += ' ';
367
-        line += cand.getAttribute('protocol'); //.toUpperCase(); // chrome M23 doesn't like this
368
-        line += ' ';
369
-        line += cand.getAttribute('priority');
370
-        line += ' ';
371
-        line += cand.getAttribute('ip');
372
-        line += ' ';
373
-        line += cand.getAttribute('port');
374
-        line += ' ';
375
-        line += 'typ';
376
-        line += ' ' + cand.getAttribute('type');
377
-        line += ' ';
378
-        switch (cand.getAttribute('type')) {
379
-            case 'srflx':
380
-            case 'prflx':
381
-            case 'relay':
382
-                if (cand.getAttribute('rel-addr') && cand.getAttribute('rel-port')) {
383
-                    line += 'raddr';
384
-                    line += ' ';
385
-                    line += cand.getAttribute('rel-addr');
386
-                    line += ' ';
387
-                    line += 'rport';
388
-                    line += ' ';
389
-                    line += cand.getAttribute('rel-port');
390
-                    line += ' ';
391
-                }
392
-                break;
393
-        }
394
-        if (cand.getAttribute('protocol').toLowerCase() == 'tcp') {
395
-            line += 'tcptype';
396
-            line += ' ';
397
-            line += cand.getAttribute('tcptype');
398
-            line += ' ';
399
-        }
400
-        line += 'generation';
401
-        line += ' ';
402
-        line += cand.getAttribute('generation') || '0';
403
-        return line + '\r\n';
404
-    }
405
-};
406
-

+ 320
- 20
libs/strophe/strophe.jingle.session.js Ver fichero

@@ -1,11 +1,9 @@
1 1
 /* jshint -W117 */
2 2
 // Jingle stuff
3
-JingleSession.prototype = Object.create(SessionBase.prototype);
4 3
 function JingleSession(me, sid, connection) {
5
-
6
-    SessionBase.call(this, connection, sid);
7
-
8 4
     this.me = me;
5
+    this.sid = sid;
6
+    this.connection = connection;
9 7
     this.initiator = null;
10 8
     this.responder = null;
11 9
     this.isInitiator = null;
@@ -37,6 +35,13 @@ function JingleSession(me, sid, connection) {
37 35
 
38 36
     this.wait = true;
39 37
     this.localStreamsSSRC = null;
38
+
39
+    /**
40
+     * The indicator which determines whether the (local) video has been muted
41
+     * in response to a user command in contrast to an automatic decision made
42
+     * by the application logic.
43
+     */
44
+    this.videoMuteByUser = false;
40 45
 }
41 46
 
42 47
 JingleSession.prototype.initiate = function (peerjid, isInitiator) {
@@ -163,22 +168,6 @@ JingleSession.prototype.accept = function () {
163 168
     );
164 169
 };
165 170
 
166
-/**
167
- * Implements SessionBase.sendSSRCUpdate.
168
- */
169
-JingleSession.prototype.sendSSRCUpdate = function(sdpMediaSsrcs, fromJid, isadd) {
170
-
171
-    var self = this;
172
-    console.log('tell', self.peerjid, 'about ' + (isadd ? 'new' : 'removed') + ' ssrcs from' + self.me);
173
-
174
-    if (!(this.peerconnection.signalingState == 'stable' && this.peerconnection.iceConnectionState == 'connected')){
175
-        console.log("Too early to send updates");
176
-        return;
177
-    }
178
-
179
-    this.sendSSRCUpdateIq(sdpMediaSsrcs, self.sid, self.initiator, self.peerjid, isadd);
180
-};
181
-
182 171
 JingleSession.prototype.terminate = function (reason) {
183 172
     this.state = 'ended';
184 173
     this.reason = reason;
@@ -675,6 +664,317 @@ JingleSession.prototype.sendTerminate = function (reason, text) {
675 664
     }
676 665
 };
677 666
 
667
+JingleSession.prototype.addSource = function (elem, fromJid) {
668
+
669
+    var self = this;
670
+    // FIXME: dirty waiting
671
+    if (!this.peerconnection.localDescription)
672
+    {
673
+        console.warn("addSource - localDescription not ready yet")
674
+        setTimeout(function()
675
+            {
676
+                self.addSource(elem, fromJid);
677
+            },
678
+            200
679
+        );
680
+        return;
681
+    }
682
+
683
+    this.peerconnection.addSource(elem);
684
+
685
+    this.modifySources();
686
+};
687
+
688
+JingleSession.prototype.removeSource = function (elem, fromJid) {
689
+
690
+    var self = this;
691
+    // FIXME: dirty waiting
692
+    if (!this.peerconnection.localDescription)
693
+    {
694
+        console.warn("removeSource - localDescription not ready yet")
695
+        setTimeout(function()
696
+            {
697
+                self.removeSource(elem, fromJid);
698
+            },
699
+            200
700
+        );
701
+        return;
702
+    }
703
+
704
+    this.peerconnection.removeSource(elem);
705
+
706
+    this.modifySources();
707
+};
708
+
709
+JingleSession.prototype.modifySources = function (successCallback) {
710
+    var self = this;
711
+    if(this.peerconnection)
712
+        this.peerconnection.modifySources(function(){
713
+            $(document).trigger('setLocalDescription.jingle', [self.sid]);
714
+            if(successCallback) {
715
+                successCallback();
716
+            }
717
+        });
718
+};
719
+
720
+/**
721
+ * Switches video streams.
722
+ * @param new_stream new stream that will be used as video of this session.
723
+ * @param oldStream old video stream of this session.
724
+ * @param success_callback callback executed after successful stream switch.
725
+ */
726
+JingleSession.prototype.switchStreams = function (new_stream, oldStream, success_callback) {
727
+
728
+    var self = this;
729
+
730
+    // Stop the stream to trigger onended event for old stream
731
+    oldStream.stop();
732
+
733
+    // Remember SDP to figure out added/removed SSRCs
734
+    var oldSdp = null;
735
+    if(self.peerconnection) {
736
+        if(self.peerconnection.localDescription) {
737
+            oldSdp = new SDP(self.peerconnection.localDescription.sdp);
738
+        }
739
+        self.peerconnection.removeStream(oldStream, true);
740
+        self.peerconnection.addStream(new_stream);
741
+    }
742
+
743
+    self.connection.jingle.localVideo = new_stream;
744
+
745
+    self.connection.jingle.localStreams = [];
746
+
747
+    //in firefox we have only one stream object
748
+    if(self.connection.jingle.localAudio != self.connection.jingle.localVideo)
749
+        self.connection.jingle.localStreams.push(self.connection.jingle.localAudio);
750
+    self.connection.jingle.localStreams.push(self.connection.jingle.localVideo);
751
+
752
+    // Conference is not active
753
+    if(!oldSdp || !self.peerconnection) {
754
+        success_callback();
755
+        return;
756
+    }
757
+
758
+    self.peerconnection.switchstreams = true;
759
+    self.modifySources(function() {
760
+        console.log('modify sources done');
761
+
762
+        success_callback();
763
+
764
+        var newSdp = new SDP(self.peerconnection.localDescription.sdp);
765
+        console.log("SDPs", oldSdp, newSdp);
766
+        self.notifyMySSRCUpdate(oldSdp, newSdp);
767
+    });
768
+};
769
+
770
+/**
771
+ * Figures out added/removed ssrcs and send update IQs.
772
+ * @param old_sdp SDP object for old description.
773
+ * @param new_sdp SDP object for new description.
774
+ */
775
+JingleSession.prototype.notifyMySSRCUpdate = function (old_sdp, new_sdp) {
776
+
777
+    var old_media = old_sdp.getMediaSsrcMap();
778
+    var new_media = new_sdp.getMediaSsrcMap();
779
+    //console.log("old/new medias: ", old_media, new_media);
780
+
781
+    var toAdd = old_sdp.getNewMedia(new_sdp);
782
+    var toRemove = new_sdp.getNewMedia(old_sdp);
783
+    //console.log("to add", toAdd);
784
+    //console.log("to remove", toRemove);
785
+    if(Object.keys(toRemove).length > 0){
786
+        this.sendSSRCUpdate(toRemove, null, false);
787
+    }
788
+    if(Object.keys(toAdd).length > 0){
789
+        this.sendSSRCUpdate(toAdd, null, true);
790
+    }
791
+};
792
+
793
+/**
794
+ * Empty method that does nothing by default. It should send SSRC update IQs to session participants.
795
+ * @param sdpMediaSsrcs array of
796
+ * @param fromJid
797
+ * @param isAdd
798
+ */
799
+JingleSession.prototype.sendSSRCUpdate = function(sdpMediaSsrcs, fromJid, isAdd) {
800
+    var self = this;
801
+    console.log('tell', self.peerjid, 'about ' + (isadd ? 'new' : 'removed') + ' ssrcs from' + self.me);
802
+
803
+    if (!(this.peerconnection.signalingState == 'stable' && this.peerconnection.iceConnectionState == 'connected')){
804
+        console.log("Too early to send updates");
805
+        return;
806
+    }
807
+
808
+    this.sendSSRCUpdateIq(sdpMediaSsrcs, self.sid, self.initiator, self.peerjid, isadd);
809
+}
810
+
811
+/**
812
+ * Sends SSRC update IQ.
813
+ * @param sdpMediaSsrcs SSRCs map obtained from SDP.getNewMedia. Cntains SSRCs to add/remove.
814
+ * @param sid session identifier that will be put into the IQ.
815
+ * @param initiator initiator identifier.
816
+ * @param toJid destination Jid
817
+ * @param isAdd indicates if this is remove or add operation.
818
+ */
819
+JingleSession.prototype.sendSSRCUpdateIq = function(sdpMediaSsrcs, sid, initiator, toJid, isAdd) {
820
+
821
+    var self = this;
822
+    var modify = $iq({to: toJid, type: 'set'})
823
+        .c('jingle', {
824
+            xmlns: 'urn:xmpp:jingle:1',
825
+            action: isAdd ? 'source-add' : 'source-remove',
826
+            initiator: initiator,
827
+            sid: sid
828
+        }
829
+    );
830
+    // FIXME: only announce video ssrcs since we mix audio and dont need
831
+    //      the audio ssrcs therefore
832
+    var modified = false;
833
+    Object.keys(sdpMediaSsrcs).forEach(function(channelNum){
834
+        modified = true;
835
+        var channel = sdpMediaSsrcs[channelNum];
836
+        modify.c('content', {name: channel.mediaType});
837
+
838
+        modify.c('description', {xmlns:'urn:xmpp:jingle:apps:rtp:1', media: channel.mediaType});
839
+        // FIXME: not completly sure this operates on blocks and / or handles different ssrcs correctly
840
+        // generate sources from lines
841
+        Object.keys(channel.ssrcs).forEach(function(ssrcNum) {
842
+            var mediaSsrc = channel.ssrcs[ssrcNum];
843
+            modify.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
844
+            modify.attrs({ssrc: mediaSsrc.ssrc});
845
+            // iterate over ssrc lines
846
+            mediaSsrc.lines.forEach(function (line) {
847
+                var idx = line.indexOf(' ');
848
+                var kv = line.substr(idx + 1);
849
+                modify.c('parameter');
850
+                if (kv.indexOf(':') == -1) {
851
+                    modify.attrs({ name: kv });
852
+                } else {
853
+                    modify.attrs({ name: kv.split(':', 2)[0] });
854
+                    modify.attrs({ value: kv.split(':', 2)[1] });
855
+                }
856
+                modify.up(); // end of parameter
857
+            });
858
+            modify.up(); // end of source
859
+        });
860
+
861
+        // generate source groups from lines
862
+        channel.ssrcGroups.forEach(function(ssrcGroup) {
863
+            if (ssrcGroup.ssrcs.length != 0) {
864
+
865
+                modify.c('ssrc-group', {
866
+                    semantics: ssrcGroup.semantics,
867
+                    xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'
868
+                });
869
+
870
+                ssrcGroup.ssrcs.forEach(function (ssrc) {
871
+                    modify.c('source', { ssrc: ssrc })
872
+                        .up(); // end of source
873
+                });
874
+                modify.up(); // end of ssrc-group
875
+            }
876
+        });
877
+
878
+        modify.up(); // end of description
879
+        modify.up(); // end of content
880
+    });
881
+    if (modified) {
882
+        self.connection.sendIQ(modify,
883
+            function (res) {
884
+                console.info('got modify result', res);
885
+            },
886
+            function (err) {
887
+                console.error('got modify error', err);
888
+            }
889
+        );
890
+    } else {
891
+        console.log('modification not necessary');
892
+    }
893
+};
894
+
895
+/**
896
+ * Determines whether the (local) video is mute i.e. all video tracks are
897
+ * disabled.
898
+ *
899
+ * @return <tt>true</tt> if the (local) video is mute i.e. all video tracks are
900
+ * disabled; otherwise, <tt>false</tt>
901
+ */
902
+JingleSession.prototype.isVideoMute = function () {
903
+    var tracks = connection.jingle.localVideo.getVideoTracks();
904
+    var mute = true;
905
+
906
+    for (var i = 0; i < tracks.length; ++i) {
907
+        if (tracks[i].enabled) {
908
+            mute = false;
909
+            break;
910
+        }
911
+    }
912
+    return mute;
913
+};
914
+
915
+/**
916
+ * Mutes/unmutes the (local) video i.e. enables/disables all video tracks.
917
+ *
918
+ * @param mute <tt>true</tt> to mute the (local) video i.e. to disable all video
919
+ * tracks; otherwise, <tt>false</tt>
920
+ * @param callback a function to be invoked with <tt>mute</tt> after all video
921
+ * tracks have been enabled/disabled. The function may, optionally, return
922
+ * another function which is to be invoked after the whole mute/unmute operation
923
+ * has completed successfully.
924
+ * @param options an object which specifies optional arguments such as the
925
+ * <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
926
+ * specifies whether the method was initiated in response to a user command (in
927
+ * contrast to an automatic decision made by the application logic)
928
+ */
929
+JingleSession.prototype.setVideoMute = function (mute, callback, options) {
930
+    var byUser;
931
+
932
+    if (options) {
933
+        byUser = options.byUser;
934
+        if (typeof byUser === 'undefined') {
935
+            byUser = true;
936
+        }
937
+    } else {
938
+        byUser = true;
939
+    }
940
+    // The user's command to mute the (local) video takes precedence over any
941
+    // automatic decision made by the application logic.
942
+    if (byUser) {
943
+        this.videoMuteByUser = mute;
944
+    } else if (this.videoMuteByUser) {
945
+        return;
946
+    }
947
+    if (mute == this.isVideoMute())
948
+    {
949
+        // Even if no change occurs, the specified callback is to be executed.
950
+        // The specified callback may, optionally, return a successCallback
951
+        // which is to be executed as well.
952
+        var successCallback = callback(mute);
953
+
954
+        if (successCallback) {
955
+            successCallback();
956
+        }
957
+    } else {
958
+        var tracks = connection.jingle.localVideo.getVideoTracks();
959
+
960
+        for (var i = 0; i < tracks.length; ++i) {
961
+            tracks[i].enabled = !mute;
962
+        }
963
+
964
+        if (this.peerconnection) {
965
+            this.peerconnection.hardMuteVideo(mute);
966
+        }
967
+
968
+        this.modifySources(callback(mute));
969
+    }
970
+};
971
+
972
+// SDP-based mute by going recvonly/sendrecv
973
+// FIXME: should probably black out the screen as well
974
+JingleSession.prototype.toggleVideoMute = function (callback) {
975
+    setVideoMute(isVideoMute(), callback);
976
+};
977
+
678 978
 JingleSession.prototype.sendMute = function (muted, content) {
679 979
     var info = $iq({to: this.peerjid,
680 980
         type: 'set'})

+ 0
- 321
libs/strophe/strophe.jingle.sessionbase.js Ver fichero

@@ -1,321 +0,0 @@
1
-/**
2
- * Base class for ColibriFocus and JingleSession.
3
- * @param connection Strophe connection object
4
- * @param sid my session identifier(resource)
5
- * @constructor
6
- */
7
-function SessionBase(connection, sid) {
8
-    this.connection = connection;
9
-    this.sid = sid;
10
-
11
-    /**
12
-     * The indicator which determines whether the (local) video has been muted
13
-     * in response to a user command in contrast to an automatic decision made
14
-     * by the application logic.
15
-     */
16
-    this.videoMuteByUser = false;
17
-}
18
-
19
-
20
-SessionBase.prototype.modifySources = function (successCallback) {
21
-    var self = this;
22
-    if(this.peerconnection)
23
-        this.peerconnection.modifySources(function(){
24
-            $(document).trigger('setLocalDescription.jingle', [self.sid]);
25
-            if(successCallback) {
26
-                successCallback();
27
-            }
28
-        });
29
-};
30
-
31
-SessionBase.prototype.addSource = function (elem, fromJid) {
32
-
33
-    var self = this;
34
-    // FIXME: dirty waiting
35
-    if (!this.peerconnection.localDescription)
36
-    {
37
-        console.warn("addSource - localDescription not ready yet")
38
-        setTimeout(function()
39
-            {
40
-                self.addSource(elem, fromJid);
41
-            },
42
-            200
43
-        );
44
-        return;
45
-    }
46
-
47
-    this.peerconnection.addSource(elem);
48
-
49
-    this.modifySources();
50
-};
51
-
52
-SessionBase.prototype.removeSource = function (elem, fromJid) {
53
-
54
-    var self = this;
55
-    // FIXME: dirty waiting
56
-    if (!this.peerconnection.localDescription)
57
-    {
58
-        console.warn("removeSource - localDescription not ready yet")
59
-        setTimeout(function()
60
-            {
61
-                self.removeSource(elem, fromJid);
62
-            },
63
-            200
64
-        );
65
-        return;
66
-    }
67
-
68
-    this.peerconnection.removeSource(elem);
69
-
70
-    this.modifySources();
71
-};
72
-
73
-/**
74
- * Switches video streams.
75
- * @param new_stream new stream that will be used as video of this session.
76
- * @param oldStream old video stream of this session.
77
- * @param success_callback callback executed after successful stream switch.
78
- */
79
-SessionBase.prototype.switchStreams = function (new_stream, oldStream, success_callback) {
80
-
81
-    var self = this;
82
-
83
-    // Stop the stream to trigger onended event for old stream
84
-    oldStream.stop();
85
-
86
-    // Remember SDP to figure out added/removed SSRCs
87
-    var oldSdp = null;
88
-    if(self.peerconnection) {
89
-        if(self.peerconnection.localDescription) {
90
-            oldSdp = new SDP(self.peerconnection.localDescription.sdp);
91
-        }
92
-        self.peerconnection.removeStream(oldStream, true);
93
-        self.peerconnection.addStream(new_stream);
94
-    }
95
-
96
-    self.connection.jingle.localVideo = new_stream;
97
-
98
-    self.connection.jingle.localStreams = [];
99
-
100
-    //in firefox we have only one stream object
101
-    if(self.connection.jingle.localAudio != self.connection.jingle.localVideo)
102
-        self.connection.jingle.localStreams.push(self.connection.jingle.localAudio);
103
-    self.connection.jingle.localStreams.push(self.connection.jingle.localVideo);
104
-
105
-    // Conference is not active
106
-    if(!oldSdp || !self.peerconnection) {
107
-        success_callback();
108
-        return;
109
-    }
110
-
111
-    self.peerconnection.switchstreams = true;
112
-    self.modifySources(function() {
113
-        console.log('modify sources done');
114
-
115
-        success_callback();
116
-
117
-        var newSdp = new SDP(self.peerconnection.localDescription.sdp);
118
-        console.log("SDPs", oldSdp, newSdp);
119
-        self.notifyMySSRCUpdate(oldSdp, newSdp);
120
-    });
121
-};
122
-
123
-/**
124
- * Figures out added/removed ssrcs and send update IQs.
125
- * @param old_sdp SDP object for old description.
126
- * @param new_sdp SDP object for new description.
127
- */
128
-SessionBase.prototype.notifyMySSRCUpdate = function (old_sdp, new_sdp) {
129
-
130
-    var old_media = old_sdp.getMediaSsrcMap();
131
-    var new_media = new_sdp.getMediaSsrcMap();
132
-    //console.log("old/new medias: ", old_media, new_media);
133
-
134
-    var toAdd = old_sdp.getNewMedia(new_sdp);
135
-    var toRemove = new_sdp.getNewMedia(old_sdp);
136
-    //console.log("to add", toAdd);
137
-    //console.log("to remove", toRemove);
138
-    if(Object.keys(toRemove).length > 0){
139
-        this.sendSSRCUpdate(toRemove, null, false);
140
-    }
141
-    if(Object.keys(toAdd).length > 0){
142
-        this.sendSSRCUpdate(toAdd, null, true);
143
-    }
144
-};
145
-
146
-/**
147
- * Empty method that does nothing by default. It should send SSRC update IQs to session participants.
148
- * @param sdpMediaSsrcs array of
149
- * @param fromJid
150
- * @param isAdd
151
- */
152
-SessionBase.prototype.sendSSRCUpdate = function(sdpMediaSsrcs, fromJid, isAdd) {
153
-    //FIXME: put default implementation here(maybe from JingleSession?)
154
-}
155
-
156
-/**
157
- * Sends SSRC update IQ.
158
- * @param sdpMediaSsrcs SSRCs map obtained from SDP.getNewMedia. Cntains SSRCs to add/remove.
159
- * @param sid session identifier that will be put into the IQ.
160
- * @param initiator initiator identifier.
161
- * @param toJid destination Jid
162
- * @param isAdd indicates if this is remove or add operation.
163
- */
164
-SessionBase.prototype.sendSSRCUpdateIq = function(sdpMediaSsrcs, sid, initiator, toJid, isAdd) {
165
-
166
-    var self = this;
167
-    var modify = $iq({to: toJid, type: 'set'})
168
-        .c('jingle', {
169
-            xmlns: 'urn:xmpp:jingle:1',
170
-            action: isAdd ? 'source-add' : 'source-remove',
171
-            initiator: initiator,
172
-            sid: sid
173
-        }
174
-    );
175
-    // FIXME: only announce video ssrcs since we mix audio and dont need
176
-    //      the audio ssrcs therefore
177
-    var modified = false;
178
-    Object.keys(sdpMediaSsrcs).forEach(function(channelNum){
179
-        modified = true;
180
-        var channel = sdpMediaSsrcs[channelNum];
181
-        modify.c('content', {name: channel.mediaType});
182
-
183
-        modify.c('description', {xmlns:'urn:xmpp:jingle:apps:rtp:1', media: channel.mediaType});
184
-        // FIXME: not completly sure this operates on blocks and / or handles different ssrcs correctly
185
-        // generate sources from lines
186
-        Object.keys(channel.ssrcs).forEach(function(ssrcNum) {
187
-            var mediaSsrc = channel.ssrcs[ssrcNum];
188
-            modify.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
189
-            modify.attrs({ssrc: mediaSsrc.ssrc});
190
-            // iterate over ssrc lines
191
-            mediaSsrc.lines.forEach(function (line) {
192
-                var idx = line.indexOf(' ');
193
-                var kv = line.substr(idx + 1);
194
-                modify.c('parameter');
195
-                if (kv.indexOf(':') == -1) {
196
-                    modify.attrs({ name: kv });
197
-                } else {
198
-                    modify.attrs({ name: kv.split(':', 2)[0] });
199
-                    modify.attrs({ value: kv.split(':', 2)[1] });
200
-                }
201
-                modify.up(); // end of parameter
202
-            });
203
-            modify.up(); // end of source
204
-        });
205
-
206
-        // generate source groups from lines
207
-        channel.ssrcGroups.forEach(function(ssrcGroup) {
208
-            if (ssrcGroup.ssrcs.length != 0) {
209
-
210
-                modify.c('ssrc-group', {
211
-                    semantics: ssrcGroup.semantics,
212
-                    xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'
213
-                });
214
-
215
-                ssrcGroup.ssrcs.forEach(function (ssrc) {
216
-                    modify.c('source', { ssrc: ssrc })
217
-                        .up(); // end of source
218
-                });
219
-                modify.up(); // end of ssrc-group
220
-            }
221
-        });
222
-
223
-        modify.up(); // end of description
224
-        modify.up(); // end of content
225
-    });
226
-    if (modified) {
227
-        self.connection.sendIQ(modify,
228
-            function (res) {
229
-                console.info('got modify result', res);
230
-            },
231
-            function (err) {
232
-                console.error('got modify error', err);
233
-            }
234
-        );
235
-    } else {
236
-        console.log('modification not necessary');
237
-    }
238
-};
239
-
240
-/**
241
- * Determines whether the (local) video is mute i.e. all video tracks are
242
- * disabled.
243
- *
244
- * @return <tt>true</tt> if the (local) video is mute i.e. all video tracks are
245
- * disabled; otherwise, <tt>false</tt>
246
- */
247
-SessionBase.prototype.isVideoMute = function () {
248
-    var tracks = connection.jingle.localVideo.getVideoTracks();
249
-    var mute = true;
250
-
251
-    for (var i = 0; i < tracks.length; ++i) {
252
-        if (tracks[i].enabled) {
253
-            mute = false;
254
-            break;
255
-        }
256
-    }
257
-    return mute;
258
-};
259
-
260
-/**
261
- * Mutes/unmutes the (local) video i.e. enables/disables all video tracks.
262
- *
263
- * @param mute <tt>true</tt> to mute the (local) video i.e. to disable all video
264
- * tracks; otherwise, <tt>false</tt>
265
- * @param callback a function to be invoked with <tt>mute</tt> after all video
266
- * tracks have been enabled/disabled. The function may, optionally, return
267
- * another function which is to be invoked after the whole mute/unmute operation
268
- * has completed successfully.
269
- * @param options an object which specifies optional arguments such as the
270
- * <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
271
- * specifies whether the method was initiated in response to a user command (in
272
- * contrast to an automatic decision made by the application logic)
273
- */
274
-SessionBase.prototype.setVideoMute = function (mute, callback, options) {
275
-    var byUser;
276
-
277
-    if (options) {
278
-        byUser = options.byUser;
279
-        if (typeof byUser === 'undefined') {
280
-            byUser = true;
281
-        } 
282
-    } else {
283
-        byUser = true;
284
-    }
285
-    // The user's command to mute the (local) video takes precedence over any
286
-    // automatic decision made by the application logic.
287
-    if (byUser) {
288
-        this.videoMuteByUser = mute;
289
-    } else if (this.videoMuteByUser) {
290
-        return;
291
-    }
292
-    if (mute == this.isVideoMute())
293
-    {
294
-        // Even if no change occurs, the specified callback is to be executed.
295
-        // The specified callback may, optionally, return a successCallback
296
-        // which is to be executed as well.
297
-        var successCallback = callback(mute);
298
-
299
-        if (successCallback) {
300
-            successCallback();
301
-        }
302
-    } else {
303
-        var tracks = connection.jingle.localVideo.getVideoTracks();
304
-
305
-        for (var i = 0; i < tracks.length; ++i) {
306
-            tracks[i].enabled = !mute;
307
-        }
308
-
309
-        if (this.peerconnection) {
310
-            this.peerconnection.hardMuteVideo(mute);
311
-        }
312
-
313
-        this.modifySources(callback(mute));
314
-    }
315
-};
316
-
317
-// SDP-based mute by going recvonly/sendrecv
318
-// FIXME: should probably black out the screen as well
319
-SessionBase.prototype.toggleVideoMute = function (callback) {
320
-    setVideoMute(isVideoMute(), callback);
321
-};

Loading…
Cancelar
Guardar