Skip to content
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

fix: validation for stalled and suspended event in iOS when headphones disconnect #6199

Merged
merged 7 commits into from
Oct 4, 2019
Merged

fix: validation for stalled and suspended event in iOS when headphones disconnect #6199

merged 7 commits into from
Oct 4, 2019

Conversation

marcodeltorob
Copy link
Contributor

Description of the problem:
When playback is ongoing in iOS + Safari and the user disconnect headphones (wired or Bluetooth) the player will throw 'suspend' or 'stalled' after a couple of seconds and 'progress' events.

Solution: Validation for stalled and suspended event for iOS browser when headphones are disconnected

@welcome
Copy link

welcome bot commented Aug 26, 2019

💖 Thanks for opening this pull request! 💖

Things that will help get your PR across the finish line:

  • Run npm run lint -- --errors locally to catch formatting errors earlier.
  • Include tests when adding/changing behavior.
  • Include screenshots and animated GIFs whenever possible.

We get a lot of pull requests on this repo, so please be patient and we will get back to you as soon as we can.

(this.el_.buffered.end(this.el_.buffered.length - 1) + SAFE_TIME_DELTA >= this.el_.currentTime)) {
this.el_.pause();
}
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's much benefit in having this as a separate function. The body of it can probably go directly into the callback below.


const disconnectionIOSListener = () => {
if ((!this.el_.paused && window.navigator.onLine) &&
(this.el_.buffered.end(this.el_.buffered.length - 1) + SAFE_TIME_DELTA >= this.el_.currentTime)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have some explanatory comments about this condition and the TIME_FUDGE_FACTOR and SAFE_TIME_DELTA (and that those come from VHS).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably have a local variable here for buffered and check if buffered has length, before trying to get the end of the buffer. Also would it make sense to use tech methods instead of el_ methods here: IE this.pause() or this.buffered()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it's possible that there are multiple buffered regions, and we're current in the first or a middle buffered region instead of the last one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good points!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gkatsev Can you explain a little more, since we try to get the end time buffered. (length - 1) and if we have multiple regions it does not matter that means that we still have buffered time and we are not experiencing a Stalled or suspend due another problem

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcodeltorob basically, we could be at the end of a buffered region which isn't the last buffered region available, so, currentTime will end up being less than the buffered region.
For example, we're at 10 seconds in (marked by |, and our buffer looks something like:

[0-10|----20-30----60-70----]

Reading the last buffered region, would give us 70 but our currentTime is 10. However, we still can't play because we've run out of buffer.
But, if the currentTime is say 5, and our buffered region has extra buffer, then we should be fine.

[0-5|5-10----20-30----60-70----]

misteroneill
misteroneill previously approved these changes Aug 28, 2019
@misteroneill misteroneill dismissed their stale review August 30, 2019 15:11

Updates needed related to buffered regions.

@gkatsev gkatsev changed the title Validation for stalled and suspended event in iOS when HP disconnected fix: validation for stalled and suspended event in iOS when headphones disconnect Aug 30, 2019

// Establish if we have an extra buffer in the current time range playing.
for (let i = 0; i < buffered.length; i++) {
if (buffered.start(i) <= this.currentTime() <= buffered.end(i) + SAFE_TIME_DELTA) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I think what we want is to check if there is anything in the forward buffer. It seems that if the currentTime is equal to the buffered.end, then we don't have anything in the forward buffer. Maybe just buffered.start <= currentTime < buffered.end?
  2. Should we adjust the buffered.start using SAFE_TIME_DELTA as well? Maybe not.
  3. We might as well break out of the loop when we set extraBuffer = true.


// Establish if we have an extra buffer in the current time range playing.
for (let i = 0; i < buffered.length; i++) {
if (buffered.start(i) <= this.currentTime() < buffered.end(i) + SAFE_TIME_DELTA) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just verified and buffered.start(i) <= this.currentTime() < buffered.end(i) doesn't work.
It'll get evaluated as if there are parenthesis around the buffered.start(i) <= this.currentTime() and evaluate it to true (potentially) which will end up being smaller than any buffered.end(i).

> [2, 4, 6, 8, 10].map((f) => 2 <= f < 8)
< [true, true, true, true, true]
> [2, 4, 6, 8, 10].map((f) => 2 <= f && f < 8)
< [true, true, true, false, false]

}

// if tech is not paused, browser has internet connection & player has extraBuffer inside the timeRange
if ((!this.paused() && window.navigator.onLine) && extraBuffer) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the extra parens are necessary as the expression will just evaluate each item in turn.

Suggested change
if ((!this.paused() && window.navigator.onLine) && extraBuffer) {
if (!this.paused() && window.navigator.onLine && extraBuffer) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, should we check extraBuffer first?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense and we can decide quicker the state of the playback.

this.on(['stalled', 'suspend'], (e) => {
const buffered = this.buffered();

if (buffered.length > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should do

if (!bufferred.length) {
  return;
}

to eliminate the scope here.

@gkatsev gkatsev merged commit c791cd8 into videojs:master Oct 4, 2019
@welcome
Copy link

welcome bot commented Oct 4, 2019

Congrats on merging your first pull request! 🎉🎉🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants