Videocontrols fail to show "click-to-play" button again after a new resource has loaded

RESOLVED FIXED in Firefox 24

Status

()

RESOLVED FIXED
5 years ago
5 years ago

People

(Reporter: roc, Assigned: roc)

Tracking

Trunk
mozilla24
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(blocking-b2g:tef+, firefox22 wontfix, firefox23 wontfix, firefox24 fixed, b2g18 verified, b2g18-v1.0.0 wontfix, b2g18-v1.0.1 fixed)

Details

(Whiteboard: [apps watch list])

Attachments

(2 attachments, 2 obsolete attachments)

Open http://cd.pn/yt/. Click-to-play. Click on the "Change" button to load a new resource. Note that no "click to play" button appears. Also if you keep the controls visible, the "current time" doesn't reset to 0 immediately.
We believe this is affecting the Youtube app on v1.0.1.
status-b2g18: --- → affected
status-b2g18-v1.0.1: --- → affected
tracking-b2g18: --- → ?
Created attachment 754413 [details] [diff] [review]
fix

This isn't a complete fix to all the issues that could arise when a new load happens. Maybe init() should be called again, or something like that. But this is less risky.
Attachment #754413 - Flags: review?(cpearce)

Updated

5 years ago
Attachment #754414 - Attachment is patch: true
Attachment #754414 - Attachment mime type: message/rfc822 → text/plain
Comment on attachment 754413 [details] [diff] [review]
fix

We need review pretty much "now" for B2G.
Attachment #754413 - Flags: review?(dolske)
Attachment #754413 - Flags: review?(jaws)
Attachment #754413 - Flags: review?(chris.double)

Comment 5

5 years ago
I think setupNewLoadState will need to be called in 'loadstart' not 'loadedmetadata' to account for the preload=none case.
Created attachment 754479 [details] [diff] [review]
fix v2, v1.0.1 version

This moves the call to setupNewLoadState to loadstart. It also makes setupNewLoadState check video.paused --- for preload=none videos, it's possible for loadstart to fire after play() has already been called, in which case we don't want to show the click-to-play button or the controls.
Attachment #754413 - Attachment is obsolete: true
Attachment #754414 - Attachment is obsolete: true
Attachment #754413 - Flags: review?(jaws)
Attachment #754413 - Flags: review?(dolske)
Attachment #754413 - Flags: review?(cpearce)
Attachment #754413 - Flags: review?(chris.double)
Attachment #754479 - Flags: review?(jaws)

Updated

5 years ago
blocking-b2g: --- → tef?

Updated

5 years ago
Whiteboard: [apps watch list]
Comment on attachment 754479 [details] [diff] [review]
fix v2, v1.0.1 version

Review of attachment 754479 [details] [diff] [review]:
-----------------------------------------------------------------

