E-Kuerschner / useAudioPlayer

React hooks for controlling audio on the web
MIT License
328 stars 36 forks source link

feat: expose underlying Howl instance and events to the client to allow for greater expandability #118

Open kilokeith opened 1 year ago

kilokeith commented 1 year ago

Prior to v2 the Howler instance was exposed. I needed access to the Howler api to get the audio context for recording. This PR attempts to add back that ability by adding a getHowl() method to the hooks. I also wanted to expose useHowlEventSync so that the events could be listened to outside the hooks.

Resolves the previously closed issues: #50 (resolved by this PR ).

E-Kuerschner commented 1 year ago

hey @kilokeith thanks for the PR! Let's get some of these changes in!

First off, I'm curious what your use case is and how you would be using the event sync hook. It's really too technical to be used by devs IMO. Perhaps there is a way we can extend existing API to make it easier to set up your own event listening? But I'll need to know more about your use case before I can offer any ideas

Regarding getHowl, I'm totally game to add that new method as an escape hatch, but I don't think we should have load return the Howl. I think this bc the lib provides a pretty clean abstraction over Howler and returning the Howl here begins to leak implementation details. One other thing to note is that the hooks do some lifecycle management over the Howl object(s). For example the destroy method may be called messing with the reference returned out of getHowl

kilokeith commented 1 year ago

For sure, I was wondering if something like destroy would cause an issue with the howler instance. Exposing the instance ends up being one of the more important features of another library use-sound, so I thought the load could work similarly.

const [play, { sound }] = useSound('/win-theme.mp3');

I didn't really have any plans useHowlEventSync myself. I thought it'd be nice to have an event system that, for instance, you could have an event listener for plays and fire analytics events that way on a more global level rather than be bound to a react render context. There's certainly bigger features I would rather develop rather than that.

Turns out I didn't need any of these added features by the time I finished my project. I wanted to share the audio context with a media recorder so that I could record the screen and get audio without accessing mic permissions or anything extra. But that doesn't come form the howler instances, it's part of the Howler window global.

What I could have used most of all was:

E-Kuerschner commented 1 year ago

hey @kilokeith i love those ideas. if you have a moment can you elaborate on this point?

Ability to play multiple sounds at once from a single load. Such as having a timeline like theatre.js where a keyframe has multiple sounds to trigger at a time, but without knowing what need to be played ahead of time it makes it hard to create multiple instances in a hook. Maybe a wrapper around load that creates a group with a single control would work.

uncvrd commented 1 year ago

@E-Kuerschner I may be able to chime in here. Are you familiar with Ableton Live or any DAW for music production? I believe Keith is stating it'd be nice to be able to display a list of audio files (like drums / vocalist / etc) and load all of them at once so that you could click "play" and have all audio files play in sync at once. I believe he also says it would be difficult to create multiple instances of hooks since those audio files would be dynamic and would need to be loaded from storage thus not knowing how many instances of the hook to create. @kilokeith correct me if I'm on the wrong path though.

I'm coming back to this package after successfully using this in production with this very exact request (made a PR like a year ago if you remember haha)

My search for this feature started from the Howler library where I found an open issue so maybe this helps give you an understanding of what I'd like to have achieved as well https://github.com/goldfire/howler.js/issues/672

Thanks for actively maintaining this library!

E-Kuerschner commented 1 year ago

Gotcha - I'm tracking! @uncvrd do you think you would mind opening up an Issue/Feature request so that we can discuss and track this there? I'm going to close out this pull request shortly. If you could just list out the high level requirements you think the feature should follow that would be awesome.

As for an API, I was considering introducing an abstraction for an audio bus which the programmer can create and programmatically add sounds too; maybe something similar to this:

const sound1 = useAudioPlayer()
sound1.load()
const sound2 = useAudioPlayer()
const bus = useAudioBus()

// an AudioBus could implement a common interface with an individual sound 
bus.load()
bus.play()
bus.pause()
mrdziuban commented 1 month ago

@E-Kuerschner is there any chance this might be merged/released? I'm also looking to get access to the underlying Howl instance to be able to get the duration