瀏覽代碼

support DTMF

release-8443
isymchych 10 年之前
父節點
當前提交
8329fe5767

+ 10
- 0
.editorconfig 查看文件

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
-
1
+/* global Strophe, $ */
2
+/* jshint -W101 */
2
 var logger = require("jitsi-meet-logger").getLogger(__filename);
3
 var logger = require("jitsi-meet-logger").getLogger(__filename);
3
 var RTC = require("./modules/RTC/RTC");
4
 var RTC = require("./modules/RTC/RTC");
4
 var XMPPEvents = require("./service/xmpp/XMPPEvents");
5
 var XMPPEvents = require("./service/xmpp/XMPPEvents");
7
 var JitsiConferenceEvents = require("./JitsiConferenceEvents");
8
 var JitsiConferenceEvents = require("./JitsiConferenceEvents");
8
 var JitsiParticipant = require("./JitsiParticipant");
9
 var JitsiParticipant = require("./JitsiParticipant");
9
 var Statistics = require("./modules/statistics/statistics");
10
 var Statistics = require("./modules/statistics/statistics");
11
+var JitsiDTMFManager = require('./modules/DTMF/JitsiDTMFManager');
10
 var JitsiTrackEvents = require("./JitsiTrackEvents");
12
 var JitsiTrackEvents = require("./JitsiTrackEvents");
11
 
13
 
12
 /**
14
 /**
18
  * @param options.connection the JitsiConnection object for this JitsiConference.
20
  * @param options.connection the JitsiConnection object for this JitsiConference.
19
  * @constructor
21
  * @constructor
20
  */
22
  */
