浏览代码

support DTMF

release-8443
isymchych 10 年前
父节点
当前提交
8329fe5767

+ 10
- 0
.editorconfig 查看文件

@@ -0,0 +1,10 @@
1
+# http://editorconfig.org
2
+root = true
3
+
4
+[*]
5
+charset = utf-8
6
+end_of_line = lf
7
+indent_size = 4
8
+indent_style = space
9
+max_line_length = 80
10
+trim_trailing_whitespace = true

+ 197
- 83
JitsiConference.js 查看文件

@@ -1,4 +1,5 @@
1
-
1
+/* global Strophe, $ */
2
+/* jshint -W101 */
2 3
 var logger = require("jitsi-meet-logger").getLogger(__filename);
3 4
 var RTC = require("./modules/RTC/RTC");
4 5
 var XMPPEvents = require("./service/xmpp/XMPPEvents");
@@ -7,6 +8,7 @@ var EventEmitter = require("events");
7 8
 var JitsiConferenceEvents = require("./JitsiConferenceEvents");
8 9
 var JitsiParticipant = require("./JitsiParticipant");
9 10
 var Statistics = require("./modules/statistics/statistics");
11
+var JitsiDTMFManager = require('./modules/DTMF/JitsiDTMFManager');
10 12
 var JitsiTrackEvents = require("./JitsiTrackEvents");
11 13
 
12 14
 /**
@@ -18,7 +20,6 @@ var JitsiTrackEvents = require("./JitsiTrackEvents");
18 20
  * @param options.connection the JitsiConnection object for this JitsiConference.
19 21
  * @constructor
20 22
  */
