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(HLS): Fix missing roles #4760

Merged
merged 6 commits into from
Dec 7, 2022

Conversation

fredrik-telia
Copy link
Contributor

@fredrik-telia fredrik-telia commented Nov 25, 2022

Issue wasn't caught by the existing tests.

Closes #4759

@google-cla
Copy link

google-cla bot commented Nov 25, 2022

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@avelad avelad added type: bug Something isn't working correctly component: HLS The issue involves Apple's HLS manifest format priority: P1 Big impact or workaround impractical; resolve before feature release labels Nov 25, 2022
@avelad avelad added this to the v4.4 milestone Nov 25, 2022
@avelad
Copy link
Member

avelad commented Nov 28, 2022

@fredrik-telia can you add a regression test? Thanks!

@github-actions
Copy link
Contributor

Incremental code coverage: 100.00%

@fredrik-telia
Copy link
Contributor Author

I might need some pointers, as there seems to be a test ( parses characteristics from text tags ) that passes, but shouldn't..

When using the player with a real stream, the role field in the stream object isn't filled, but the unit test seems to pass.

@fredrik-telia
Copy link
Contributor Author

fredrik-telia commented Nov 29, 2022

I need some help understanding why this line in the function testHlsParser in hls_parser_unit.js is truthy:

expect(actual).toEqual(manifest);
when they are, in fact, not equal at all

