Question

Widget API Broken due to Chrome AutoPlay policy


@SoundCloudDev In your Widget API: SC.Widget.Events.READY is now broken due to Chrome's new AutoPlay policy. It is not possible to get the audio to autoplay anymore. Do you know a fix for this issue?

23 replies

I must preface this by explaining that the code execution starts from a click on a link, so Auto Play should work.

What I have found out so far, is that if the call to the:

```
player.bind(SC.Widget.Events.READY,function(){
onSCPlayerReady(player)
}
```

Is made from within an Ajax call, Chrome throws a warning about AudioContext & refuses to play the audio. It seems to be complaining about the fact that there is no user interaction. I think the event context is being lost inside the Ajax call.

When I make the call from a normal function, in other words, not inside an inner function, auto Play works fine. But, I have to make the call from within an Ajax request.

I have tried all the normal fixes like:

```
var that = this;
```

And:

```
$.ajax({
url: url,
context: this
})...
```

Please can someone help me, as this problem has seriously broken my audio application.

In Firefox, it works fine...
Userlevel 7
Badge +3
Hi there,

Hmm, it looks like this might be something only the end user has a say in. This article is addressing the topic on Chrome's end: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes
The problem occurred because the Ajax called was wrapped inside:

jQuery(loading).fadeIn("slow",function(){
// Ajax code...
})

For some reason the event context gets lost and Chrome/SoundCloud throws a wobbly. This is some kind of obscure bug, that took me a week to resolve, by removing the code, line by line! The strange thing is, is that I don't even have an AudioContext set up in my code, so I have no idea why Chrome/SoundCloud were complaining about this!

Anyway, thanks for your help!
OK. I spoke too soon. Tonight, Google Chrome got updated automatically to the most recent version. After this, auto play stopped working again with a Google Audio Context policy warning. But, I have not set up an audio context. I am using the an iframe that is initiated on page load. I have created a play button that runs the code above. Fairly simple stuff.

Any ideas about how to resolve this problem. I am getting serously hacked off with Google.

The thing is, it works in every other browser including mobile Safari iOS 12.

Come on Google. Stop messing with our applications.
The Audio Context warning gets thrown just before I call:

player.play();

I was was thinking maybe I need to mute the audio?

When I muted my YouTube videos, they started playing automatically again????

I really think the SoundCloud technical team need to talk to Google about this and try to find some way that developers can enable auto play.
I will try the following tomorrow and let you know the results:

```
player.setVolume(0);
```

**Google's Auto Play policy explicitly states:**

Chrome's autoplay policies are simple:
  • Muted autoplay is always allowed
**Google's Auto Play policy goes on to state:**

Autoplay with sound is allowed if:
  • User has interacted with the domain (click, tap, etc.).
Now, each of my audio tracks has a big red play button next to it. When a user clicks on the button it uses an 'onClick' handler to send data through several functions, until it ends up firing the SoundCloud Widget API's:

```
player.bind(SC.Widget.Events.READY,function(){
player.play();
});
```

Now, it looks like I am adhering to Google's Auto Play policy, so why isn't it working?

And why on earth am I getting an 'Audio Context' warning in the console. I haven't set up an Audio Context, unless SoundCloud is creating one, behind the scenes.

If this is the case, the SoundCloud engineers need to to supply us with a hook, to interact with it. Then we can just add:

```
AudioContext.resume();
```
And why am I writing replies to myself?

This is is an important issue. It is affecting many developers globally. And, if SoundCloud fails to respond, many developers will start using alternative audio APIs. This is a competitive market place.

Please can someone at SoundCloud create a pull request to resolve some of the points above.
And I have just found out that:

```
player.isPaused();
```

Returns the player object itself and not a boolean as expected?

Has the SoundCloud Widget API been recently updated, because some strange things are happening now?
Does anyone know how I can get hold of the AudioContext that is created within the Soundcloud IFRAME?
Userlevel 1
The only solution I could find was to explicitly add allowed domain names under
Chrome settings > Content Settings > Sound

Which is not quite what you want to ask your visitors to do ...
D-Heap. Thanks for this. You are right, this needs to be a programmatic solution.

I have found out that when the SoundCloud player is inserted into the IFRAME, the Widget API script, the parent page's head, uses postMesage() to communicate with the SoundCloud API script in the IFRAME head. The SoundCloud API uses AudioContext & Web Audio to create the player.

I need to find a way way to get a reference to the AudioContext, so that I can do something like:

AudioContext.resume();

But, I have a feeling that the IFRAME CORS policy will prevent this reference from being available to any script outside the IFRAME.
I have to say D-Heap that it felt so good, to add:

[.*]localhost to my Content Settings -> Sound

And seeing my audio play again, like it used to.
Good call, but it is not really a viable solution to ask users, many of whom, can barely type in a web address to the browser bar, to change their Chrome settings.

But, I am trying to work out, whether SoundCloud can create a viable solution, by allowing us to access the AudioContext within the IFRAME.

SoundCloud could provide us with a proxy function like:

player.audioContextResume()

Which would use postMessage() to send a flag to the SoundCloud API to apply:

AudioContext.resume()

Within the IFRAME.

This might work?
Userlevel 1
The solution was in fact in @Mathis reply.

https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#iframe

Adding `allow="autoplay"` to the iframe allows using the `widget.play()` method, as long as it comes from a gesture.
D-Heap. Holy smoke. This works. I have spent weeks trying to fix this and all it required was 'allow=autoplay'. The thing is, I read Google's policy several times and they kept talking about 'AudioContext.resume()' and I know for a fact that SoundCloud uses the Web Audio API to create their player, so I immediately thought it was something to do with AudioContext.

I have a lot of apologies to make now, including a Google bug report that needs deleting.

Wow. I am so pleased. What a relief.

Thanks so much for your help!
I may also suggest to the SoundCloud team that it should add this information to the Widget API Documentation. I realise that this is a Google Chrome restriction, but it directly relates to the SoundCloud Widget API, which uses an IFRAME.
Userlevel 1
Documentation is your friend 🙂
Should've read that more carefully myself...

Happy that helped you anyways.

FYI Safari has a similar restriction but it works cross-domain whereas Chrome requires the `allow` attribute.
Userlevel 7
Badge +3
Hey hey.

Super happy to see there was some to and fro here and this could be sorted out. I have to say my knowledge in writing code is quite basic, so I would not have been able to get to the bottom of this - thanks @D-Heap for stepping in!
Yes. Thanks to both of you.

It's a sad day for Chrome, when mobile Safari requires fewer restrictions to get it's audio to work!😉
Just one other question.

Does:

player.seekTo();

Refer to the absolute position in the timeline or the relative position?

For instance:

player.seekTo(0);

Will this take me to the beginning of the timeline, if the audio has just triggered the FINISH event?
What seems to be happening when I do:

player.bind(SC.Widget.Events.FINISH,function(event){
player.pause();
player.seekTo(0);
console.log("FINISHED");
});

Is that the FINISH event is triggered twice?
Userlevel 1
@charlesr1971 Please see the docs >> https://developers.soundcloud.com/docs/api/html5-widget#methods

seekTo(milliseconds)

When the FINISH event triggers, the player rewinds to the beginning of the track - if not a playlist.

Also see >> https://w.soundcloud.com/player/api_playground.html

Select `Sound widget by Pro Unlim User` and reload the widget, then go the the end of the track and when it finishes playing you can see that the `currentPosition` is set to zero.

You can track the progress with `SC.Widget.Events.PLAY_PROGRESS`
D-Heap. That's very useful to know that the track rewinds once it is finished.

Thanks...

Charlie

Reply