21
-
22 23
 function JitsiConference(options) {
23 24
     if(!options.name || options.name.toLowerCase() !== options.name) {
24 25
         logger.error("Invalid conference name (no conference name passed or it"
@@ -37,6 +38,8 @@ function JitsiConference(options) {
37 38
     setupListeners(this);
38 39
     this.participants = {};
39 40
     this.lastActiveSpeaker = null;
41
+    this.dtmfManager = null;
42
+    this.somebodySupportsDTMF = false;
40 43
 }
41 44
 
42 45
 /**
@@ -46,7 +49,7 @@ function JitsiConference(options) {
46 49
 JitsiConference.prototype.join = function (password) {
47 50
     if(this.room)
48 51
         this.room.join(password, this.connection.tokenPassword);
49
-}
52
+};
50 53
 
51 54
 /**
52 55
  * Leaves the conference.
@@ -55,14 +58,17 @@ JitsiConference.prototype.leave = function () {
55 58
     if(this.xmpp)
56 59
         this.xmpp.leaveRoom(this.room.roomjid);
57 60
     this.room = null;
58
-}
61
+};
59 62
 
60 63
 /**
61 64
  * Returns the local tracks.
62 65
  */
63 66
 JitsiConference.prototype.getLocalTracks = function () {
64
-    if(this.rtc)
67
+    if (this.rtc) {
65 68
         return this.rtc.localStreams;
69
+    } else {
70
+        return [];
71
+    }
66 72
 };
67 73
 
68 74
 
@@ -77,7 +83,7 @@ JitsiConference.prototype.getLocalTracks = function () {
77 83
 JitsiConference.prototype.on = function (eventId, handler) {
78 84
     if(this.eventEmitter)
79 85
         this.eventEmitter.on(eventId, handler);
80
-}
86
+};
81 87
 
82 88
 /**
83 89
  * Removes event listener
@@ -89,7 +95,7 @@ JitsiConference.prototype.on = function (eventId, handler) {
89 95
 JitsiConference.prototype.off = function (eventId, handler) {
90 96
     if(this.eventEmitter)
91 97
         this.eventEmitter.removeListener(eventId, handler);
92
-}
98
+};
93 99
 
94 100
 // Common aliases for event emitter
95 101
 JitsiConference.prototype.addEventListener = JitsiConference.prototype.on;
@@ -104,7 +110,7 @@ JitsiConference.prototype.removeEventListener = JitsiConference.prototype.off;
104 110
  JitsiConference.prototype.addCommandListener = function (command, handler) {
105 111
     if(this.room)
106 112
         this.room.addPresenceListener(command, handler);
107
- }
113
+ };
108 114
 
109 115
 /**
110 116
   * Removes command  listener
@@ -113,7 +119,7 @@ JitsiConference.prototype.removeEventListener = JitsiConference.prototype.off;
113 119
  JitsiConference.prototype.removeCommandListener = function (command) {
114 120
     if(this.room)
115 121
         this.room.removePresenceListener(command);
116
- }
122
+ };
117 123
 
118 124
 /**
119 125
  * Sends text message to the other participants in the conference
@@ -122,7 +128,7 @@ JitsiConference.prototype.removeEventListener = JitsiConference.prototype.off;
122 128
 JitsiConference.prototype.sendTextMessage = function (message) {
123 129
     if(this.room)
124 130
         this.room.sendMessage(message);
125
-}
131
+};
126 132
 
127 133
 /**
128 134
  * Send presence command.
@@ -134,7 +140,7 @@ JitsiConference.prototype.sendCommand = function (name, values) {
134 140
         this.room.addToPresence(name, values);
135 141
         this.room.sendPresence();
136 142
     }
137
-}
143
+};
138 144
 
139 145
 /**
140 146
  * Send presence command one time.
@@ -144,7 +150,7 @@ JitsiConference.prototype.sendCommand = function (name, values) {
144 150
 JitsiConference.prototype.sendCommandOnce = function (name, values) {
145 151
     this.sendCommand(name, values);
146 152
     this.removeCommand(name);
147
-}
153
+};
148 154
 
149 155
 /**
150 156
  * Send presence command.
@@ -155,7 +161,7 @@ JitsiConference.prototype.sendCommandOnce = function (name, values) {
155 161
 JitsiConference.prototype.removeCommand = function (name) {
156 162
     if(this.room)
157 163
         this.room.removeFromPresence(name);
158
-}
164
+};
159 165
 
160 166
 /**
161 167
  * Sets the display name for this conference.
@@ -166,7 +172,7 @@ JitsiConference.prototype.setDisplayName = function(name) {
166 172
         this.room.addToPresence("nick", {attributes: {xmlns: 'http://jabber.org/protocol/nick'}, value: name});
167 173
         this.room.sendPresence();
168 174
     }
169
-}
175
+};
170 176
 
171 177
 /**
172 178
  * Adds JitsiLocalTrack object to the conference.
@@ -180,20 +186,18 @@ JitsiConference.prototype.addTrack = function (track) {
180 186
         var audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);
181 187
         track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, muteHandler);
182 188
         track.addEventListener(JitsiTrackEvents.TRACK_STOPPED, stopHandler);
183
-        track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
184
-            audioLevelHandler);
185
-        this.addEventListener(JitsiConferenceEvents.TRACK_REMOVED, function (track) {
186
-            track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED,
187
-                muteHandler);
188
-            track.removeEventListener(JitsiTrackEvents.TRACK_STOPPED,
189
-                stopHandler);
190
-            track.removeEventListener(
191
-                JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevelHandler);
192
-        })
189
+        track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevelHandler);
190
+        this.addEventListener(JitsiConferenceEvents.TRACK_REMOVED, function (someTrack) {
191
+            if (someTrack !== track) {
192
+                return;
193
+            }
194
+            track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, muteHandler);
195
+            track.removeEventListener(JitsiTrackEvents.TRACK_STOPPED, stopHandler);
196
+            track.removeEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevelHandler);
197
+        });
193 198
         this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
194 199
     }.bind(this));
195
-
196
-}
200
+};
197 201
 
198 202
 /**
199 203
  * Fires TRACK_AUDIO_LEVEL_CHANGED change conference event.
@@ -203,7 +207,7 @@ JitsiConference.prototype._fireAudioLevelChangeEvent = function (audioLevel) {
203 207
     this.eventEmitter.emit(
204 208
         JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,
205 209
         this.myUserId(), audioLevel);
206
-}
210
+};
207 211
 
208 212
 /**
209 213
  * Fires TRACK_MUTE_CHANGED change conference event.
@@ -222,7 +226,23 @@ JitsiConference.prototype.removeTrack = function (track) {
222 226
         this.rtc.removeLocalStream(track);
223 227
         this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
224 228
     }.bind(this));
225
-}
229
+};
230
+
231
+/**
232
+ * Get role of the local user.
233
+ * @returns {string} user role: 'moderator' or 'none'
234
+ */
235
+JitsiConference.prototype.getRole = function () {
236
+    return this.room.role;
237
+};
238
+
239
+/**
240
+ * Check if local user is moderator.
241
+ * @returns {boolean} true if local user is moderator, false otherwise.
242
+ */
243
+JitsiConference.prototype.isModerator = function () {
244
+    return this.room.isModerator();
245
+};
226 246
 
227 247
 /**
228 248
  * Elects the participant with the given id to be the selected participant or the speaker.
@@ -232,41 +252,138 @@ JitsiConference.prototype.selectParticipant = function(participantId) {
232 252
     if (this.rtc) {
233 253
         this.rtc.selectedEndpoint(participantId);
234 254
     }
235
-}
255
+};
236 256
 
237 257
 /**
238 258
  *
239 259
  * @param id the identifier of the participant
240 260
  */
241 261
 JitsiConference.prototype.pinParticipant = function(participantId) {
242
-    if(this.rtc)
262
+    if (this.rtc) {
243 263
         this.rtc.pinEndpoint(participantId);
244
-}
264
+    }
265
+};
245 266
 
246 267
 /**
247 268
  * Returns the list of participants for this conference.
248
- * @return Object a list of participant identifiers containing all conference participants.
269
+ * @return Array<JitsiParticipant> a list of participant identifiers containing all conference participants.
249 270
  */
250 271
 JitsiConference.prototype.getParticipants = function() {
251
-    return this.participants;
252
-}
272
+    return Object.keys(this.participants).map(function (key) {
273
+        return this.participants[key];
274
+    }, this);
275
+};
253 276
 
254 277
 /**
255 278
  * @returns {JitsiParticipant} the participant in this conference with the specified id (or
256
- * null if there isn't one).
279
+ * undefined if there isn't one).
257 280
  * @param id the id of the participant.
258 281
  */
259 282
 JitsiConference.prototype.getParticipantById = function(id) {
260
-    if(this.participants)
261
-        return this.participants[id];
262
-    return null;
263
-}
283
+    return this.participants[id];
284
+};
264 285
 
