Index: chrome/browser/resources/media_internals/media_internals.js |
diff --git a/chrome/browser/resources/media_internals/media_internals.js b/chrome/browser/resources/media_internals/media_internals.js |
index 5d80b289547ec1aa2cc44a2d2848ee461ea0ddb4..7218c06b8d8596c554c6f6bdf9ee337043d65822 100644 |
--- a/chrome/browser/resources/media_internals/media_internals.js |
+++ b/chrome/browser/resources/media_internals/media_internals.js |
@@ -3,14 +3,22 @@ |
// found in the LICENSE file. |
<include src="cache_entry.js"/> |
-<include src="item_store.js"/> |
<include src="disjoint_range_set.js"/> |
+<include src="event_list.js"/> |
+<include src="item_store.js"/> |
+<include src="media_player.js"/> |
+<include src="metrics.js"/> |
+<include src="util.js"/> |
cr.define('media', function() { |
+ 'use strict'; |
// Stores information on open audio streams, referenced by id. |
var audioStreams = new media.ItemStore; |
+ // Active media players, indexed by 'render_id:player_id'. |
+ var mediaPlayers = {}; |
+ |
// Cached files indexed by key and source id. |
var cacheEntriesByKey = {}; |
var cacheEntries = {}; |
@@ -26,27 +34,31 @@ cr.define('media', function() { |
var audioStreamDiv; |
var cacheDiv; |
+ // A timer used to limit the rate of redrawing the Media Players section. |
+ var redrawTimer = null; |
+ |
/** |
* Initialize variables and ask MediaInternals for all its data. |
*/ |
- initialize = function() { |
+ function initialize() { |
audioStreamDiv = document.getElementById('audio-streams'); |
cacheDiv = document.getElementById('cache-entries'); |
+ |
// Get information about all currently active media. |
chrome.send('getEverything'); |
- }; |
+ } |
/** |
* Write the set of audio streams to the DOM. |
*/ |
- printAudioStreams = function() { |
+ function printAudioStreams() { |
/** |
* Render a single stream as a <li>. |
* @param {Object} stream The stream to render. |
* @return {HTMLElement} A <li> containing the stream information. |
*/ |
- printStream = function(stream) { |
+ function printStream(stream) { |
var out = document.createElement('li'); |
out.id = stream.id; |
out.className = 'audio-stream'; |
@@ -54,9 +66,10 @@ cr.define('media', function() { |
out.textContent += 'Audio stream ' + stream.id.split('.')[1]; |
out.textContent += ' is ' + (stream.playing ? 'playing' : 'paused'); |
- out.textContent += ' at ' + Math.round(stream.volume * 100) + '% volume.'; |
+ out.textContent += ' at ' + (stream.volume * 100).toFixed(0); |
+ out.textContent += '% volume.'; |
return out; |
- }; |
+ } |
var out = document.createElement('ul'); |
audioStreams.map(printStream).forEach(function(s) { |
@@ -65,12 +78,22 @@ cr.define('media', function() { |
audioStreamDiv.textContent = ''; |
audioStreamDiv.appendChild(out); |
- }; |
+ } |
+ |
+ /** |
+ * Redraw each MediaPlayer. |
+ */ |
+ function printMediaPlayers() { |
+ for (var key in mediaPlayers) { |
+ mediaPlayers[key].redraw(); |
+ } |
+ redrawTimer = null; |
+ } |
/** |
* Write the set of sparse CacheEntries to the DOM. |
*/ |
- printSparseCacheEntries = function() { |
+ function printSparseCacheEntries() { |
var out = document.createElement('ul'); |
for (var key in cacheEntriesByKey) { |
if (cacheEntriesByKey[key].sparse) |
@@ -79,17 +102,17 @@ cr.define('media', function() { |
cacheDiv.textContent = ''; |
cacheDiv.appendChild(out); |
- }; |
+ } |
/** |
* Receiving data for an audio stream. |
* Add it to audioStreams and update the page. |
* @param {Object} stream JSON representation of an audio stream. |
*/ |
- addAudioStream = function(stream) { |
+ function addAudioStream(stream) { |
audioStreams.addItem(stream); |
printAudioStreams(); |
- }; |
+ } |
/** |
* Receiving all data. |
@@ -97,32 +120,47 @@ cr.define('media', function() { |
* @param {Object} stuff JSON containing lists of data. |
* @param {Object} stuff.audio_streams A dictionary of audio streams. |
*/ |
- onReceiveEverything = function(stuff) { |
+ function onReceiveEverything(stuff) { |
audioStreams.addItems(stuff.audio_streams); |
printAudioStreams(); |
- }; |
+ } |
/** |
* Removing an item from the appropriate store. |
* @param {string} id The id of the item to be removed, in the format |
* "item_type.identifying_info". |
*/ |
- onItemDeleted = function(id) { |
+ function onItemDeleted(id) { |
var type = id.split('.')[0]; |
switch (type) { |
- case 'audio_streams': |
- audioStreams.removeItem(id); |
- printAudioStreams(); |
- break; |
+ case 'audio_streams': |
+ audioStreams.removeItem(id); |
+ printAudioStreams(); |
+ break; |
} |
- }; |
+ } |
+ |
+ /** |
+ * A render process has ended, delete any media players associated with it. |
+ * @param {number} renderer The id of the render process. |
+ */ |
+ function onRendererTerminated(renderer) { |
+ for (var key in mediaPlayers) { |
+ if (mediaPlayers[key].renderer == renderer) { |
+ document.getElementById('media-players').removeChild(mediaPlayers[key]); |
+ delete mediaPlayers[key]; |
+ break; |
+ } |
+ } |
+ printMediaPlayers(); |
+ } |
/** |
* Receiving net events. |
* Update cache information and update that section of the page. |
* @param {Array} updates A list of net events that have occurred. |
*/ |
- onNetUpdate = function(updates) { |
+ function onNetUpdate(updates) { |
updates.forEach(function(update) { |
var id = update.source.id; |
if (!cacheEntries[id]) |
@@ -166,7 +204,7 @@ cr.define('media', function() { |
delete requestURLs[update.source.id]; |
if (range && key) { |
if (!cacheEntriesByKey[key]) { |
- cacheEntriesByKey[key] = new CacheEntry; |
+ cacheEntriesByKey[key] = new media.CacheEntry; |
cacheEntriesByKey[key].key = key; |
} |
cacheEntriesByKey[key].size = range[1]; |
@@ -176,7 +214,7 @@ cr.define('media', function() { |
}); |
printSparseCacheEntries(); |
- }; |
+ } |
/** |
* Receiving values for constants. Store them for later use. |
@@ -184,29 +222,58 @@ cr.define('media', function() { |
* @param {Object} constants.eventTypes A dictionary of event name -> int. |
* @param {Object} constants.eventPhases A dictionary of event phase -> int. |
*/ |
- onReceiveConstants = function(constants) { |
+ function onReceiveConstants(constants) { |
var events = constants.eventTypes; |
- for (var e in events) |
+ for (var e in events) { |
eventTypes[events[e]] = e; |
+ } |
var phases = constants.eventPhases; |
- for (var p in phases) |
+ for (var p in phases) { |
eventPhases[phases[p]] = p; |
- }; |
+ } |
+ } |
+ |
+ /** |
+ * Receiving notification of a media event. |
+ * @param {Object} event The json representation of a MediaLogEvent. |
+ */ |
+ function onMediaEvent(event) { |
+ var source = event.renderer + ':' + event.player; |
+ var item = mediaPlayers[source] || |
+ new media.MediaPlayer({id: source, renderer: event.renderer}); |
+ mediaPlayers[source] = item; |
+ item.addEvent(event); |
+ |
+ // Both media and net events could provide the size of the file. |
+ // Media takes priority, but keep the size in both places synchronized. |
+ if (cacheEntriesByKey[item.properties.url]) { |
+ item.properties.total_bytes = item.properties.total_bytes || |
+ cacheEntriesByKey[item.properties.url].size; |
+ cacheEntriesByKey[item.properties.url].size = item.properties.total_bytes; |
+ } |
+ |
+ // Events tend to arrive in groups; don't redraw the page too often. |
+ if (!redrawTimer) |
+ redrawTimer = setTimeout(printMediaPlayers, 50); |
+ } |
return { |
initialize: initialize, |
addAudioStream: addAudioStream, |
+ cacheEntriesByKey: cacheEntriesByKey, |
onReceiveEverything: onReceiveEverything, |
onItemDeleted: onItemDeleted, |
+ onRendererTerminated: onRendererTerminated, |
onNetUpdate: onNetUpdate, |
onReceiveConstants: onReceiveConstants, |
+ onMediaEvent: onMediaEvent |
}; |
}); |
/** |
* Initialize everything once we have access to the DOM. |
*/ |
-window.onload = function() { |
+document.addEventListener('DOMContentLoaded', function() { |
media.initialize(); |
-}; |
+}); |