actual (using console.log(JSON.stringify(actual)):

'{"presentationTimeline":{"presentationStartTime_":null,"presentationDelay_":0,"duration_":null,"segmentAvailabilityDuration_":null,"maxSegmentDuration_":1,"minSegmentStartTime_":null,"maxSegmentEndTime_":null,"clockOffset_":0,"static_":true,"userSeekStart_":0,"autoCorrectDrift_":true,"availabilityTimeOffset_":0,"startTimeLocked_":false},"variants":[{"id":2,"language":"und","primary":false,"audio":null,"video":{"id":1,"originalId":null,"segmentIndex":null,"mimeType":"video/mp4","codecs":"avc1","encrypted":false,"drmInfos":[],"keyIds":{},"language":"und","label":null,"type":"video","primary":false,"trickModeVideo":null,"emsgSchemeIdUris":null,"frameRate":60,"width":960,"height":540,"roles":[],"forced":false,"channelsCount":null,"audioSamplingRate":null,"spatialAudio":false,"closedCaptions":null},"bandwidth":200,"allowedByApplication":true,"allowedByKeySystem":true,"decodingInfos":[]}],"textStreams":[{"id":3,"originalId":"English (caption)","segmentIndex":null,"mimeType":"text/vtt","codecs":"","encrypted":false,"drmInfos":[],"keyIds":{},"language":"en","label":"English (caption)","type":"text","primary":true,"trickModeVideo":null,"emsgSchemeIdUris":null,"roles":[],"forced":false,"channelsCount":null,"audioSamplingRate":null,"spatialAudio":false,"closedCaptions":null},{"id":4,"originalId":"English (caption)","segmentIndex":null,"mimeType":"text/vtt","codecs":"","encrypted":false,"drmInfos":[],"keyIds":{},"language":"en","label":"English (caption)","type":"text","primary":true,"trickModeVideo":null,"emsgSchemeIdUris":null,"roles":[],"forced":false,"channelsCount":null,"audioSamplingRate":null,"spatialAudio":false,"closedCaptions":null}],"imageStreams":[],"offlineSessionIds":[],"minBufferTime":0,"sequenceMode":true}'

vs manifest (same deal using JSON.stringify):

'{"variants":[{"sample":{"audio":null,"video":{"sample":{"type":"video"}}}}],"textStreams":[{"sample":{"type":"text","language":"en","kind":"subtitle","mimeType":"application/mp4","codecs":""}},{"sample":{"type":"text","language":"en","kind":"subtitle","mimeType":"application/mp4","codecs":"","roles":["public.accessibility.describes-spoken-dialog","public.accessibility.describes-music-and-sound"]}}],"imageStreams":[],"presentationTimeline":{},"offlineSessionIds":[],"minBufferTime":0,"sequenceMode":true}'

Maybe I'm missing something?

@avelad
Copy link
Member

avelad commented Dec 5, 2022

@theodab can you review it? Thanks!

@avelad avelad self-requested a review December 7, 2022 11:05
avelad
avelad previously approved these changes Dec 7, 2022
@martinstark
Copy link
Contributor

@avelad the issue that @fredrik-telia is pointing out looks quite serious, since that would mean the unit tests that currently exist for hls parser don't actually verify anything. It looks like whatever two objects are compared will pass the test. Should this be reported as a separate issue?

@avelad
Copy link
Member

avelad commented Dec 7, 2022

I think so

Copy link
Contributor

@martinstark martinstark left a comment

Choose a reason for hiding this comment

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

would it make sense to also populate the kind property now that roles are being included?

@joeyparrish joeyparrish changed the title fix: respect characteristics when creating stream object fix(HLS): Fix missing roles Dec 7, 2022
joeyparrish
joeyparrish previously approved these changes Dec 7, 2022
@joeyparrish
Copy link
Member

I need some help understanding why this line in the function testHlsParser in hls_parser_unit.js is truthy:

expect(actual).toEqual(manifest); when they are, in fact, not equal at all

actual (using console.log(JSON.stringify(actual)):

'{"presentationTimeline":{"presentationStartTime_":null,"presentationDelay_":0,"duration_":null,"segmentAvailabilityDuration_":null,"maxSegmentDuration_":1,"minSegmentStartTime_":null,"maxSegmentEndTime_":null,"clockOffset_":0,"static_":true,"userSeekStart_":0,"autoCorrectDrift_":true,"availabilityTimeOffset_":0,"startTimeLocked_":false},"variants":[{"id":2,"language":"und","primary":false,"audio":null,"video":{"id":1,"originalId":null,"segmentIndex":null,"mimeType":"video/mp4","codecs":"avc1","encrypted":false,"drmInfos":[],"keyIds":{},"language":"und","label":null,"type":"video","primary":false,"trickModeVideo":null,"emsgSchemeIdUris":null,"frameRate":60,"width":960,"height":540,"roles":[],"forced":false,"channelsCount":null,"audioSamplingRate":null,"spatialAudio":false,"closedCaptions":null},"bandwidth":200,"allowedByApplication":true,"allowedByKeySystem":true,"decodingInfos":[]}],"textStreams":[{"id":3,"originalId":"English (caption)","segmentIndex":null,"mimeType":"text/vtt","codecs":"","encrypted":false,"drmInfos":[],"keyIds":{},"language":"en","label":"English (caption)","type":"text","primary":true,"trickModeVideo":null,"emsgSchemeIdUris":null,"roles":[],"forced":false,"channelsCount":null,"audioSamplingRate":null,"spatialAudio":false,"closedCaptions":null},{"id":4,"originalId":"English (caption)","segmentIndex":null,"mimeType":"text/vtt","codecs":"","encrypted":false,"drmInfos":[],"keyIds":{},"language":"en","label":"English (caption)","type":"text","primary":true,"trickModeVideo":null,"emsgSchemeIdUris":null,"roles":[],"forced":false,"channelsCount":null,"audioSamplingRate":null,"spatialAudio":false,"closedCaptions":null}],"imageStreams":[],"offlineSessionIds":[],"minBufferTime":0,"sequenceMode":true}'

vs manifest (same deal using JSON.stringify):

'{"variants":[{"sample":{"audio":null,"video":{"sample":{"type":"video"}}}}],"textStreams":[{"sample":{"type":"text","language":"en","kind":"subtitle","mimeType":"application/mp4","codecs":""}},{"sample":{"type":"text","language":"en","kind":"subtitle","mimeType":"application/mp4","codecs":"","roles":["public.accessibility.describes-spoken-dialog","public.accessibility.describes-music-and-sound"]}}],"imageStreams":[],"presentationTimeline":{},"offlineSessionIds":[],"minBufferTime":0,"sequenceMode":true}'

Maybe I'm missing something?

Here's an expanded version of what you logged in "manifest" for clarity:

{
  "variants": [
    {
      "sample": {
        "audio": null,
        "video": {
          "sample": {
            "type": "video"
          }
        }
      }
    }
  ],
  "textStreams": [
    {
      "sample": {
        "type": "text",
        "language": "en",
        "kind": "subtitle",
        "mimeType": "application/mp4",
        "codecs": ""
      }
    },
    {
      "sample": {
        "type": "text",
        "language": "en",
        "kind": "subtitle",
        "mimeType": "application/mp4",
        "codecs": "",
        "roles": [
          "public.accessibility.describes-spoken-dialog",
          "public.accessibility.describes-music-and-sound"
        ]
      }
    }
  ],
  "imageStreams": [],
  "presentationTimeline": {},
  "offlineSessionIds": [],
  "minBufferTime": 0,
  "sequenceMode": true
}

What you're missing in the serialization through JSON is that some of those objects are not actual variants, but rather partial matchers constructed with jasmine.objectContaining(). They only contain certain fields, and others will be ignored in the comparison. This is intentional, and good to keep tests focused on the specific behaviors they are verifying. When you serialize one of these partial matchers, you see it's sample field, which is a private field used by the matcher to drive it custom matching behavior within jasmine.

I'll double-check the existing unit tests to make sure this partial matching is working correctly.

@joeyparrish
Copy link
Member

Partial matching is working, but the test has a particular step that loads the relevant data:

await loadAllStreamsFor(actual);

This is unrealistic in this case, because it triggers lazy-loading for all streams. The only way a user would trigger a similar code path is by cycling through every text track, audio language, and resolution.

So roles are only missing before lazy-loading, and every single test case triggers lazy-loading on every single track before checking expectations.

I'll add a test case that fails without your fix.

@joeyparrish
Copy link
Member

would it make sense to also populate the kind property now that roles are being included?

Looks like the answer is "yes". That is also missing in the regression test I'm creating.

@joeyparrish joeyparrish dismissed stale reviews from avelad and themself via cca43ca December 7, 2022 22:00
@joeyparrish
Copy link
Member

I added a regression test. You'll see that it's failing on two counts: missing kind and malformed roles.

@joeyparrish
Copy link
Member

I fixed two bugs in this PR:

  • kind missing
  • roles should be an array, not a string

Both of these were caught by the new test I added.

lib/hls/hls_parser.js Outdated Show resolved Hide resolved
lib/hls/hls_parser.js Outdated Show resolved Hide resolved
@joeyparrish
Copy link
Member

Thank you to @fredrik-telia and @martinstark for highlighting the test issues. I'm very glad to have both the bug and the test issues fixed now!

I will merge this when the test pass is complete.

@joeyparrish joeyparrish merged commit 2bc481d into shaka-project:main Dec 7, 2022
joeyparrish added a commit that referenced this pull request Dec 8, 2022
Issue wasn't caught by the existing tests.

Closes #4759

Co-authored-by: Joey Parrish <[email protected]>
joeyparrish added a commit that referenced this pull request Dec 8, 2022
Issue wasn't caught by the existing tests.

Closes #4759

Co-authored-by: Joey Parrish <[email protected]>
@github-actions github-actions bot added the status: archived Archived and locked; will not be updated label Jul 25, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
component: HLS The issue involves Apple's HLS manifest format priority: P1 Big impact or workaround impractical; resolve before feature release status: archived Archived and locked; will not be updated type: bug Something isn't working correctly
Projects
None yet
Development

Successfully merging this pull request may close these issues.

HLS subtitles lose role information
5 participants