"use strict";

exports.__esModule = true;
exports.useAudioManager = void 0;
var _react = require("react");
var _howler = require("howler");
// A callback that keeps its instance and won't make Howler to re create every time
var useStableCallback = callback => {
  var callbackRef = (0, _react.useRef)(null);
  callbackRef.current = callback;
  return (0, _react.useCallback)(function () {
    return callbackRef.current && callbackRef.current(...arguments);
  }, []);
};
var useRaf = _ref => {
  var {
    callback,
    enabled
  } = _ref;
  var stableCallback = useStableCallback(callback);

  // we use useLayoutEffect here because it fires synchronously after all DOM mutations
  // and before the next requestAnimationFrame. If we use useEffect (which runs after requestAnimationFrame)
  // we'll get an endless loop of frames that causes a memory leak.
  (0, _react.useLayoutEffect)(() => {
    if (enabled) {
      var id;
      var loop = () => {
        stableCallback();
        id = requestAnimationFrame(loop);
      };
      id = requestAnimationFrame(loop);
      return () => {
        cancelAnimationFrame(id);
      };
    }
  }, [enabled, stableCallback]);
};
var useAudioManager = _ref2 => {
  var {
    src,
    playing,
    format,
    preload,
    webAudioAPI,
    allowSeekLoop,
    volume,
    onEnd,
    onLoad,
    onPlay,
    onPause,
    onSeek,
    onLoadError,
    onDestroy
  } = _ref2;
  var stableOnEnd = useStableCallback(onEnd);
  var stableOnLoad = useStableCallback(onLoad);
  var stableOnPlay = useStableCallback(onPlay);
  var stableOnPause = useStableCallback(onPause);
  var stableOnSeek = useStableCallback(onSeek);
  var stableOnLoadError = useStableCallback(onLoadError);
  var stableOnDestroy = useStableCallback(onDestroy);
  var audioManager = (0, _react.useRef)(null);
  var [_seek, _setSeek] = (0, _react.useState)(0);
  var [loadingState, setLoadingState] = (0, _react.useState)('unloaded');
  var [wasEverPlayed, setWasEverPlayed] = (0, _react.useState)(false);
  var duration = (0, _react.useMemo)(() => {
    if (!audioManager.current || loadingState !== 'loaded') {
      return 0;
    }
    return audioManager.current.duration();
  }, [loadingState]);
  var _destroy = (0, _react.useCallback)(() => {
    if (audioManager.current) {
      setLoadingState('unloaded');
      setWasEverPlayed(false);
      _setSeek(0);
      audioManager.current.stop();
      audioManager.current.unload();
      audioManager.current = null;
      stableOnDestroy();
    }
  }, [setLoadingState, setWasEverPlayed, _setSeek, stableOnDestroy]);
  var _onPlay = (0, _react.useCallback)(() => {
    setWasEverPlayed(true);
    stableOnPlay();
  }, [stableOnPlay, setWasEverPlayed]);
  var _onLoad = (0, _react.useCallback)(() => {
    // Keeping a duplicate state because when Howler state changes it won't cause a render
    // and we want to react to this change.
    setLoadingState(audioManager.current.state());
    stableOnLoad();
  }, [stableOnLoad, setLoadingState]);
  var _onEnd = (0, _react.useCallback)(() => {
    _setSeek(0);
    stableOnEnd();
  }, [stableOnEnd, _setSeek]);
  var _onLoadError = (0, _react.useCallback)((_, errorMsg) => {
    stableOnLoadError(errorMsg);
  }, [stableOnLoadError]);
  var _load = (0, _react.useCallback)(() => {
    if (audioManager.current) {
      audioManager.current.load();
      setLoadingState(audioManager.current.state());
    }
  }, [setLoadingState]);
  var _play = (0, _react.useCallback)(() => {
    if (audioManager.current) {
      if (loadingState === 'unloaded') {
        _load();
      }
      if (loadingState === 'loaded' && !audioManager.current.playing()) {
        audioManager.current.play();
      }
    }
  }, [loadingState, _load]);
  var _pause = (0, _react.useCallback)(() => {
    if (audioManager.current) {
      audioManager.current.pause();
    }
  }, []);

  // There is an open bug in howler that if play is locked it returns the howler object when
  // getting "seek" instead of a number. this solves the issue until they fix it,.
  // https://github.com/goldfire/howler.js/issues/1189
  var _readSeek = (0, _react.useCallback)(() => {
    if (!audioManager.current || loadingState !== 'loaded') {
      return 0;
    }
    var currentSeek = audioManager.current.seek();
    if (typeof currentSeek !== 'number') {
      var internalSeek = audioManager.current._sounds[0]._seek;
      if (typeof internalSeek !== 'number') {
        currentSeek = 0;
      }
      currentSeek = internalSeek;
    }
    return currentSeek;
  }, [loadingState]);
  var _updateSeek = (0, _react.useCallback)(() => {
    // Keeping a duplicate seek state because when Howler seek changes it won't cause a render
    // and we want to react to this change (expose an updated seek to audioManager consumer).
    _setSeek(_readSeek());
  }, [_readSeek]);
  var setSeek = (0, _react.useCallback)(pos => {
    if (audioManager.current && loadingState === 'loaded') {
      audioManager.current.seek(pos);
      _setSeek(pos);
    }
  }, [loadingState]);

  // starts a request animation frame loop that updates the seek every frame.
  // stops the loop if paused or if slider is being dragged
  useRaf({
    callback: _updateSeek,
    enabled: playing && allowSeekLoop
  });
  (0, _react.useEffect)(() => {
    if (src) {
      audioManager.current = new _howler.Howl({
        src,
        format,
        preload: preload === 'none' ? false : preload === 'auto' ? true : preload,
        onload: _onLoad,
        html5: !webAudioAPI,
        onend: _onEnd,
        onplay: _onPlay,
        onloaderror: _onLoadError,
        onpause: stableOnPause,
        onseek: stableOnSeek
      });
    }
    return () => _destroy();
  }, [audioManager, _destroy, format, src, _onEnd, _onLoad, _onLoadError, stableOnPlay, stableOnPause, stableOnSeek, preload, webAudioAPI, _onPlay]);
  (0, _react.useEffect)(() => {
    if (playing) {
      _play();
    }
    if (!playing && wasEverPlayed) {
      _pause();
    }
  }, [_pause, _play, playing, wasEverPlayed]);
  (0, _react.useEffect)(() => {
    if (audioManager.current && volume !== undefined) {
      audioManager.current.volume(volume);
    }
  }, [volume]);
  return (0, _react.useMemo)(() => ({
    loadingState,
    duration,
    seek: _seek,
    setSeek
  }), [loadingState, duration, _seek, setSeek]);
};
exports.useAudioManager = useAudioManager;
//# sourceMappingURL=AudioManager.js.map