265 286
 JitsiConference.prototype.onMemberJoined = function (jid, email, nick) {
266
-    if(this.eventEmitter)
267
-        this.eventEmitter.emit(JitsiConferenceEvents.USER_JOINED, Strophe.getResourceFromJid(jid));
268
-//    this.participants[jid] = new JitsiParticipant();
269
-}
287
+    var id = Strophe.getResourceFromJid(jid);
288
+    var participant = new JitsiParticipant(id, this, nick);
289
+    this.eventEmitter.emit(JitsiConferenceEvents.USER_JOINED, id);
290
+    this.participants[id] = participant;
291
+    this.connection.xmpp.connection.disco.info(
292
+        jid, "" /* node */, function(iq) {
293
+            participant._supportsDTMF = $(iq).find('>query>feature[var="urn:xmpp:jingle:dtmf:0"]').length > 0;
294
+            this.updateDTMFSupport();
295
+        }.bind(this)
296
+    );
297
+};
298
+
299
+JitsiConference.prototype.onMemberLeft = function (jid) {
300
+    var id = Strophe.getResourceFromJid(jid);
301
+    delete this.participants[id];
302
+    this.eventEmitter.emit(JitsiConferenceEvents.USER_LEFT, id);
303
+};
304
+
305
+JitsiConference.prototype.onUserRoleChanged = function (jid, role) {
306
+    var id = Strophe.getResourceFromJid(jid);
307
+    var participant = this.getParticipantById(id);
308
+    if (!participant) {
309
+        return;
310
+    }
311
+    participant._role = role;
312
+    this.eventEmitter.emit(JitsiConferenceEvents.USER_ROLE_CHANGED, id, role);
313
+};
314
+
315
+JitsiConference.prototype.onDisplayNameChanged = function (jid, displayName) {
316
+    var id = Strophe.getResourceFromJid(jid);
317
+    var participant = this.getParticipantById(id);
318
+    if (!participant) {
319
+        return;
320
+    }
321
+    participant._displayName = displayName;
322
+    this.eventEmitter.emit(JitsiConferenceEvents.DISPLAY_NAME_CHANGED, id, displayName);
323
+};
324
+
325
+JitsiConference.prototype.onTrackAdded = function (track) {
326
+    var id = track.getParticipantId();
327
+    var participant = this.getParticipantById(id);
328
+    if (!participant) {
329
+        return;
330
+    }
331
+    // add track to JitsiParticipant
332
+    participant._tracks.push(track);
333
+
334
+    var emitter = this.eventEmitter;
335
+    track.addEventListener(
336
+        JitsiTrackEvents.TRACK_STOPPED,
337
+        function () {
338
+            // remove track from JitsiParticipant
339
+            var pos = participant._tracks.indexOf(track);
340
+            if (pos > -1) {
341
+                participant._tracks.splice(pos, 1);
342
+            }
343
+            emitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
344
+        }
345
+    );
346
+    track.addEventListener(
347
+        JitsiTrackEvents.TRACK_MUTE_CHANGED,
348
+        function () {
349
+            emitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track);
350
+        }
351
+    );
352
+    track.addEventListener(
353
+        JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
354
+        function (audioLevel) {
355
+            emitter.emit(JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED, id, audioLevel);
356
+        }
357
+    );
358
+
359
+    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
360
+};
361
+
362
+JitsiConference.prototype.updateDTMFSupport = function () {
363
+    var somebodySupportsDTMF = false;
364
+    var participants = this.getParticipants();
365
+
366
+    // check if at least 1 participant supports DTMF
367
+    for (var i = 0; i < participants.length; i += 1) {
368
+        if (participants[i].supportsDTMF()) {
369
+            somebodySupportsDTMF = true;
370
+            break;
371
+        }
372
+    }
373
+    if (somebodySupportsDTMF !== this.somebodySupportsDTMF) {
374
+        this.somebodySupportsDTMF = somebodySupportsDTMF;
375
+        this.eventEmitter.emit(JitsiConferenceEvents.DTMF_SUPPORT_CHANGED, somebodySupportsDTMF);
376
+    }
377
+};
378
+
379
+/**
380
+ * Allows to check if there is at least one user in the conference
381
+ * that supports DTMF.
382
+ * @returns {boolean} true if somebody supports DTMF, false otherwise
383
+ */
384
+JitsiConference.prototype.isDTMFSupported = function () {
385
+    return this.somebodySupportsDTMF;
386
+};
270 387
 