21
-
22
 function JitsiConference(options) {
23
 function JitsiConference(options) {
23
     if(!options.name || options.name.toLowerCase() !== options.name) {
24
     if(!options.name || options.name.toLowerCase() !== options.name) {
24
         logger.error("Invalid conference name (no conference name passed or it"
25
         logger.error("Invalid conference name (no conference name passed or it"
37
     setupListeners(this);
38
     setupListeners(this);
38
     this.participants = {};
39
     this.participants = {};
39
     this.lastActiveSpeaker = null;
40
     this.lastActiveSpeaker = null;
41
+    this.dtmfManager = null;
42
+    this.somebodySupportsDTMF = false;
40
 }
43
 }
41
 
44
 
42
 /**
45
 /**
46
 JitsiConference.prototype.join = function (password) {
49
 JitsiConference.prototype.join = function (password) {
47
     if(this.room)
50
     if(this.room)
48
         this.room.join(password, this.connection.tokenPassword);
51
         this.room.join(password, this.connection.tokenPassword);
49
-}
52
+};
50
 
53
 
51
 /**
54
 /**
52
  * Leaves the conference.
55
  * Leaves the conference.
55
     if(this.xmpp)
58
     if(this.xmpp)
56
         this.xmpp.leaveRoom(this.room.roomjid);
59
         this.xmpp.leaveRoom(this.room.roomjid);
57
     this.room = null;
60
     this.room = null;
58
-}
61
+};
59
 
62
 
60
 /**
63
 /**
61
  * Returns the local tracks.
64
  * Returns the local tracks.
62
  */
65
  */
63
 JitsiConference.prototype.getLocalTracks = function () {
66
 JitsiConference.prototype.getLocalTracks = function () {
64
-    if(this.rtc)
67
+    if (this.rtc) {
65
         return this.rtc.localStreams;
68
         return this.rtc.localStreams;
69
+    } else {
70
+        return [];
71
+    }
66
 };
72
 };
67
 
73
 
68
 
74
 
77
 JitsiConference.prototype.on = function (eventId, handler) {
83
 JitsiConference.prototype.on = function (eventId, handler) {
78
     if(this.eventEmitter)
84
     if(this.eventEmitter)
79
         this.eventEmitter.on(eventId, handler);
85
         this.eventEmitter.on(eventId, handler);
80
-}
86
+};
81
 
87
 
82
 /**
88
 /**
83
  * Removes event listener
89
  * Removes event listener
89
 JitsiConference.prototype.off = function (eventId, handler) {
95
 JitsiConference.prototype.off = function (eventId, handler) {
90
     if(this.eventEmitter)
96
     if(this.eventEmitter)
91
         this.eventEmitter.removeListener(eventId, handler);
97
         this.eventEmitter.removeListener(eventId, handler);
92
-}
98
+};
93
 
99
 
94
 // Common aliases for event emitter
100
 // Common aliases for event emitter
95
 JitsiConference.prototype.addEventListener = JitsiConference.prototype.on;
101
 JitsiConference.prototype.addEventListener = JitsiConference.prototype.on;
104
  JitsiConference.prototype.addCommandListener = function (command, handler) {
110
  JitsiConference.prototype.addCommandListener = function (command, handler) {
105
     if(this.room)
111
     if(this.room)
106
         this.room.addPresenceListener(command, handler);
112
         this.room.addPresenceListener(command, handler);
107
- }
113
+ };
108
 
114
 
109
 /**
115
 /**
110
   * Removes command  listener
116
   * Removes command  listener
113
  JitsiConference.prototype.removeCommandListener = function (command) {
119
  JitsiConference.prototype.removeCommandListener = function (command) {
114
     if(this.room)
120
     if(this.room)
115
         this.room.removePresenceListener(command);
121
         this.room.removePresenceListener(command);
116
- }
122
+ };
117
 
123
 
118
 /**
124
 /**
119
  * Sends text message to the other participants in the conference
125
  * Sends text message to the other participants in the conference
122
 JitsiConference.prototype.sendTextMessage = function (message) {
128
 JitsiConference.prototype.sendTextMessage = function (message) {
123
     if(this.room)
129
     if(this.room)
124
         this.room.sendMessage(message);
130
         this.room.sendMessage(message);
125
-}
131
+};
126
 
132
 
127
 /**
133
 /**
128
  * Send presence command.
134
  * Send presence command.
134
         this.room.addToPresence(name, values);
140
         this.room.addToPresence(name, values);
135
         this.room.sendPresence();
141
         this.room.sendPresence();
136
     }
142
     }
137
-}
143
+};
138
 
144
 
139
 /**
145
 /**
140
  * Send presence command one time.
146
  * Send presence command one time.
144
 JitsiConference.prototype.sendCommandOnce = function (name, values) {
150
 JitsiConference.prototype.sendCommandOnce = function (name, values) {
145
     this.sendCommand(name, values);
151
     this.sendCommand(name, values);
146
     this.removeCommand(name);
152
     this.removeCommand(name);
147
-}
153
+};
148
 
154
 
149
 /**
155
 /**
150
  * Send presence command.
156
  * Send presence command.
155
 JitsiConference.prototype.removeCommand = function (name) {
161
 JitsiConference.prototype.removeCommand = function (name) {
156
     if(this.room)
162
     if(this.room)
157
         this.room.removeFromPresence(name);
163
         this.room.removeFromPresence(name);
158
-}
164
+};
159
 
165
 
160
 /**
166
 /**
161
  * Sets the display name for this conference.
167
  * Sets the display name for this conference.
166
         this.room.addToPresence("nick", {attributes: {xmlns: 'http://jabber.org/protocol/nick'}, value: name});
172
         this.room.addToPresence("nick", {attributes: {xmlns: 'http://jabber.org/protocol/nick'}, value: name});
167
         this.room.sendPresence();
173
         this.room.sendPresence();
168
     }
174
     }
169
-}
175
+};
170
 
176
 
171
 /**
177
 /**
172
  * Adds JitsiLocalTrack object to the conference.
178
  * Adds JitsiLocalTrack object to the conference.
180
         var audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);
186
         var audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);
181
         track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, muteHandler);
187
         track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, muteHandler);
182
         track.addEventListener(JitsiTrackEvents.TRACK_STOPPED, stopHandler);
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
         this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
198
         this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
194
     }.bind(this));
199
     }.bind(this));
195
-
196
-}
200
+};
197
 
201
 
198
 /**
202
 /**
199
  * Fires TRACK_AUDIO_LEVEL_CHANGED change conference event.
203
  * Fires TRACK_AUDIO_LEVEL_CHANGED change conference event.
203
     this.eventEmitter.emit(
207
     this.eventEmitter.emit(
204
         JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,
208
         JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,
205
         this.myUserId(), audioLevel);
209
         this.myUserId(), audioLevel);
206
-}
210
+};
207
 
211
 
208
 /**
212
 /**
209
  * Fires TRACK_MUTE_CHANGED change conference event.
213
  * Fires TRACK_MUTE_CHANGED change conference event.
222
         this.rtc.removeLocalStream(track);
226
         this.rtc.removeLocalStream(track);
223
         this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
227
         this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
224
     }.bind(this));
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
  * Elects the participant with the given id to be the selected participant or the speaker.
248
  * Elects the participant with the given id to be the selected participant or the speaker.
232
     if (this.rtc) {
252
     if (this.rtc) {
233
         this.rtc.selectedEndpoint(participantId);
253
         this.rtc.selectedEndpoint(participantId);
234
     }
254
     }
235
-}
255
+};
236
 
256
 
237
 /**
257
 /**
238
  *
258
  *
239
  * @param id the identifier of the participant
259
  * @param id the identifier of the participant
240
  */
260
  */
241
 JitsiConference.prototype.pinParticipant = function(participantId) {
261
 JitsiConference.prototype.pinParticipant = function(participantId) {
242
-    if(this.rtc)
262
+    if (this.rtc) {
243
         this.rtc.pinEndpoint(participantId);
263
         this.rtc.pinEndpoint(participantId);
244
-}
264
+    }
265
+};
245
 
266
 
246
 /**
267
 /**
247
  * Returns the list of participants for this conference.
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
 JitsiConference.prototype.getParticipants = function() {
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
  * @returns {JitsiParticipant} the participant in this conference with the specified id (or
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
  * @param id the id of the participant.
280
  * @param id the id of the participant.
258
  */
281
  */
259
 JitsiConference.prototype.getParticipantById = function(id) {
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
 JitsiConference.prototype.onMemberJoined = function (jid, email, nick) {
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
  * Returns the local user's ID
389
  * Returns the local user's ID
274
  */
391
  */
275
 JitsiConference.prototype.myUserId = function () {
392
 JitsiConference.prototype.myUserId = function () {
276
     return (this.room && this.room.myroomjid)? Strophe.getResourceFromJid(this.room.myroomjid) : null;
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
  * Setups the listeners needed for the conference.
418
  * Setups the listeners needed for the conference.
290
     conference.room.addListener(XMPPEvents.REMOTE_STREAM_RECEIVED,
428
     conference.room.addListener(XMPPEvents.REMOTE_STREAM_RECEIVED,
291
         function (data, sid, thessrc) {
429
         function (data, sid, thessrc) {
292
             var track = conference.rtc.createRemoteStream(data, sid, thessrc);
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
 //        conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_LEFT);
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
     conference.room.addListener(XMPPEvents.CONNECTION_RESTORED, function () {
459
     conference.room.addListener(XMPPEvents.CONNECTION_RESTORED, function () {
346
         conference.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_RESTORED);
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
         conference.eventEmitter.emit(JitsiConferenceEvents.SETUP_FAILED);
463
         conference.eventEmitter.emit(JitsiConferenceEvents.SETUP_FAILED);
350
     });
464
     });
351
 
465
 

+ 2
- 1
JitsiConferenceEvents.js 查看文件

75
     /**
75
     /**
76
      * Indicates that conference has been left.
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
 module.exports = JitsiConferenceEvents;
82
 module.exports = JitsiConferenceEvents;

+ 23
- 18
JitsiParticipant.js 查看文件

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

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
     return this.type;
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
  * Returns the RTCMediaStream from the browser (?).
114
  * Returns the RTCMediaStream from the browser (?).
101
  */
115
  */

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

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
-var Events = {
2
-    DTMF_SUPPORT_CHANGED: "members.dtmf_support_changed"
3
-};
4
-
5
-module.exports = Events;

Loading…
取消
儲存