Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

recording.js 7.4KB

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