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.

actions.js 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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. NOTIFY_CAMERA_ERROR,
  10. NOTIFY_MIC_ERROR,
  11. REMOVE_PENDING_DEVICE_REQUESTS,
  12. SET_AUDIO_INPUT_DEVICE,
  13. SET_VIDEO_INPUT_DEVICE,
  14. UPDATE_DEVICE_LIST
  15. } from './actionTypes';
  16. import {
  17. areDeviceLabelsInitialized,
  18. getDeviceIdByLabel,
  19. getDevicesFromURL,
  20. setAudioOutputDeviceId
  21. } from './functions';
  22. const logger = require('jitsi-meet-logger').getLogger(__filename);
  23. /**
  24. * Maps the WebRTC string for device type to the keys used to store configure,
  25. * within redux, which devices should be used by default.
  26. */
  27. const DEVICE_TYPE_TO_SETTINGS_KEYS = {
  28. audioInput: {
  29. currentDeviceId: 'micDeviceId',
  30. userSelectedDeviceId: 'userSelectedMicDeviceId',
  31. userSelectedDeviceLabel: 'userSelectedMicDeviceLabel'
  32. },
  33. audioOutput: {
  34. currentDeviceId: 'audioOutputDeviceId',
  35. userSelectedDeviceId: 'userSelectedAudioOutputDeviceId',
  36. userSelectedDeviceLabel: 'userSelectedAudioOutputDeviceLabel'
  37. },
  38. videoInput: {
  39. currentDeviceId: 'audioOutputDeviceId',
  40. userSelectedDeviceId: 'userSelectedCameraDeviceId',
  41. userSelectedDeviceLabel: 'userSelectedCameraDeviceLabel'
  42. }
  43. };
  44. /**
  45. * Adds a pending device request.
  46. *
  47. * @param {Object} request - The request to be added.
  48. * @returns {{
  49. * type: ADD_PENDING_DEVICE_REQUEST,
  50. * request: Object
  51. * }}
  52. */
  53. export function addPendingDeviceRequest(request) {
  54. return {
  55. type: ADD_PENDING_DEVICE_REQUEST,
  56. request
  57. };
  58. }
  59. /**
  60. * Configures the initial A/V devices before the conference has started.
  61. *
  62. * @returns {Function}
  63. */
  64. export function configureInitialDevices() {
  65. return (dispatch, getState) => {
  66. const deviceLabels = getDevicesFromURL(getState());
  67. let updateSettingsPromise;
  68. if (deviceLabels) {
  69. updateSettingsPromise = dispatch(getAvailableDevices()).then(() => {
  70. const state = getState();
  71. if (!areDeviceLabelsInitialized(state)) {
  72. // The labels are not available if the A/V permissions are
  73. // not yet granted.
  74. Object.keys(deviceLabels).forEach(key => {
  75. dispatch(addPendingDeviceRequest({
  76. type: 'devices',
  77. name: 'setDevice',
  78. device: {
  79. kind: key.toLowerCase(),
  80. label: deviceLabels[key]
  81. },
  82. // eslint-disable-next-line no-empty-function
  83. responseCallback() {}
  84. }));
  85. });
  86. return;
  87. }
  88. const newSettings = {};
  89. Object.keys(deviceLabels).forEach(key => {
  90. const label = deviceLabels[key];
  91. const deviceId = getDeviceIdByLabel(state, label, key);
  92. if (deviceId) {
  93. const settingsTranslationMap = DEVICE_TYPE_TO_SETTINGS_KEYS[key];
  94. newSettings[settingsTranslationMap.currentDeviceId] = deviceId;
  95. newSettings[settingsTranslationMap.userSelectedDeviceId] = deviceId;
  96. newSettings[settingsTranslationMap.userSelectedDeviceLabel] = label;
  97. }
  98. });
  99. dispatch(updateSettings(newSettings));
  100. });
  101. } else {
  102. updateSettingsPromise = Promise.resolve();
  103. }
  104. return updateSettingsPromise
  105. .then(() => {
  106. const userSelectedAudioOutputDeviceId = getUserSelectedOutputDeviceId(getState());
  107. return setAudioOutputDeviceId(userSelectedAudioOutputDeviceId, dispatch)
  108. .catch(ex => logger.warn(`Failed to set audio output device.
  109. Default audio output device will be used instead ${ex}`));
  110. });
  111. };
  112. }
  113. /**
  114. * Queries for connected A/V input and output devices and updates the redux
  115. * state of known devices.
  116. *
  117. * @returns {Function}
  118. */
  119. export function getAvailableDevices() {
  120. return dispatch => new Promise(resolve => {
  121. const { mediaDevices } = JitsiMeetJS;
  122. if (mediaDevices.isDeviceListAvailable()
  123. && mediaDevices.isDeviceChangeAvailable()) {
  124. mediaDevices.enumerateDevices(devices => {
  125. dispatch(updateDeviceList(devices));
  126. resolve(devices);
  127. });
  128. } else {
  129. resolve([]);
  130. }
  131. });
  132. }
  133. /**
  134. * Signals that an error occurred while trying to obtain a track from a camera.
  135. *
  136. * @param {Object} error - The device error, as provided by lib-jitsi-meet.
  137. * @param {string} error.name - The constant for the type of the error.
  138. * @param {string} error.message - Optional additional information about the
  139. * error.
  140. * @returns {{
  141. * type: NOTIFY_CAMERA_ERROR,
  142. * error: Object
  143. * }}
  144. */
  145. export function notifyCameraError(error) {
  146. return {
  147. type: NOTIFY_CAMERA_ERROR,
  148. error
  149. };
  150. }
  151. /**
  152. * Signals that an error occurred while trying to obtain a track from a mic.
  153. *
  154. * @param {Object} error - The device error, as provided by lib-jitsi-meet.
  155. * @param {Object} error.name - The constant for the type of the error.
  156. * @param {string} error.message - Optional additional information about the
  157. * error.
  158. * @returns {{
  159. * type: NOTIFY_MIC_ERROR,
  160. * error: Object
  161. * }}
  162. */
  163. export function notifyMicError(error) {
  164. return {
  165. type: NOTIFY_MIC_ERROR,
  166. error
  167. };
  168. }
  169. /**
  170. * Remove all pending device requests.
  171. *
  172. * @returns {{
  173. * type: REMOVE_PENDING_DEVICE_REQUESTS
  174. * }}
  175. */
  176. export function removePendingDeviceRequests() {
  177. return {
  178. type: REMOVE_PENDING_DEVICE_REQUESTS
  179. };
  180. }
  181. /**
  182. * Signals to update the currently used audio input device.
  183. *
  184. * @param {string} deviceId - The id of the new audio input device.
  185. * @returns {{
  186. * type: SET_AUDIO_INPUT_DEVICE,
  187. * deviceId: string
  188. * }}
  189. */
  190. export function setAudioInputDevice(deviceId) {
  191. return {
  192. type: SET_AUDIO_INPUT_DEVICE,
  193. deviceId
  194. };
  195. }
  196. /**
  197. * Signals to update the currently used video input device.
  198. *
  199. * @param {string} deviceId - The id of the new video input device.
  200. * @returns {{
  201. * type: SET_VIDEO_INPUT_DEVICE,
  202. * deviceId: string
  203. * }}
  204. */
  205. export function setVideoInputDevice(deviceId) {
  206. return {
  207. type: SET_VIDEO_INPUT_DEVICE,
  208. deviceId
  209. };
  210. }
  211. /**
  212. * Signals to update the list of known audio and video devices.
  213. *
  214. * @param {Array<MediaDeviceInfo>} devices - All known available audio input,
  215. * audio output, and video input devices.
  216. * @returns {{
  217. * type: UPDATE_DEVICE_LIST,
  218. * devices: Array<MediaDeviceInfo>
  219. * }}
  220. */
  221. export function updateDeviceList(devices) {
  222. return {
  223. type: UPDATE_DEVICE_LIST,
  224. devices
  225. };
  226. }
  227. /**
  228. * Signals to check new and old devices for newly added devices and notify.
  229. *
  230. * @param {Array<MediaDeviceInfo>} newDevices - Array of the new devices.
  231. * @param {Array<MediaDeviceInfo>} oldDevices - Array of the old devices.
  232. * @returns {{
  233. * type: CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
  234. * newDevices: Array<MediaDeviceInfo>,
  235. * oldDevices: Array<MediaDeviceInfo>
  236. * }}
  237. */
  238. export function checkAndNotifyForNewDevice(newDevices, oldDevices) {
  239. return {
  240. type: CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
  241. newDevices,
  242. oldDevices
  243. };
  244. }