271 388
 /**
272 389
  * Returns the local user's ID
@@ -274,7 +391,28 @@ JitsiConference.prototype.onMemberJoined = function (jid, email, nick) {
274 391
  */
275 392
 JitsiConference.prototype.myUserId = function () {
276 393
     return (this.room && this.room.myroomjid)? Strophe.getResourceFromJid(this.room.myroomjid) : null;
277
-}
394
+};
395
+
396
+JitsiConference.prototype.sendTones = function (tones, duration, pause) {
397
+    if (!this.dtmfManager) {
398
+        var connection = this.connection.xmpp.connection.jingle.activecall.peerconnection;
399
+        if (!connection) {
400
+            logger.warn("cannot sendTones: no conneciton");
401
+            return;
402
+        }
403
+
404
+        var tracks = this.getLocalTracks().filter(function (track) {
405
+            return track.isAudioTrack();
406
+        });
407
+        if (!tracks.length) {
408
+            logger.warn("cannot sendTones: no local audio stream");
409
+            return;
410
+        }
411
+        this.dtmfManager = new JitsiDTMFManager(tracks[0], connection);
412
+    }
413
+
414
+    this.dtmfManager.sendTones(tones, duration, pause);
415
+};
278 416
 
279 417
 /**
280 418
  * Setups the listeners needed for the conference.
@@ -290,27 +428,9 @@ function setupListeners(conference) {
290 428
     conference.room.addListener(XMPPEvents.REMOTE_STREAM_RECEIVED,
291 429
         function (data, sid, thessrc) {
292 430
             var track = conference.rtc.createRemoteStream(data, sid, thessrc);
293
-            if(!track)
294
-                return;
295
-            conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED,
296
-                track);
297
-            track.addEventListener(JitsiTrackEvents.TRACK_STOPPED,
298
-                function () {
299
-                    conference.eventEmitter.emit(
300
-                        JitsiConferenceEvents.TRACK_REMOVED, track);
301
-                });
302
-            track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED,
303
-                function () {
304
-                    conference.eventEmitter.emit(
305
-                        JitsiConferenceEvents.TRACK_MUTE_CHANGED, track);
306
-                });
307
-            var userId = track.getParitcipantId();
308
-            track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
309
-                function (audioLevel) {
310
-                    conference.eventEmitter.emit(
311
-                        JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,
312
-                        userId, audioLevel);
313
-                });
431
+            if (track) {
432
+                conference.onTrackAdded(track);
433
+            }
314 434
         }
315 435
     );
316 436
 
@@ -322,30 +442,24 @@ function setupListeners(conference) {
322 442
 //        conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_LEFT);
323 443
 //    });
324 444
 
325
-    conference.room.addListener(XMPPEvents.MUC_MEMBER_JOINED,
326
-        conference.onMemberJoined.bind(conference));
327
-    conference.room.addListener(XMPPEvents.MUC_MEMBER_LEFT,function (jid) {
328
-        conference.eventEmitter.emit(JitsiConferenceEvents.USER_LEFT,
329
-            Strophe.getResourceFromJid(jid));
330
-    });
445
+    conference.room.addListener(XMPPEvents.MUC_MEMBER_JOINED, conference.onMemberJoined.bind(conference));
446
+    conference.room.addListener(XMPPEvents.MUC_MEMBER_LEFT, conference.onMemberLeft.bind(conference));
331 447
 
332
-    conference.room.addListener(XMPPEvents.DISPLAY_NAME_CHANGED,
333
-        function (from, displayName) {
334
-            conference.eventEmitter.emit(
335
-                JitsiConferenceEvents.DISPLAY_NAME_CHANGED,
336
-                Strophe.getResourceFromJid(from), displayName);
337
-        });
448
+    conference.room.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, conference.onDisplayNameChanged.bind(conference));
338 449
 
339
-    conference.room.addListener(XMPPEvents.CONNECTION_INTERRUPTED,
340
-        function () {
341
-            conference.eventEmitter.emit(
342
-                JitsiConferenceEvents.CONNECTION_INTERRUPTED);
343
-        });
450
+    conference.room.addListener(XMPPEvents.LOCAL_ROLE_CHANGED, function (role) {
451
+        conference.eventEmitter.emit(JitsiConferenceEvents.USER_ROLE_CHANGED, conference.myUserId(), role);
452
+    });
453
+    conference.room.addListener(XMPPEvents.MUC_ROLE_CHANGED, conference.onUserRoleChanged.bind(conference));
454
+
455
+    conference.room.addListener(XMPPEvents.CONNECTION_INTERRUPTED, function () {
456
+        conference.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_INTERRUPTED);
457
+    });
344 458
 
345 459
     conference.room.addListener(XMPPEvents.CONNECTION_RESTORED, function () {
346 460
         conference.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_RESTORED);
347 461
     });
348
-    conference.room.addListener(XMPPEvents.CONFERENCE_SETUP_FAILED, function() {
462
+    conference.room.addListener(XMPPEvents.CONFERENCE_SETUP_FAILED, function () {
349 463
         conference.eventEmitter.emit(JitsiConferenceEvents.SETUP_FAILED);
350 464
     });
351 465
 

+ 2
- 1
JitsiConferenceEvents.js 查看文件

@@ -75,7 +75,8 @@ var JitsiConferenceEvents = {
75 75
     /**
76 76
      * Indicates that conference has been left.
77 77
      */
