hristoterezov 10 vuotta sitten
vanhempi
commit
cfd44dddb2
3 muutettua tiedostoa jossa 253 lisäystä ja 0 poistoa
  1. 225
    0
      modules/xmpp/recording.js
  2. 27
    0
      modules/xmpp/strophe.jibri.js
  3. 1
    0
      modules/xmpp/xmpp.js

+ 225
- 0
modules/xmpp/recording.js Näytä tiedosto

@@ -0,0 +1,225 @@
1
+/* global $, $iq, config, connection, focusMucJid, messageHandler,
2
+   Toolbar, Util */
3
+var Moderator = require("./moderator");
4
+
5
+
6
+var recordingToken = null;
7
+var recordingEnabled;
8
+
9
+/**
10
+ * Whether to use a jirecon component for recording, or use the videobridge
11
+ * through COLIBRI.
12
+ */
13
+var useJirecon;
14
+
15
+var useJibri;
16
+var eventEmitter;
17
+
18
+/**
19
+ * The ID of the jirecon recording session. Jirecon generates it when we
20
+ * initially start recording, and it needs to be used in subsequent requests
21
+ * to jirecon.
22
+ */
23
+var jireconRid = null;
24
+
25
+/**
26
+ * The callback to update the recording button. Currently used from colibri
27
+ * after receiving a pending status.
28
+ */
29
+var recordingStateChangeCallback = null;
30
+
31
+function setRecordingToken(token) {
32
+    recordingToken = token;
33
+}
34
+
35
+function setRecordingJirecon(state, token, callback, connection) {
36
+    if (state == recordingEnabled){
37
+        return;
38
+    }
39
+
40
+    var iq = $iq({to: config.hosts.jirecon, type: 'set'})
41
+        .c('recording', {xmlns: 'http://jitsi.org/protocol/jirecon',
42
+            action: (state === 'on') ? 'start' : 'stop',
43
+            mucjid: connection.emuc.roomjid});
44
+    if (state === 'off'){
45
+        iq.attrs({rid: jireconRid});
46
+    }
47
+
48
+    console.log('Start recording');
49
+
50
+    connection.sendIQ(
51
+        iq,
52
+        function (result) {
53
+            // TODO wait for an IQ with the real status, since this is
54
+            // provisional?
55
+            //FIXME: state should reflect the NEW state.
56
+            jireconRid = $(result).find('recording').attr('rid');
57
+            console.log('Recording ' +
58
+                ((state === 'on') ? 'started' : 'stopped') +
59
+                '(jirecon)' + result);
60
+            recordingEnabled = state;
61
+            if (state === 'off'){
62
+                jireconRid = null;
63
+            }
64
+
65
+            callback(state);
66
+        },
67
+        function (error) {
68
+            console.log('Failed to start recording, error: ', error);
69
+            callback(recordingEnabled);
70
+        });
71
+}
72
+
73
+function setRecordingJibri(state, token, callback, connection) {
74
+    if (state == recordingEnabled){
75
+        return;
76
+    }
77
+
78
+    var focusJid = connection.emuc.focusMucJid;
79
+    var iq = $iq({to: focusJid, type: 'set'})
80
+        .c('jibri', {
81
+            xmlns: 'http://jitsi.org/protocol/jibri',
82
+            action: (state === 'on') ? 'start' : 'stop'
83
+            //TODO: add the stream id?
84
+        }).up();
85
+
86
+    console.log('Set jibri recording: '+state, iq);
87
+
88
+    connection.sendIQ(
89
+        iq,
90
+        function (result) {
91
+            var recordingEnabled = $(result).find('jibri').attr('state');
92
+            console.log('Jibri recording is now: ' + recordingEnabled);
93
+            //TODO hook us up to further jibri IQs so we can update the status
94
+            callback(recordingEnabled);
95
+        },
96
+        function (error) {
97
+            console.log('Failed to start recording, error: ', error);
98
+            callback(recordingEnabled);
99
+        });
100
+}
101
+
102
+// Sends a COLIBRI message which enables or disables (according to 'state')
103
+// the recording on the bridge. Waits for the result IQ and calls 'callback'
104
+// with the new recording state, according to the IQ.
105
+function setRecordingColibri(state, token, callback, connection) {
106
+    var elem = $iq({to: connection.emuc.focusMucJid, type: 'set'});
107
+    elem.c('conference', {
108
+        xmlns: 'http://jitsi.org/protocol/colibri'
109
+    });
110
+    elem.c('recording', {state: state, token: token});
111
+
112
+    connection.sendIQ(elem,
113
+        function (result) {
114
+            console.log('Set recording "', state, '". Result:', result);
115
+            var recordingElem = $(result).find('>conference>recording');
116
+            var newState = recordingElem.attr('state');
117
+
118
+            recordingEnabled = newState;
119
+            callback(newState);
120
+
121
+            if (newState === 'pending' && !recordingStateChangeCallback) {
122
+                recordingStateChangeCallback = callback;
123
+                connection.addHandler(function(iq){
124
+                    var state = $(iq).find('recording').attr('state');
125
+                    if (state)
126
+                        recordingStateChangeCallback(state);
127
+                }, 'http://jitsi.org/protocol/colibri', 'iq', null, null, null);
128
+            }
129
+        },
130
+        function (error) {
131
+            console.warn(error);
132
+            callback(recordingEnabled);
133
+        }
134
+    );
135
+}
136
+
137
+function setRecording(state, token, callback, connection) {
138
+    if (useJibri) {
139
+        setRecordingJibri(state, token, callback, connection);
140
+    } else if (useJirecon){
141
+        setRecordingJirecon(state, token, callback, connection);
142
+    } else {
143
+        setRecordingColibri(state, token, callback, connection);
144
+    }
145
+}
146
+
147
+function handleJibriIq(iq) {
148
+    //TODO verify it comes from the focus
149
+
150
+    var newState = $(iq).find('jibri').attr('state');
151
+    if (newState) {
152
+        eventEmitter.emit('recording.state_changed', newState);
153
+    }
154
+}
155
+
156
+var Recording = {
157
+    init: function (ee) {
158
+        eventEmitter = ee;
159
+        useJirecon = config.hosts &&
160
+            (typeof config.hosts.jirecon != "undefined");
161
+        useJibri = config.recordingUseJibri;
162
+        connection.jibri.setHandler(handleJibriIq);
163
+    },
164
+    toggleRecording: function (tokenEmptyCallback,
165
+                               recordingStateChangeCallback,
166
+                               connection) {
167
+        if (!Moderator.isModerator()) {
168
+            console.log(
169
+                    'non-focus, or conference not yet organized:' +
170
+                    ' not enabling recording');
171
+            return;
172
+        }
173
+
174
+        var self = this;
175
+        // Jirecon does not (currently) support a token.
176
+        if (!recordingToken && !useJirecon) {
177
+            tokenEmptyCallback(function (value) {
178
+                setRecordingToken(value);
179
+                self.toggleRecording(tokenEmptyCallback,
180
+                                     recordingStateChangeCallback,
181
+                                     connection);
182
+            });
183
+
184
+            return;
185
+        }
186
+
187
+        var oldState = recordingEnabled;
188
+        var newState = (oldState === 'off' || !oldState) ? 'on' : 'off';
189
+
190
+        setRecording(newState,
191
+            recordingToken,
192
+            function (state) {
193
+                console.log("New recording state: ", state);
194
+                if (state === oldState) {
195
+                    // FIXME: new focus:
196
+                    // this will not work when moderator changes
197
+                    // during active session. Then it will assume that
198
+                    // recording status has changed to true, but it might have
199
+                    // been already true(and we only received actual status from
200
+                    // the focus).
201
+                    //
202
+                    // SO we start with status null, so that it is initialized
203
+                    // here and will fail only after second click, so if invalid
204
+                    // token was used we have to press the button twice before
205
+                    // current status will be fetched and token will be reset.
206
+                    //
207
+                    // Reliable way would be to return authentication error.
208
+                    // Or status update when moderator connects.
209
+                    // Or we have to stop recording session when current
210
+                    // moderator leaves the room.
211
+
212
+                    // Failed to change, reset the token because it might
213
+                    // have been wrong
214
+                    setRecordingToken(null);
215
+                }
216
+                recordingStateChangeCallback(state);
217
+
218
+            },
219
+            connection
220
+        );
221
+    }
222
+
223
+};
224
+
225
+module.exports = Recording;

