#Does audio play makes an event happen? or does an event makes audio play happen?

1 messages · Page 1 of 1 (latest)

harsh vapor
#

Let's say I am building a simple audio player with xstate.

My initial machine is like this:

const audioMachine = createMachine({
  id: 'audio_player',
  initial: 'pause',
  states: {
    pause: {
      on: {
        START_PLAY: 'play',
      },
    },
    play: {
      on: {
        STOP_PLAY: 'pause',
      },
    },
  },
})

I intend to customize my Audio player therefore I don't use the default audio tag.

Now I have two directions to integrate it.

  1. Make my machine reacts to audio element.
  2. Make the audio element reacts to my machine.

My first attempt: make my machine reacts to audio element.

const AudioPlayer = ({ src }) => {
  const audioRef = useRef(null);
  const [state, send] = useMachine(audioMachine);

  useEffect(() => {
    const audio = new Audio(audioSrc)
    audioRef.current = audio
    audio.addEventListener('play', () => send('START_PLAY'));
    audio.addEventListener('pause', () => send('STOP_PLAY'));
    
    // return ....
  }, [send]);

  return (
    <div>Play and Pause Button should be here</div>
  );
};

export default AudioPlayer;

I don't like this version, because I feel that the my state machine is not controlling the audio player.

My gut is that the machine should control the player. When the START_PLAY event is fired by machine, the audio should play as an side-effect. But I am not sure.

raw bramble
#

You can have side-effects in the machine:

#

With React, you can implement it like this:

const [state, send] = useMachine(audioMachine, {
  actions: {
    playAudio: () => { audioRef.current.play() },
    pauseAudio: () => { audioRef.current.pause() }
  }
});
#

(the actions become e.g. entry: 'playAudio' etc.)

glass bison
#

How are you looking to extend the audio element?

raw bramble
#

No need to extend; you can reference it. See modified example

glass bison
raw bramble
glass bison
harsh vapor
# glass bison How are you looking to extend the audio element?

My idea:

  • Let user customize the jump seconds
  • User can create a-b loop
  • User can choose to auto replay ( and there is some interaction between autoReplay and a-b point ...)
  • Audio should auto play when it's playable

I built it with React useEffect at first, but I don't like how the code I wrote.

I am trying Xstate to see if the code is more maitainable.

harsh vapor
# raw bramble With React, you can implement it like this: ```ts const [state, send] = useMachi...

Thanks. I ended up putting the HTMLAudioElement into the context of my machine.

I had 3 states when audio is ready:

  • tryPlay
  • playing
  • pause

Then I use invoke in tryPlay to play the audio, because audio.play() returns a promise which resolves when audio starts playing.

I am not sure if it's an anti-pattern to put HTMLAudioElement inside context.

My implementation now is like this: https://github.com/YuPototo/web_player/blob/try_xstate/src/machines/machine_player.ts

GitHub

Contribute to YuPototo/web_player development by creating an account on GitHub.