goldfire / howler.js

Javascript audio library for the modern web.
https://howlerjs.com
MIT License
23.29k stars 2.21k forks source link

Add dynamically musics to src #825

Open Farkal opened 6 years ago

Farkal commented 6 years ago

I explain my problem : I have a website with a lot of musics and i need to allow my users to listen to this musics, but there is so much musics that I can't use an array and define it at the beginning. So is there any solution ? Right now I have to create a new Howler instance, set the events, the volume etc... each time an user want to play a track. At least it should be possible to just change the src and not recreate all the instance of the object no ?

giray123 commented 6 years ago

Is there any disadvantages to create the instance over and over again for you?

Farkal commented 6 years ago

Yes on chrome on mobile it doesn't work, the events are not linked to the new instance and refuse to play the music.

Farkal commented 6 years ago

I create a function for the Howl object and it work, chrome stop annoying me and i am able to load my musics easily :

changeSrc: function(newSrc) {
      var self = this;
      self.stop();
      self._src = newSrc;

      let sounds = self._sounds;

      self._sprite = {};
      self._duration = 0;

      sounds[0]._node.src = newSrc;

      self.load();
    },
jasongrishkoff commented 6 years ago

@Farkal Where did you add this function, and how do you call it?

jasongrishkoff commented 6 years ago

Got it! Added it to the howler.js file as part of the Howl.prototype object.

Farkal commented 6 years ago

I find a new way to implement this:

changeSrc: function (newSrc) {
            let self = this;
            self.unload();
            self._src = newSrc;
            self.load();
        }
sebamacchia commented 5 years ago

@Farkal @jasongrishkoff im working in a sampler project and i need to update the src from the url in a json file, is there any way to do that??, any idea?

ayberkcal commented 5 years ago

@Farkal @jasongrishkoff im working in a sampler project and i need to update the src from the url in a json file, is there any way to do that??, any idea?

You can write an helper parse source urls from json file and push to another array. After that you can play audios from array on howlerjs onload event.

ayberkcal commented 5 years ago

I find a new way to implement this:

changeSrc: function (newSrc) {
            let self = this;
            self.unload();
            self._src = newSrc;
            self.load();
        }

Really good solution rather than old one. But there are two point important if anyone use these solutions. -First solution does not clear cache and some cases this is good. But somehome (I did not have a time to debug) onend event fired more than one. -Second solution works clear. But if you need to use cache you should do some modification on unload method like that: Change method signature like that: unload: function(dontRemoveCache)

Get into the if condition this lines in the unload method:

            // Delete this sound from the cache (if no other Howl is using it).
            if(!dontRemoveCache) {
                var remCache = true;
                for (i = 0; i < Howler._howls.length; i++) {
                    if (Howler._howls[i]._src === self._src) {
                        remCache = false;
                        break;
                    }
                }

                if (cache && remCache) {
                    delete cache[self._src];
                }
            }

Lastly use this changeSrc method instead of above:

changeSrc: function (newSrc) {
            var self = this;
            self.unload(true);
            self._src = newSrc;
            self.load();
        }
vin-ni commented 5 years ago

Get into the if condition this lines in the unload method:

            // Delete this sound from the cache (if no other Howl is using it).
            if(!dontRemoveCache) {
                var remCache = true;
                for (i = 0; i < Howler._howls.length; i++) {
                    if (Howler._howls[i]._src === self._src) {
                        remCache = false;
                        break;
                    }
                }

                if (cache && remCache) {
                    delete cache[self._src];
                }
            }

Lastly use this changeSrc method instead of above:

changeSrc: function (newSrc) {
            var self = this;
            self.unload(true);
            self._src = newSrc;
            self.load();
        }

This worked for me. Just copying the edited code from version 2.1.2 to make it easier to edit (it's the second unload function):

unload: function (dontRemoveCache) {
      var self = this;

      // Stop playing any active sounds.
      var sounds = self._sounds;
      for (var i = 0; i < sounds.length; i++) {
        // Stop the sound if it is currently playing.
        if (!sounds[i]._paused) {
          self.stop(sounds[i]._id);
        }

        // Remove the source or disconnect.
        if (!self._webAudio) {
          // Set the source to 0-second silence to stop any downloading (except in IE).
          self._clearSound(sounds[i]._node);

          // Remove any event listeners.
          sounds[i]._node.removeEventListener('error', sounds[i]._errorFn, false);
          sounds[i]._node.removeEventListener(Howler._canPlayEvent, sounds[i]._loadFn, false);

          // Release the Audio object back to the pool.
          Howler._releaseHtml5Audio(sounds[i]._node);
        }

        // Empty out all of the nodes.
        delete sounds[i]._node;

        // Make sure all timers are cleared out.
        self._clearTimer(sounds[i]._id);
      }

      // Remove the references in the global Howler object.
      var index = Howler._howls.indexOf(self);
      if (index >= 0) {
        Howler._howls.splice(index, 1);
      }

      // Delete this sound from the cache (if no other Howl is using it).
      if (!dontRemoveCache) {
        var remCache = true;
        for (i = 0; i < Howler._howls.length; i++) {
          if (Howler._howls[i]._src === self._src || self._src.indexOf(Howler._howls[i]._src) >= 0) {
            remCache = false;
            break;
          }
        }

        if (cache && remCache) {
          delete cache[self._src];
        }
      }

      // Clear global errors.
      Howler.noAudio = false;

      // Clear out `self`.
      self._state = 'unloaded';
      self._sounds = [];
      self = null;

      return null;
    },
taka1156 commented 3 years ago
スクリーンショット 2020-10-04 21 32 04 スクリーンショット 2020-10-05 14 41 43 スクリーンショット 2020-10-05 15 31 07
import { Howl } from 'howler';

let audioPlayer  = null;

Howl.prototype.changeSong = function(o) {
  var self = this;
  self.unload();
  self._duration = 0; // init duration
  self._sprite = {};// init sprite
  self._src = typeof o.src !== 'string' ? o.src : [o.src];
  self._format = typeof o.format !== 'string' ? o.format : [o.format];
  self.load(); // => update duration, sprite(var timeout)
};

function generateHowlerAudio(song) {
  if (audioPlayer == null) {
    audioPlayer = new Howl({
      src: song.src,
      format: song.format,
      preload: true,
      autoplay: false,
      loop: false,
      volume: 1
    });
  } else {
    audioPlayer.changeSong(song);
  }
}
cnp96 commented 3 years ago

Faced this issue in Safari. Turns out I wasn't unloading the Audio player.


export default function useHowler(options: HowlerOptions) {
  const player = useRef();

  useEffect(() => {
    player.current = new Howl(options);

    // Unload the Audio player during unmount --cleanup
    return () => {
      player.current && player.current.unload();
    }
  }, []); 

  return { play: ..., stop: ..., fade: ... }  
}