(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.
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.
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:
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.
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 https://github.com/discourse/discourse/pull/10160 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:
Press play: GET /secure-media-uploads/dev/original/4X/6/1/8/618a6b19a07de18205cc9889cb604e414b30372b.mp3 which returns a status of Finished
Press pause.
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.
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.
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.
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.
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.