Skip to content

Instantly share code, notes, and snippets.

@chaance
Last active January 4, 2020 05:32
Show Gist options
  • Save chaance/348adc77c0c93fa8e57dfe5b83229dc6 to your computer and use it in GitHub Desktop.
Save chaance/348adc77c0c93fa8e57dfe5b83229dc6 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
// Available variables:
// - Machine
// - interpret
// - assign
// - send
// - sendParent
// - spawn
// - raise
// - actions
// - XState (all XState exports)
let AudioStates = {};
let AudioEvents = {};
setAudioStates(AudioStates);
setAudioEvents(AudioEvents);
const commonNonErrorEvents = {
[AudioEvents.SetCanPlay]: {
actions: assign({ canPlay: true }),
},
[AudioEvents.Buffer]: AudioStates.Buffering,
[AudioEvents.SetTime]: {
actions: (context, event) => {
if (context.audio) {
context.audio.currentTime = event.time;
}
},
},
[AudioEvents.HandleTimeChange]: {
actions: (_, event) => {
assign({ currentTime: event.time });
},
},
[AudioEvents.SetVolume]: {
actions: (context, event) => {
const { audio, volume: previousVolume } = context;
const { volume: newVolume } = event;
if (audio) {
audio.volume = Math.max(Math.min(newVolume / 100, 1), 0);
}
assign({ previousVolume, volume: newVolume });
},
},
[AudioEvents.ToggleMute]: {
actions: context => {
const { audio, previousVolume, volume } = context;
const newVolume =
volume === 0 ? (previousVolume >= 1 ? 100 : previousVolume) : 0;
if (audio) {
audio.volume = Math.max(Math.min(newVolume / 100, 1), 0);
}
assign({
previousVolume: volume,
volume: newVolume,
});
},
},
[AudioEvents.ToggleLoop]: {
actions: context => {
assign({ loop: !context.loop });
},
},
};
const commonEvents = {
// React to any prop changes, a la getDerivedStateFromProps
[AudioEvents.GetDataFromProps]: {
actions: assign((context, event) => {
return Object.assign(Object.assign({}, context), event.props);
}),
},
// Should fire any time a ref is attached to a new DOM node
[AudioEvents.Mount]: {
target: AudioStates.Idle,
actions: assign((context, event) => {
return Object.assign(Object.assign({}, context), {
canPlay: false,
previouslyPlaying: false,
audio: event.audio,
});
}),
},
[AudioEvents.Reset]: {
target: AudioStates.Idle,
actions: assign({ previouslyPlaying: false }),
},
[AudioEvents.SetError]: {
target: AudioStates.Error,
actions: assign((context, event) => {
return Object.assign(Object.assign({}, context), {
previouslyPlaying: false,
error: event.error,
});
}),
},
};
const playerMachine = Machine({
id: 'player',
initial: AudioStates.Idle,
context: {
canPlay: false,
currentTime: 0,
error: null,
loop: false,
preload: false,
previouslyPlaying: false,
volume: 100,
previousVolume: 100,
},
states: {
[AudioStates.Idle]: {
on: {
...commonEvents,
[AudioEvents.Buffer]: AudioStates.Buffering,
[AudioEvents.Play]: [
{
target: AudioStates.Playing,
cond: context => context.canPlay,
},
{
target: AudioStates.Buffering,
actions: assign({ previouslyPlaying: true }),
},
],
},
entry: context => {
if (context.audio) {
context.audio.pause();
context.audio.currentTime = 0;
}
},
},
[AudioStates.Buffering]: {
on: {
...commonEvents,
[AudioEvents.BufferComplete]: [
{
target: AudioStates.Playing,
cond: context => context.previouslyPlaying,
actions: assign({ canPlay: true }),
},
{
target: AudioStates.PlayReady,
actions: assign({ canPlay: true }),
},
],
},
entry: assign({ canPlay: false }),
},
[AudioStates.PlayReady]: {
on: {
...commonEvents,
...commonNonErrorEvents,
[AudioEvents.Play]: AudioStates.Playing,
[AudioEvents.SeekStart]: AudioStates.Seeking,
},
},
[AudioStates.Playing]: {
on: {
...commonEvents,
...commonNonErrorEvents,
[AudioEvents.Pause]: AudioStates.Paused,
[AudioEvents.SeekStart]: AudioStates.Seeking,
[AudioEvents.Complete]: [
{
target: AudioStates.Playing,
cond: context => context.loop,
actions: context => {
if (context.audio) {
context.audio.currentTime = 0;
}
},
},
{
target: AudioStates.Idle,
actions: [
context => {
if (context.audio) {
context.audio.pause();
context.audio.currentTime = 0;
}
},
assign({ previouslyPlaying: false }),
],
},
],
},
entry: context => {
context.audio && context.audio.play();
},
exit: assign({ previouslyPlaying: true }),
},
[AudioStates.Paused]: {
on: {
...commonEvents,
...commonNonErrorEvents,
[AudioEvents.Play]: AudioStates.Playing,
[AudioEvents.SeekStart]: AudioStates.Seeking,
},
entry: context => {
context.audio && context.audio.pause();
},
exit: assign({ previouslyPlaying: false }),
},
[AudioStates.Seeking]: {
on: {
...commonEvents,
...commonNonErrorEvents,
[AudioEvents.SeekStop]: [
{
target: AudioStates.Playing,
cond: context => context.previouslyPlaying && context.canPlay,
},
{
target: AudioStates.Buffering,
cond: context => context.previouslyPlaying && !context.canPlay,
},
{ target: AudioStates.Paused },
],
},
entry: context => {
context.audio && context.audio.pause();
},
exit: (context, event) => {
if (context.audio && event.type === AudioEvents.SeekStop) {
context.audio.currentTime = event.time;
}
},
},
[AudioStates.Error]: {
on: Object.assign({}, commonEvents),
entry: assign({ previouslyPlaying: false }),
},
},
});
function setAudioStates(AudioStates) {
AudioStates["Idle"] = "IDLE";
AudioStates["Buffering"] = "BUFFERING";
AudioStates["PlayReady"] = "PLAY_READY";
AudioStates["Playing"] = "PLAYING";
AudioStates["Paused"] = "PAUSED";
AudioStates["Seeking"] = "SEEKING";
AudioStates["Error"] = "ERROR";
};
function setAudioEvents(AudioEvents) {
AudioEvents["Buffer"] = "BUFFER";
AudioEvents["BufferComplete"] = "BUFFER_COMPLETE";
AudioEvents["Complete"] = "COMPLETE";
AudioEvents["GetDataFromProps"] = "GET_DATA_FROM_PROPS";
AudioEvents["HandleTimeChange"] = "HANDLE_TIME_CHANGE";
AudioEvents["Mount"] = "MOUNT";
AudioEvents["Pause"] = "PAUSE";
AudioEvents["Play"] = "PLAY";
AudioEvents["PlayFromStart"] = "PLAY_FROM_START";
AudioEvents["Reset"] = "RESET";
AudioEvents["SetCanPlay"] = 'SET_CAN_PLAY';
AudioEvents["SeekStart"] = "SEEK_START";
AudioEvents["SeekStop"] = "SEEK_STOP";
AudioEvents["SetError"] = "SET_ERROR";
AudioEvents["SetTime"] = "SET_TIME";
AudioEvents["SetVolume"] = "SET_VOLUME";
AudioEvents["Stall"] = "STALL";
AudioEvents["Stop"] = "STOP";
AudioEvents["ToggleLoop"] = "TOGGLE_LOOP";
AudioEvents["ToggleMute"] = "TOGGLE_MUTE";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment