0

Add AirPlay support to player. Closes #1963

This commit is contained in:
Gabe Kangas 2022-06-21 15:38:37 -07:00
parent 2cd6756d01
commit 0c439ccba4
No known key found for this signature in database
GPG Key ID: 9A56337728BC81EA
3 changed files with 66 additions and 38 deletions

View File

@ -122,6 +122,67 @@ export default function OwncastPlayer(props: Props) {
} }
}; };
const setupLatencyCompensator = player => {
const tech = player.tech({ IWillNotUseThisInPlugins: true });
// VHS is required.
if (!tech || !tech.vhs) {
return;
}
const latencyCompensatorEnabledSaved = getLocalStorage(LATENCY_COMPENSATION_ENABLED);
if (latencyCompensatorEnabledSaved === 'true' && tech && tech.vhs) {
startLatencyCompensator();
} else {
stopLatencyCompensator();
}
};
const createSettings = async (player, videojs) => {
const videoQualities = await getVideoSettings();
const menuButton = createVideoSettingsMenuButton(
player,
videojs,
videoQualities,
toggleLatencyCompensator,
);
player.controlBar.addChild(
menuButton,
{},
// eslint-disable-next-line no-underscore-dangle
player.controlBar.children_.length - 2,
);
setupLatencyCompensator(player);
};
const setupAirplay = (player, videojs) => {
// eslint-disable-next-line no-prototype-builtins
if (window.hasOwnProperty('WebKitPlaybackTargetAvailabilityEvent')) {
const videoJsButtonClass = videojs.getComponent('Button');
const ConcreteButtonClass = videojs.extend(videoJsButtonClass, {
// The `init()` method will also work for constructor logic here, but it is
// deprecated. If you provide an `init()` method, it will override the
// `constructor()` method!
constructor() {
videoJsButtonClass.call(this, player);
},
handleClick() {
try {
const videoElement = document.getElementsByTagName('video')[0];
(videoElement as any).webkitShowPlaybackTargetPicker();
} catch (e) {
console.error(e);
}
},
});
const concreteButtonInstance = player.controlBar.addChild(new ConcreteButtonClass());
concreteButtonInstance.addClass('vjs-airplay');
}
};
// Register keyboard shortcut for the space bar to toggle playback // Register keyboard shortcut for the space bar to toggle playback
useHotkeys('space', togglePlayback, { useHotkeys('space', togglePlayback, {
enableOnContentEditable: false, enableOnContentEditable: false,
@ -181,23 +242,7 @@ export default function OwncastPlayer(props: Props) {
const handlePlayerReady = (player, videojs) => { const handlePlayerReady = (player, videojs) => {
playerRef.current = player; playerRef.current = player;
setSavedVolume(); setSavedVolume();
setupAirplay(player, videojs);
const setupLatencyCompensator = () => {
const tech = player.tech({ IWillNotUseThisInPlugins: true });
// VHS is required.
if (!tech || !tech.vhs) {
return;
}
const latencyCompensatorEnabledSaved = getLocalStorage(LATENCY_COMPENSATION_ENABLED);
if (latencyCompensatorEnabledSaved === 'true' && tech && tech.vhs) {
startLatencyCompensator();
} else {
stopLatencyCompensator();
}
};
// You can handle player events here, for example: // You can handle player events here, for example:
player.on('waiting', () => { player.on('waiting', () => {
@ -234,24 +279,7 @@ export default function OwncastPlayer(props: Props) {
playbackMetrics = new PlaybackMetrics(player, videojs); playbackMetrics = new PlaybackMetrics(player, videojs);
playbackMetrics.setClockSkew(clockSkew); playbackMetrics.setClockSkew(clockSkew);
const createSettings = async () => { createSettings(player, videojs);
const videoQualities = await getVideoSettings();
const menuButton = createVideoSettingsMenuButton(
player,
videojs,
videoQualities,
toggleLatencyCompensator,
);
player.controlBar.addChild(
menuButton,
{},
// eslint-disable-next-line no-underscore-dangle
player.controlBar.children_.length - 2,
);
setupLatencyCompensator();
};
createSettings();
}; };
useEffect(() => { useEffect(() => {

View File

Before

Width:  |  Height:  |  Size: 160 B

After

Width:  |  Height:  |  Size: 160 B

View File

@ -13,9 +13,9 @@
background-color: var(--theme-background) !important; background-color: var(--theme-background) !important;
} }
// .vjs-airplay .vjs-icon-placeholder::before { .vjs-airplay .vjs-icon-placeholder::before {
// content: url("../img/airplay.png"); content: url("./airplay.png");
// } }
.vjs-quality-selector .vjs-icon-placeholder { .vjs-quality-selector .vjs-icon-placeholder {
font-family: VideoJS; font-family: VideoJS;