소스 검색

Add support for jirecon and colibri in the recording

master
hristoterezov 9 년 전
부모
커밋
115ce537d1
6개의 변경된 파일280개의 추가작업 그리고 93개의 파일을 삭제
  1. 2
    3
      JitsiConference.js
  2. 2
    0
      doc/API.md
  3. 132
    54
      lib-jitsi-meet.js
  4. 12
    12
      lib-jitsi-meet.min.js
  5. 5
    4
      modules/xmpp/ChatRoom.js
  6. 127
    20
      modules/xmpp/recording.js

+ 2
- 3
JitsiConference.js 파일 보기

@@ -568,11 +568,10 @@ JitsiConference.prototype.getRecordingURL = function () {
568 568
 
569 569
 /**
570 570
  * Starts/stops the recording
571
- * @param token a token for authentication.
572 571
  */
573
-JitsiConference.prototype.toggleRecording = function (token, followEntity) {
572
+JitsiConference.prototype.toggleRecording = function (options) {
574 573
     if(this.room)
575
-        return this.room.toggleRecording(token, followEntity);
574
+        return this.room.toggleRecording(options);
576 575
     return new Promise(function(resolve, reject){
577 576
         reject(new Error("The conference is not created yet!"))});
578 577
 }

+ 2
- 0
doc/API.md 파일 보기

@@ -150,6 +150,8 @@ This objects represents the server connection. You can create new ```JitsiConnec
150 150
         2. resolution - the prefered resolution for the local video.
151 151
         3. openSctp - boolean property. Enables/disables datachannel support. **NOTE: we recommend to set that option to true**
152 152
         4. disableAudioLevels - boolean property. Enables/disables audio levels.
153
+        5. recordingType - the type of recording to be used
154
+        6. jirecon
153 155
 
154 156
 5. addEventListener(event, listener) - Subscribes the passed listener to the event.
155 157
     - event - one of the events from ```JitsiMeetJS.events.connection``` object.

+ 132
- 54
lib-jitsi-meet.js
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
파일 보기


+ 12
- 12
lib-jitsi-meet.min.js
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
파일 보기


+ 5
- 4
modules/xmpp/ChatRoom.js 파일 보기

@@ -284,8 +284,9 @@ ChatRoom.prototype.onPresence = function (pres) {
284 284
         if (member.isFocus) {
285 285
             this.focusMucJid = from;
286 286
             if(!this.recording) {
287
-                this.recording = new Recorder(this.eventEmitter, this.connection,
288
-                    this.focusMucJid);
287
+                this.recording = new Recorder(this.options.recordingType,
288
+                    this.eventEmitter, this.connection, this.focusMucJid,
289
+                    this.options.jirecon, this.roomjid);
289 290
                 if(this.lastJibri)
290 291
                     this.recording.handleJibriPresence(this.lastJibri);
291 292
             }
@@ -698,9 +699,9 @@ ChatRoom.prototype.getRecordingURL = function () {
698 699
  * Starts/stops the recording
699 700
  * @param token token for authentication
700 701
  */
701
-ChatRoom.prototype.toggleRecording = function (token, followEntity) {
702
+ChatRoom.prototype.toggleRecording = function (options) {
702 703
     if(this.recording)
703
-        return this.recording.toggleRecording(token, followEntity);
704
+        return this.recording.toggleRecording(options);
704 705
 
705 706
     return new Promise(function(resolve, reject){
706 707
         reject(new Error("The conference is not created yet!"))});

+ 127
- 20
modules/xmpp/recording.js 파일 보기

@@ -3,15 +3,31 @@
3 3
 var XMPPEvents = require("../../service/XMPP/XMPPEvents");
4 4
 var logger = require("jitsi-meet-logger").getLogger(__filename);
5 5
 
6
-function Recording(ee, connection, focusMucJid) {
7
-    this.eventEmitter = ee;
6
+function Recording(type, eventEmitter, connection, focusMucJid, jirecon,
7
+    roomjid) {
8
+    this.eventEmitter = eventEmitter;
8 9
     this.connection = connection;
9 10
     this.state = "off";
10 11
     this.focusMucJid = focusMucJid;
12
+    this.jirecon = jirecon;
11 13
     this.url = null;
14
+    this.type = type;
12 15
     this._isSupported = false;
16
+    /**
17
+     * The ID of the jirecon recording session. Jirecon generates it when we
18
+     * initially start recording, and it needs to be used in subsequent requests
19
+     * to jirecon.
20
+     */
21
+    this.jireconRid = null;
22
+    this.roomjid = roomjid;
13 23
 }
14 24
 
25
+Recording.types = {
26
+    COLIBRI: "colibri",
27
+    JIRECON: "jirecon",
28
+    JIBRI: "jibri"
29
+};
30
+
15 31
 Recording.prototype.handleJibriPresence = function (jibri) {
16 32
     var attributes = jibri.attributes;
17 33
     if(!attributes)
@@ -26,20 +42,20 @@ Recording.prototype.handleJibriPresence = function (jibri) {
26 42
     this.eventEmitter.emit(XMPPEvents.RECORDING_STATE_CHANGED);
27 43
 };
28 44
 
29
-Recording.prototype.setRecording = function (state, streamId, followEntity,
30
-    callback, errCallback){
45
+Recording.prototype.setRecordingJibri = function (state, callback, errCallback,
46
+    options) {
31 47
     if (state == this.state){
32
-        return;
48
+        errCallback(new Error("Invalid state!"));
33 49
     }
34
-
50
+    options = options || {};
35 51
     // FIXME jibri does not accept IQ without 'url' attribute set ?
36 52
 
37 53
     var iq = $iq({to: this.focusMucJid, type: 'set'})
38 54
         .c('jibri', {
39 55
             "xmlns": 'http://jitsi.org/protocol/jibri',
40 56
             "action": (state === 'on') ? 'start' : 'stop',
41
-            "streamid": streamId,
42
-            "follow-entity": followEntity
57
+            "streamid": options.streamId,
58
+            "follow-entity": options.followEntity
43 59
         }).up();
44 60
 
45 61
     logger.log('Set jibri recording: '+state, iq.nodeTree);
@@ -56,39 +72,130 @@ Recording.prototype.setRecording = function (state, streamId, followEntity,
56 72
         });
57 73
 };
58 74
 
59
-Recording.prototype.toggleRecording = function (token, followEntity) {
75
+Recording.prototype.setRecordingJirecon =
76
+function (state, callback, errCallback, options) {
77
+    if (state == this.state){
78
+        errCallback(new Error("Invalid state!"));
79
+    }
80
+
81
+    var iq = $iq({to: this.jirecon, type: 'set'})
82
+        .c('recording', {xmlns: 'http://jitsi.org/protocol/jirecon',
83
+            action: (state === 'on') ? 'start' : 'stop',
84
+            mucjid: this.roomjid});
85
+    if (state === 'off'){
86
+        iq.attrs({rid: this.jireconRid});
87
+    }
88
+
89
+    console.log('Start recording');
90
+    var self = this;
91
+    this.connection.sendIQ(
92
+        iq,
93
+        function (result) {
94
+            // TODO wait for an IQ with the real status, since this is
95
+            // provisional?
96
+            self.jireconRid = $(result).find('recording').attr('rid');
97
+            console.log('Recording ' +
98
+                ((state === 'on') ? 'started' : 'stopped') +
99
+                '(jirecon)' + result);
100
+            self.state = state;
101
+            if (state === 'off'){
102
+                self.jireconRid = null;
103
+            }
104
+
105
+            callback(state);
106
+        },
107
+        function (error) {
108
+            console.log('Failed to start recording, error: ', error);
109
+            errCallback(error);
110
+        });
111
+};
112
+
113
+// Sends a COLIBRI message which enables or disables (according to 'state')
114
+// the recording on the bridge. Waits for the result IQ and calls 'callback'
115
+// with the new recording state, according to the IQ.
116
+Recording.prototype.setRecordingColibri =
117
+function (state, callback, errCallback, options) {
118
+    var elem = $iq({to: this.focusMucJid, type: 'set'});
119
+    elem.c('conference', {
120
+        xmlns: 'http://jitsi.org/protocol/colibri'
121
+    });
122
+    elem.c('recording', {state: state, token: options.token});
123
+
124
+    var self = this;
125
+    this.connection.sendIQ(elem,
126
+        function (result) {
127
+            console.log('Set recording "', state, '". Result:', result);
128
+            var recordingElem = $(result).find('>conference>recording');
129
+            var newState = recordingElem.attr('state');
130
+
131
+            self.state = newState;
132
+            callback(newState);
133
+
134
+            if (newState === 'pending') {
135
+                connection.addHandler(function(iq){
136
+                    var state = $(iq).find('recording').attr('state');
137
+                    if (state) {
138
+                        self.state = newState;
139
+                        callback(state);
140
+                    }
141
+                }, 'http://jitsi.org/protocol/colibri', 'iq', null, null, null);
142
+            }
143
+        },
144
+        function (error) {
145
+            console.warn(error);
146
+            errCallback(error);
147
+        }
148
+    );
149
+};
150
+
151
+Recording.prototype.setRecording =
152
+function (state, callback, errCallback, options) {
153
+    switch(this.type){
154
+        case Recording.types.JIRECON:
155
+            this.setRecordingJirecon(state, callback, errCallback, options);
156
+            break;
157
+        case Recording.types.COLIBRI:
158
+            this.setRecordingColibri(state, callback, errCallback, options);
159
+            break;
160
+        case Recording.types.JIBRI:
161
+            this.setRecordingJibri(state, callback, errCallback, options);
162
+            break;
163
+        default:
164
+            console.error("Unknown recording type!");
165
+            return;
166
+    }
167
+};
168
+
169
+Recording.prototype.toggleRecording = function (options) {
60 170
     var self = this;
61 171
     return new Promise(function(resolve, reject) {
62
-        if (!token) {
172
+        if ((!options.token && self.type === Recording.types.COLIBRI) ||
173
+            (!options.streamId && self.type === Recording.types.JIBRI)){
63 174
             reject(new Error("No token passed!"));
64 175
             logger.error("No token passed!");
65 176
             return;
66 177
         }
67
-        if(self.state === "on") {
68
-            reject(new Error("Recording is already started!"));
69
-            logger.error("Recording is already started!");
70
-            return;
71
-        }
72 178
 
73 179
         var oldState = self.state;
74 180
         var newState = (oldState === 'off' || !oldState) ? 'on' : 'off';
75 181
 
76 182
         self.setRecording(newState,
77
-            token, followEntity,
78 183
             function (state, url) {
79 184
                 logger.log("New recording state: ", state);
80 185
                 if (state && state !== oldState) {
186
+                    if(state !== "on" && state !== "off") {
187
+                     //state === "pending" we are waiting for the real state
188
+                        return;
189
+                    }
81 190
                     self.state = state;
82 191
                     self.url = url;
83 192
                     resolve();
84 193
                 } else {
85 194
                     reject(new Error("State not changed!"));
86 195
                 }
87
-            },
88
-            function (error) {
196
+            }, function (error) {
89 197
                 reject(error);
90
-            }
91
-        );
198
+            }, options);
92 199
     });
93 200
 };
94 201
 

Loading…
취소
저장