Secure media audio does not play on Safari on the first click

(Probably since the update to 2.5.0 stable) secure media audio files do not play on Safari on the first click. It requires two or three clicks on the play icon in order to start the audio. On the first clicks, no request is received on the web server. Only the third click or so sends the request.

This seems like a browser issue since it only happens on Safari, but it feels a bit suspect that this started happening around the update to 2.5.0.

Does anyone have a related experience?

Not sure if this is related to this or not. Secure media uploads expire

2 Likes

@martin any ideas here?

I’ll take a look tomorrow. Sounds like a Safari issue if it takes two or three clicks there – will try it out my iPhone.

3 Likes

I can confirm that this is buggy for me on iOS both with Safari and Firefox. The audio does not play until multiple play/pauses are done. The widget component looks the same in both (I think Firefox mobile is just a wrapper around the mobile safari rendering engine). I tried this on iOS 13.5.1.

There are a bunch of quite recent audio issues in the WebKit bug tracker but I am not sure if any are relevant https://bugs.webkit.org/buglist.cgi?bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=product&field0-0-1=component&field0-0-2=alias&field0-0-3=short_desc&field0-0-4=status_whiteboard&field0-0-5=content&no_redirect=1&order=changeddate%20DESC%2Cbug_status%2Cpriority%2Cassigned_to%2Cbug_id&query_format=advanced&type0-0-0=substring&type0-0-1=substring&type0-0-2=substring&type0-0-3=substring&type0-0-4=substring&type0-0-5=matches&value0-0-0=audio&value0-0-1=audio&value0-0-2=audio&value0-0-3=audio&value0-0-4=audio&value0-0-5="audio".

This w3schools audio clip does work for me in iOS Safari and Firefox Tryit Editor v3.6. Possibly the issue is that we use preload="none"? That is the only difference I can think of…or that our 302 redirect of the secure media URL to the actual audio URL causes some issue?

Some possible clues that lead me to think it is the redirect causing the issue:

1 Like

It looks like there is no request fired towards the server on the first clicks, so the issue must be before the 302…

3 Likes

@martin have you been able find anything regarding this issue?

Unfortunately not I have been busy on other projects. I have this on my list though and I am hoping to start looking it more thoroughly soon. We have briefly discussed similar issues internally as well.

5 Likes

This has been an adventure so far…so I was able to set up remote debugging between Chrome on my Ubuntu machine and iOS Safari on my iPhone, with many tribulations. Annoyingly, however, the Network tab is blank, which is kinda the most important one for this.

I have found that setting preload="metadata" makes the audio play on first click in iOS Safari, where if it is set to preload="none" then it requires a sequence of Play > Pause > Play to actually play the audio.

I tried this out with video and it appears that a similar issue exists.

Changing to preload="none" was done because of your bug report here Secure media uploads expire. We are in a kind of annoying twilight zone here now because putting the preload back to metadata will re-introduce the above issue. We have recently bumped the presigned URL expiry to 5 minutes FIX: Increase time of DOWNLOAD_URL_EXPIRES_AFTER_SECONDS to 5 minutes by martin-brennan · Pull Request #10160 · discourse/discourse · GitHub so the original bug will be less of an issue now…but still an issue.

I am still thinking about this and messing around with things…I am not sure if we can have the best of both worlds here. It is not an ideal experience for secure media to require multiple clicks to view.

Edit: I got the Network tab of my debugger working. An example on our internal Discourse instance for a preload="none" audio tag:

  1. Press play: GET /secure-media-uploads/dev/original/4X/6/1/8/618a6b19a07de18205cc9889cb604e414b30372b.mp3 which returns a status of Finished

  2. Press pause.

  3. Press play: GET presigned_url_here which returns a status of 206 Partial Content, and the audio loads correctly.

The strange thing here is that with preload=“metadata” we get the exact same sequence of requests, with only one play click. It is like Safari fetches the metadata on first click of Play, then needs a pause and play again to play the audio.

I am not sure if this happens on other devices e.g. Android? I don’t have a device to test with there.

5 Likes

That is an impressive debugging session!

One question:

What does this response look like? Finished is not a HTTP response code, right?

Thank you!

Good question! And yes you are correct Finished is not a status code. I get no additional information from the Network tab here:

The size is 0B and the time is 0ms.

1 Like

This inspired me to set up mitmproxy and take another look at what is going on here. It seems like that first “Finished” request is not leaving the iOS device / Safari browser. The mitm proxy does not register anything until the second time PLAY is being clicked.

1 Like

Would it makes sense to use preload="metadata" only for Safari (both iOS and desktop, I can repro this on desktop too), and preload="none" elsewhere?

(Also, this doesn’t look like it’s happening on Android for me, tested in a PWA.)

3 Likes

Yes I think we will have to go down that route. Thanks for testing on Android & Desktop Safari too. The preload attribute is cooked at the moment, so I guess we would need some client-side code to detect that the browser is Safari and switch out the preload attribute. Will do some experiments with this today.

3 Likes

To ensure I’m understanding this correctly, the bug will resurface on audio where Safari makes a download chunking point past the 5 minute mark?

Yes, but with this new fix I think I can get around this by only changing the preload attribute when the post with the media comes into view (e.g. via scrolling). The issue is that once the metadata is fetched from the secure media URL, the presigned URL is generated and used in the player, which expires in 5 minutes. So if you don’t press play in that 5 minutes the URL will have expired.

I am wondering if I can use JS to play then pause the media, whether that makes a difference to the 206 partial content requests that are sent later, which do not seem to be beholden to the presigned URL expiry. I could be wrong here though, I need to play around some more.

Edit: Confirmed on an Android device using Chrome myself that this issue does not exist there.

4 Likes

With @martinwoodward’s blessing, I made a few commits today that switch to using preload="metadata" for all audio/video elements in all contexts, secure media included. This should fix the issue described here.

Note that if the user stays on the page for longer than 5 minutes, they will most likely not be able to play the audio/video, because the secure URLs are currently only valid for 5 minutes.

4 Likes

Sorry for the late response - this issue is indeed fixed now :tada:

Thanks @pmusaraj and @martin !

3 Likes