Closed Bug 1126465 Opened 11 years ago Closed 11 years ago

MediaSourceReader seek can get scuttled when it mid-airs with the tail-end of an outstanding Request{Audio,Video}Data

Categories

(Core :: Audio/Video, defect, P1)

x86
macOS
defect

Tracking

()

RESOLVED FIXED
mozilla38
Tracking Status
firefox36 --- fixed
firefox37 --- fixed
firefox38 --- fixed

People

(Reporter: bholley, Assigned: bholley)

References

(Blocks 1 open bug)

Details

Attachments

(11 files, 1 obsolete file)

1.99 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
1.69 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
6.63 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
10.70 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
5.26 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
10.25 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
3.66 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
4.89 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
3.79 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
14.89 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
12.65 KB, patch
mattwoodrow
: review+
Details | Diff | Splinter Review
This is the source (or a source) of the timeouts I've been investigating in bug 1126052. The basic problem is that MediaSourceReader doesn't wait for any previous sample requests it has made to be resolved before it starts trying to seek. So if one of those requests get resolved at the right moment during seek, we overwrite mLast{Audio,Video}Time to a time in the old region we've seek away from. This means that the MDSM will just keep requesting and dropping samples in Drop{Audio,Video}UpToSeekTarget, and we'll get stuck. MediaSourceReader::On{Audio,Video}Decoded _try_ to deal with this problem by checking for {m{Audio,Video}IsSeeking before updating mLast{Audio,Video}Time, but these values don't actually remain true for the full duration that the old sample request might be resolved. And indeed, I'm not sure we can really put a latest bound on when that might happen. The two decent solutions I can think of are: (A) Waiting for any outstanding requests to be resolved before initiating the seek, or (B) Implementing some sort of promise cancellation (probably only for exclusive promises). I'll investigate solutions here after lunch.
This isn't right, and it means that we can't assume at the top of On{Audio,Video}{,Not}Decoded() that we're fresh out of promise dispatch, which we want to do.
Attachment #8556141 - Flags: review?(matt.woodrow)
Attachment #8556145 - Attachment description: Part 4 - Implement the ability to disconnect outstanding promises. v1 → Part 5 - Implement the ability to disconnect outstanding promises. v1
The duplication of the IsSeeking() checks before all the Request{Audio,Video}Data callsites is ugly. We'll fix this in the next patch by applying the same disconnect treatment to the seek promise.
Attachment #8556149 - Flags: review?(matt.woodrow)
Attachment #8556141 - Flags: review?(matt.woodrow) → review+
Attachment #8556142 - Flags: review?(matt.woodrow) → review+
Attachment #8556150 - Flags: review?(matt.woodrow) → review+
Attachment #8556151 - Flags: review?(matt.woodrow) → review+
Attachment #8556152 - Flags: review?(matt.woodrow) → review+
Comment on attachment 8556153 [details] [diff] [review] Part 10 - Use a MediaPromiseConsumerHolder to track subdecoder seeks. v1 Review of attachment 8556153 [details] [diff] [review]: ----------------------------------------------------------------- ::: dom/media/mediasource/MediaSourceReader.cpp @@ +694,5 @@ > ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); > + mWaitingForSeekData = false; > + mPendingSeekTime = -1; > + mSeekRequest.DisconnectIfExists(); > + mSeekPromise.RejectIfExists(NS_OK, __func__); Not calling CancelSeek on the sub-decoders seems like it could potentially break things in the future. With MSR we had the issue where the seek promise might never be resolved without an explicit cancel, if any of the other readers ever add this behaviour then this would break. Should at least add a comment about this. ::: dom/media/mediasource/MediaSourceReader.h @@ +175,5 @@ > + DoVideoRequest(); > + } > + > + void RejectAudioPromiseWithDecodeError() { mAudioPromise.Reject(DECODE_ERROR, __func__); } > + void RejectVideoPromiseWithDecodeError() { mVideoPromise.Reject(DECODE_ERROR, __func__); } Don't we need to call Complete on mSeekRequest for these too?
Attachment #8556143 - Flags: review?(matt.woodrow) → review+
Comment on attachment 8556144 [details] [diff] [review] Part 4 - Introduce machinery to hold onto MediaPromise::Consumer references, and use it for MediaSourceReader subdecoders. v1 Review of attachment 8556144 [details] [diff] [review]: ----------------------------------------------------------------- ::: dom/media/MediaPromise.h @@ +252,5 @@ > > template<typename TargetType, typename ThisType, > typename ResolveMethodType, typename RejectMethodType> > + already_AddRefed<Consumer> RefableThen(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal, > + ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod) Can we instead just have a single version of Then that returns an nsRefPtr (like we do for functioms that return a promise)? That way callers that don't care about the Consumer can just ignore the return value and be fine. It's not a huge deal, I'm just not a big fan of 'RefableThen'.
Attachment #8556144 - Flags: review?(matt.woodrow) → review+
Comment on attachment 8556145 [details] [diff] [review] Part 5 - Implement the ability to disconnect outstanding promises. v1 Review of attachment 8556145 [details] [diff] [review]: ----------------------------------------------------------------- ::: dom/media/MediaPromise.h @@ +90,5 @@ > { > public: > NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Consumer) > + > + void Neuter() Can we call this Disconnect (which I like more) and stay consistent with MediaPromiseConsumerHolder?
Attachment #8556145 - Flags: review?(matt.woodrow) → review+
Comment on attachment 8556149 [details] [diff] [review] Part 6 - Cancel sample requests when seeks start, disallow them while seeks are happening, and assert against seeks when samples arrive. v1 Review of attachment 8556149 [details] [diff] [review]: ----------------------------------------------------------------- ::: dom/media/mediasource/MediaSourceReader.cpp @@ +691,5 @@ > + // Any previous requests we've been waiting on are now unwanted. > + mAudioRequest.DisconnectIfExists(); > + mVideoRequest.DisconnectIfExists(); > + > + // Additionally, reject any outstanding promises _we_made that we might have missing space
Attachment #8556149 - Flags: review?(matt.woodrow) → review+
(In reply to Matt Woodrow (:mattwoodrow) from comment #16) > > template<typename TargetType, typename ThisType, > > typename ResolveMethodType, typename RejectMethodType> > > + already_AddRefed<Consumer> RefableThen(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal, > > + ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod) > > Can we instead just have a single version of Then that returns an nsRefPtr > (like we do for functioms that return a promise)? > > That way callers that don't care about the Consumer can just ignore the > return value and be fine. > > It's not a huge deal, I'm just not a big fan of 'RefableThen'. Yeah, that would be my preference in general. But I got a lot of armchair criticism with the whole "returning an nsRefPtr" thing, because a lot of Gecko hackers think it's evil and it's discouraged in docs like [1]. I figured that it wasn't really necessary here, so I might as well appease them people. Open to better names though. ;-) [1] https://developer.mozilla.org/en-US/docs/Using_nsCOMPtr/Getting_Started_Guide(In reply to Matt Woodrow (:mattwoodrow) from comment #17) > Comment on attachment 8556145 [details] [diff] [review] > > + void Neuter() > > Can we call this Disconnect (which I like more) and stay consistent with > MediaPromiseConsumerHolder? Sure.
Good point on both counts.
Attachment #8556153 - Attachment is obsolete: true
Attachment #8556153 - Flags: review?(matt.woodrow)
Attachment #8556211 - Flags: review?(matt.woodrow)
(In reply to Bobby Holley (Busy with media, don't ask for DOM/JS/XPConnect things) from comment #19) > Yeah, that would be my preference in general. But I got a lot of armchair > criticism with the whole "returning an nsRefPtr" thing, because a lot of > Gecko hackers think it's evil and it's discouraged in docs like [1]. I > figured that it wasn't really necessary here, so I might as well appease > them people. Open to better names though. ;-) > Fair enough. There was talk of making already_AddRefed<T> call Release() on the contained pointer during the dtor if it hadn't been assigned to something else before then, that would be sufficient for this use case.
Comment on attachment 8556211 [details] [diff] [review] Part 10 - Use a MediaPromiseConsumerHolder to track subdecoder seeks. v2 Review of attachment 8556211 [details] [diff] [review]: ----------------------------------------------------------------- ::: dom/media/mediasource/MediaSourceReader.h @@ +175,5 @@ > + DoVideoRequest(); > + } > + > + void CompleteSeekAndRejectAudioPromise() { mSeekRequest.Complete(); mAudioPromise.Reject(DECODE_ERROR, __func__); } > + void CompleteSeekAndRejectVideoPromise() { mSeekRequest.Complete(); mVideoPromise.Reject(DECODE_ERROR, __func__); } Split these onto multiple lines.
Attachment #8556211 - Flags: review?(matt.woodrow) → review+
(In reply to Matt Woodrow (:mattwoodrow) from comment #21) > There was talk of making already_AddRefed<T> call Release() on the contained > pointer during the dtor if it hadn't been assigned to something else before > then, that would be sufficient for this use case. Yes, and the MediaPromise use-case. Though then it starts to smell a lot like nsRefPtr, and doesn't solve the footguns in comment 19. (In reply to Matt Woodrow (:mattwoodrow) from comment #22) > Split these onto multiple lines. Will do - thanks for the fast reviews!
(In reply to Wes Kocher (:KWierso) from comment #25) > Backed out in > https://hg.mozilla.org/integration/mozilla-inbound/rev/3f102935baa3 for B2G > OSX build bustage: > https://treeherder.mozilla.org/logviewer.html#?job_id=6047886&repo=mozilla- > inbound Gah, sorry for not noticing that - I had previous infra-related bustage on that platform, and my eyes just glazed over it. Indeed, the fact that it fails only on that configuration (and that the failure doesn't seem correct) makes me think this is a compiler bug. Let's see if this fixes it: https://treeherder.mozilla.org/#/jobs?repo=try&revision=e66d5b914a50
Flags: needinfo?(bobbyholley)
Be sure to look at the web-platform-tests-4 results on that, too, since you had multiple failures in it.
(In reply to Phil Ringnalda (:philor) from comment #27) > Be sure to look at the web-platform-tests-4 results on that, too, since you > had multiple failures in it. Thanks for pointing that out. Looks like we need to track audio and video seek requests separately, since really we're only guaranteed that the MDSM will not issue two sample requests for the same media type, whereas it may indeed dispatch an audio request while an existing video request is doing its pre-request seek (or vice versa).
I don't know why this wasn't obvious to me before.
Attachment #8556344 - Flags: review?(matt.woodrow)
Attachment #8556344 - Flags: review?(matt.woodrow) → review+
The backout was caused by b2g osx debug build failures, which turned out to be a compile error that I've worked around. Green try run here: https://treeherder.mozilla.org/#/jobs?repo=try&revision=15a0d8cafad3 and web-platform-tests-4 failures, which I fixed with a combination of Part 10.5 (attached in this bug), and bumping the timeout on one test: https://treeherder.mozilla.org/#/jobs?repo=try&revision=09f02089dfe3 Landed to m-i: https://hg.mozilla.org/integration/mozilla-inbound/pushloghtml?changeset=b0e2b65a0cce
(In reply to Bobby Holley (Busy with media, don't ask for DOM/JS/XPConnect things) from comment #31) > and web-platform-tests-4 failures, which I fixed with a combination of Part > 10.5 (attached in this bug), and bumping the timeout on one test: Wasn't enough. We're still seeing frequent Windows timeouts in redundant-seek since your push.
Flags: needinfo?(bobbyholley)
Since nobody's around on IRC to look into the failures and we'd like to merge inbound some time in the near future, I've gone ahead and disabled the test. https://hg.mozilla.org/integration/mozilla-inbound/rev/6b9ee0581d40
Flags: needinfo?(bobbyholley)
Blocks: 1127920
(In reply to Ryan VanderMeulen [:RyanVM UTC-5] from comment #33) > Since nobody's around on IRC to look into the failures and we'd like to > merge inbound some time in the near future, I've gone ahead and disabled the > test. > > https://hg.mozilla.org/integration/mozilla-inbound/rev/6b9ee0581d40 Thanks for doing that instead of backing out! I'll look into this in bug 1127920.
Blocks: 1127203
Comment on attachment 8556141 [details] [diff] [review] Part 1 - Stop invoking On*NotDecoded when we didn't actually go through the promise. v1 Approval Request Comment [Feature/regressing bug #]: MSE [User impact if declined]: Youtube playback can fail after seeking. [Describe test coverage new/current, TreeHerder]: landed on m-c. [Risks and why]: This is quite a large set of changes. There are two components. Most of the seek changes are MSE-specific, so they're moderately risky for that feature, but since we can't ship without them, and not shipping means the code is disabled, the risk of regression outside the MSE code is low. The second component involves adding new methods to the MediaPromise framework. That is used by non-MSE playback code, but Bobby described the risk of those additions as low as well. [String/UUID change made/needed]: None
Attachment #8556141 - Flags: approval-mozilla-beta?
Attachment #8556141 - Flags: approval-mozilla-aurora?
Request is for all patches on this bug.
Depends on: 1128576
Comment on attachment 8556141 [details] [diff] [review] Part 1 - Stop invoking On*NotDecoded when we didn't actually go through the promise. v1 I am approving all the patches on this bug. However, for the record, even if I am sure you know what you are doing, I would have hope for smaller patches that late in the cycle...
Attachment #8556141 - Flags: approval-mozilla-beta?
Attachment #8556141 - Flags: approval-mozilla-beta+
Attachment #8556141 - Flags: approval-mozilla-aurora?
Attachment #8556141 - Flags: approval-mozilla-aurora+
Depends on: 1132034
No longer depends on: 1132034
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: