yapi.js, an adaptive streaming web player

76
INTRODUCE YAPI.JS (AN ADAPTIVE STREAMING WEB PLAYER) PART2 KKBOXVideo 陳建辰 jessechen

Upload: jesse-chien-chen-chen

Post on 20-Jan-2017

877 views

Category:

Software


2 download

TRANSCRIPT

Page 1: Yapi.js, An Adaptive Streaming Web Player

INTRODUCE YAPI.JS

(AN ADAPTIVE STREAMING WEB PLAYER)

PART2

KKBOXVideo陳建辰 jessechen

Page 2: Yapi.js, An Adaptive Streaming Web Player

AGENDA

• yapi.js, video element and MSE

• Introduce yapi sample control panel

• Test cases

Page 3: Yapi.js, An Adaptive Streaming Web Player

BRIEF SUMMARY OF LAST PRESENTATION

http://goo.gl/cQoq2K

Page 4: Yapi.js, An Adaptive Streaming Web Player

HOW TO USE YAPI.JS

var yapi = new yapi.MediaPlayer().initialize();

yapi.attachView(<video></video>);

yapi.load(MANIFEST_URL);

Page 5: Yapi.js, An Adaptive Streaming Web Player

YAPI.JS / VIDEO ELEMENT / MSE

Page 6: Yapi.js, An Adaptive Streaming Web Player

VIDEO ELEMENT

var videoNode = document.createElement(‘video’);

videoNode.src = VIDEO_URL;

With html5 video element, you can play single video source easily

more info here: https://goo.gl/Fyi3Z3

Page 7: Yapi.js, An Adaptive Streaming Web Player

MSE

“ MSE (Media Source Extension) extends HTMLMediaElement to allow JavaScript to generate media streams for playback.

Allowing JavaScript to generate streams facilitates a variety of use cases like adaptive streaming and time shifting live streams. “

Page 8: Yapi.js, An Adaptive Streaming Web Player

var video = document.createElement(‘video’);

video.src = VIDEO_URL

MEDIASOURCE IS A ‘SOURCE’

set ‘src’ attribute of video element to an url pointed to media source

new window.MediaSource();window.URL.createObjectURL(ms);

Page 9: Yapi.js, An Adaptive Streaming Web Player

SOURCE BUFFER

sourceBufferVideo = ms.addSourceBuffer(VIDEO_CODEC); sourceBufferAudio = ms.addSourceBuffer(AUDIO_CODEC);

// get stream buffer via network

sourceBufferVideo.appendBuffer(buffer);

// sourcebuffer provides buffer info after append complete

Page 10: Yapi.js, An Adaptive Streaming Web Player

BUFFER INFO

var buffered = sourceBuffer.buffered; buffered.length; // how many discontinuous buffered time range

buffered.start(0); // first buffer start time

buffered.end(0); // first buffer end time

get buffer information from buffered attribute

Page 11: Yapi.js, An Adaptive Streaming Web Player

ADAPTIVE STREAMING// assume segment of time 0s~5s is needed // yapi would decide which bitrate to download loadSegment(segment_1_240p_url); // segment file doesn’t have meta data, we have to append it first sourceBuffer.appendBuffer(init_240p_buffer); // then loaded segment sourceBuffer.appendBuffer(segment_1_240p_buffer); // if yapi decide to load 480p for 5~10s (adaptive algorithm) // then yapi repeat same process, but with 480p // then playback would be 240p during 0~5s and 480p for 5~10s

Page 12: Yapi.js, An Adaptive Streaming Web Player

GRAPH

yapi append stream buffer to sourcebuffer ‘adaptively’

MediaSource

Media Element media element plays

while available

Page 13: Yapi.js, An Adaptive Streaming Web Player

MSE EXTENDS MEDIA ELEMENT

• MSE focus on providing stream buffer to media element

• playback behavior still hold by media element

Page 14: Yapi.js, An Adaptive Streaming Web Player

MEDIA EVENTS

http://www.w3.org/2010/05/video/mediaevents.html

Dispatched by HTML5 media element, notifying playback process

Page 15: Yapi.js, An Adaptive Streaming Web Player

USEFUL EVENTS FOR YAPI.JS

loadstart: Indicate loading media begins, this fires when setting src attribute

loadedmetadata: while element has basic info of playback, e.g duration

timeupdate: while current time of playback is ticking

seeking/seeked: while conducting seek

ended: playback ends

play/playing: playback resume from other status to playing

Page 16: Yapi.js, An Adaptive Streaming Web Player

yapi

