You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

recording.js 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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. /**
  12. * The ID of the jirecon recording session. Jirecon generates it when we
  13. * initially start recording, and it needs to be used in subsequent requests
  14. * to jirecon.
  15. */
  16. var jireconRid = null;
  17. /**
  18. * The callback to update the recording button. Currently used from colibri
  19. * after receiving a pending status.
  20. */
  21. var recordingStateChangeCallback = null;
  22. function setRecordingToken(token) {
  23. recordingToken = token;
  24. }
  25. function setRecordingJirecon(state, token, callback, connection) {
  26. if (state == recordingEnabled){
  27. return;
  28. }
  29. var iq = $iq({to: config.hosts.jirecon, type: 'set'})
  30. .c('recording', {xmlns: 'http://jitsi.org/protocol/jirecon',
  31. action: (state === 'on') ? 'start' : 'stop',
  32. mucjid: connection.emuc.roomjid});
  33. if (state === 'off'){
  34. iq.attrs({rid: jireconRid});
  35. }
  36. console.log('Start recording');
  37. connection.sendIQ(
  38. iq,
  39. function (result) {
  40. // TODO wait for an IQ with the real status, since this is
  41. // provisional?
  42. jireconRid = $(result).find('recording').attr('rid');
  43. console.log('Recording ' +
  44. ((state === 'on') ? 'started' : 'stopped') +
  45. '(jirecon)' + result);
  46. recordingEnabled = state;
  47. if (state === 'off'){
  48. jireconRid = null;
  49. }
  50. callback(state);
  51. },
  52. function (error) {
  53. console.log('Failed to start recording, error: ', error);
  54. callback(recordingEnabled);
  55. });
  56. }
  57. // Sends a COLIBRI message which enables or disables (according to 'state')
  58. // the recording on the bridge. Waits for the result IQ and calls 'callback'
  59. // with the new recording state, according to the IQ.
  60. function setRecordingColibri(state, token, callback, connection) {
  61. var elem = $iq({to: connection.emuc.focusMucJid, type: 'set'});
  62. elem.c('conference', {
  63. xmlns: 'http://jitsi.org/protocol/colibri'
  64. });
  65. elem.c('recording', {state: state, token: token});
  66. connection.sendIQ(elem,
  67. function (result) {
  68. console.log('Set recording "', state, '". Result:', result);
  69. var recordingElem = $(result).find('>conference>recording');
  70. var newState = recordingElem.attr('state');
  71. recordingEnabled = newState;
  72. callback(newState);
  73. if (newState === 'pending' && !recordingStateChangeCallback) {
  74. recordingStateChangeCallback = callback;
  75. connection.addHandler(function(iq){
  76. var state = $(iq).find('recording').attr('state');
  77. if (state)
  78. recordingStateChangeCallback(state);
  79. }, 'http://jitsi.org/protocol/colibri', 'iq', null, null, null);
  80. }
  81. },
  82. function (error) {
  83. console.warn(error);
  84. callback(recordingEnabled);
  85. }
  86. );
  87. }
  88. function setRecording(state, token, callback, connection) {
  89. if (useJirecon){
  90. setRecordingJirecon(state, token, callback, connection);
  91. } else {
  92. setRecordingColibri(state, token, callback, connection);
  93. }
  94. }
  95. var Recording = {
  96. init: function () {
  97. useJirecon = config.hosts &&
  98. (typeof config.hosts.jirecon != "undefined");
  99. },
  100. toggleRecording: function (tokenEmptyCallback,
  101. recordingStateChangeCallback,
  102. connection) {
  103. if (!Moderator.isModerator()) {
  104. console.log(
  105. 'non-focus, or conference not yet organized:' +
  106. ' not enabling recording');
  107. return;
  108. }
  109. var self = this;
  110. // Jirecon does not (currently) support a token.
  111. if (!recordingToken && !useJirecon) {
  112. tokenEmptyCallback(function (value) {
  113. setRecordingToken(value);
  114. self.toggleRecording(tokenEmptyCallback,
  115. recordingStateChangeCallback,
  116. connection);
  117. });
  118. return;
  119. }
  120. var oldState = recordingEnabled;
  121. var newState = (oldState === 'off' || !oldState) ? 'on' : 'off';
  122. setRecording(newState,
  123. recordingToken,
  124. function (state) {
  125. console.log("New recording state: ", state);
  126. if (state === oldState) {
  127. // FIXME: new focus:
  128. // this will not work when moderator changes
  129. // during active session. Then it will assume that
  130. // recording status has changed to true, but it might have
  131. // been already true(and we only received actual status from
  132. // the focus).
  133. //
  134. // SO we start with status null, so that it is initialized
  135. // here and will fail only after second click, so if invalid
  136. // token was used we have to press the button twice before
  137. // current status will be fetched and token will be reset.
  138. //
  139. // Reliable way would be to return authentication error.
  140. // Or status update when moderator connects.
  141. // Or we have to stop recording session when current
  142. // moderator leaves the room.
  143. // Failed to change, reset the token because it might
  144. // have been wrong
  145. setRecordingToken(null);
  146. }
  147. recordingStateChangeCallback(state);
  148. },
  149. connection
  150. );
  151. }
  152. };
  153. module.exports = Recording;