How can I stop and resume a live audio stream in HTML5 and not just pause it?

A notable issue when creating a simple audio streaming element in HTML5 is that the tag <audio>

does not behave as you would expect when it comes to playing and pausing a streaming audio stream.

I'm using the most basic HTML5 code to stream audio, a tag <audio>

with controls sourced from a live stream, which can be demonstrated here: http://jsfiddle.net/uzzz03ha/

Current result . When the stream is first played, it plays whatever happens as expected. However, when it is paused and played again, the audio resumes exactly where it left off when the thread was previously paused. The user is now listening to the delayed version of the stream. This event is browser independent.

Desired result . When the thread is paused, I want the thread to stop. When it plays again, I want it to resume where the current thread is, not where it was when the user paused the thread.

Does anyone know how to properly restore this audio stream after paused?

Some unsuccessful attempts I have made to fix this issue:

  • Changing the currentTime

    audio element does nothing for audio streaming.
  • I removed the audio element from the DOM when the user stopped playing the stream, and added it back in when the user resumes playing. The thread still continues when the user is stopped and worse, but loads another copy of the thread behind.
  • I added a random GET variable to the end of the stream url every time the stream is played, trying to trick the browser into thinking it is playing a new stream. Playback is still resuming when the user paused the stream.
+4


source to share


4 answers


The best way to stop the thread and then start it again seems to remove the source and then call the load:



var sourceElement = document.querySelector("source");
var originalSourceUrl = sourceElement.getAttribute("src");
var audioElement = document.querySelector("audio");

function pause() {
    sourceElement.setAttribute("src", "");
    audioElement.pause();
    // settimeout, otherwise pause event is not raised normally
    setTimeout(function () { 
        audioElement.load(); // This stops the stream from downloading
    });
}

function play() {
    if (!sourceElement.getAttribute("src")) {
        sourceElement.setAttribute("src", originalSourceUrl);
        audioElement.load(); // This restarts the stream download
    }
    audioElement.play();
}

      

+5


source


One solution I came across while troubleshooting this issue was to completely ignore the play and pause functions on the audio element and just set the audio element's volume property to 0 when the user wants to stop playing, then set the property volumes back to 1 when the user wants to resume playback.

The JavaScript code for such a function would appear as if you were using jQuery ( also demonstrated in this script ):

/*
 * Play/Stop Live Audio Streams
 * "audioElement" should be a jQuery object
 */
function streamPlayStop(audioElement) {
  if (audioElement[0].paused) {
    audioElement[0].play();
  } else if (!audioElement[0].volume) {
    audioElement[0].volume = 1;
  } else {
    audioElement[0].volume = 0;
  }
}

      

I must warn you that even if this provides the desired functionality for stopping and resuming live audio streams, it is not ideal because the stream, when stopped, is actually still playing and loading in the background using the bandwidth to process.

However, this solution does not necessarily takes up more bandwidth than simple use .play()

and .pause()

streaming audio elements. Just using the tag audio

with streaming audio uses up a lot of bandwidth anyway, because as soon as the streaming audio is played, it continues to download the content of the stream in the background while it is paused.




It should be noted that this method will not work on iOS due to the targeted built-in restrictions for iPhones and iPads :

On iOS devices, the sound level is always under the physical control of users. The property is volume

not configurable in JavaScript. Reading the property volume

always returns 1

.

If you decide to use the workaround in this answer, you need to create a backup for iOS devices that normally uses the play()

and functions pause()

, or your frontend won't be able to pause the thread.

+1


source


Resetting the audio source and calling the method load()

seems to be the easiest solution if you want to stop loading from the stream.

Since this is a stream, the browser will only stop loading when the user disconnects. The reset is necessary in order to protect your users from burning their cellular data or to avoid showing outdated content that the browser has loaded when they pause audio playback.

Be aware, however, that when the source attribute is set to an empty string, for example, so that the audio.src= ""

page's hostname will be set instead of the audio source. If you use a random word, that word will be added as a path.

Therefore, as shown below, setting audio.src=""

means that audio.src=== "https://stacksnippets.net/js"

. Installation audio.src="meow"

will make the source instead audio.src=== "https://stacksnippets.net/js/meow"

. So the 3rd paragraph is not visible.

const audio1 = document.getElementById('audio1');
const audio2 = document.getElementById('audio2');
document.getElementById('p1').innerHTML = 'First audio source: ${audio1.src}';
document.getElementById('p2').innerHTML = 'Second audio source: ${audio2.src}';

if (audio1.src === "") {
  document.getElementById('p3').innerHTML = "You can see me because the audio source is set to an empty string";
}
      

<audio id="audio1" src=""></audio>
<audio id="audio2" src="meow"></audio>

<p id="p1"></p>

<p id="p2"></p>

<p id="p3"></p>
      

Run codeHide result


Keep this in mind if you are relying on the sound source at the moment. Using the about URI scheme seems to trick it into behaving more reliably. Thus, using "about:" or "about: about", "about: blank", etc. Will work fine.

const resetAudioSource = "about:"

const audio = document.getElementById('audio');
audio.src = resetAudioSource;

document.getElementById('p1').innerHTML = 'Audio source: -- "${audio.src}"';

// Somewhere else in your code...

if (audio.src === resetAudioSource){
  document.getElementById('p2').innerHTML = "You can see me because you reset the audio source."
}
      

<audio id="audio"></audio>
<p id="p1"></p>
<p id="p2"></p>
      

Run codeHide result


Resetting audio.src

and calling .load()

will cause the audio to try to load a new source. The above is useful if you want to show the counter component during audio loading, but do not want to show this component when resetting the audio source.

A working example can be found here: https://jsfiddle.net/v2xuczrq/

If the source is reset using a random word, then there might be a onError

loader that pops up when you also pause the sound, or until its onError

event handler onError

. https://jsfiddle.net/jcwvue0s/

UPDATE: the lines "javascript:;" and "javascript: void (0)" can be used in place of the "about:" URI, and it seems to work even better as it will also stop the console warnings caused by "about:".

+1


source


Unfortunately, the audio stream in HTML5 is a bit wrong as it doesn't actually broadcast. An audio file (.wav, .mp3, etc.) is required to upload and download HTML5. It will not accept streaming streaming formats (online radio, PCM streaming data, etc.).

Your jsfiddle.net/uzzz03ha/ example does not use a live audio stream, it uses a pre-recorded file. HTML5 buffers this file a bit and then plays it back. Pausing and resuming audio stops time because it "knows" this pre-recorded file. Cole's answer will help you hack the pause / play issue, but you will still be left with the html5 issue not accepting live streams. You will also have to hack this path.

So, unfortunately I don't have an answer to your question, as I found your question while trying to solve the same problem. This post may help you in the right direction: Play Live Audio Stream - html5

-2


source







All Articles