78
-    CONFERENCE_LEFT: "conference.left"
78
+    CONFERENCE_LEFT: "conference.left",
79
+    DTMF_SUPPORT_CHANGED: "conference.dtmf_support_changed"
79 80
 };
80 81
 
81 82
 module.exports = JitsiConferenceEvents;

+ 23
- 18
JitsiParticipant.js 查看文件

@@ -5,6 +5,7 @@ function JitsiParticipant(id, conference, displayName){
5 5
     this._id = id;
6 6
     this._conference = conference;
7 7
     this._displayName = displayName;
8
+    this._supportsDTMF = false;
8 9
 }
9 10
 
10 11
 /**
@@ -12,34 +13,34 @@ function JitsiParticipant(id, conference, displayName){
12 13
  */
13 14
 JitsiParticipant.prototype.getConference = function() {
14 15
     return this._conference;
15
-}
16
+};
16 17
 
17 18
 /**
18 19
  * @returns {Array.<JitsiTrack>} The list of media tracks for this participant.
19 20
  */
20 21
 JitsiParticipant.prototype.getTracks = function() {
21 22
 
22
-}
23
+};
23 24
 
24 25
 /**
25 26
  * @returns {String} The ID (i.e. JID) of this participant.
26 27
  */
27 28
 JitsiParticipant.prototype.getId = function() {
28 29
     return this._id;
29
-}
30
+};
30 31
 
