您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

functions.js 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. // @flow
  2. import { JitsiTrackErrors } from '../lib-jitsi-meet';
  3. import { getLocalParticipant } from '../participants';
  4. import { toState } from '../redux';
  5. import {
  6. AVATAR_ID_COMMAND,
  7. AVATAR_URL_COMMAND,
  8. EMAIL_COMMAND,
  9. JITSI_CONFERENCE_URL_KEY
  10. } from './constants';
  11. /**
  12. * Attach a set of local tracks to a conference.
  13. *
  14. * @param {JitsiConference} conference - Conference instance.
  15. * @param {JitsiLocalTrack[]} localTracks - List of local media tracks.
  16. * @protected
  17. * @returns {Promise}
  18. */
  19. export function _addLocalTracksToConference(
  20. conference: { addTrack: Function, getLocalTracks: Function },
  21. localTracks: Array<Object>) {
  22. const conferenceLocalTracks = conference.getLocalTracks();
  23. const promises = [];
  24. for (const track of localTracks) {
  25. // XXX The library lib-jitsi-meet may be draconian, for example, when
  26. // adding one and the same video track multiple times.
  27. if (conferenceLocalTracks.indexOf(track) === -1) {
  28. promises.push(
  29. conference.addTrack(track).catch(err => {
  30. _reportError(
  31. 'Failed to add local track to conference',
  32. err);
  33. }));
  34. }
  35. }
  36. return Promise.all(promises);
  37. }
  38. /**
  39. * Evaluates a specific predicate for each {@link JitsiConference} known to the
  40. * redux state features/base/conference while it returns {@code true}.
  41. *
  42. * @param {Function | Object} stateful - The redux store, state, or
  43. * {@code getState} function.
  44. * @param {Function} predicate - The predicate to evaluate for each
  45. * {@code JitsiConference} know to the redux state features/base/conference
  46. * while it returns {@code true}.
  47. * @returns {boolean} If the specified {@code predicate} returned {@code true}
  48. * for all {@code JitsiConference} instances known to the redux state
  49. * features/base/conference.
  50. */
  51. export function forEachConference(
  52. stateful: Function | Object,
  53. predicate: (Object, URL) => boolean) {
  54. const state = toState(stateful)['features/base/conference'];
  55. for (const v of Object.values(state)) {
  56. // Does the value of the base/conference's property look like a
  57. // JitsiConference?
  58. if (v && typeof v === 'object') {
  59. // $FlowFixMe
  60. const url: URL = v[JITSI_CONFERENCE_URL_KEY];
  61. // XXX The Web version of Jitsi Meet does not utilize
  62. // JITSI_CONFERENCE_URL_KEY at the time of this writing. An
  63. // alternative is necessary then to recognize JitsiConference
  64. // instances and myUserId is as good as any other property.
  65. if ((url || typeof v.myUserId === 'function')
  66. && !predicate(v, url)) {
  67. return false;
  68. }
  69. }
  70. }
  71. return true;
  72. }
  73. /**
  74. * Returns the current {@code JitsiConference} which is joining or joined and is
  75. * not leaving. Please note the contrast with merely reading the
  76. * {@code conference} state of the feature base/conference which is not joining
  77. * but may be leaving already.
  78. *
  79. * @param {Function|Object} stateful - The redux store, state, or
  80. * {@code getState} function.
  81. * @returns {JitsiConference|undefined}
  82. */
  83. export function getCurrentConference(stateful: Function | Object) {
  84. const { conference, joining, leaving }
  85. = toState(stateful)['features/base/conference'];
  86. return (
  87. conference
  88. ? conference === leaving ? undefined : conference
  89. : joining);
  90. }
  91. /**
  92. * Handle an error thrown by the backend (i.e. lib-jitsi-meet) while
  93. * manipulating a conference participant (e.g. pin or select participant).
  94. *
  95. * @param {Error} err - The Error which was thrown by the backend while
  96. * manipulating a conference participant and which is to be handled.
  97. * @protected
  98. * @returns {void}
  99. */
  100. export function _handleParticipantError(err: { message: ?string }) {
  101. // XXX DataChannels are initialized at some later point when the conference
  102. // has multiple participants, but code that pins or selects a participant
  103. // might be executed before. So here we're swallowing a particular error.
  104. // TODO Lib-jitsi-meet should be fixed to not throw such an exception in
  105. // these scenarios.
  106. if (err.message !== 'Data channels support is disabled!') {
  107. throw err;
  108. }
  109. }
  110. /**
  111. * Determines whether a specific string is a valid room name.
  112. *
  113. * @param {(string|undefined)} room - The name of the conference room to check
  114. * for validity.
  115. * @returns {boolean} If the specified room name is valid, then true; otherwise,
  116. * false.
  117. */
  118. export function isRoomValid(room: ?string) {
  119. return typeof room === 'string' && room !== '';
  120. }
  121. /**
  122. * Remove a set of local tracks from a conference.
  123. *
  124. * @param {JitsiConference} conference - Conference instance.
  125. * @param {JitsiLocalTrack[]} localTracks - List of local media tracks.
  126. * @protected
  127. * @returns {Promise}
  128. */
  129. export function _removeLocalTracksFromConference(
  130. conference: { removeTrack: Function },
  131. localTracks: Array<Object>) {
  132. return Promise.all(localTracks.map(track =>
  133. conference.removeTrack(track)
  134. .catch(err => {
  135. // Local track might be already disposed by direct
  136. // JitsiTrack#dispose() call. So we should ignore this error
  137. // here.
  138. if (err.name !== JitsiTrackErrors.TRACK_IS_DISPOSED) {
  139. _reportError(
  140. 'Failed to remove local track from conference',
  141. err);
  142. }
  143. })
  144. ));
  145. }
  146. /**
  147. * Reports a specific Error with a specific error message. While the
  148. * implementation merely logs the specified msg and err via the console at the
  149. * time of this writing, the intention of the function is to abstract the
  150. * reporting of errors and facilitate elaborating on it in the future.
  151. *
  152. * @param {string} msg - The error message to report.
  153. * @param {Error} err - The Error to report.
  154. * @private
  155. * @returns {void}
  156. */
  157. function _reportError(msg, err) {
  158. // TODO This is a good point to call some global error handler when we have
  159. // one.
  160. console.error(msg, err);
  161. }
  162. /**
  163. * Sends a representation of the local participant such as her avatar (URL),
  164. * e-mail address, and display name to (the remote participants of) a specific
  165. * conference.
  166. *
  167. * @param {Function|Object} stateful - The redux store, state, or
  168. * {@code getState} function.
  169. * @param {JitsiConference} conference - The {@code JitsiConference} to which
  170. * the representation of the local participant is to be sent.
  171. * @returns {void}
  172. */
  173. export function sendLocalParticipant(
  174. stateful: Function | Object,
  175. conference: { sendCommand: Function, setDisplayName: Function }) {
  176. const { avatarID, avatarURL, email, name } = getLocalParticipant(stateful);
  177. avatarID && conference.sendCommand(AVATAR_ID_COMMAND, {
  178. value: avatarID
  179. });
  180. avatarURL && conference.sendCommand(AVATAR_URL_COMMAND, {
  181. value: avatarURL
  182. });
  183. email && conference.sendCommand(EMAIL_COMMAND, {
  184. value: email
  185. });
  186. conference.setDisplayName(name);
  187. }