Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[audio] Breaking controls and state when passing HTMLAudioElement as AudioSource #722

Open
yanickrochon opened this issue Dec 6, 2024 · 1 comment

Comments

@yanickrochon
Copy link

Describe the bug

When passing a HTMLAudioElement to createAudio, the state.player gets updated, however the original listeners aren't updated. (Also, any previous listeners aren't removed.)

The following code is problematic:

const {
  play,
  pause,
  setVolume: _setVolume,
  seek,
} = makeAudioPlayer(store.player, {
  loadeddata: () => {
    setStore({
      state: AudioState.READY,
      duration: player.duration,
    });
    if (playing && playing()) {
      play().catch((e: DOMException) => {
        if (e.name === "NotAllowedError") {
          setStore("state", AudioState.ERROR);
        }
      });
    }
  },
  timeupdate: () => setStore("currentTime", player.currentTime),
  loadstart: () => setStore("state", AudioState.LOADING),
  playing: () => setStore("state", AudioState.PLAYING),
  pause: () => setStore("state", AudioState.PAUSED),
  error: () => setStore("state", AudioState.ERROR),
  ended: () => setStore("state", AudioState.COMPLETE),
});

// ...

if (src instanceof Function) {
  createEffect(() => {
    const newSrc = src();
    if (newSrc instanceof HTMLAudioElement) {
      setStore("player", newSrc);
    } else {
      setAudioSrc(store.player, newSrc);
    }
    seek(0);
  });
}

Because src can be an instance of HTMLAudioPlayer, then the initial audio player is replaced by src, however the functions returned by makeAudioPlayer are still bound to the initial player. Idem for the handlers.

Minimal Reproduction Link

https://stackblitz.com/edit/github-8tkaus?file=src%2FApp.tsx

@yanickrochon yanickrochon changed the title Breaking audio controls when passing HTMLAudioElement as AudioSource [audio] Breaking controls and state when passing HTMLAudioElement as AudioSource Dec 6, 2024
@yanickrochon
Copy link
Author

My solution to this would be to implement #721 and remove HTMLAudioElement from AudioSource; do not allow src to be of type HTMLAudioElement.

This would allow this to work reactively:

const [audioSource, setAudioSource] = createSignal<AudioSource>();
const [state, controls] = createAudio(audioSource);

createEffect(() => {
  const context = new AudioContext();
  const destination = context.createMediaStreamDestination();

  const bufferSource = context.createBufferSource();
  bufferSource.buffer = audioBuffer;   // an instance of AudioBuffer
  bufferSource.connect(destination);
  
  setAudioSource(destination.stream satisfies MediaStream);
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant