-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose MediaSession.activate() and define any implicit activation in terms of it #50
Comments
I like how this provides the ability to activate your session for receiving remote control events before starting playback. If we extend the MediaSession with the ability to probe the system for other playing audio, we can properly support the use case where you can set up your app with lock screen UI, meta-data and all and then wait for the play command, provided no other audio is playing on your system. On iOS the meta-data wouldn't show until you start playing, but otherwise it should work fine. |
My issue with an 'activate-then-play' model vs. our current model of 'activate-on-play' (+ the proposed With the activate-then-play approach (top diagram above) a web developer could The worst part of the proposal is that an "activate-then-play" approach actually encourages web developers to In the "activate-on-play" approach (bottom diagram above) it is not possible to interrupt another tab or application's media from playing out until media actually begins playing out in the current tab. That enables a smooth handover to happen between media content and means other web apps do not interrupt, e.g. my currently playing music, until it is unavoidable (because we now need the audio channel and any platform media key bindings available for the new content). Unless there is an actual use case for allowing what could be an indeterminate amount of time to pass between What is the use case for that potentially indeterminate gap between |
Rich, did you see the use-case described in the comment one above yours or did you disagree with it in any way? I see no reason for the potential gap actually being a problem. If so, we would see them in native apps as well. |
Lest anyone get the wrong impression from the (very nice) illustration, the activation trigger isn't "non-zero samples are being sent to the audio output" but rather "the audio output is in use, potentially playing silence". In any model, it will thus be possible to simply play silence with Web Audio to get all the power. This issue isn't motivated by use cases, but by matching the power of native APIs as far as possible. Even having worked in this area for months, I'm not comfortable betting that I know better than the author's of the native APIs and that there will in fact not be any important use cases. |
Here's a use case that isn't that far-fetched: you have an immersive experience like the opening sequence of a game, but it starts in silence with only visuals. After some time, a media element is used to ramp up some music. It would be silly if one has to use Web Audio in silence or pad the media element with silence instead of simply activating the session early and playing the music when the time comes. |
I don't disagree with the use case, per se. If you want to grab media key controls at the expense of anything currently playing elsewhere without replacing it with any media of your own immediately then you could still do that. You would confuse a lot of users as to why their music has stopped and their headphone buttons no longer resume that music in another tab or app but...you could still do it. See below...
If you really wanted to you could achieve the same thing by running the first code snippet in #48 (comment). That gives you exactly the same thing, admittedly with silence still being output to the speakers. But...then you could just That's not the main use case though in my opinion. The main use case is late binding of the media focus activation (and, thus, delaying the interruption of any other currently playing media to the last possible moment) to enable smooth transitions between web apps and native apps without a web page idly sitting on media focus, perhaps indefinitely. Activate-on-play optimizes for the late binding use case. Activate-then-play optimizes for the early binding use case. |
My use-case depended on MediaSession growing the ability to tell if there is another active MediaSession or other music playing. There are APIs for this on both iOS and Android. So no at the expense of anything currently playing involved. Given this, the (web)app may want to setup a state where it's ready to play, show lock-screen controls for that and just await a remote control event or a play from elsewhere to start the playlist. It would do so by first checking for other currently playing audio and if there is no currently playing audio call activate() to get the ability to get events and set meta-data. Granted, the app could do this with a silent media element or WebAudio as well in the implicit activation scenario, but it's far from elegant and the playback state in the remote controls would be wrong. It would show a playing instead of a paused state. |
Requiring web developers to poke at the audio output (in silence) before they actually want to play works, but I too would characterize it as "far from elegant" or indeed "silly." |
@doomdavve wrote:
@foolip wrote:
Activate-then-play is really the exact same thing, just the other way around. But, crucially, what the current model, activate-on-play, does is to optimize for the 80% use case: interrupt any other currently playing media at the last possible moment when it is immediately replaced by new playing media content. If any web page activates a new MediaSession when its loads and thus interrupts my music from playing and then never plays any media of its own, as a user I'm not going to be happy (see a selection of real user complaints about this listed below @ #50 (comment)). If it means I then press my headphone button and now, seemingly randomly, some new media starts playing from this new web page instead of the music I was just listening to, I'm not going to be happy for the same reasons. |
Nothing stands in the way of catering to the 80% use case and making that API harder to make mistakes with. I mean "define any implicit activation in terms of it" and not "never do implicit activation." I don't think implicit activation for Web Audio looks helpful, but for media elements it does, at the very least as part of a declarative syntax like |
I did some searching and the activate-then-play approach used in native platforms is causing UX problems between native apps: Related Google search: https://www.google.com/search?q=%22stops+when+i+open%22 https://community.spotify.com/t5/Help-iOS-iPhone-iPad/Spotify-stops-playing-when-switching-to-other-apps-on-iPad/td-p/500764 What some applications are doing is requesting audio focus early and not before any media actually starts playing and not, as users are expecting, immediately after the user has signalled an intent to actually play media in that app. Users are posting to forums that their music or podcasts are pausing 'seemingly randomly' when opening another app. For a full explanation of what these applications are doing, see my previous comment @ #50 (comment). |
A couple of other comments:
IIUC, calling
I think we should consider an API that lets a web developer detect if anything else is playing on the system. The particular use case I have in mind is: if I'm playing music in a backgrounded app or tab then don't play my web game's background music - only play e.g. its sound effects (just keep playing the background music that was already running when the web page was loaded). |
No, there is no such connection. The only connection I've been able to find is that meta data isn't updated/fetched from app until you start playing. |
From the iOS Remote Control Events documentation:
Is the iOS Remote Control Events documentation wrong? |
...
I re-did my experiments and you do need to be the "Now Playing" app to receive the events. It's not clear to me exactly how the "Now Playing" app is defined but I can tell that you don't have to be actively playing audio. It's does seem that you must have been playing audio sometime in the past though, even though your app may have been restarted in the mean time. (The latter part confused me for some time.) Side note: One other particular issue that confused me for a long time was that prepareToPlay() on the AVAudioPlayer grabbed audio focus behind my back. (This might be an indication we should be careful where we do implicit invocation in general.) I think this issue was part of the problems described in the URLs you posted. |
I think we are getting a bit off track in this issue. This is about how to activate a session, and neither iOS nor Android require playback for activation. Making activation explicit matches the actual order of events and gives web developers more power that would otherwise be hidden inside of media elements and Web Audio. More power leaves more room for mistakes, and it's a price worth paying. In #50 (comment) we don't know if the cause is sloppy use of explicit activation or accidental implicit activation, which is what happened in http://stackoverflow.com/questions/24153917/how-can-i-avoid-interrupting-audio-that-is-already-playing-when-my-app-launches and for @doomdavve too. |
IRC discussion with @annevk: |
We (@foolip, @doomdavve and I) discussed the following use case today: var el = document.createElement("audio");
var session = new MediaSession("content");
el.src = "music.mp3";
el.controls = true;
el.session = session;
document.body.appendChild(el); If a media element is played via its We could aim to fix this by adding a Activate-on-play (implicit media session activation) solves this issue without needing to expose any additional hooks or events to web developers. tl;dr it's very difficult to |
Couldn't you just define that as doing the activation and then playing? |
To be clear, it seems fine to me to have both explicit and implicit activation. And I don't really see a conflict. |
Right, while it's in principle possible to have only explicit activation, I don't propose that. If we have a explicit activation, then implicit activation should happen as you're ready to play (buffered enough, |
While reading this thread, that's exactly what I wanted to propose: let people use |
…ants' This commit removes the implicit reliance media element-only objects from the generic media session algorithms in the spec. The specification now defines 'audio-producing participants' that provides a better abstraction point on which we can add additional audio-producing object types (such as e.g. Web Audio). This commit does not enable e.g. Web Audio to obtain media focus yet pending the outcome of #48 and #50. This commit fixes #49 pending review.
An open question is if there should be any restrictions on when
I'm inclined to start with no restrictions and add them only if we see any abuse that can't be dealt with by other means, but don't feel super strongly either way. |
We think that we should have the same restrictions as .play()/autoplay. If you can activate with these, there is no reasons why the methods couldn't behave the same way. How to translate that in spec words might be hard though ;) |
In #50 (comment) we showed that, in certain situations, the web platform lacks any appropriate hooks for invoking With that in mind, explicit activation via When nuisance.com interrupts my currently playing music by invoking Let's not make it a feature of this API to disrupt a user's ongoing music arbitrarily at any time unless you're committing to actually replacing it with something else immediately. Also, let's not make users choose between playing music on their phones and browsing the web at the same time (at the risk of constant unsolicited interruptions); or only being able to do one of these activities at a time (to avoid such potentially unsolicited interruptions from pausing my music). |
That only makes sense if you restrict playing things by default, which I don't think we were planning on doing? |
Also, please consider telephony and Web Audio here. They need to work well. |
I have it on my TODO to prepare a PR for |
* Let MediaSession.deactivate() return a promise. * Drop implicit activation and decativation for AudioContext. Fixes w3c#50
Also: * Let MediaSession.deactivate() return a promise. * Drop implicit activation and decativation for AudioContext. Fixes w3c#50
Also: * Let MediaSession.deactivate() return a promise. * Drop implicit activation and decativation for AudioContext. Fixes w3c#50
It has become apparent that our current model, which requires that one of the media session's participants start using the audio output device, is actually slightly more restrictive than iOS, and of course also Android. Both platforms make it possible to request audio focus, thus interrupting other apps, before beginning to produce any audio output. The iOS restriction is that you will not become the "now playing" app until you start producing audio, which is what gives you control over the playback controls in the drawer.
I propose something like this:
Using with media elements:
Using with Web Audio:
It's clear that you activate and then play. This is the actual order in the current model as well, but the activation is implicit by attempting to play.
This is not to the exclusion of implicit activation by media elements, but that could be defined in terms of the web-facing API. For Web Audio I can't see a reason to do implicit activation at all.
The text was updated successfully, but these errors were encountered: