瀏覽代碼

Basic Jibri recording refactoring.

dev1
yanas 9 年之前
父節點
當前提交
638bec6375
共有 6 個檔案被更改,包括 116 行新增40 行删除
  1. 6
    6
      JitsiConference.js
  2. 1
    1
      JitsiConferenceEvents.js
  3. 23
    0
      JitsiRecorderErrors.js
  4. 1
    1
      doc/example/example.js
  5. 84
    31
      modules/xmpp/recording.js
  6. 1
    1
      service/xmpp/XMPPEvents.js

+ 6
- 6
JitsiConference.js 查看文件

@@ -673,7 +673,7 @@ JitsiConference.prototype.isRecordingSupported = function () {
673 673
 JitsiConference.prototype.getRecordingState = function () {
674 674
     if(this.room)
675 675
         return this.room.getRecordingState();
676
-    return "off";
676
+    return Recording.status.OFF;
677 677
 }
678 678
 
679 679
 /**
@@ -692,10 +692,10 @@ JitsiConference.prototype.toggleRecording = function (options) {
692 692
     if(this.room)
693 693
         return this.room.toggleRecording(options, function (status, error) {
694 694
             this.eventEmitter.emit(
695
-                JitsiConferenceEvents.RECORDING_STATE_CHANGED, status, error);
695
+                JitsiConferenceEvents.RECORDER_STATE_CHANGED, status, error);
696 696
         }.bind(this));
697 697
     this.eventEmitter.emit(
698
-        JitsiConferenceEvents.RECORDING_STATE_CHANGED, "error",
698
+        JitsiConferenceEvents.RECORDER_STATE_CHANGED, "error",
699 699
         new Error("The conference is not created yet!"));
700 700
 }
701 701
 
@@ -994,10 +994,10 @@ function setupListeners(conference) {
994 994
         conference.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_INTERRUPTED);
995 995
     });
996 996
 
997
-    conference.room.addListener(XMPPEvents.RECORDING_STATE_CHANGED,
998
-        function () {
997
+    conference.room.addListener(XMPPEvents.RECORDER_STATE_CHANGED,
998
+        function (state) {
999 999
             conference.eventEmitter.emit(
1000
-                JitsiConferenceEvents.RECORDING_STATE_CHANGED);
1000
+                JitsiConferenceEvents.RECORDER_STATE_CHANGED, state);
1001 1001
         });
1002 1002
 
1003 1003
     conference.room.addListener(XMPPEvents.PHONE_NUMBER_CHANGED, function () {

+ 1
- 1
JitsiConferenceEvents.js 查看文件

@@ -111,7 +111,7 @@ var JitsiConferenceEvents = {
111 111
     /**
112 112
      * Indicates that recording state changed.
113 113
      */
114
-    RECORDING_STATE_CHANGED: "conference.recordingStateChanged",
114
+    RECORDER_STATE_CHANGED: "conference.recorderStateChanged",
115 115
     /**
116 116
      * Indicates that phone number changed.
117 117
      */

+ 23
- 0
JitsiRecorderErrors.js 查看文件

@@ -0,0 +1,23 @@
1
+/**
2
+ * Enumeration with the errors for the conference.
3
+ * @type {{string: string}}
4
+ */
5
+var JitsiRecorderErrors = {
6
+    /**
7
+     * Indicates that the recorder is currently unavailable.
8
+     */
9
+    RECORDER_UNAVAILABLE: "recorder.unavailable",
10
+
11
+    /**
12
+     * Indicates that the authentication token is missing.
13
+     */
14
+    NO_TOKEN: "recorder.noToken",
15
+
16
+    /**
17
+     * Indicates that a state change failed.
18
+     */
19
+    STATE_CHANGE_FAILED: "recorder.stateChangeFailed",
20
+
21
+};
22
+
23
+module.exports = JitsiRecorderErrors;

+ 1
- 1
doc/example/example.js 查看文件

@@ -121,7 +121,7 @@ function onConnectionSuccess(){
121 121
       function(userID, audioLevel){
122 122
           console.log(userID + " - " + audioLevel);
123 123
       });
124
-    room.on(JitsiMeetJS.events.conference.RECORDING_STATE_CHANGED, function () {
124
+    room.on(JitsiMeetJS.events.conference.RECORDER_STATE_CHANGED, function () {
125 125
         console.log(room.isRecordingSupported() + " - " +
126 126
             room.getRecordingState() + " - " +
127 127
             room.getRecordingURL());

+ 84
- 31
modules/xmpp/recording.js 查看文件

@@ -1,19 +1,26 @@
1 1
 /* global $, $iq, config, connection, focusMucJid, messageHandler,
2 2
    Toolbar, Util, Promise */
3 3
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
4
+var JitsiRecorderErrors = require("../../JitsiRecorderErrors");
5
+
4 6
 var logger = require("jitsi-meet-logger").getLogger(__filename);
5 7
 
6 8
 function Recording(type, eventEmitter, connection, focusMucJid, jirecon,
7 9
     roomjid) {
8 10
     this.eventEmitter = eventEmitter;
9 11
     this.connection = connection;
10
-    this.state = "off";
12
+    this.state = null;
11 13
     this.focusMucJid = focusMucJid;
12 14
     this.jirecon = jirecon;
13 15
     this.url = null;
14 16
     this.type = type;
15
-    this._isSupported = ((type === Recording.types.JIBRI)
16
-        || (type === Recording.types.JIRECON && !this.jirecon))? false : true;
17
+    this._isSupported
18
+        = ( type === Recording.types.JIRECON && !this.jirecon
19
+            || type === Recording.types.JIBRI && !this._isServiceAvailable)
20
+            ? false : true;
21
+
22
+    this._isServiceAvailable = false;
23
+
17 24
     /**
18 25
      * The ID of the jirecon recording session. Jirecon generates it when we
19 26
      * initially start recording, and it needs to be used in subsequent requests
@@ -29,18 +36,43 @@ Recording.types = {
29 36
     JIBRI: "jibri"
30 37
 };
31 38
 
39
+Recording.status = {
40
+    ON: "on",
41
+    OFF: "off",
42
+    AVAILABLE: "available",
43
+    UNAVAILABLE: "unavailable",
44
+    START: "start",
45
+    STOP: "stop",
46
+    PENDING: "pending"
47
+};
48
+
32 49
 Recording.prototype.handleJibriPresence = function (jibri) {
33 50
     var attributes = jibri.attributes;
34 51
     if(!attributes)
35 52
         return;
36 53
 
37
-    this._isSupported =
38
-        (attributes.status && attributes.status !== "undefined");
39
-    if(this._isSupported) {
40
-        this.url = attributes.url || null;
41
-        this.state = attributes.status || "off";
42
-    }
43
-    this.eventEmitter.emit(XMPPEvents.RECORDING_STATE_CHANGED);
54
+    var newState = attributes.status;
55
+    console.log("handle jibri presence : ", newState);
56
+    var oldIsAvailable = this._isServiceAvailable;
57
+    // The service is available if the statu isn't undefined.
58
+    this._isServiceAvailable =
59
+        (newState && newState !== "undefined");
60
+
61
+    if (newState === "undefined"
62
+        || oldIsAvailable != this._isServiceAvailable
63
+        // If we receive an OFF state without any recording in progress we
64
+        // consider this to be an initial available state.
65
+        || (this.state === Recording.status.AVAILABLE
66
+            && newState === Recording.status.OFF))
67
+        this.state = (newState === "undefined")
68
+                        ? Recording.status.UNAVAILABLE
69
+                        : Recording.status.AVAILABLE;
70
+    else
71
+        this.state = attributes.status;
72
+
73
+    logger.log("Handle Jibri presence: ", this.state);
74
+
75
+    this.eventEmitter.emit(XMPPEvents.RECORDER_STATE_CHANGED, this.state);
44 76
 };
45 77
 
46 78
 Recording.prototype.setRecordingJibri = function (state, callback, errCallback,
@@ -49,21 +81,23 @@ Recording.prototype.setRecordingJibri = function (state, callback, errCallback,
49 81
         errCallback(new Error("Invalid state!"));
50 82
     }
51 83
     options = options || {};
52
-    // FIXME jibri does not accept IQ without 'url' attribute set ?
53 84
 
85
+    // FIXME jibri does not accept IQ without 'url' attribute set ?
54 86
     var iq = $iq({to: this.focusMucJid, type: 'set'})
55 87
         .c('jibri', {
56
-            "xmlns": 'http://jitsi.org/protocol/jibri',
57
-            "action": (state === 'on') ? 'start' : 'stop',
58
-            "streamid": options.streamId,
59
-            "follow-entity": options.followEntity
88
+        "xmlns": 'http://jitsi.org/protocol/jibri',
89
+        "action": (state === Recording.status.ON)
90
+                    ? Recording.status.START
91
+                    : Recording.status.STOP,
92
+        "streamid": options.streamId,
60 93
         }).up();
61 94
 
62
-    logger.log('Set jibri recording: '+state, iq.nodeTree);
63
-    console.log(iq.nodeTree);
95
+    logger.log('Set jibri recording: ' + state, iq.nodeTree);
96
+    logger.log(iq.nodeTree);
64 97
     this.connection.sendIQ(
65 98
         iq,
66 99
         function (result) {
100
+            logger.log("Result", result);
67 101
             callback($(result).find('jibri').attr('state'),
68 102
             $(result).find('jibri').attr('url'));
69 103
         },
@@ -74,20 +108,23 @@ Recording.prototype.setRecordingJibri = function (state, callback, errCallback,
74 108
 };
75 109
 
76 110
 Recording.prototype.setRecordingJirecon =
77
-function (state, callback, errCallback, options) {
111
+    function (state, callback, errCallback, options) {
112
+
78 113
     if (state == this.state){
79 114
         errCallback(new Error("Invalid state!"));
80 115
     }
81 116
 
82 117
     var iq = $iq({to: this.jirecon, type: 'set'})
83 118
         .c('recording', {xmlns: 'http://jitsi.org/protocol/jirecon',
84
-            action: (state === 'on') ? 'start' : 'stop',
119
+            action: (state === Recording.status.ON)
120
+                ? Recording.status.START
121
+                : Recording.status.STOP,
85 122
             mucjid: this.roomjid});
86 123
     if (state === 'off'){
87 124
         iq.attrs({rid: this.jireconRid});
88 125
     }
89 126
 
90
-    console.log('Start recording');
127
+    logger.log('Start recording');
91 128
     var self = this;
92 129
     this.connection.sendIQ(
93 130
         iq,
@@ -96,10 +133,10 @@ function (state, callback, errCallback, options) {
96 133
             // provisional?
97 134
             self.jireconRid = $(result).find('recording').attr('rid');
98 135
             console.log('Recording ' +
99
-                ((state === 'on') ? 'started' : 'stopped') +
136
+                ((state === Recording.status.ON) ? 'started' : 'stopped') +
100 137
                 '(jirecon)' + result);
101 138
             self.state = state;
102
-            if (state === 'off'){
139
+            if (state === Recording.status.OFF){
103 140
                 self.jireconRid = null;
104 141
             }
105 142
 
@@ -168,30 +205,46 @@ function (state, callback, errCallback, options) {
168 205
 };
169 206
 
170 207
 /**
171
- *Starts/stops the recording
208
+ * Starts/stops the recording.
172 209
  * @param token token for authentication
173 210
  * @param statusChangeHandler {function} receives the new status as argument.
174 211
  */
175 212
 Recording.prototype.toggleRecording = function (options, statusChangeHandler) {
176
-    if ((!options.token && this.type === Recording.types.COLIBRI) ||
177
-        (!options.streamId && this.type === Recording.types.JIBRI)){
178
-        statusChangeHandler("error", new Error("No token passed!"));
213
+    var oldState = this.state;
214
+
215
+    // If the recorder is currently unavailable we throw an error.
216
+    if (oldState === Recording.status.UNAVAILABLE)
217
+        statusChangeHandler("error",
218
+            new Error(JitsiRecorderErrors.RECORDER_UNAVAILABLE));
219
+
220
+    // If we're about to turn ON the recording we need either a streamId or
221
+    // an authentication token depending on the recording type. If we don't
222
+    // have any of those we throw an error.
223
+    if ((oldState === Recording.status.OFF
224
+        || oldState === Recording.status.AVAILABLE)
225
+        && ((!options.token && this.type === Recording.types.COLIBRI) ||
226
+        (!options.streamId && this.type === Recording.types.JIBRI))) {
227
+        statusChangeHandler("error",
228
+            new Error(JitsiRecorderErrors.NO_TOKEN));
179 229
         logger.error("No token passed!");
180 230
         return;
181 231
     }
182 232
 
183
-    var oldState = this.state;
184
-    var newState = (oldState === 'off' || !oldState) ? 'on' : 'off';
233
+    var newState = (oldState === Recording.status.AVAILABLE
234
+                    || oldState === Recording.status.OFF)
235
+                    ? Recording.status.ON
236
+                    : Recording.status.OFF;
237
+
185 238
     var self = this;
239
+    logger.log("Toggle recording (old state, new state): ", oldState, newState);
186 240
     this.setRecording(newState,
187 241
         function (state, url) {
188
-            logger.log("New recording state: ", state);
242
+            // If the state is undefined we're going to wait for presence
243
+            // update.
189 244
             if (state && state !== oldState) {
190 245
                 self.state = state;
191 246
                 self.url = url;
192 247
                 statusChangeHandler(state);
193
-            } else {
194
-                statusChangeHandler("error", new Error("Status not changed!"));
195 248
             }
196 249
         }, function (error) {
197 250
             statusChangeHandler("error", error);

+ 1
- 1
service/xmpp/XMPPEvents.js 查看文件

@@ -95,7 +95,7 @@ var XMPPEvents = {
95 95
     /**
96 96
      * Indicates that recording state changed.
97 97
      */
98
-    RECORDING_STATE_CHANGED: "xmpp.recordingStateChanged",
98
+    RECORDER_STATE_CHANGED: "xmpp.recorderStateChanged",
99 99
     // Designates an event indicating that we received statistics from a
100 100
     // participant in the MUC.
101 101
     REMOTE_STATS: "xmpp.remote_stats",

Loading…
取消
儲存