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.

functions.js 7.0KB

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