::: toolkit/content/widgets/videocontrols.xml
@@ +357,5 @@
>                      // Since the play button will be showing, we don't want to
>                      // show the throbber behind it. The throbber here will
>                      // only show if needed after the play button has been pressed.
> +                    if (!this.clickToPlay.hidden) {
> +                        this.startFade(this.statusOverlay, false, true);

This change seems to work against the goal of the comment above it.
Comment on attachment 754479 [details] [diff] [review]
fix v2, v1.0.1 version

Review of attachment 754479 [details] [diff] [review]:
-----------------------------------------------------------------

Random omg-definitely-not-for-this-bug ponder:

I wonder if it would be useful to have each media event carry the full state of the media element as it was when the event was dispatched. The existing complexity in setupStatusFader() got me thinking about this as a way to avoid subtle bugs caused by mixing the "as it was" state implied by an event and "as it is" state returned by media.someProperty.

For example, aiui a listener for the "paused" event is not assured to find that media.paused == true. But it could be assured to find that event.mediaState.paused == true. In theory, code that was entirely event-driven could then have a stronger set of invariants and be easier to test -- dispatching any single event at it would be sufficient, and every event could effectively be a full reset / initialization.  The event name essentially becomes an hint for "what changed". A media.sendGenericStateEvent() method+event might be useful for first setup.

I suppose the inverse would be to listen for all media events, and have the listener update the controls based on the current state.

::: toolkit/content/widgets/videocontrols.xml
@@ +357,5 @@
>                      // Since the play button will be showing, we don't want to
>                      // show the throbber behind it. The throbber here will
>                      // only show if needed after the play button has been pressed.
> +                    if (!this.clickToPlay.hidden) {
> +                        this.startFade(this.statusOverlay, false, true);

this.startFadeOut(this.statusOverlay, true);

@@ +473,5 @@
>                      this._handleCustomEventsBound = this.handleCustomEvents.bind(this);
>                      this.video.addEventListener("media-showStatistics", this._handleCustomEventsBound, false, true);
>                  },
>  
> +                setupNewLoadState : function() {

Hmm. This is sorta what setupInitialState() was intended to do, although originally aimed more are the binding being attached at an arbitrary time than loading a new resource.

I'd like to move towards a single "resetState()" kind of thing, but I suppose what you've got is safest for B2G's immediate needs.

@@ -1392,5 @@
> -                    //
> -                    // (Note: the |controls| attribute is already handled via layout/style/html.css)
> -                    var shouldShow = (!(this.video.autoplay && this.video.mozAutoplayEnabled) || !this.dynamicControls);
> -                    // Hide the overlay if the video time is non-zero or if an error occurred to workaround bug 718107.
> -                    this.startFade(this.clickToPlay, shouldShow && !this.isAudioOnly &&

Note that this doesn't apply on m-c because this line changed. Just a gentile reminder to make sure that change carries over to setupNewLoadState(). Would be nice if diff had a way to represent moving code. And ponies.
Attachment #754479 - Flags: review?(jaws)
Attachment #754479 - Flags: review?(dolske)
Attachment #754479 - Flags: review?(cpearce)
Attachment #754479 - Flags: review+
(In reply to Jared Wein [:jaws] from comment #7)
> ::: toolkit/content/widgets/videocontrols.xml
> @@ +357,5 @@
> >                      // Since the play button will be showing, we don't want to
> >                      // show the throbber behind it. The throbber here will
> >                      // only show if needed after the play button has been pressed.
> > +                    if (!this.clickToPlay.hidden) {
> > +                        this.startFade(this.statusOverlay, false, true);
> 
> This change seems to work against the goal of the comment above it.

Then I'm confused ... This code hides the throbber if the play button is showing. Which is exactly what the comment says!

(In reply to Justin Dolske [:Dolske] from comment #8)
> I wonder if it would be useful to have each media event carry the full state
> of the media element as it was when the event was dispatched. The existing
> complexity in setupStatusFader() got me thinking about this as a way to
> avoid subtle bugs caused by mixing the "as it was" state implied by an event
> and "as it is" state returned by media.someProperty.

Yes, I agree this is an issue. I tried to get it fixed in the HTML5 spec (so during event dispatch the element's methods would return state "as it was" when the event was triggered) but that was rejected. Your suggestion is a good one.

> ::: toolkit/content/widgets/videocontrols.xml
> @@ +357,5 @@
> >                      // Since the play button will be showing, we don't want to
> >                      // show the throbber behind it. The throbber here will
> >                      // only show if needed after the play button has been pressed.
> > +                    if (!this.clickToPlay.hidden) {
> > +                        this.startFade(this.statusOverlay, false, true);
> 
> this.startFadeOut(this.statusOverlay, true);

OK, will do.

> @@ +473,5 @@
> >                      this._handleCustomEventsBound = this.handleCustomEvents.bind(this);
> >                      this.video.addEventListener("media-showStatistics", this._handleCustomEventsBound, false, true);
> >                  },
> >  
> > +                setupNewLoadState : function() {
> 
> Hmm. This is sorta what setupInitialState() was intended to do, although
> originally aimed more are the binding being attached at an arbitrary time
> than loading a new resource.
> 
> I'd like to move towards a single "resetState()" kind of thing, but I
> suppose what you've got is safest for B2G's immediate needs.

Yes, I fully agree.
Oh, I meant to add:

There's also the question as to if the CTP UI state should really be shown again when an element's resource is (re)set. I think there was some vague notion of CTP being mainly useful for calling attention to the media when the page _first_ loads. After which, once the user has interacted with the element, CTP is perhaps no longer so useful (which is why it's not shown again after the playback first ends). EG, a page doing a "slideshow" of videos back-to-back might not want the CTP UI flashing into view between playbacks.

But mostly this falls in to the "need more usage feedback" as to what makes sense.
(In reply to Jared Wein [:jaws] from comment #7)
> Comment on attachment 754479 [details] [diff] [review]
> fix v2, v1.0.1 version
> 
> Review of attachment 754479 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: toolkit/content/widgets/videocontrols.xml
> @@ +357,5 @@
> >                      // Since the play button will be showing, we don't want to
> >                      // show the throbber behind it. The throbber here will
> >                      // only show if needed after the play button has been pressed.
> > +                    if (!this.clickToPlay.hidden) {
> > +                        this.startFade(this.statusOverlay, false, true);
> 
> This change seems to work against the goal of the comment above it.

I misunderstood this code change. After changing this to use startFadeOut it will be clearer.
Status: NEW → ASSIGNED
OS: Linux → All
Hardware: x86_64 → All
Version: unspecified → Trunk
Created attachment 754641 [details] [diff] [review]
patch updated to comments

[Approval Request Comment]
Bug caused by (feature/regressing bug #): none
User impact if declined: Play button fails to appear in some apps when a new media resource is loaded into an existing media element (especially in Youtube app)
Testing completed: a small amount of testing by me and Chris Double
Risk to taking this patch (and alternatives if risky): similar to bug 876426. Fairly low risk, videocontrols not used much in b2g 1.0.1.
String or UUID changes made by this patch: none
Attachment #754641 - Flags: approval-mozilla-b2g18?
Hmm, on central we have
                    var shouldShow = (!(this.video.autoplay && this.video.mozAutoplayEnabled) || !this.dynamicControls);
                    // Hide the overlay if the video time is non-zero or if the video is already playing
                    // or if an error occurred to workaround bug 718107.
                    this.startFade(this.clickToPlay, shouldShow && this.video.paused && !this.isAudioOnly &&
                                   this.video.currentTime == 0 && !this.hasError(), true);
                    this.startFade(this.controlBar, shouldShow, true);

Note that the "paused" check I added to shouldShow has been added to startFade(this.clickToPlay) here.

I'm pretty sure we don't want to bring up the controlBar for a video that's already playing. So I'm going to carry my change forward.
Attachment #754641 - Flags: approval-mozilla-b2g18? → approval-mozilla-b2g18+
Hmm...the timeout is coming from a webrtc crashtest that currently only runs on FxAndroid and Desktop Firefox. That test in particular runs a PC handshake, reloads the page, and repeats that same process 5 times in a row.
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #9)
> I tried to get it fixed in the HTML5 spec (so
> during event dispatch the element's methods would return state "as it was"
> when the event was triggered) but that was rejected. Your suggestion is a
> good one.

Wouldn't implementing "as it was" be compatible with what the spec defines? I.e. if we implement "as it was" we wouldn't be failing test harnesses, but websites would work more reliably in Firefox.

We'd of course need to be upfront about it and let people on the lists know. Implementation behavior weighs very heavily.
https://hg.mozilla.org/mozilla-central/rev/6a70ea277263
Status: ASSIGNED → RESOLVED
Last Resolved: 5 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla24
status-b2g18: affected → fixed
status-b2g18-v1.0.0: --- → wontfix
status-b2g18-v1.0.1: affected → fixed
status-firefox22: --- → wontfix
status-firefox23: --- → wontfix
status-firefox24: --- → fixed
(In reply to Jonas Sicking (:sicking) from comment #20)
> Wouldn't implementing "as it was" be compatible with what the spec defines?
> I.e. if we implement "as it was" we wouldn't be failing test harnesses, but
> websites would work more reliably in Firefox.

I think there would be observable differences especially once you combine media elements with other Web platform features.

> We'd of course need to be upfront about it and let people on the lists know.
> Implementation behavior weighs very heavily.

Justin's idea of passing state into the event makes a lot of sense to me and sidesteps the spec issues.

However, we also might be able to keep the current behavior and refactor the videocontrols code to get mostly the same benefits, per Justin's comment above "I suppose the inverse would be to listen for all media events, and have the listener update the controls based on the current state." I think we should try that.
Not clear how this got uplifted to v1.0.1 without being tef+ - setting that flag now so we can keep this tracked correctly in case of backout/regressions.
blocking-b2g: tef? → tef+
tracking-b2g18: ? → ---
(In reply to Robert O'Callahan (:roc) (Mozilla Corporation) from comment #13)

> I'm pretty sure we don't want to bring up the controlBar for a video that's
> already playing. So I'm going to carry my change forward.

Yeah, and is also consistent with the existing check there to not initially show controls for autoplay videos.

Updated

5 years ago
Keywords: verifyme
QA Contact: jsmith
Works fine on b2g18 5/31 build.
status-b2g18: fixed → verified

Updated

5 years ago
Keywords: verifyme

Updated

5 years ago
Depends on: 898940
You need to log in before you can comment on or make changes to this bug.