Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

ActiveDeviceDetector.js 3.8KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { getLogger } from 'jitsi-meet-logger';
  2. import * as JitsiTrackEvents from '../../JitsiTrackEvents';
  3. import RTC from '../RTC/RTC';
  4. import Statistics from '../statistics/statistics';
  5. const logger = getLogger(__filename);
  6. // If after 3000 ms the detector did not find any active devices consider that there aren't any usable ones available
  7. // i.e. audioLevel > 0.008
  8. const DETECTION_TIMEOUT = 3000;
  9. /**
  10. * Go through all audio devices on the system and return one that is active, i.e. has audio signal.
  11. *
  12. * @returns Promise<Object> - Object containing information about the found device.
  13. */
  14. export default function getActiveAudioDevice() {
  15. return new Promise(resolve => {
  16. RTC.enumerateDevices(devices => {
  17. const audioDevices = devices.filter(device => device.kind === 'audioinput');
  18. const devicePromiseArray = [];
  19. for (const micDevice of audioDevices) {
  20. const devicePromise = RTC.obtainAudioAndVideoPermissions({ devices: [ 'audio' ],
  21. micDeviceId: micDevice.deviceId }).then(tracks => {
  22. // We expect a single device to be available when obtained from obtainAudioAndVideoPermissions
  23. // that's why only take p.value[0].
  24. const track = tracks[0];
  25. const originalStream = track.getOriginalStream();
  26. Statistics.startLocalStats(originalStream, track.setAudioLevel.bind(track));
  27. track.addEventListener(JitsiTrackEvents.LOCAL_TRACK_STOPPED, () => {
  28. Statistics.stopLocalStats(originalStream);
  29. });
  30. return track;
  31. });
  32. devicePromiseArray.push(devicePromise);
  33. }
  34. Promise.allSettled(devicePromiseArray).then(outcomeArray => {
  35. const successfulPromises = outcomeArray.filter(p => p.status === 'fulfilled');
  36. const rejectedPromises = outcomeArray.filter(p => p.status === 'rejected');
  37. const availableDevices = successfulPromises.map(p => p.value);
  38. const rejectReasons = rejectedPromises.map(p => p.value);
  39. for (const reason of rejectReasons) {
  40. logger.error('Failed to acquire audio device with error: ', reason);
  41. }
  42. // Setup event handlers for monitored devices.
  43. for (const device of availableDevices) {
  44. device.on(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevel => {
  45. // This is a very naive approach but works, a more accurate one would be to use rnnoise in
  46. // order to limit the number of false positives. The 0.008 constant is due to how
  47. // LocalStatsCollector from lib-jitsi-meet publishes audio-levels, in this case 0.008 denotes //
  48. // no input.
  49. if (audioLevel > 0.008) {
  50. stopActiveDevices(availableDevices);
  51. resolve({ deviceId: device.deviceId,
  52. deviceLabel: device.track.label });
  53. }
  54. });
  55. }
  56. // Cancel the detection in case no devices was found with audioLevel > 0 in the set timeout.
  57. setTimeout(() => {
  58. stopActiveDevices(availableDevices);
  59. resolve({ deviceId: '',
  60. deviceLabel: '' });
  61. }, DETECTION_TIMEOUT);
  62. });
  63. });
  64. });
  65. }
  66. /**
  67. * Stop the streams of the provided JitsiLocalTracks.
  68. *
  69. * @param {Array<JitsiLocalTrack>} deviceList - Array of JitsiLocalTracks to stop.
  70. * @returns {void}
  71. */
  72. function stopActiveDevices(deviceList) {
  73. for (const device of deviceList) {
  74. device.stopStream();
  75. }
  76. }