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.

AbstractAudioContextAdapter.js 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import logger from '../logger';
  2. import { RecordingAdapter } from './RecordingAdapter';
  3. /**
  4. * Base class for {@code AudioContext}-based recording adapters.
  5. */
  6. export class AbstractAudioContextAdapter extends RecordingAdapter {
  7. /**
  8. * The {@code AudioContext} instance.
  9. */
  10. _audioContext = null;
  11. /**
  12. * The {@code ScriptProcessorNode} instance.
  13. */
  14. _audioProcessingNode = null;
  15. /**
  16. * The {@code MediaStreamAudioSourceNode} instance.
  17. */
  18. _audioSource = null;
  19. /**
  20. * The {@code MediaStream} instance, representing the current audio device.
  21. */
  22. _stream = null;
  23. /**
  24. * Sample rate.
  25. */
  26. _sampleRate = 44100;
  27. /**
  28. * Constructor.
  29. */
  30. constructor() {
  31. super();
  32. // sampleRate is browser and OS dependent.
  33. // Setting sampleRate explicitly is in the specs but not implemented
  34. // by browsers.
  35. // See: https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/
  36. // AudioContext#Browser_compatibility
  37. // And https://bugs.chromium.org/p/chromium/issues/detail?id=432248
  38. this._audioContext = new AudioContext();
  39. this._sampleRate = this._audioContext.sampleRate;
  40. logger.log(`Current sampleRate ${this._sampleRate}.`);
  41. }
  42. /**
  43. * Sets up the audio graph in the AudioContext.
  44. *
  45. * @protected
  46. * @param {string} micDeviceId - The current microphone device ID.
  47. * @param {Function} callback - Callback function to
  48. * handle AudioProcessingEvents.
  49. * @returns {Promise}
  50. */
  51. _initializeAudioContext(micDeviceId, callback) {
  52. if (typeof callback !== 'function') {
  53. return Promise.reject('a callback function is required.');
  54. }
  55. return this._getAudioStream(micDeviceId)
  56. .then(stream => {
  57. this._stream = stream;
  58. this._audioSource
  59. = this._audioContext.createMediaStreamSource(stream);
  60. this._audioProcessingNode
  61. = this._audioContext.createScriptProcessor(4096, 1, 1);
  62. this._audioProcessingNode.onaudioprocess = callback;
  63. logger.debug('AudioContext is set up.');
  64. })
  65. .catch(err => {
  66. logger.error(`Error calling getUserMedia(): ${err}`);
  67. return Promise.reject(err);
  68. });
  69. }
  70. /**
  71. * Connects the nodes in the {@code AudioContext} to start the flow of
  72. * audio data.
  73. *
  74. * @protected
  75. * @returns {void}
  76. */
  77. _connectAudioGraph() {
  78. this._audioSource.connect(this._audioProcessingNode);
  79. this._audioProcessingNode.connect(this._audioContext.destination);
  80. }
  81. /**
  82. * Disconnects the nodes in the {@code AudioContext}.
  83. *
  84. * @protected
  85. * @returns {void}
  86. */
  87. _disconnectAudioGraph() {
  88. this._audioProcessingNode.onaudioprocess = undefined;
  89. this._audioProcessingNode.disconnect();
  90. this._audioSource.disconnect();
  91. }
  92. /**
  93. * Replaces the current microphone MediaStream.
  94. *
  95. * @protected
  96. * @param {string} micDeviceId - New microphone ID.
  97. * @returns {Promise}
  98. */
  99. _replaceMic(micDeviceId) {
  100. if (this._audioContext && this._audioProcessingNode) {
  101. return this._getAudioStream(micDeviceId).then(newStream => {
  102. const newSource = this._audioContext
  103. .createMediaStreamSource(newStream);
  104. this._audioSource.disconnect();
  105. newSource.connect(this._audioProcessingNode);
  106. this._stream = newStream;
  107. this._audioSource = newSource;
  108. });
  109. }
  110. return Promise.resolve();
  111. }
  112. }