Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

functions.js 7.2KB

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