Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

functions.js 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // @flow
  2. import type { Dispatch } from 'redux';
  3. import {
  4. addPendingDeviceRequest,
  5. areDeviceLabelsInitialized,
  6. getAudioOutputDeviceId,
  7. getAvailableDevices,
  8. getDeviceIdByLabel,
  9. groupDevicesByKind,
  10. setAudioInputDeviceAndUpdateSettings,
  11. setAudioOutputDevice,
  12. setVideoInputDeviceAndUpdateSettings
  13. } from '../base/devices';
  14. import { isIosMobileBrowser } from '../base/environment/utils';
  15. import JitsiMeetJS from '../base/lib-jitsi-meet';
  16. import { toState } from '../base/redux';
  17. import {
  18. getUserSelectedCameraDeviceId,
  19. getUserSelectedMicDeviceId,
  20. getUserSelectedOutputDeviceId
  21. } from '../base/settings';
  22. /**
  23. * Returns the properties for the device selection dialog from Redux state.
  24. *
  25. * @param {(Function|Object)} stateful -The (whole) redux state, or redux's
  26. * {@code getState} function to be used to retrieve the state.
  27. * @returns {Object} - The properties for the device selection dialog.
  28. */
  29. export function getDeviceSelectionDialogProps(stateful: Object | Function) {
  30. const state = toState(stateful);
  31. const settings = state['features/base/settings'];
  32. const { conference } = state['features/base/conference'];
  33. const { permissions } = state['features/base/devices'];
  34. const isMobileSafari = isIosMobileBrowser();
  35. const cameraChangeSupported = JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('input');
  36. const speakerChangeSupported = JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('output');
  37. const userSelectedCamera = getUserSelectedCameraDeviceId(state);
  38. const userSelectedMic = getUserSelectedMicDeviceId(state);
  39. let disableAudioInputChange = !JitsiMeetJS.mediaDevices.isMultipleAudioInputSupported();
  40. let disableVideoInputSelect = !cameraChangeSupported;
  41. let selectedAudioInputId = isMobileSafari ? userSelectedMic : settings.micDeviceId;
  42. let selectedAudioOutputId = getAudioOutputDeviceId();
  43. let selectedVideoInputId = isMobileSafari ? userSelectedCamera : settings.cameraDeviceId;
  44. // audio input change will be a problem only when we are in a
  45. // conference and this is not supported, when we open device selection on
  46. // welcome page changing input devices will not be a problem
  47. // on welcome page we also show only what we have saved as user selected devices
  48. if (!conference) {
  49. disableAudioInputChange = false;
  50. disableVideoInputSelect = false;
  51. selectedAudioInputId = userSelectedMic;
  52. selectedAudioOutputId = getUserSelectedOutputDeviceId(state);
  53. selectedVideoInputId = userSelectedCamera;
  54. }
  55. // we fill the device selection dialog with the devices that are currently
  56. // used or if none are currently used with what we have in settings(user selected)
  57. return {
  58. availableDevices: state['features/base/devices'].availableDevices,
  59. disableAudioInputChange,
  60. disableDeviceChange: !JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(),
  61. disableVideoInputSelect,
  62. hasAudioPermission: permissions.audio,
  63. hasVideoPermission: permissions.video,
  64. hideAudioInputPreview: disableAudioInputChange || !JitsiMeetJS.isCollectingLocalStats(),
  65. hideAudioOutputPreview: !speakerChangeSupported,
  66. hideAudioOutputSelect: !speakerChangeSupported,
  67. hideVideoInputPreview: !cameraChangeSupported,
  68. selectedAudioInputId,
  69. selectedAudioOutputId,
  70. selectedVideoInputId
  71. };
  72. }
  73. /**
  74. * Processes device requests from external applications.
  75. *
  76. * @param {Dispatch} dispatch - The redux {@code dispatch} function.
  77. * @param {Function} getState - The redux function that gets/retrieves the redux
  78. * state.
  79. * @param {Object} request - The request to be processed.
  80. * @param {Function} responseCallback - The callback that will send the
  81. * response.
  82. * @returns {boolean} - True if the request has been processed and false otherwise.
  83. */
  84. export function processExternalDeviceRequest( // eslint-disable-line max-params
  85. dispatch: Dispatch<any>,
  86. getState: Function,
  87. request: Object,
  88. responseCallback: Function) {
  89. if (request.type !== 'devices') {
  90. return false;
  91. }
  92. const state = getState();
  93. const settings = state['features/base/settings'];
  94. let result = true;
  95. switch (request.name) {
  96. case 'isDeviceListAvailable':
  97. responseCallback(JitsiMeetJS.mediaDevices.isDeviceListAvailable());
  98. break;
  99. case 'isDeviceChangeAvailable':
  100. responseCallback(
  101. JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(
  102. request.deviceType));
  103. break;
  104. case 'isMultipleAudioInputSupported':
  105. responseCallback(JitsiMeetJS.isMultipleAudioInputSupported());
  106. break;
  107. case 'getCurrentDevices':
  108. dispatch(getAvailableDevices()).then(devices => {
  109. if (areDeviceLabelsInitialized(state)) {
  110. const deviceDescriptions = {
  111. audioInput: undefined,
  112. audioOutput: undefined,
  113. videoInput: undefined
  114. };
  115. const currentlyUsedDeviceIds = new Set([
  116. getAudioOutputDeviceId(),
  117. settings.micDeviceId,
  118. settings.cameraDeviceId
  119. ]);
  120. devices.forEach(device => {
  121. const { deviceId, kind } = device;
  122. if (currentlyUsedDeviceIds.has(deviceId)) {
  123. switch (kind) {
  124. case 'audioinput':
  125. deviceDescriptions.audioInput = device;
  126. break;
  127. case 'audiooutput':
  128. deviceDescriptions.audioOutput = device;
  129. break;
  130. case 'videoinput':
  131. deviceDescriptions.videoInput = device;
  132. break;
  133. }
  134. }
  135. });
  136. responseCallback(deviceDescriptions);
  137. } else {
  138. // The labels are not available if the A/V permissions are
  139. // not yet granted.
  140. dispatch(addPendingDeviceRequest({
  141. type: 'devices',
  142. name: 'getCurrentDevices',
  143. responseCallback
  144. }));
  145. }
  146. });
  147. break;
  148. case 'getAvailableDevices':
  149. dispatch(getAvailableDevices()).then(devices => {
  150. if (areDeviceLabelsInitialized(state)) {
  151. responseCallback(groupDevicesByKind(devices));
  152. } else {
  153. // The labels are not available if the A/V permissions are
  154. // not yet granted.
  155. dispatch(addPendingDeviceRequest({
  156. type: 'devices',
  157. name: 'getAvailableDevices',
  158. responseCallback
  159. }));
  160. }
  161. });
  162. break;
  163. case 'setDevice': {
  164. const { device } = request;
  165. if (!areDeviceLabelsInitialized(state)) {
  166. dispatch(addPendingDeviceRequest({
  167. type: 'devices',
  168. name: 'setDevice',
  169. device,
  170. responseCallback
  171. }));
  172. return true;
  173. }
  174. const { label, id } = device;
  175. const deviceId = label
  176. ? getDeviceIdByLabel(state, device.label, device.kind)
  177. : id;
  178. if (deviceId) {
  179. switch (device.kind) {
  180. case 'audioinput':
  181. dispatch(setAudioInputDeviceAndUpdateSettings(deviceId));
  182. break;
  183. case 'audiooutput':
  184. dispatch(setAudioOutputDevice(deviceId));
  185. break;
  186. case 'videoinput':
  187. dispatch(setVideoInputDeviceAndUpdateSettings(deviceId));
  188. break;
  189. default:
  190. result = false;
  191. }
  192. } else {
  193. result = false;
  194. }
  195. responseCallback(result);
  196. break;
  197. }
  198. default:
  199. return false;
  200. }
  201. return true;
  202. }