31 32
 /**
32 33
  * @returns {String} The human-readable display name of this participant.
33 34
  */
34 35
 JitsiParticipant.prototype.getDisplayName = function() {
35 36
     return this._displayName;
36
-}
37
+};
37 38
 
38 39
 /**
39 40
  * @returns {Boolean} Whether this participant is a moderator or not.
40 41
  */
41 42
 JitsiParticipant.prototype.isModerator = function() {
42
-}
43
+};
43 44
 
44 45
 // Gets a link to an etherpad instance advertised by the participant?
45 46
 //JitsiParticipant.prototype.getEtherpad = function() {
@@ -52,14 +53,14 @@ JitsiParticipant.prototype.isModerator = function() {
52 53
  */
53 54
 JitsiParticipant.prototype.isAudioMuted = function() {
54 55
 
55
-}
56
+};
56 57
 
57 58
 /*
58 59
  * @returns {Boolean} Whether this participant has muted their video.
59 60
  */
60 61
 JitsiParticipant.prototype.isVideoMuted = function() {
61 62
 
62
-}
63
+};
63 64
 
64 65
 /*
65 66
  * @returns {???} The latest statistics reported by this participant (i.e. info used to populate the GSM bars)
@@ -67,70 +68,74 @@ JitsiParticipant.prototype.isVideoMuted = function() {
67 68
  */
68 69
 JitsiParticipant.prototype.getLatestStats = function() {
69 70
 
70
-}
71
+};
71 72
 
72 73
 /**
73 74
  * @returns {String} The role of this participant.
74 75
  */
75 76
 JitsiParticipant.prototype.getRole = function() {
76 77
 
77
-}
78
+};
78 79
 
79 80
 /*
80 81
  * @returns {Boolean} Whether this participant is the conference focus (i.e. jicofo).
81 82
  */
82 83
 JitsiParticipant.prototype.isFocus = function() {
83 84
 
84
-}
85
+};
85 86
 
86 87
 /*
87 88
  * @returns {Boolean} Whether this participant is a conference recorder (i.e. jirecon).
88 89
  */
89 90
 JitsiParticipant.prototype.isRecorder = function() {
90 91
 
91
-}
92
+};
92 93
 
93 94
 /*
94 95
  * @returns {Boolean} Whether this participant is a SIP gateway (i.e. jigasi).
95 96
  */
96 97
 JitsiParticipant.prototype.isSipGateway = function() {
97 98
 
98
-}
99
+};
99 100
 
100 101
 /**
101 102
  * @returns {String} The ID for this participant's avatar.
102 103
  */
103 104
 JitsiParticipant.prototype.getAvatarId = function() {
104 105
 
105
-}
106
+};
106 107
 
107 108
 /**
108 109
  * @returns {Boolean} Whether this participant is currently sharing their screen.
109 110
  */
110 111
 JitsiParticipant.prototype.isScreenSharing = function() {
111 112
 
112
-}
113
+};
113 114
 
114 115
 /**
115 116
  * @returns {String} The user agent of this participant (i.e. browser userAgent string).
116 117
  */
117 118
 JitsiParticipant.prototype.getUserAgent = function() {
118 119
 
119
-}
120
+};
120 121
 
121 122
 /**
122 123
  * Kicks the participant from the conference (requires certain privileges).
123 124
  */
124 125
 JitsiParticipant.prototype.kick = function() {
125 126
 
126
-}
127
+};
127 128
 
