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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import JitsiMeetJS from '../lib-jitsi-meet';
  2. import {
  3. getUserSelectedOutputDeviceId,
  4. updateSettings
  5. } from '../settings';
  6. import {
  7. ADD_PENDING_DEVICE_REQUEST,
  8. CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
  9. REMOVE_PENDING_DEVICE_REQUESTS,
  10. SET_AUDIO_INPUT_DEVICE,
  11. SET_VIDEO_INPUT_DEVICE,
  12. UPDATE_DEVICE_LIST
  13. } from './actionTypes';
  14. import {
  15. areDeviceLabelsInitialized,
  16. getDeviceIdByLabel,
  17. getDevicesFromURL,
  18. setAudioOutputDeviceId
  19. } from './functions';
  20. const logger = require('jitsi-meet-logger').getLogger(__filename);
  21. /**
  22. * Adds a pending device request.
  23. *
  24. * @param {Object} request - The request to be added.
  25. * @returns {{
  26. * type: ADD_PENDING_DEVICE_REQUEST,
  27. * request: Object
  28. * }}
  29. */
  30. export function addPendingDeviceRequest(request) {
  31. return {
  32. type: ADD_PENDING_DEVICE_REQUEST,
  33. request
  34. };
  35. }
  36. /**
  37. * Configures the initial A/V devices before the conference has started.
  38. *
  39. * @returns {Function}
  40. */
  41. export function configureInitialDevices() {
  42. return (dispatch, getState) => {
  43. const deviceLabels = getDevicesFromURL(getState());
  44. let updateSettingsPromise;
  45. if (deviceLabels) {
  46. updateSettingsPromise = dispatch(getAvailableDevices()).then(() => {
  47. const state = getState();
  48. if (!areDeviceLabelsInitialized(state)) {
  49. // The labels are not available if the A/V permissions are
  50. // not yet granted.
  51. Object.keys(deviceLabels).forEach(key => {
  52. dispatch(addPendingDeviceRequest({
  53. type: 'devices',
  54. name: 'setDevice',
  55. device: {
  56. kind: key.toLowerCase(),
  57. label: deviceLabels[key]
  58. },
  59. // eslint-disable-next-line no-empty-function
  60. responseCallback() {}
  61. }));
  62. });
  63. return;
  64. }
  65. const newSettings = {};
  66. const devicesKeysToSettingsKeys = {
  67. audioInput: 'micDeviceId',
  68. audioOutput: 'audioOutputDeviceId',
  69. videoInput: 'cameraDeviceId'
  70. };
  71. Object.keys(deviceLabels).forEach(key => {
  72. const label = deviceLabels[key];
  73. const deviceId = getDeviceIdByLabel(state, label, key);
  74. if (deviceId) {
  75. newSettings[devicesKeysToSettingsKeys[key]] = deviceId;
  76. }
  77. });
  78. dispatch(updateSettings(newSettings));
  79. });
  80. } else {
  81. updateSettingsPromise = Promise.resolve();
  82. }
  83. return updateSettingsPromise
  84. .then(() => {
  85. const userSelectedAudioOutputDeviceId = getUserSelectedOutputDeviceId(getState());
  86. return setAudioOutputDeviceId(userSelectedAudioOutputDeviceId, dispatch)
  87. .catch(ex => logger.warn(`Failed to set audio output device.
  88. Default audio output device will be used instead ${ex}`));
  89. });
  90. };
  91. }
  92. /**
  93. * Queries for connected A/V input and output devices and updates the redux
  94. * state of known devices.
  95. *
  96. * @returns {Function}
  97. */
  98. export function getAvailableDevices() {
  99. return dispatch => new Promise(resolve => {
  100. const { mediaDevices } = JitsiMeetJS;
  101. if (mediaDevices.isDeviceListAvailable()
  102. && mediaDevices.isDeviceChangeAvailable()) {
  103. mediaDevices.enumerateDevices(devices => {
  104. dispatch(updateDeviceList(devices));
  105. resolve(devices);
  106. });
  107. } else {
  108. resolve([]);
  109. }
  110. });
  111. }
  112. /**
  113. * Remove all pending device requests.
  114. *
  115. * @returns {{
  116. * type: REMOVE_PENDING_DEVICE_REQUESTS
  117. * }}
  118. */
  119. export function removePendingDeviceRequests() {
  120. return {
  121. type: REMOVE_PENDING_DEVICE_REQUESTS
  122. };
  123. }
  124. /**
  125. * Signals to update the currently used audio input device.
  126. *
  127. * @param {string} deviceId - The id of the new audio input device.
  128. * @returns {{
  129. * type: SET_AUDIO_INPUT_DEVICE,
  130. * deviceId: string
  131. * }}
  132. */
  133. export function setAudioInputDevice(deviceId) {
  134. return {
  135. type: SET_AUDIO_INPUT_DEVICE,
  136. deviceId
  137. };
  138. }
  139. /**
  140. * Signals to update the currently used video input device.
  141. *
  142. * @param {string} deviceId - The id of the new video input device.
  143. * @returns {{
  144. * type: SET_VIDEO_INPUT_DEVICE,
  145. * deviceId: string
  146. * }}
  147. */
  148. export function setVideoInputDevice(deviceId) {
  149. return {
  150. type: SET_VIDEO_INPUT_DEVICE,
  151. deviceId
  152. };
  153. }
  154. /**
  155. * Signals to update the list of known audio and video devices.
  156. *
  157. * @param {Array<MediaDeviceInfo>} devices - All known available audio input,
  158. * audio output, and video input devices.
  159. * @returns {{
  160. * type: UPDATE_DEVICE_LIST,
  161. * devices: Array<MediaDeviceInfo>
  162. * }}
  163. */
  164. export function updateDeviceList(devices) {
  165. return {
  166. type: UPDATE_DEVICE_LIST,
  167. devices
  168. };
  169. }
  170. /**
  171. * Signals to check new and old devices for newly added devices and notify.
  172. *
  173. * @param {Array<MediaDeviceInfo>} newDevices - Array of the new devices.
  174. * @param {Array<MediaDeviceInfo>} oldDevices - Array of the old devices.
  175. * @returns {{
  176. * type: CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
  177. * newDevices: Array<MediaDeviceInfo>,
  178. * oldDevices: Array<MediaDeviceInfo>
  179. * }}
  180. */
  181. export function checkAndNotifyForNewDevice(newDevices, oldDevices) {
  182. return {
  183. type: CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
  184. newDevices,
  185. oldDevices
  186. };
  187. }