-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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 captions disappear on unbuffered seeks when user activates, deactivates, and reactivates captions #2674
Fix captions disappear on unbuffered seeks when user activates, deactivates, and reactivates captions #2674
Conversation
…tivating, activating subtitles
…bug-user-activate-and-deactivate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great. Any chance you could try adding a test for this? Maybe player_unit.js?
@joeyparrish While further investigating this issue, I found a more elegant solution, and one that, from the way the code and unit tests are currently written, it seems that we assume already exists. I've described it in the edited summary of the pull request. Furthermore, I found another bug (which I now fixed) while fixing this issue, where captions show up in 2 different languages simultaneously when turned off, then back on in a different language. This happens because the UI library calls |
@@ -251,6 +251,7 @@ shaka.media.StreamingEngine = class { | |||
this.abortOperations_(state).catch(() => {}); | |||
this.mediaStates_.delete(ContentType.TEXT); | |||
} | |||
this.currentTextStream_ = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, wow, that certainly should have been there. :-)
This member is new in v3.0 if I recall correctly.
test/player_unit.js
Outdated
@@ -341,6 +341,19 @@ describe('Player', () => { | |||
expect(streamingEngine.switchTextStream).not.toHaveBeenCalled(); | |||
expect(streamingEngine.unloadTextStream).not.toHaveBeenCalled(); | |||
}); | |||
|
|||
it('unloads text stream when captions are turned off', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that this test only verifies that unloadTextStream() is called, but your fix was to make sure that getCurrentTextStream() returns null after unloadTextStream().
So instead of verifying the call to unloadTextStream() happened (which is an implementation detail), I think you should be verifying the value of getCurrentTextStream() at the end (which is the observable behavior in the rest of the system).
ui/text_selection.js
Outdated
if (this.player) { // May have become null while awaiting | ||
this.player.selectTextLanguage(track.language, track.roles[0]); | ||
} | ||
await this.player.setTextTrackVisibility(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving the visibility change after selectTextLanguage() removes the need to check for this.player
. We know it's non-null at the start of the method, but it may become null in the middle of an async call if someone calls destroy()
.
But I'm also not entirely sure why you changed this. Can you explain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, sorry, now I see your comment from before:
I found another bug (which I now fixed) while fixing this issue, where captions show up in 2 different languages simultaneously when turned off, then back on in a different language. This happens because the UI library calls setTextTrackVisibility then selectTextLanguage, which both try to switch the text stream to different languages. However, if we reverse the order in which they are called, then when setTextTrackVisibility is called after selectTextLanguage, it will see that a language is already selected, and won't try to switch the text stream, fixing the issue!
Then please remove the if (this.player)
above and leave a comment explaining why these calls need to be in this order. Otherwise, we may change it back some day without realizing we broke anything. (Even better would be an automated test for this, but I would accept a strongly-worded comment in this case.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good otherwise. Thanks!
test/player_unit.js
Outdated
await player.setTextTrackVisibility(true); | ||
await player.load(fakeManifestUri, 0, fakeMimeType); | ||
expect(streamingEngine.switchTextStream).toHaveBeenCalled(); | ||
expect(shaka.test.Util.invokeSpy(streamingEngine.getCurrentTextStream)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The invokeSpy wrapper is a compiler hack since the compiler doesn't see jasmine Spy objects as callable. But in this case, I believe this method is not a Spy, so you should be able to remove the wrapper and call it directly. Same below.
If I'm wrong, as I often am, build/check.py would complain after removing the wrapper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just verified, and it seems like there is a Jasmine Spy created for this method in simple_fakes.js
(https://github.com/google/shaka-player/blob/master/test/test/util/simple_fakes.js#L103). Consequently, the compiler complains when I remove the wrapper and call the method directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see. This is player_unit, so streamingEngine is a fake. Now the spy part makes more sense.
But since the fix is in StreamingEngine, testing with a fake StreamingEngine doesn't verify the fix. :-) You could comment out your one-line fix, and this test would still pass.
You'll need to test this in test/media/streaming_engine_unit.js instead.
All tests passed! |
When the subtitles are turned off, unloadTextStream() on streaming engine is called, but currentTextStream is never set to null. When the captions are turned back on, a check in player.js sees that the current text stream is not null, so it assumes it exists, and is ready to go. Thus captions are never loaded. Clearing (setting to null) the current stream on unloadTextStream ensures the text stream is properly initialized the next time it is called, and in a state so that captions can resume being parsed. After further investigation, it seems that the unit tests are written in a way that assumes that the text stream is nulled when unloadTextStream is called. So this fix is definitely something that we assume already happens. Closes #2671
What is the bug?
#2671
Why does this bug exist?
When the subtitles are turned off,
unloadTextStream()
on streaming engine is called, butcurrentTextStream
is never set to null. When the captions are turned back on, a check inplayer.js
sees that the current text stream is not null, so it assumes it exists, and is ready to go. Thus captions are never loaded.What is the fix?
Clearing (setting to null) the current stream on
unloadTextStream
ensures the text stream is properly initialized the next time it is called, and in a state so that captions can resume being parsed.Notes
After further investigation, it seems that the unit tests are written in a way that assumes that the text stream is nulled when unloadTextStream is called. So this fix is definitely something that we assume already happens.