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

feat: Add support for Document Picture-in-Picture #4969

Merged
merged 14 commits into from
Feb 10, 2023
21 changes: 21 additions & 0 deletions externs/pictureinpicture.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,24 @@ HTMLMediaElement.prototype.webkitSupportsPresentationMode = function(mode) {};

/** @type {string} */
HTMLMediaElement.prototype.webkitPresentationMode;


/**
* @see https://wicg.github.io/document-picture-in-picture/#api
* @constructor
*/
function documentPictureInPicture() {}


/**
* @return {!Promise}
*/
documentPictureInPicture.prototype.requestWindow = function(options) {};


/** @type {Window} */
documentPictureInPicture.prototype.window;


/** @type {?function(!Event)} */
documentPictureInPicture.prototype.onenter;
40 changes: 40 additions & 0 deletions ui/pip_button.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
*/
async onPipClick_() {
try {
if ('documentPictureInPicture' in window) {
avelad marked this conversation as resolved.
Show resolved Hide resolved
await this.toggleDocumentPictureInPicture_();
theodab marked this conversation as resolved.
Show resolved Hide resolved
return;
}
if (!document.pictureInPictureElement) {
// If you were fullscreen, leave fullscreen first.
if (document.fullscreenElement) {
Expand All @@ -137,6 +141,42 @@ shaka.ui.PipButton = class extends shaka.ui.Element {
}
}

/**
* The Document Picture-in-Picture API makes it possible to open an
* always-on-top window that can be populated with arbitrary HTML content.
* https://developer.chrome.com/docs/web-platform/document-picture-in-picture
* @private
*/
async toggleDocumentPictureInPicture_() {
// Close Picture-in-Picture window if any.
if (documentPictureInPicture.window) {
documentPictureInPicture.window.close();
return;
}

// Open a Picture-in-Picture window.
const pipPlayer = this.localVideo_.parentNode;
const pipWindow = await documentPictureInPicture.requestWindow({
width: pipPlayer.offsetWidth,
height: pipPlayer.offsetHeight,
copyStyleSheets: true,
});

// Make sure player fits in the Picture-in-Picture window.
const styles = document.createElement('style');
styles.append(`[data-shaka-player-container] {
width: 100% !important; max-height: 100%}`);
pipWindow.document.head.append(styles);

// Move player to the Picture-in-Picture window.
const parentPlayer = pipPlayer.parentNode;
pipWindow.document.body.append(pipPlayer);

// Listen for the PiP closing event to move the player back.
pipWindow.addEventListener('unload', () => {
joeyparrish marked this conversation as resolved.
Show resolved Hide resolved
parentPlayer.append(pipPlayer);
}, {once: true});
}

/** @private */
onEnterPictureInPicture_() {
Expand Down