128 129
 /**
129 130
  * Asks this participant to mute themselves.
130 131
  */
131 132
 JitsiParticipant.prototype.askToMute = function() {
132 133
 
133
-}
134
+};
135
+
136
+JitsiParticipant.prototype.supportsDTMF = function () {
137
+    return this._supportsDTMF;
138
+};
134 139
 
135 140
 
136
-module.exports = JitsiParticipant();
141
+module.exports = JitsiParticipant;

+ 0
- 47
modules/DTMF/DTMF.js 查看文件

@@ -1,47 +0,0 @@
1
-/* global APP */
2
-
3
-/**
4
- * A module for sending DTMF tones.
5
- */
6
-var DTMFSender;
7
-var initDtmfSender = function() {
8
-    // TODO: This needs to reset this if the peerconnection changes
9
-    // (e.g. the call is re-made)
10
-    if (DTMFSender)
11
-        return;
12
-
13
-    var localAudio = APP.RTC.localAudio;
14
-    if (localAudio && localAudio.getTracks().length > 0)
15
-    {
16
-        var peerconnection
17
-            = APP.xmpp.getConnection().jingle.activecall.peerconnection;
18
-        if (peerconnection) {
19
-            DTMFSender =
20
-                peerconnection.peerconnection
21
-                    .createDTMFSender(localAudio.getTracks()[0]);
22
-            console.log("Initialized DTMFSender");
23
-        }
24
-        else {
25
-            console.log("Failed to initialize DTMFSender: no PeerConnection.");
26
-        }
27
-    }
28
-    else {
29
-        console.log("Failed to initialize DTMFSender: no audio track.");
30
-    }
31
-};
32
-
33
-var DTMF = {
34
-    sendTones: function (tones, duration, pause) {
35
-        if (!DTMFSender)
36
-            initDtmfSender();
37
-
38
-        if (DTMFSender){
39
-            DTMFSender.insertDTMF(tones,
40
-                                  (duration || 200),
41
-                                  (pause || 200));
42
-        }
43
-    }
44
-};
45
-
46
-module.exports = DTMF;
47
-

+ 15
- 0
modules/DTMF/JitsiDTMFManager.js 查看文件

@@ -0,0 +1,15 @@
1
+var logger = require("jitsi-meet-logger").getLogger(__filename);
2
+
3
+function JitsiDTMFManager (localAudio, peerConnection) {
4
+    var tracks = localAudio._getTracks();
5
+    if (!tracks.length) {
6
+        throw new Error("Failed to initialize DTMFSender: no audio track.");
7
+    }
8
+    this.dtmfSender = peerConnection.peerconnection.createDTMFSender(tracks[0]);
9
+    logger.debug("Initialized DTMFSender");
10
+}
11
+
12
+
13
+JitsiDTMFManager.prototype.sendTones = function (tones, duration, pause) {
14
+    this.dtmfSender.insertDTMF(tones, (duration || 200), (pause || 200));
15
+};

+ 14
- 0
modules/RTC/JitsiTrack.js 查看文件

@@ -96,6 +96,20 @@ JitsiTrack.prototype.getType = function() {
96 96
     return this.type;
97 97
 };
98 98
 
99
+/**
100
+ * Check if this is audiotrack.
101
+ */
102
+JitsiTrack.prototype.isAudioTrack = function () {
103
+    return this.getType() === JitsiTrack.AUDIO;
104
+};
105
+
106
+/**
107
+ * Check if this is videotrack.
108
+ */
109
+JitsiTrack.prototype.isVideoTrack = function () {
110
+    return this.getType() === JitsiTrack.VIDEO;
111
+};
112
+
99 113
 /**
100 114
  * Returns the RTCMediaStream from the browser (?).
101 115
  */

+ 0
- 128
modules/members/MemberList.js 查看文件