+ 27
- 0
modules/xmpp/strophe.jibri.js Näytä tiedosto

@@ -0,0 +1,27 @@
1
+/* jshint -W117 */
2
+
3
+var jibriHandler;
4
+module.exports = function() {
5
+    Strophe.addConnectionPlugin('jibri',
6
+        {
7
+            JIBRI_XMLNS: 'http://jitsi.org/protocol/jibri',
8
+            connection: null,
9
+            init: function (conn) {
10
+                this.connection = conn;
11
+
12
+                this.connection.addHandler(
13
+                    this.onJibri.bind(this), this.JIBRI_XMLNS, 'iq', 'set',
14
+                    null, null);
15
+            },
16
+            onJibri: function (iq) {
17
+                console.info("Received a Jibri IQ", iq);
18
+                if (jibriHandler) {
19
+                    jibriHandler.onJibri(iq);
20
+                }
21
+            },
22
+            setHandler: function (handler) {
23
+                jibriHandler = handler;
24
+            }
25
+        }
26
+    );
27
+};

+ 1
- 0
modules/xmpp/xmpp.js Näytä tiedosto

@@ -27,6 +27,7 @@ function initStrophePlugins(XMPP)
27 27
 //    require("./strophe.moderate")(XMPP, eventEmitter);
28 28
     require("./strophe.util")();
29 29
     require("./strophe.ping")(XMPP, XMPP.eventEmitter);
30
+    require("./strophe.jibri")();
30 31
     require("./strophe.rayo")();
31 32
     require("./strophe.logger")();
32 33
 }

Loading…
Peruuta
Tallenna