text: const { EventEmitter } = require('events');
  
  /**
   * Audio Player for Google Assistant
   */
  class AudioPlayer extends EventEmitter {
      constructor(audioOutDeviceId = 'default') {
          super();
  
          this.audioOutDeviceId = audioOutDeviceId;
          this.initialize();
      }
  
      initialize() {
          /** Variables for the Audio Player */
          this.mediaSource = new MediaSource();
  
          this.audioPlayer = new Audio();
  
          this.audioBuffer = null;
  
          this.audioQueue = [];
  
          this.setup();
          this.setupAudioProcessor();
      }
  
      /**
       * Reconstructs the current player.
       */
      reset() {
          this.initialize();
      }
  
      /**
       * Setups the player with the given buffer as source.
       */
      setup() {
          this.audioPlayer.addEventListener('waiting', () => {
              console.log('[Audio Player] Player is waiting on data...');
              this.emit('waiting');
          });
  
          this.audioPlayer.preload = 'none';
          this.audioPlayer.autoplay = true;
          this.audioPlayer.src = URL.createObjectURL(this.mediaSource);
      }
  
      /**
       * Appends or queue's audio data into the buffer.
       * @param {*} buffer
       */
      appendBuffer(buffer) {
          if (this.audioBuffer.updating || this.audioQueue.length > 0) {
              this.audioQueue.push(buffer);
          } else {
              this.audioBuffer.appendBuffer(buffer);
          }
      }
  
      /**
       * Set's up the audio processor required to process the mpeg receiving by Google.
       */
      setupAudioProcessor() {
          this.mediaSource.addEventListener('sourceopen', () => {
              this.audioBuffer = this.mediaSource.addSourceBuffer('audio/mpeg');
              this.audioBuffer.mode = 'sequence';
              this.audioBuffer.addEventListener('update', () => {
                  if (this.audioQueue.length > 0 && this.audioBuffer && !this.audioBuffer.updating) {
                      this.audioBuffer.appendBuffer(this.audioQueue.shift());
                      this.play();
                  }
              });
  
              this.audioBuffer.addEventListener('error', (e) => {
                  console.log('AudioBuffer Error: ', e);
              });
  
              this.emit('ready');
          });
      }
  
      /**
       * Play's the Audio Player if nessesary.
       */
      play() {
          this.audioPlayer.setSinkId(this.audioOutDeviceId);
  
          if (this.audioPlayer.paused) {
              this.audioPlayer.play().then(() => {
                  console.log('Assistant Audio is playing...');
              }).catch(e => console.log('something went wrong starting the player...', e));
          }
      }
  
      /**
       * Empties the audioQueue and resets the current player.
       */
      stop() {
          this.audioQueue = [];
          this.audioPlayer.src = '';
          this.reset();
      }
  
      /**
       * Sets the `sinkId` of the audio element to the given
       * speaker's device ID.
       *
       * @param {string} audioOutDeviceId
       * Device ID of desired speaker source
       */
      setDeviceId(audioOutDeviceId) {
          this.audioOutDeviceId = audioOutDeviceId;
          this.audioPlayer.setSinkId(this.audioOutDeviceId);
      }
  
      playPingStart() {
          const pingPlayer = new Audio('../res/pingStart.mp3');
          pingPlayer.setSinkId(this.audioOutDeviceId);
          pingPlayer.play();
          this.emit('ping-start');
      }
  
      playPingStop() {
          const pingPlayer = new Audio('../res/pingStop.mp3');
          pingPlayer.setSinkId(this.audioOutDeviceId);
          pingPlayer.play();
          this.emit('ping-stop');
      }
  
      playPingSuccess() {
          const pingPlayer = new Audio('../res/pingSuccess.mp3');
          pingPlayer.setSinkId(this.audioOutDeviceId);
          pingPlayer.play();
          this.emit('ping-success');
      }
  }
  
  module.exports = AudioPlayer;
  