@@ -1,128 +0,0 @@
1
-/* global APP, require, $ */
2
-
3
-/**
4
- * This module is meant to (eventually) contain and manage all information
5
- * about members/participants of the conference, so that other modules don't
6
- * have to do it on their own, and so that other modules can access members'
7
- * information from a single place.
8
- *
9
- * Currently this module only manages information about the support of jingle
10
- * DTMF of the members. Other fields, as well as accessor methods are meant to
11
- * be added as needed.
12
- */
13
-
14
-var XMPPEvents = require("../../service/xmpp/XMPPEvents");
15
-var Events = require("../../service/members/Events");
16
-var EventEmitter = require("events");
17
-
18
-var eventEmitter = new EventEmitter();
19
-
20
-/**
21
- * The actual container.
22
- */
23
-var members = {};
24
-
25
-/**
26
- * There is at least one member that supports DTMF (i.e. is jigasi).
27
- */
28
-var atLeastOneDtmf = false;
29
-
30
-
31
-function registerListeners() {
32
-    APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_JOINED, onMucMemberJoined);
33
-    APP.xmpp.addListener(XMPPEvents.MUC_MEMBER_LEFT, onMucMemberLeft);
34
-}
35
-
36
-/**
37
- * Handles a new member joining the MUC.
38
- */
39
-function onMucMemberJoined(jid, id, displayName) {
40
-    var member = {
41
-        displayName: displayName
42
-    };
43
-
44
-    APP.xmpp.getConnection().disco.info(
45
-        jid, "" /* node */, function(iq) { onDiscoInfoReceived(jid, iq); });
46
-
47
-    members[jid] = member;
48
-}
49
-
50
-/**
51
- * Handles a member leaving the MUC.
52
- */
53
-function onMucMemberLeft(jid) {
54
-    delete members[jid];
55
-    updateAtLeastOneDtmf();
56
-}
57
-
58
-/**
59
- * Handles the reception of a disco#info packet from a particular JID.
60
- * @param jid the JID sending the packet.
61
- * @param iq the packet.
62
- */
63
-function onDiscoInfoReceived(jid, iq) {
64
-    if (!members[jid])
65
-        return;
66
-
67
-    var supportsDtmf
68
-        = $(iq).find('>query>feature[var="urn:xmpp:jingle:dtmf:0"]').length > 0;
69
-    updateDtmf(jid, supportsDtmf);
70
-}
71
-
72
-/**
73
- * Updates the 'supportsDtmf' field for a member.
74
- * @param jid the jid of the member.
75
- * @param newValue the new value for the 'supportsDtmf' field.
76
- */
77
-function updateDtmf(jid, newValue) {
78
-    var oldValue = members[jid].supportsDtmf;
79
-    members[jid].supportsDtmf = newValue;
80
-
81
-    if (newValue != oldValue) {
82
-        updateAtLeastOneDtmf();
83
-    }
84
-}
85
-
86
-/**
87
- * Checks each member's 'supportsDtmf' field and updates
88
- * 'atLastOneSupportsDtmf'.
89
- */
90
-function updateAtLeastOneDtmf() {
91
-    var newAtLeastOneDtmf = false;
92
-    for (var key in members) {
93
-        if (typeof members[key].supportsDtmf !== 'undefined'
94
-            && members[key].supportsDtmf) {
95
-            newAtLeastOneDtmf= true;
96
-            break;
97
-        }
98
-    }
99
-
100
-    if (atLeastOneDtmf != newAtLeastOneDtmf) {
101
-        atLeastOneDtmf = newAtLeastOneDtmf;
102
-        eventEmitter.emit(Events.DTMF_SUPPORT_CHANGED, atLeastOneDtmf);
103
-    }
104
-}
105
-
106
-
107
-/**
108
- * Exported interface.
109
- */
110
-var Members = {
111
-    start: function() {
112
-        registerListeners();
113
-    },
114
-    addListener: function(type, listener) {
115
-        eventEmitter.on(type, listener);
116
-    },
117
-    removeListener: function (type, listener) {
118
-        eventEmitter.removeListener(type, listener);
119
-    },
120
-    size: function () {
121
-        return Object.keys(members).length;
122
-    },
123
-    getMembers: function () {
124
-        return members;
125
-    }
126
-};
127
-
128
-module.exports = Members;

+ 0
- 5
service/members/Events.js 查看文件

@@ -1,5 +0,0 @@
1
-var Events = {
2
-    DTMF_SUPPORT_CHANGED: "members.dtmf_support_changed"
3
-};
4
-
5
-module.exports = Events;

正在加载...
取消
保存