Skip to content

Commit

Permalink
fix: handle initial duplicate webkitneedskey to prevent error dialog (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonocasey committed May 18, 2021
1 parent 9c4f577 commit 5ded675
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 21 deletions.
77 changes: 77 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: ci

on: [push, pull_request]

jobs:
should-skip:
continue-on-error: true
runs-on: ubuntu-latest
# Map a step output to a job output
outputs:
should-skip-job: ${{steps.skip-check.outputs.should_skip}}
steps:
- id: skip-check
uses: fkirc/skip-duplicate-actions@v2.1.0
with:
github_token: ${{github.token}}

ci:
needs: should-skip
if: ${{needs.should-skip.outputs.should-skip-job != 'true' || github.ref == 'refs/heads/main'}}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
env:
BROWSER_STACK_USERNAME: ${{secrets.BROWSER_STACK_USERNAME}}
BROWSER_STACK_ACCESS_KEY: ${{secrets.BROWSER_STACK_ACCESS_KEY}}
runs-on: ${{matrix.os}}
steps:
- name: checkout code
uses: actions/checkout@v2

- name: Cache dependencies
uses: actions/cache@v2
with:
path: |
~/.npm
**/node_modules
key: ${{runner.os}}-npm-${{hashFiles('**/package-lock.json')}}
restore-keys: |
${{runner.os}}-npm-
${{runner.os}}-
- name: read node version from .nvmrc
run: echo ::set-output name=NVMRC::$(cat .nvmrc)
shell: bash
id: nvm

- name: update apt cache on linux w/o browserstack
run: sudo apt-get update
if: ${{startsWith(matrix.os, 'ubuntu') && !env.BROWSER_STACK_USERNAME}}

- name: install ffmpeg/pulseaudio for firefox on linux w/o browserstack
run: sudo apt-get install ffmpeg pulseaudio
if: ${{startsWith(matrix.os, 'ubuntu') && !env.BROWSER_STACK_USERNAME}}

- name: start pulseaudio for firefox on linux w/o browserstack
run: pulseaudio -D
if: ${{startsWith(matrix.os, 'ubuntu') && !env.BROWSER_STACK_USERNAME}}

- name: setup node
uses: actions/setup-node@v1
with:
node-version: '${{steps.nvm.outputs.NVMRC}}'

# turn off the default setup-node problem watchers...
- run: echo "::remove-matcher owner=eslint-compact::"
- run: echo "::remove-matcher owner=eslint-stylish::"
- run: echo "::remove-matcher owner=tsc::"

- name: npm install
run: npm i --prefer-offline --no-audit

- name: run npm test
uses: GabrielBB/xvfb-action@v1
with:
run: npm run test
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
lts/carbon
10
16 changes: 0 additions & 16 deletions .travis.yml

This file was deleted.

6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Maintenance Status: Stable
- [Available Options](#available-options)
- [`keySystems`](#keysystems)
- [`emeHeaders`](#emeheaders)
- [`firstWebkitneedkeyTimeout`](#firstwebkitneedkeytimeout)
- [Setting Options per Source](#setting-options-per-source)
- [Setting Options for All Sources](#setting-options-for-all-sources)
- [Header Hierarchy and Removal](#header-hierarchy-and-removal)
Expand Down Expand Up @@ -361,6 +362,11 @@ emeHeaders: {
}
```

#### `firstWebkitneedkeyTimeout`
> Default: 1000
The amount of time in milliseconds to wait on the first `webkitneedkey` event before making the key request. This was implemented due to a bug in Safari where rendition switches at the start of playback can cause `webkitneedkey` to fire multiple times, with only the last one being valid.

### Setting Options per Source

This is the recommended way of setting most options. Each source may have a different set of requirements; so, it is best to define options on a per source basis.
Expand Down
9 changes: 8 additions & 1 deletion scripts/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ module.exports = function(config) {

// see https://github.com/videojs/videojs-generate-karma-config
// for options
const options = {};
const options = {
browserstackLaunchers(defaults) {
delete defaults.bsSafariElCapitan;
delete defaults.bsEdgeWin10;
delete defaults.bsIE11Win10;
return defaults;
}
};

config = generate(config, options);

Expand Down
44 changes: 41 additions & 3 deletions src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,7 @@ const onPlayerReady = (player, emeError) => {
setupSessions(player);

if (window.WebKitMediaKeys) {
// Support Safari EME with FairPlay
// (also used in early Chrome or Chrome with EME disabled flag)
player.tech_.el_.addEventListener('webkitneedkey', (event) => {
const handleFn = (event) => {
// TODO convert to videojs.log.debug and add back in
// https://github.com/videojs/video.js/pull/4780
// videojs.log('eme', 'Received a \'webkitneedkey\' event');
Expand All @@ -226,6 +224,46 @@ const onPlayerReady = (player, emeError) => {
setupSessions(player);
handleWebKitNeedKeyEvent(event, getOptions(player), player.tech_)
.catch(emeError);
};

// Support Safari EME with FairPlay
// (also used in early Chrome or Chrome with EME disabled flag)
player.tech_.el_.addEventListener('webkitneedkey', (event) => {
const options = getOptions(player);
const firstWebkitneedkeyTimeout = options.firstWebkitneedkeyTimeout || 1000;
const src = player.src();
// on source change or first startup reset webkitneedkey options.

player.eme.webkitneedkey_ = player.eme.webkitneedkey_ || {};

// if the source changed we need to handle the first event again.
// track source changes internally.
if (player.eme.webkitneedkey_.src !== src) {
player.eme.webkitneedkey_ = {
handledFirstEvent: false,
src
};
}
// It's possible that at the start of playback a rendition switch
// on a small player in safari's HLS implementation will cause
// two webkitneedkey events to occur. We want to make sure to cancel
// our first existing request if we get another within 1 second. This
// prevents a non-fatal player error from showing up due to a
// request failure.
if (!player.eme.webkitneedkey_.handledFirstEvent) {
// clear the old timeout so that a new one can be created
// with the new rendition's event data
player.clearTimeout(player.eme.webkitneedkey_.timeout);
player.eme.webkitneedkey_.timeout = player.setTimeout(() => {
player.eme.webkitneedkey_.handledFirstEvent = true;
player.eme.webkitneedkey_.timeout = null;
handleFn(event);
}, firstWebkitneedkeyTimeout);
// after we have a verified first request, we will request on
// every other event like normal.
} else {
handleFn(event);
}
});

} else if (window.MediaKeys) {
Expand Down

0 comments on commit 5ded675

Please sign in to comment.