YAPI PROXY EVENTS

Media Elementeventevent with same name

Page 17: Yapi.js, An Adaptive Streaming Web Player

ADDITIONAL EVENTSloadedmanifest: after manifest is loaded/parsed

bitratechanged: when bitrate is changed

enableabr: when adaptive activation changed

buffering: when playback pending

cuechanged: webvtt subtitle cue changed (in and out)

Page 18: Yapi.js, An Adaptive Streaming Web Player

BEHAVIOR WITH MEDIA SOURCE

Page 19: Yapi.js, An Adaptive Streaming Web Player

SEEK BEHAVIOR 1

• mediaElement.currentTime = TIME_SEEK_TOwill conduct seek

• use yapi.seek(TIME_SEEK_TO) instead

Page 20: Yapi.js, An Adaptive Streaming Web Player

SEEK BEHAVIOR 2

• seek is totally done by mediaElement, so yapi.js listen to seeking and seeked event to know seek starts and ends

• seeking event dispatched by yapi would have seekFrom and seekTo as parameters

Page 21: Yapi.js, An Adaptive Streaming Web Player

PENDING DETECTION

• No useful event to indicate pending situation waiting stalled emptied

• pending detection is done on every timeupdate event, yapi.js would check media source buffered length

Page 22: Yapi.js, An Adaptive Streaming Web Player

PLAYBACK END

• mediaElement dispatch ended event natively when playback goes to end

• but not while attaching media source to it

• mediaSource.endOfStream() must be invoked beforehand

Page 23: Yapi.js, An Adaptive Streaming Web Player

yapi

YAPI ENCAPSULATE MEDIA ELEMENT

Media Elementexternal api

Page 24: Yapi.js, An Adaptive Streaming Web Player

SUMMARY

• media source provide stream buffer for mediaElementmediaElement.src = createObjectURL(ms)

• listen to events dispatched by yapi, instead of mediaElement

• use api exposed by yapi (call api of mediaElement not recommended) e.g seek

Page 25: Yapi.js, An Adaptive Streaming Web Player

M3U8 ON SAFARI

• attach m3u8 to mediaElement on safari by simplymediaElement.src = URL_TO_M3U8

Page 26: Yapi.js, An Adaptive Streaming Web Player

INTRODUCE YAPI SAMPLE UI

Page 27: Yapi.js, An Adaptive Streaming Web Player
Page 28: Yapi.js, An Adaptive Streaming Web Player
Page 29: Yapi.js, An Adaptive Streaming Web Player

MediaCtrlPanel… and its children

Volume UI

HOW’D YOU ASSEMBLE?

ProgressBar slider

slider

client

yapi

Page 30: Yapi.js, An Adaptive Streaming Web Player

SLIDER CLASS

• slider constructor takes a node and orientation as mandatory parameters

• it focus on 1. locate pointer with given param (event or percentage)2. return location with given param3. notify listeners events occurred

Page 31: Yapi.js, An Adaptive Streaming Web Player

TAKE A LOOK AT PROGRESS BAR

• played bar

• buffered bar

• seek time indicator

• preview

Page 32: Yapi.js, An Adaptive Streaming Web Player

AND VOLUME UI

• value bar

Page 33: Yapi.js, An Adaptive Streaming Web Player

BEHAVIOR FLOWscenario 1: progress changed by app. e.g yapi.seek(TIME) invoked

MediaCtrlPanel ProgressBar slideryapi

scenario 2: progress changed by user interaction, e.g click on slider

MediaCtrlPanel ProgressBar slideryapi

Page 34: Yapi.js, An Adaptive Streaming Web Player

SCENARIO 1: FROM APP

MediaCtrlPanel.onSeeking(event)yapi.seek(time)

MediaCtrlPanel listens to ‘seeking’ event emitted from yapi, then calculates percentage of current progress

(currentTime / totalDuration)

Page 35: Yapi.js, An Adaptive Streaming Web Player

SCENARIO 1: FROM APP

MediaCtrlPanel. ProgressBar.locatePointer(percentage)yapi.seek(time)

Page 36: Yapi.js, An Adaptive Streaming Web Player

SCENARIO 1: FROM APP

MediaCtrlPanel. ProgressBar.locatePointer(percentage)

slider.locatePointer(percentage)

yapi.seek(time)

progressBar update played bar

Page 37: Yapi.js, An Adaptive Streaming Web Player

SCENARIO 1: FROM APP

MediaCtrlPanel. ProgressBar.locatePointer(percentage)

slider.locatePointer(percentage)

yapi.seek(time)

