Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // This file contains common utilities to find video/audio elements on a page | |
| 6 // and collect metrics for each. | |
| 7 | |
| 8 (function() { | |
| 9 // MediaMetric class responsible for collecting metrics on a media element. | |
| 10 // It attaches required event listeners in order to collect different metrics. | |
| 11 function MediaMetric(element) { | |
|
nduca
2013/07/09 23:07:19
should a MediaMetricBase base class, a HTML5Media
shadi
2013/07/11 00:49:13
PTAL. I kept all fields common to any media metric
| |
| 12 this.metrics = {}; | |
| 13 this.info = {}; | |
| 14 this.element = element; | |
| 15 this.isHTML5 = element instanceof HTMLMediaElement; | |
|
nduca
2013/07/09 23:07:19
this could be a getter on MediaMetric.
shadi
2013/07/11 00:49:13
This is avoided with subclasses.
| |
| 16 // Listen to when a Telemetry 'Play' action gets called. | |
| 17 this.element.addEventListener('willPlay', this.onWillPlay, false); | |
| 18 if (this.isHTML5) | |
| 19 this.initHTML5(); | |
|
nduca
2013/07/09 23:07:19
what happens if you accidentally bind a media metr
shadi
2013/07/11 00:49:13
Done.
| |
| 20 } | |
|
nduca
2013/07/09 23:07:19
should you explode if this isnt' html5?
shadi
2013/07/11 00:49:13
not really. If there are no html5 elements in the
| |
| 21 | |
| 22 MediaMetric.prototype.onWillPlay = function() { | |
| 23 this.ttp_timer = new Timer(); | |
|
nduca
2013/07/09 23:07:19
name this fully
shadi
2013/07/11 00:49:13
Done.
| |
| 24 }; | |
| 25 | |
| 26 MediaMetric.prototype.initHTML5 = function() { | |
| 27 // Set the basic event handlers for HTML5 media element. | |
| 28 var metric = this; | |
| 29 function onVideoLoad(event) { | |
| 30 // If a 'Play' action is performed, then ttp_time != undefined. | |
| 31 if (metric.ttp_timer == undefined) | |
| 32 metric.ttp_timer = new Timer(); | |
| 33 } | |
| 34 // For the cases where autoplay=true, and without a 'play' action, we want | |
| 35 // to start ttp_timer at 'play' or 'loadedmetadata' events. | |
| 36 this.element.addEventListener('play', onVideoLoad); | |
| 37 this.element.addEventListener('loadedmetadata', onVideoLoad); | |
| 38 this.element.addEventListener('playing', function(e) { | |
| 39 metric.onPlaying(e); | |
| 40 }); | |
| 41 this.element.addEventListener('ended', function(e) { | |
| 42 metric.onEnded(e); | |
| 43 }); | |
| 44 }; | |
| 45 | |
| 46 MediaMetric.prototype.onPlaying = function(event) { | |
| 47 // Playing event can fire more than once if seeking. | |
| 48 if (!this.metrics['ttp']) | |
| 49 this.metrics['ttp'] = [this.ttp_timer.stop(), 'sec']; | |
| 50 }; | |
| 51 | |
| 52 MediaMetric.prototype.onEnded = function(event) { | |
| 53 this.metrics['playback_time'] = [this.ttp_timer.stop(), 'sec']; | |
| 54 }; | |
| 55 | |
| 56 MediaMetric.prototype.getElementInfo = function() { | |
| 57 // Return information about the media element for this metric. | |
| 58 if (this.element.id) | |
| 59 this.info['id'] = this.element.id; | |
| 60 if (this.isHTML5) { | |
| 61 // Add interesting media specific tags. | |
| 62 if (this.element.src) | |
| 63 this.info['src'] = this.element.src; | |
| 64 } | |
| 65 return this.info; | |
| 66 }; | |
| 67 | |
| 68 MediaMetric.prototype.getMetrics = function() { | |
| 69 // Returns all collected metrics for the element | |
| 70 if (this.isHTML5) { | |
| 71 this.metrics['decoded_frame_count'] = | |
| 72 [this.element.webkitDecodedFrameCount, 'frames']; | |
| 73 this.metrics['dropped_frame_count'] = | |
| 74 [this.element.webkitDroppedFrameCount, 'frames']; | |
| 75 this.metrics['decoded_video_bytes'] = | |
| 76 [this.element.webkitVideoDecodedByteCount, 'bytes']; | |
| 77 this.metrics['decoded_audio_bytes'] = | |
| 78 [this.element.webkitAudioDecodedByteCount, 'bytes']; | |
| 79 } | |
| 80 return this.metrics; | |
| 81 }; | |
| 82 | |
| 83 MediaMetric.prototype.getSummary = function() { | |
| 84 return { | |
| 85 'info': this.getElementInfo(), | |
| 86 'metrics': this.getMetrics() | |
| 87 }; | |
| 88 }; | |
| 89 | |
| 90 function Timer() { | |
|
nduca
2013/07/09 23:07:19
why does this not call start()?
and why not just
shadi
2013/07/11 00:49:13
It is usually the case where you need to start the
| |
| 91 this.start_ = getCurrentTime(); | |
| 92 this.times_ = []; | |
| 93 } | |
| 94 | |
| 95 Timer.prototype = { | |
| 96 start: function() { | |
| 97 this.start_ = getCurrentTime(); | |
| 98 }, | |
| 99 | |
| 100 stop: function() { | |
| 101 // Store time logs in secs. | |
| 102 var delta = (getCurrentTime() - this.start_) / 1000; | |
| 103 this.times_.push(delta); | |
| 104 return delta; | |
| 105 } | |
| 106 }; | |
| 107 | |
| 108 function LoadMediaMetrics() { | |
|
nduca
2013/07/09 23:07:19
This isn't really loading. createMediaMetricsForDo
shadi
2013/07/11 00:49:13
Done.
| |
| 109 // Searches for all video and audio elements on the page and creates a | |
| 110 // corresponding media metric instance for each. | |
| 111 var media = document.querySelectorAll('video, audio'); | |
|
nduca
2013/07/09 23:07:19
mediaElements
shadi
2013/07/11 00:49:13
Done.
| |
| 112 for (var i = 0; i < media.length; i++) { | |
|
nduca
2013/07/09 23:07:19
one liners dont get {}
shadi
2013/07/11 00:49:13
Done.
| |
| 113 mediaMetrics.push(new MediaMetric(media[i])); | |
|
nduca
2013/07/09 23:07:19
explicitly say window.__mediaMetrics perhaps inste
shadi
2013/07/11 00:49:13
Done.
| |
| 114 } | |
| 115 } | |
| 116 | |
| 117 function getCurrentTime() { | |
| 118 if (window.performance) | |
| 119 return (performance.now || | |
| 120 performance.mozNow || | |
| 121 performance.msNow || | |
| 122 performance.oNow || | |
| 123 performance.webkitNow).call(window.performance); | |
| 124 else | |
| 125 return Date().getTime(); | |
|
nduca
2013/07/09 23:07:19
Date.now()? does't create garbage...
shadi
2013/07/11 00:49:13
Done.
| |
| 126 } | |
| 127 | |
| 128 function getAllMetrics() { | |
| 129 // Returns a summary (info + metrics) for all media metrics. | |
| 130 var metrics = []; | |
| 131 for (var i = 0; i < mediaMetrics.length; i++) { | |
|
nduca
2013/07/09 23:07:19
one line fors get no bracez
shadi
2013/07/11 00:49:13
Done.
| |
| 132 metrics.push(mediaMetrics[i].getSummary()); | |
| 133 } | |
| 134 return metrics; | |
| 135 } | |
| 136 | |
| 137 // Stores metrics for all media elements on the page upon loading. | |
| 138 var mediaMetrics = []; | |
| 139 window.__mediaMetrics = mediaMetrics; | |
| 140 window.__getAllMetrics = getAllMetrics; | |
| 141 LoadMediaMetrics(); | |
|
nduca
2013/07/09 23:07:19
you should keep injection of the script separate f
shadi
2013/07/11 00:49:13
Is there a good reason for this? Is there a case w
| |
| 142 })(); | |
| OLD | NEW |