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.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Copyright @ 2015 Atlassian Pty Ltd
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* global $, $iq, config, connection, focusMucJid, messageHandler, Moderator,
  17. Toolbar, Util */
  18. var Moderator = require("./moderator");
  19. var recordingToken = null;
  20. var recordingEnabled;
  21. /**
  22. * Whether to use a jirecon component for recording, or use the videobridge
  23. * through COLIBRI.
  24. */
  25. var useJirecon = (typeof config.hosts.jirecon != "undefined");
  26. /**
  27. * The ID of the jirecon recording session. Jirecon generates it when we
  28. * initially start recording, and it needs to be used in subsequent requests
  29. * to jirecon.
  30. */
  31. var jireconRid = null;
  32. function setRecordingToken(token) {
  33. recordingToken = token;
  34. }
  35. function setRecording(state, token, callback, connection) {
  36. if (useJirecon){
  37. setRecordingJirecon(state, token, callback, connection);
  38. } else {
  39. setRecordingColibri(state, token, callback, connection);
  40. }
  41. }
  42. function setRecordingJirecon(state, token, callback, connection) {
  43. if (state == recordingEnabled){
  44. return;
  45. }
  46. var iq = $iq({to: config.hosts.jirecon, type: 'set'})
  47. .c('recording', {xmlns: 'http://jitsi.org/protocol/jirecon',
  48. action: state ? 'start' : 'stop',
  49. mucjid: connection.emuc.roomjid});
  50. if (!state){
  51. iq.attrs({rid: jireconRid});
  52. }
  53. console.log('Start recording');
  54. connection.sendIQ(
  55. iq,
  56. function (result) {
  57. // TODO wait for an IQ with the real status, since this is
  58. // provisional?
  59. jireconRid = $(result).find('recording').attr('rid');
  60. console.log('Recording ' + (state ? 'started' : 'stopped') +
  61. '(jirecon)' + result);
  62. recordingEnabled = state;
  63. if (!state){
  64. jireconRid = null;
  65. }
  66. callback(state);
  67. },
  68. function (error) {
  69. console.log('Failed to start recording, error: ', error);
  70. callback(recordingEnabled);
  71. });
  72. }
  73. // Sends a COLIBRI message which enables or disables (according to 'state')
  74. // the recording on the bridge. Waits for the result IQ and calls 'callback'
  75. // with the new recording state, according to the IQ.
  76. function setRecordingColibri(state, token, callback, connection) {
  77. var elem = $iq({to: connection.emuc.focusMucJid, type: 'set'});
  78. elem.c('conference', {
  79. xmlns: 'http://jitsi.org/protocol/colibri'
  80. });
  81. elem.c('recording', {state: state, token: token});
  82. connection.sendIQ(elem,
  83. function (result) {
  84. console.log('Set recording "', state, '". Result:', result);
  85. var recordingElem = $(result).find('>conference>recording');
  86. var newState = ('true' === recordingElem.attr('state'));
  87. recordingEnabled = newState;
  88. callback(newState);
  89. },
  90. function (error) {
  91. console.warn(error);
  92. callback(recordingEnabled);
  93. }
  94. );
  95. }
  96. var Recording = {
  97. toggleRecording: function (tokenEmptyCallback,
  98. startingCallback, startedCallback, connection) {
  99. if (!Moderator.isModerator()) {
  100. console.log(
  101. 'non-focus, or conference not yet organized:' +
  102. ' not enabling recording');
  103. return;
  104. }
  105. var self = this;
  106. // Jirecon does not (currently) support a token.
  107. if (!recordingToken && !useJirecon) {
  108. tokenEmptyCallback(function (value) {
  109. setRecordingToken(value);
  110. self.toggleRecording(tokenEmptyCallback,
  111. startingCallback, startedCallback, connection);
  112. });
  113. return;
  114. }
  115. var oldState = recordingEnabled;
  116. startingCallback(!oldState);
  117. setRecording(!oldState,
  118. recordingToken,
  119. function (state) {
  120. console.log("New recording state: ", state);
  121. if (state === oldState) {
  122. // FIXME: new focus:
  123. // this will not work when moderator changes
  124. // during active session. Then it will assume that
  125. // recording status has changed to true, but it might have
  126. // been already true(and we only received actual status from
  127. // the focus).
  128. //
  129. // SO we start with status null, so that it is initialized
  130. // here and will fail only after second click, so if invalid
  131. // token was used we have to press the button twice before
  132. // current status will be fetched and token will be reset.
  133. //
  134. // Reliable way would be to return authentication error.
  135. // Or status update when moderator connects.
  136. // Or we have to stop recording session when current
  137. // moderator leaves the room.
  138. // Failed to change, reset the token because it might
  139. // have been wrong
  140. setRecordingToken(null);
  141. }
  142. startedCallback(state);
  143. },
  144. connection
  145. );
  146. }
  147. }
  148. module.exports = Recording;