Browse Source

Basic Jibri recording refactoring.

dev1
yanas 9 years ago
parent
commit
638bec6375

+ 6
- 6
JitsiConference.js View File

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

+ 1
- 1
JitsiConferenceEvents.js View File

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

+ 23
- 0
JitsiRecorderErrors.js View File

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 View File

121
       function(userID, audioLevel){
121
       function(userID, audioLevel){
122
           console.log(userID + " - " + audioLevel);
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
         console.log(room.isRecordingSupported() + " - " +
125
         console.log(room.isRecordingSupported() + " - " +
126
             room.getRecordingState() + " - " +
126
             room.getRecordingState() + " - " +
127
             room.getRecordingURL());
127
             room.getRecordingURL());

+ 84
- 31
modules/xmpp/recording.js View File

1
 /* global $, $iq, config, connection, focusMucJid, messageHandler,
1
 /* global $, $iq, config, connection, focusMucJid, messageHandler,
2
    Toolbar, Util, Promise */
2
    Toolbar, Util, Promise */
3
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
3
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
4
+var JitsiRecorderErrors = require("../../JitsiRecorderErrors");
5
+
4
 var logger = require("jitsi-meet-logger").getLogger(__filename);
6
 var logger = require("jitsi-meet-logger").getLogger(__filename);
5
 
7
 
6
 function Recording(type, eventEmitter, connection, focusMucJid, jirecon,
8
 function Recording(type, eventEmitter, connection, focusMucJid, jirecon,
7
     roomjid) {
9
     roomjid) {
8
     this.eventEmitter = eventEmitter;
10
     this.eventEmitter = eventEmitter;
9
     this.connection = connection;
11
     this.connection = connection;
10
-    this.state = "off";
12
+    this.state = null;
11
     this.focusMucJid = focusMucJid;
13
     this.focusMucJid = focusMucJid;
12
     this.jirecon = jirecon;
14
     this.jirecon = jirecon;
13
     this.url = null;
15
     this.url = null;
14
     this.type = type;
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
      * The ID of the jirecon recording session. Jirecon generates it when we
25
      * The ID of the jirecon recording session. Jirecon generates it when we
19
      * initially start recording, and it needs to be used in subsequent requests
26
      * initially start recording, and it needs to be used in subsequent requests
29
     JIBRI: "jibri"
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
 Recording.prototype.handleJibriPresence = function (jibri) {
49
 Recording.prototype.handleJibriPresence = function (jibri) {
33
     var attributes = jibri.attributes;
50
     var attributes = jibri.attributes;
34
     if(!attributes)
51
     if(!attributes)
35
         return;
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
 Recording.prototype.setRecordingJibri = function (state, callback, errCallback,
78
 Recording.prototype.setRecordingJibri = function (state, callback, errCallback,
49
         errCallback(new Error("Invalid state!"));
81
         errCallback(new Error("Invalid state!"));
50
     }
82
     }
51
     options = options || {};
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
     var iq = $iq({to: this.focusMucJid, type: 'set'})
86
     var iq = $iq({to: this.focusMucJid, type: 'set'})
55
         .c('jibri', {
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
         }).up();
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
     this.connection.sendIQ(
97
     this.connection.sendIQ(
65
         iq,
98
         iq,
66
         function (result) {
99
         function (result) {
100
+            logger.log("Result", result);
67
             callback($(result).find('jibri').attr('state'),
101
             callback($(result).find('jibri').attr('state'),
68
             $(result).find('jibri').attr('url'));
102
             $(result).find('jibri').attr('url'));
69
         },
103
         },
74
 };
108
 };
75
 
109
 
76
 Recording.prototype.setRecordingJirecon =
110
 Recording.prototype.setRecordingJirecon =
77
-function (state, callback, errCallback, options) {
111
+    function (state, callback, errCallback, options) {
112
+
78
     if (state == this.state){
113
     if (state == this.state){
79
         errCallback(new Error("Invalid state!"));
114
         errCallback(new Error("Invalid state!"));
80
     }
115
     }
81
 
116
 
82
     var iq = $iq({to: this.jirecon, type: 'set'})
117
     var iq = $iq({to: this.jirecon, type: 'set'})
83
         .c('recording', {xmlns: 'http://jitsi.org/protocol/jirecon',
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
             mucjid: this.roomjid});
122
             mucjid: this.roomjid});
86
     if (state === 'off'){
123
     if (state === 'off'){
87
         iq.attrs({rid: this.jireconRid});
124
         iq.attrs({rid: this.jireconRid});
88
     }
125
     }
89
 
126
 
90
-    console.log('Start recording');
127
+    logger.log('Start recording');
91
     var self = this;
128
     var self = this;
92
     this.connection.sendIQ(
129
     this.connection.sendIQ(
93
         iq,
130
         iq,
96
             // provisional?
133
             // provisional?
97
             self.jireconRid = $(result).find('recording').attr('rid');
134
             self.jireconRid = $(result).find('recording').attr('rid');
98
             console.log('Recording ' +
135
             console.log('Recording ' +
99
-                ((state === 'on') ? 'started' : 'stopped') +
136
+                ((state === Recording.status.ON) ? 'started' : 'stopped') +
100
                 '(jirecon)' + result);
137
                 '(jirecon)' + result);
101
             self.state = state;
138
             self.state = state;
102
-            if (state === 'off'){
139
+            if (state === Recording.status.OFF){
103
                 self.jireconRid = null;
140
                 self.jireconRid = null;
104
             }
141
             }
105
 
142
 
168
 };
205
 };
169
 
206
 
170
 /**
207
 /**
171
- *Starts/stops the recording
208
+ * Starts/stops the recording.
172
  * @param token token for authentication
209
  * @param token token for authentication
173
  * @param statusChangeHandler {function} receives the new status as argument.
210
  * @param statusChangeHandler {function} receives the new status as argument.
174
  */
211
  */
175
 Recording.prototype.toggleRecording = function (options, statusChangeHandler) {
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
         logger.error("No token passed!");
229
         logger.error("No token passed!");
180
         return;
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
     var self = this;
238
     var self = this;
239
+    logger.log("Toggle recording (old state, new state): ", oldState, newState);
186
     this.setRecording(newState,
240
     this.setRecording(newState,
187
         function (state, url) {
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
             if (state && state !== oldState) {
244
             if (state && state !== oldState) {
190
                 self.state = state;
245
                 self.state = state;
191
                 self.url = url;
246
                 self.url = url;
192
                 statusChangeHandler(state);
247
                 statusChangeHandler(state);
193
-            } else {
194
-                statusChangeHandler("error", new Error("Status not changed!"));
195
             }
248
             }
196
         }, function (error) {
249
         }, function (error) {
197
             statusChangeHandler("error", error);
250
             statusChangeHandler("error", error);

+ 1
- 1
service/xmpp/XMPPEvents.js View File

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

Loading…
Cancel
Save