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

Implement MediaPool for amp-story #12156

Merged
merged 30 commits into from Nov 22, 2017
Merged

Implement MediaPool for amp-story #12156

merged 30 commits into from Nov 22, 2017

Conversation

newmuis
Copy link
Contributor

@newmuis newmuis commented Nov 21, 2017

This PR changes the way we handle media within amp-story. Instead of using the media elements (audio, video) that are directly in the document, we swap them in and out of the DOM so that the same few media elements are recycled, but the sources are simply changed to reflect the media on the current amp-story-page.

Since this is such a big change to how we play media within amp-story, it ends up fixing (or partially fixing) a few of the media-related issues we have:

It may also complicate some other issues:

Tests are still a work in progress.

/cc @alanorozco @prateekbh

* The delay (in milliseconds) to wait between polling for loaded resources.
*/
const LOAD_TIMER_POLL_DELAY_MS = 250;
const PAGE_MEDIA_SELECTOR = 'amp-audio, amp-video, amp-img, anim';
Copy link
Contributor

Choose a reason for hiding this comment

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

amp-anim ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whoops! Done

this.mediaPoolPromise_ = new Promise(resolve => {
this.setMediaPool = mediaPool => {
this.mediaLayoutPromise_
.then(() => resolve(mediaPool));
Copy link
Contributor

Choose a reason for hiding this comment

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

+ .catch( reject )

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


return Promise.all([
this.beforeVisible(),
this.mediaLayoutPromise_,
Copy link
Contributor

Choose a reason for hiding this comment

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

mediaPoolPromise_ seems to cover mediaLayoutPromise_ anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

this.markPageAsShown_();
this.resolveLoadPromise_();
waitForMediaLayout_() {
const mediaSet = scopedQuerySelectorAll(this.element, PAGE_MEDIA_SELECTOR);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: you can use toArray from dom.js and then call map directly instead of on prototype.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, on another PR, a reviewer (don't remember who) advised that I do this instead to avoid allocating extra arrays.

Copy link
Contributor

Choose a reason for hiding this comment

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

sgtm. In the grand scheme of things, neither of the option would make a real difference.

if (!canPageBeShown) {
canPageBeShown = pageElement.canBeShown;
}
return mediaEl.mozHasAudio ||
Copy link
Contributor

Choose a reason for hiding this comment

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

interesting! I hope muted which comes with autoplay does not mess this up.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not the right definition! No one should look at this as a good example of how to detect whether a media element has audio, because it's not right! This causes #11857, but this was the previous definition; I'm just porting it over from page-elements.js as part of the refactor in this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

got it.

this.copyAttributes_(domMediaEl, poolMediaEl);
sources.applyToElement(poolMediaEl);
poolMediaEl.setAttribute(REPLACED_MEDIA_ATTRIBUTE, domMediaEl.id);
domMediaEl.parentElement.replaceChild(poolMediaEl, domMediaEl);
Copy link
Contributor

Choose a reason for hiding this comment

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

without resetting the private this.video_ reference in amp-video, this will break some functionality. Most may be irrelevant to STAMP but one that probably matters is "SessionMedia" stuff (e.g. when you play a video and then lock your phone, the lock screen shows the poster and media controls for the video that was just playing).

Also not setting this.video_ will keep reference count > 0 which will keep the old dom node in memory for no good reason.

(I don't mind STAMP accessing .video_ for now, later however we may wanna to officially add swapVideo() to AMP core)

Let's also make sure there are enough tests in STAMPs to catch bug if amp-video does refactoring in a way that may break STAMP.

A good long-term solution could be STAMP having its own player amp-stamp-video. amp-video is not a lot of code anyway. Most things are handle by video-manager which STAMP version of video player can register to as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

MediaPool actually keeps the DOM node in memory anyway; if a video is evicted from the MediaPool, we put back the original video.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see. I assume simply unattaching it from the DOM frees up hardware decoding space on iOS though

const currentTime = mediaEl.currentTime;

mediaEl.muted = false;
return mediaEl.play().then(() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

play is not always a promise (MS Edge/IE)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wrapped in Promise.resolve, which (I think?) should handle both cases.

@newmuis newmuis merged commit b29ade9 into ampproject:master Nov 22, 2017
ghost pushed a commit that referenced this pull request Dec 6, 2017
* Change progress bar to not handle active page, since active page updates progress bar through PAGE_PROGRESS events

* Revert "Change progress bar to not handle active page, since active page updates progress bar through PAGE_PROGRESS events"

This reverts commit 0500899.

* Add media pool to manage playback of media elements.

* Update to work without PageElements

* Allow preloading, muting/unmuting, and blessing videos

* Rough commit to wait for media layout before registering/playing

* Fix registration and cleanup some code

* Revert changes to amp-audio and amp-video, as they are no longer necessary since we wait for layout to complete.

* Fix lint and type errors.

* Add default media and fix unblessing

* Remove AudioManager, since audio is now managed by MediaPool and AmpStoryPage directly.

* Add basic unit tests for MediaPool

* Add extensions and AmpStoryHint

* Remove amp-audio and amp-video changes

* Fix review comments

* Fix sync

* Remove blacklisted outerHTML calls.

* Use single quotes instead of backticks for string literals
alanorozco added a commit to alanorozco/amphtml that referenced this pull request Dec 6, 2017
alanorozco added a commit that referenced this pull request Dec 7, 2017
cvializ pushed a commit that referenced this pull request Dec 7, 2017
cvializ pushed a commit that referenced this pull request Dec 7, 2017
jpettitt pushed a commit to jpettitt/amphtml that referenced this pull request Dec 11, 2017
alanorozco added a commit to alanorozco/amphtml that referenced this pull request Dec 24, 2017
gzgogo pushed a commit to gzgogo/amphtml that referenced this pull request Jan 26, 2018
* Change progress bar to not handle active page, since active page updates progress bar through PAGE_PROGRESS events

* Revert "Change progress bar to not handle active page, since active page updates progress bar through PAGE_PROGRESS events"

This reverts commit 0500899.

* Add media pool to manage playback of media elements.

* Update to work without PageElements

* Allow preloading, muting/unmuting, and blessing videos

* Rough commit to wait for media layout before registering/playing

* Fix registration and cleanup some code

* Revert changes to amp-audio and amp-video, as they are no longer necessary since we wait for layout to complete.

* Fix lint and type errors.

* Add default media and fix unblessing

* Remove AudioManager, since audio is now managed by MediaPool and AmpStoryPage directly.

* Add basic unit tests for MediaPool

* Add extensions and AmpStoryHint

* Remove amp-audio and amp-video changes

* Fix review comments

* Fix sync

* Remove blacklisted outerHTML calls.

* Use single quotes instead of backticks for string literals
gzgogo pushed a commit to gzgogo/amphtml that referenced this pull request Jan 26, 2018
thekorn pushed a commit to edelight/amphtml that referenced this pull request Sep 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants