Home Manual Reference Source

src/WebAudio/Player.js

import {authorisedRequest, request} from '../api/communication';
import AudioContext from './AudioContext';

/**
 * Player
 * Simple Audio Player based on Web Audio API technology
 */
export default class Player extends AudioContext {
  /**
   * Private object to hold AudioBuffer node.
   * @private
   */
  audioBuffer = null;

  /**
   * Private object to hold AudioBufferSourceNode node.
   * @private
   */
  audioSource = null;

  createBufferSource() {
    this.disconnectBufferSource();

    // Create a sound source
    this.audioSource = this.audioContext.createBufferSource();

    // Select what to play
    this.audioSource.buffer = this.audioBuffer;

    // Connect to the speakers!
    this.audioSource.connect(this.audioContext.destination);

    // Add some event handlers;
    this.audioSource.addEventListener('ended', this.suspendAudioContext);
  }

  disconnectBufferSource() {
    if (this.audioSourceExists()) {
      this.audioSource.disconnect();
      this.audioSource.removeEventListener('ended', this.suspendAudioContext);
    }
  }

  /**
   * Get an audio stream from an URL.
   *
   * If the withItslToken is provided (and set to true) use the authorizedRequest method to load
   * the audio. This in effect will set the ITSLanguage bearer token (if available) to the request.
   *
   * For both request methods goes: there's no check whether you're trying to load from ITSLanguage
   * backend system or not.
   *
   * @param {string} url - Url to load.
   * @param {boolean} withItslToken - Make use of authorizedRequest or just request if set to false.
   */
  async load(url, withItslToken = true) {
    if (!url) {
      return;
    }

    // Determine whether to ask authorized, or not.
    const requestMethod = withItslToken ? authorisedRequest : request;
    const {audioContext} = this;

    try {
      const response = await requestMethod('GET', url);
      const audioData = await response.arrayBuffer();
      audioContext.decodeAudioData(audioData, decodedAudio => {
        this.audioBuffer = decodedAudio;
        this.fireEvent('loaded');
      });
    } catch (error) {
      this.error(`${error.name}: ${error.message}`);
    }
  }

  /**
   * Returns if the audioBuffer has been created and loaded, or not.

   * @returns {boolean} The audioBuffer created.
   */
  audioBufferExists() {
    return Boolean(this.audioBuffer);
  }

  /**
   * Return if audioSource has been created, or not.
   *
   * @returns {boolean} The audioSource created.
   */
  audioSourceExists() {
    return Boolean(this.audioSource);
  }

  /**
   * Start audio playback of that what is in the buffer.
   */
  play() {
    this.createBufferSource();

    if (this.audioContext.state === 'suspended') {
      this.audioContext.resume();
    }

    // play the source now
    this.audioSource.start();
    this.fireEvent('playing');
  }

  /**
   * Stop playback of audio.
   * Check for buffer and source to exist, if not, exit.
   */
  stop() {
    if (!this.audioBufferExists() && !this.audioSourceExists()) {
      return;
    }

    this.audioSource.stop();
    this.fireEvent('stopped');
  }

  pause() {
    if (!this.audioBufferExists() && !this.audioSourceExists()) {
      return;
    }

    this.audioSource.stop();
    this.fireEvent('pause');
  }
}