'Set up ScripProcessorNode to allow continous playback on iOS lock-screen

I'm creating a Vue front end for a music streaming application and want to be able to have the JavaScript of the app jump to the next song when the current song has ended. This is working flawlessly when having the site open in iOS Safari, but if I have a locked screen and the song ends there, the audio stops. I'm testing it on the latest iOS version (15.4.1 as of writing this).

The way I've set it up in Vue is like this:

Vue template:

<template>
  <div id="player">
    <audio ref="player"></audio>
  </div>
</template>

JavaScript

<script>
...
methods: {    
    initTrack(track) {
        var player = this.$refs.player;
        player.src = `http://<API-URL>/stream?id=${track.id}`;
        player.load();
        player.play();
    },
}
...
mounted() {
    var player = this.$refs.player;
    player.onended = () => {
        if (this.trackQueue.length) this.initTrack(this.trackQueue[0]);
    }
  }
</script>

I found this answer talking about possible solutions, and I've implemented it the way it's described, to use the onended event of the audio player and then load and play the new source of the audio within that function. But it's still not working.

I want to try the step described at the bottom of the post:

A hack... set up a ScriptProcessorNode on a Web Audio context. Set the buffer size to like 512 samples or something. Then, on script process, force a timeupdate event for your Audio Element. This keeps your JavaScript there ticking away. ScriptProcessorNode has to have special privileges here, by its nature.

I just wonder how the "setting up of the ScripProcessorNode" for this specific cause is done in practice? And if anyone have any updated approaches for working around this behavior, since this post was written a few years ago, I would gladly appreciate any solutions.



Solution 1:[1]

Seems like it's working if I put the onended event within the same function that's loading and playing the track, and then calling that function again within the onended event, like this:

initTrack(){
      this.queueIndex++
      this.src = "http://<API-URL>/stream?id=" + this.queue[this.queueIndex].id
      this.$refs.player.src = this.src
      this.$refs.player.load()
      this.$refs.player.play()
      this.$refs.player.onended = () => {
        this.initTrack()
      }
    }

queue is an array containing all the songs that the player should play through. For each time the initTrack function runs, it increments the current index of that array with queueIndex and then uses that index to load and play the next track in the array.

Every time I click a new track to play, it resets the queueIndex variable to -1.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 tobiasg