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

Add audio support for amp-story #11509

Merged
merged 8 commits into from
Oct 3, 2017
Merged

Add audio support for amp-story #11509

merged 8 commits into from
Oct 3, 2017

Conversation

newmuis
Copy link
Contributor

@newmuis newmuis commented Sep 29, 2017

This is utility class to help manage playback of audio for the amp-story component.

Copy link
Contributor

@dvoytenko dvoytenko left a comment

Choose a reason for hiding this comment

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

Bunch of stylistic comments. Deferring main logic review to @aghassemi . However, should there be tests here?



/** @typedef {{ source: AudioBufferSourceNode, gainNode: GainNode }} */
let AudioSource;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be suffixed with Def

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed entirely; it's actually unused now.

const VOLUME_CHANGE_DURATION_MS = 500;

/**
* @const {!function(number): number}
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove !

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

* @const {string}
*/
const PLAYABLE_ID_PREFIX = 'i-amphtml-playable-';

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: remove extra line. Just one-line separator b/w constants.

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



export class AudioManager {
constructor(win, rootElement) {
Copy link
Contributor

Choose a reason for hiding this comment

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

jsdoc for args

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

* represented by the specified sourceElement.
*/
createPlayable_(sourceElement) {
if (!(sourceElement instanceof Element)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

User assertElement

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

}


nowPlayingChanged_() {
Copy link
Contributor

Choose a reason for hiding this comment

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

jsdoc

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



class Playable {
constructor(win, sourceElement) {
Copy link
Contributor

Choose a reason for hiding this comment

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

jsdoc

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.sourceElement_ = sourceElement;

this.depth_ = Playable.calculateDepthForElement(sourceElement);
Copy link
Contributor

Choose a reason for hiding this comment

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

jsdoc

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

* An HTMLMediaElement that potentially has audio.
*/
class MediaElementPlayable extends Playable {
constructor(win, element) {
Copy link
Contributor

Choose a reason for hiding this comment

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

jsdoc

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Deferred to super constructor

class MediaElementPlayable extends Playable {
constructor(win, element) {
super(win, element);
this.element_ = element;
Copy link
Contributor

Choose a reason for hiding this comment

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

jsdoc

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Deferred to sourceElement in super class

@newmuis newmuis moved this from Awaiting Review to Needs Work in Stories - By Type Oct 2, 2017
/**
* @const {string}
*/
const PLAYABLE_ID_PREFIX = 'i-amphtml-playable-';
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: maybe i-amphtml-playable-audio- to account for other playable types later given nextId_ is scoped to audio.js only?

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

export function upgradeBackgroundAudio(element) {
if (element.hasAttribute('background-audio')) {
const audioEl = element.ownerDocument.createElement('audio');
const audioSrc = element.getAttribute('background-audio');
Copy link
Contributor

Choose a reason for hiding this comment

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

do one of assertHttpsUrl or assertAbsoluteHttpOrHttpsUrl on audioSrc depending on your requirements.

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

audioEl.setAttribute('src', audioSrc);
audioEl.setAttribute('preload', 'auto');
audioEl.setAttribute('loop', '');
audioEl.setAttribute('autoplay', '');
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a point in adding autoplay given mobile ignores it and desktop will soon ignore it too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They only ignore it if it's unmuted, right? Added muted attribute.

Copy link
Contributor

Choose a reason for hiding this comment

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

not sure what they do for "audio", autoplay for muted audio is sort of strange although you may get some preloading advantages by using autoplay attr? regardless, this looks fine to me.

*/
load(sourceElement) {
const playable = this.getPlayable_(sourceElement) ||
this.createPlayable_(sourceElement);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: alternative pattern that I slightly prefer : getOrCreatePlayable_


/**
* @param {!Element} sourceElement The element causing audio to be played.
* @return {!Playable} The {@link Playable} instance to play the audio
Copy link
Contributor

Choose a reason for hiding this comment

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

!Playable is not correct since this can return undefined. How about making it throw (by using dev().assert) if sourceElement is not Element or HTMLMediaElement?

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. It actually has to be Element AND HTMLMediaElement, but since HTMLMediaElement implies Element, I only checked for HTMLMediaElement.

/**
* Loads the audio for the specified.
* @param {!Element} sourceElement The element whose audio should be loaded.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

document return param

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

}

/** @private */
getMediaElementChildren_(element) {
Copy link
Contributor

Choose a reason for hiding this comment

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

doesn't seem to be used in this file (and is private) is used outside, make public

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed

* @private
*/
addToNowPlaying_(playable) {
const index = this.nowPlaying_.indexOf(playable);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: .includes

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

prioritiesByDepth[depth] = depthCount - iteration;
});

// Set volumes on each of the playables that is currently playing, based on
Copy link
Contributor

Choose a reason for hiding this comment

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

very cool!

}

/** @override */
setVolume(volume, durationMs, unusedEasingFn) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's document somewhere the iOS's restriction on setting volume and how that's handled.

@ampprojectbot ampprojectbot added this to the Pending Triage milestone Oct 2, 2017
@newmuis newmuis moved this from Needs Work to Awaiting Review in Stories - By Type Oct 3, 2017
@newmuis newmuis moved this from Awaiting Review to Ready to Merge (approved + comments addressed) in Stories - By Type Oct 3, 2017
@newmuis
Copy link
Contributor Author

newmuis commented Oct 3, 2017

Filed #11546 to track the unit tests.

@newmuis newmuis dismissed dvoytenko’s stale review October 3, 2017 16:49

Comments addressed

@alanorozco alanorozco merged commit c4bee20 into ampproject:master Oct 3, 2017
@newmuis newmuis moved this from Ready to Merge (approved + comments addressed) to Merged in Stories - By Type Oct 3, 2017
@newmuis newmuis moved this from Migration to amphtml repo to Done in Stories - By Type Jan 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Development

Successfully merging this pull request may close these issues.

None yet

6 participants