slider.locatePointer would invoke method locatePointerInternal,with1. it’s argument 2. notToDispatchEvent as true (I know it’s tricky)

Page 38: Yapi.js, An Adaptive Streaming Web Player

SCENARIO 2: FROM SLIDER

assume user conduct seek by click on slider, b/c slider.addEventListener(‘click', locatePointerInternal);

so it will dispatch POINTER_LOCATED event

slider

(Remember notToDispatchEvent param?)

Page 39: Yapi.js, An Adaptive Streaming Web Player

SCENARIO 2: FROM SLIDER

progressBar listens to ‘POINTER_LOCATED’ event andupdate played bar

ProgressBar slider

Page 40: Yapi.js, An Adaptive Streaming Web Player

SCENARIO 2: FROM SLIDER

MediaCtrlPanel also listens to ‘POINTER_LOCATED’ eventand it will invoke yapi.seek(calculatedTime)

(percentage of time is within POINTER_LOCATED event obj)

MediaCtrlPanel ProgressBarslideryapi

Page 41: Yapi.js, An Adaptive Streaming Web Player

A LESSON

“ take care of flow direction, or it might be an infinite loop “

MediaCtrlPanel ProgressBar slideryapi

yapi MediaCtrlPanel ProgressBar slider

Page 42: Yapi.js, An Adaptive Streaming Web Player

LET’S TALK ABOUT EVENT

Page 43: Yapi.js, An Adaptive Streaming Web Player

LISTEN TO EVENT

consider on these 2 phrases

“ progressBar listens to ‘POINTER_LOCATED’ event “

“ MediaCtrlPanel also listens to ‘POINTER_LOCATED’ event “

Page 44: Yapi.js, An Adaptive Streaming Web Player

BAD IMPLEMENTATIONbut it works!

progressBar.addEventListener();mediaCtrlPanel.addEventListener();

slider.addEventListener(POINTER_LOCATED, callback);

Page 45: Yapi.js, An Adaptive Streaming Web Player

ADD LISTENERit would call method with same name of eventBus

slider eventBus.addEventListener(POINTER_LOCATED, callback)

while invoking this, eventBus will manipulate an object holding map of event name and callback.

in the case, POINTER_LOCATED would be key, and an array as value with callback pushed into it.

Page 46: Yapi.js, An Adaptive Streaming Web Player

DISPATCH EVENTPOINTER_LOCATED is an event from slider

it will find array of key: POINTER_LOCATED, and invoke every element (callback) of it.

slider eventBus.dispatchEvent(POINTER_LOCATED)

Page 47: Yapi.js, An Adaptive Streaming Web Player

WHAT’S THE BAD PART?• mediaCtrlPanl needs a reference of slider

MediaCtrlPanel ProgressBar sliderconflicts with

mediaCtrlPanel.addEventListener();

slider.addEventListener();

• for every dispatcher, an eventBus instance is neededslider eventBus.addEventListener() eventBus.dispatchEvent()

assume progressBar would dispatch a ‘PROGRESS_BAR_HIDE’ event, then every module which listens this event needs progressBar reference,

and progressBar needs a private eventBus for mapping

progressBar? another eventBus

Page 48: Yapi.js, An Adaptive Streaming Web Player

TAKE A LOOK AT DOM EVENT

while click on <td> <table> would also get it

“by default”

http://www.w3.org/TR/DOM-Level-3-Events/

HOW COME?

<td>.addEventListener(‘click’, callback)<table>.addEventListener(‘click’, callback)

Page 49: Yapi.js, An Adaptive Streaming Web Player

TAKE A LOOK AT DOM EVENT

http://www.w3.org/TR/DOM-Level-3-Events/

a singleton eventBus holds by every node

while add listener

it knows which node listens

while dispatchingit invoke callback with node as context

Page 50: Yapi.js, An Adaptive Streaming Web Player

THEREFORE

MediaCtrlPanel… and its children

Volume UI

ProgressBar slider

slider

eventBus

that’s why DI needed

Page 51: Yapi.js, An Adaptive Streaming Web Player

SUMMARY

• find common part and reuse it

• remember: behavior has direction

• event indicates states of application, handle it well

Page 52: Yapi.js, An Adaptive Streaming Web Player

client

INITIALIZE CTRL PANEL

MediaCtrlPanelProgressBar

Volume UI

• in client app, invoke new MediaCtrlPanel()

• call setup method, it loads template html

• then apply component functions and initialize progress-bar and volume-ui

Page 53: Yapi.js, An Adaptive Streaming Web Player

INITIALIZATION DETAIL• in client app, invoke new MediaCtrlPanel()

• in panel.setup(), loads template html

• after html loaded, apply component functions

also initialize progress-bar and volume-ui

Page 54: Yapi.js, An Adaptive Streaming Web Player

IF A MODULE HANDLING THIS• that module called ‘yapiDOM’ with a method ‘render’

• takes 2 parameters:1. constructor of a component, 2. selected node this component would mount on

• while `render()` invoked, yapiDOM will instantiate given constructor and run setup method of component(load template and apply component functions )

Page 55: Yapi.js, An Adaptive Streaming Web Player

IT WOULD BE LIKE…

very similar to React !

Page 56: Yapi.js, An Adaptive Streaming Web Player

ATTACH VARIABLE

• attach yapi player to media ctrl panel, and listens to player event

Page 57: Yapi.js, An Adaptive Streaming Web Player

IF YAPIDOM ALSO HANDLES THIS

• yapiDOM has another method ‘createElement’

• takes 2 parameters:1. constructor of a component, 2. object with map of key/variable

• while `createElement()` invoked, yapiDOM will instantiate given constructor and run setup method of component

Page 58: Yapi.js, An Adaptive Streaming Web Player

SETUP COMPONENT

1. load html (js sync / html async)

2. apply component functions

3. hold reference of given map object

4. return created component node

Page 59: Yapi.js, An Adaptive Streaming Web Player

IT WOULD BE LIKE…

just like React !

Page 60: Yapi.js, An Adaptive Streaming Web Player

SUB COMPONENT

• create target component inside setup method of media ctrl panel

Page 61: Yapi.js, An Adaptive Streaming Web Player

SUMMARYComponent

1. have a conventional ‘setup’ method with yapiDOM

2. setting these while setup:• template• behavior• reference

yapiDOM

1. createElement method:run instance method ‘setup’ of given component class

2. render method:append node to target node

attach singleton eventBus here

Page 62: Yapi.js, An Adaptive Streaming Web Player

UNIT TEST JASMINE / KARMA

Page 63: Yapi.js, An Adaptive Streaming Web Player

JASMINE =MOCHA +

CHAI + SINON

framework

assertion

spy

Page 64: Yapi.js, An Adaptive Streaming Web Player

COMPARISONsetup of running on browser

jasmine

mocha

Page 65: Yapi.js, An Adaptive Streaming Web Player

COMPARISON

https://github.com/ddhp/test-framework-comparison

Page 66: Yapi.js, An Adaptive Streaming Web Player

RUN ON COMMAND LINE

• can be run on phantomJS, a headless browser

• easier integrate with CI

Page 67: Yapi.js, An Adaptive Streaming Web Player

TASK RUNNER

• grunt-mocha takes html file as source

• for grunt-jasmine, set up source, vendor, spec javascript files in task config

Page 68: Yapi.js, An Adaptive Streaming Web Player

WHICH I PREFER

• flexibility comes with complexity

• mocha can do everything, so it’s important that you make choice and being consistent

• jasmine is capable enough for client-side unit test

Page 69: Yapi.js, An Adaptive Streaming Web Player

TDD / BDD

• mocha.setup() can decide which strategy to use (link)

• it’s just the difference between syntax

Page 70: Yapi.js, An Adaptive Streaming Web Player

TIPS OF WRITING TEST• it doesn’t matter which strategy to adopt, just get your hands

dirty

• get code coverage 100%

• add relevant test case while adding feature (b/c there must be a reason you do this)

• also while fixing bug (prevent from occurs again)

Page 71: Yapi.js, An Adaptive Streaming Web Player

INTRODUCE KARMA

Page 72: Yapi.js, An Adaptive Streaming Web Player

CONSIDER THESE FEATURES

• watch on modification

• preprocess

• run on different browsers simultaneously

• code coverage report

Page 73: Yapi.js, An Adaptive Streaming Web Player

KARMA IS…

• a test runner

• would spawn a server by default on port 9876 which serves test cases

Page 74: Yapi.js, An Adaptive Streaming Web Player

CONFIG KARMA• list needed plugins

• decide which framework and browsers to run on

• setup preprocessors

• list reporters

• list required helpers, vendors, sources and specs in files

Page 75: Yapi.js, An Adaptive Streaming Web Player

TIPS

• setup different config for developing and CIdeveloping: runs on different browsers CI: runs on phantomjs with coverage report

• if grunt-watch is exploited, it’s better to disable watch feature of karma i.e each karma run is a single run, and re-run it when file changed