13

I am trying to stream a Shoutcast URL using HTML5 Audio on a Cordova app.

The problem I have run into is this: There appears to be no callback that fires when an audio stream loses connection to the ShoutCast URL. At this stage, the audio element shows that it is playing the audio, but there is no audio.

Code

Radio = {
    initialized: false,
    isBuffering: false,
    interrupted: false,
    isPlaying: false,
    media: null,
    trackName: '',
    url: 'shoutcast_url',
    initialize: function () {
        if (!this.media) {
            this.media = new Audio(this.url);

            this.media.preload = "none";

            this.media.onerror = function (e) {
                App.alert("Unable to connect to Radio");
                Radio.interrupt();
            };

            this.media.onwaiting = function (e) {
                Radio.set_buffering(true);
            };

            this.media.onplaying = function (e) {
                Radio.set_buffering(false);
            };
        }
    },
    set_buffering: function (value) {
    ...
    }

Scenario

  • Connect to the Internet (say, through a hotspot) and start the audio radio.
  • Disconnect the hotspot from the Internet.

After the buffered content is played, the audio stops playing. But no callbacks are fired that indicate loss of connection.

  • media.networkState is 2 (NETWORK_LOADING)
  • media.playbackRate is 1 (Playing forward at normal rate)
  • media.readyState is 4 (HAVE_ENOUGH_DATA)
  • media.preload is none

The callbacks that I tried, (which did not fire when connection was lost) are:

  • onstalled
  • onreset
  • onsuspend
  • onerror
  • onprogress
  • onwaiting

Question - Is there an audio callback that will fire when it is unable to play the audio due to lack of connection?

If not, is there any method which will update readyState or networkState? If so, I could just set a timer to check these values.

Ajoy
  • 1,814
  • 3
  • 28
  • 54
  • Can you show how you listened for the events? Stalled, for example, should work, as is documented here: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events – Raymond Camden Feb 24 '16 at 11:47
  • @RaymondCamden Added my current code to the question. I had the callbacks added in `initialize()`. – Ajoy Feb 24 '16 at 14:59
  • So did you try stalled yet? this.media.addEventListener("stalled", ... – Raymond Camden Feb 24 '16 at 15:16
  • No, I did not add an event listener. I thought that `onstalled` would function the same. Anyway, I will update the question after I try this out. – Ajoy Feb 24 '16 at 15:25
  • @RaymondCamden `this.media.addEventListener("stalled", ..` doesn't fire either. It fires when the media is played the first time, but it does not fire when I disconnect the Internet connection.... – Ajoy Feb 25 '16 at 04:11
  • You got me there - sorry I can't help more. – Raymond Camden Feb 25 '16 at 13:56
  • have you tried to listen to the "ended" event? i know it doesn't make much sense since it's a stream but i had cases of wrong callbacks being triggered before –  Feb 28 '16 at 10:36
  • @joyrex (Sorry for the late reply) But `ended` wasn't triggered either. – Ajoy Mar 03 '16 at 11:16
  • @Ajoy this might be a roundabout way, but have you tried, hooking up the audio with WebAudio and analyzing that data? – mido Mar 04 '16 at 02:13
  • @mido What interface should I use? Most of them deal with processing audio... – Ajoy Mar 04 '16 at 09:17
  • @Ajoy you could create an Javascript Node from the Audio Context, and listen to `onaudioprocess `, look at the buffer values, if they all remain to be zeros, you can identify the issue that way... long shot, but believe it would work – mido Mar 04 '16 at 09:42
  • @RaymondCamden found the solution. Posted an answer. – Ajoy Apr 02 '16 at 06:51

3 Answers3

6

Are you sure that loss of connection is actually what you want? The audio can stop and your connection effectively lost without the underlying TCP connection actually being closed. You could have no data for hours, effectively dead connection, but still have that TCP connection active.

Instead, I would recommend looking at the playback time. (Your onprogress handler is also effective.) If that isn't increasing after a timeout that you set (10 seconds or whatever is appropriate for your situation), then clear the audio player and attempt to reconnect.

Brad
  • 146,404
  • 44
  • 300
  • 476
  • I want to be notified when there is no audio being played, either because of buffering or due to loss of connection. `onwaiting` does fire just before the audio is played (because `preload` is none). – Ajoy Feb 25 '16 at 04:54
  • `media.duration` and `media.currentTime` are both always `0` because this is an audio URL. The callback `onprogress` does not update either. – Ajoy Feb 25 '16 at 04:55
  • @brad I have a similar issue with the TCP connection. I am not sure but when the internet goes down it sends only 30 requests(or 30 seconds) after that it stops sending requests but if it came back before 30 requests it starts streaming and audio play without issue. So even if the internet comes back online it doesn't play audio. What could be that limit? Here is my question https://stackoverflow.com/questions/67056630/partial-audio-download-problem-when-internet-get-disconnected – Omi Apr 16 '21 at 09:41
4

When a supported audio stream is played using HTML5 Audio, the best way to figure out if the audio is playing is to listen to the event timeupdate.

The timeupdate event is fired when the time indicated by the currentTime attribute has been updated.

The event fires only when audio is being played. If the audio stops, due to any reason, timeupdate doesn't fire either.

However, browser support is not complete.

  • On Android 5.0 (Chrome 48), timeupdate never fires nor is currentTime updated.
  • On latest desktop browsers (Mozilla 45 and Chrome 49), timeupdate functions as documented.
Ajoy
  • 1,814
  • 3
  • 28
  • 54
  • Would you please provide more details? I've got a Cordova app using "cordova-plugin-media" and the following code only fires once (when the stream begins). audioStream.ontimeupdate = alert("timeupdate fired"); – Andrew Bucklin Apr 14 '16 at 00:54
  • @AndrewBucklin `timeupdate` does not fire on Lollipop (as far as I have understood) – Ajoy Apr 14 '16 at 03:22
-3

You could listen for the online event to restart the stream:

window.addEventListener('online', function() {
  audio.play();
});
  • `online` event has nothing to do with audio streams. – Ajoy Nov 06 '17 at 17:39
  • In the scenario you laid out, the audio stream stops playing after you disconnect the internet. The 'online' event will be fired when the internet comes back online. – JonathanPuckey Nov 26 '17 at 10:10
  • As long as the device is connected to a Wi-Fi, `offline` will not fire; neither would `online`. This question is for those cases where connection is lost between the WiFi router and the internet. – Ajoy Nov 26 '17 at 11:41