Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 <include src="cache_entry.js"/> | 5 <include src="cache_entry.js"/> |
| 6 <include src="disjoint_range_set.js"/> | |
| 7 <include src="event_list.js"/> | |
| 6 <include src="item_store.js"/> | 8 <include src="item_store.js"/> |
| 7 <include src="disjoint_range_set.js"/> | 9 <include src="media_player.js"/> |
| 10 <include src="metrics.js"/> | |
| 11 <include src="util.js"/> | |
| 8 | 12 |
| 9 cr.define('media', function() { | 13 cr.define('media', function() { |
| 14 'use strict'; | |
| 10 | 15 |
| 11 // Stores information on open audio streams, referenced by id. | 16 // Stores information on open audio streams, referenced by id. |
| 12 var audioStreams = new media.ItemStore; | 17 var audioStreams = new media.ItemStore; |
| 13 | 18 |
| 19 // Active media players, indexed by 'render_id:player_id'. | |
| 20 var mediaPlayers = {}; | |
| 21 | |
| 14 // Cached files indexed by key and source id. | 22 // Cached files indexed by key and source id. |
| 15 var cacheEntriesByKey = {}; | 23 var cacheEntriesByKey = {}; |
| 16 var cacheEntries = {}; | 24 var cacheEntries = {}; |
| 17 | 25 |
| 18 // Map of event source -> url. | 26 // Map of event source -> url. |
| 19 var requestURLs = {}; | 27 var requestURLs = {}; |
| 20 | 28 |
| 21 // Constants passed to us from Chrome. | 29 // Constants passed to us from Chrome. |
| 22 var eventTypes = {}; | 30 var eventTypes = {}; |
| 23 var eventPhases = {}; | 31 var eventPhases = {}; |
| 24 | 32 |
| 25 // The <div>s on the page in which to display information. | 33 // The <div>s on the page in which to display information. |
| 26 var audioStreamDiv; | 34 var audioStreamDiv; |
| 27 var cacheDiv; | 35 var cacheDiv; |
| 28 | 36 |
| 37 // A timer used to limit the rate of redrawing the Media Players section. | |
| 38 var redrawTimer = null; | |
| 39 | |
| 29 /** | 40 /** |
| 30 * Initialize variables and ask MediaInternals for all its data. | 41 * Initialize variables and ask MediaInternals for all its data. |
| 31 */ | 42 */ |
| 32 initialize = function() { | 43 function initialize() { |
| 33 audioStreamDiv = document.getElementById('audio-streams'); | 44 audioStreamDiv = document.getElementById('audio-streams'); |
| 34 cacheDiv = document.getElementById('cache-entries'); | 45 cacheDiv = document.getElementById('cache-entries'); |
| 46 | |
| 35 // Get information about all currently active media. | 47 // Get information about all currently active media. |
| 36 chrome.send('getEverything'); | 48 chrome.send('getEverything'); |
| 37 }; | 49 }; |
|
arv (Not doing code reviews)
2011/09/23 15:59:01
no semicolon after function declarations
scherkus (not reviewing)
2011/09/23 17:43:23
Done.
| |
| 38 | 50 |
| 39 /** | 51 /** |
| 40 * Write the set of audio streams to the DOM. | 52 * Write the set of audio streams to the DOM. |
| 41 */ | 53 */ |
| 42 printAudioStreams = function() { | 54 function printAudioStreams() { |
| 43 | 55 |
| 44 /** | 56 /** |
| 45 * Render a single stream as a <li>. | 57 * Render a single stream as a <li>. |
| 46 * @param {Object} stream The stream to render. | 58 * @param {Object} stream The stream to render. |
| 47 * @return {HTMLElement} A <li> containing the stream information. | 59 * @return {HTMLElement} A <li> containing the stream information. |
| 48 */ | 60 */ |
| 49 printStream = function(stream) { | 61 function printStream(stream) { |
| 50 var out = document.createElement('li'); | 62 var out = document.createElement('li'); |
| 51 out.id = stream.id; | 63 out.id = stream.id; |
| 52 out.className = 'audio-stream'; | 64 out.className = 'audio-stream'; |
| 53 out.setAttribute('status', stream.status); | 65 out.setAttribute('status', stream.status); |
| 54 | 66 |
| 55 out.textContent += 'Audio stream ' + stream.id.split('.')[1]; | 67 out.textContent += 'Audio stream ' + stream.id.split('.')[1]; |
| 56 out.textContent += ' is ' + (stream.playing ? 'playing' : 'paused'); | 68 out.textContent += ' is ' + (stream.playing ? 'playing' : 'paused'); |
| 57 out.textContent += ' at ' + Math.round(stream.volume * 100) + '% volume.'; | 69 out.textContent += ' at ' + Math.round(stream.volume * 100) + '% volume.'; |
| 58 return out; | 70 return out; |
| 59 }; | 71 }; |
| 60 | 72 |
| 61 var out = document.createElement('ul'); | 73 var out = document.createElement('ul'); |
| 62 audioStreams.map(printStream).forEach(function(s) { | 74 audioStreams.map(printStream).forEach(function(s) { |
| 63 out.appendChild(s) | 75 out.appendChild(s) |
| 64 }); | 76 }); |
| 65 | 77 |
| 66 audioStreamDiv.textContent = ''; | 78 audioStreamDiv.textContent = ''; |
| 67 audioStreamDiv.appendChild(out); | 79 audioStreamDiv.appendChild(out); |
| 68 }; | 80 }; |
| 69 | 81 |
| 70 /** | 82 /** |
| 83 * Redraw each MediaPlayer. | |
| 84 */ | |
| 85 function printMediaPlayers() { | |
| 86 for (var id in mediaPlayers) { | |
| 87 mediaPlayers[id].redraw(); | |
| 88 } | |
| 89 redrawTimer = null; | |
| 90 }; | |
| 91 | |
| 92 /** | |
| 71 * Write the set of sparse CacheEntries to the DOM. | 93 * Write the set of sparse CacheEntries to the DOM. |
| 72 */ | 94 */ |
| 73 printSparseCacheEntries = function() { | 95 function printSparseCacheEntries() { |
| 74 var out = document.createElement('ul'); | 96 var out = document.createElement('ul'); |
| 75 for (var key in cacheEntriesByKey) { | 97 for (var key in cacheEntriesByKey) { |
| 76 if (cacheEntriesByKey[key].sparse) | 98 if (cacheEntriesByKey[key].sparse) |
| 77 out.appendChild(cacheEntriesByKey[key].toListItem()); | 99 out.appendChild(cacheEntriesByKey[key].toListItem()); |
| 78 } | 100 } |
| 79 | 101 |
| 80 cacheDiv.textContent = ''; | 102 cacheDiv.textContent = ''; |
| 81 cacheDiv.appendChild(out); | 103 cacheDiv.appendChild(out); |
| 82 }; | 104 }; |
| 83 | 105 |
| 84 /** | 106 /** |
| 85 * Receiving data for an audio stream. | 107 * Receiving data for an audio stream. |
| 86 * Add it to audioStreams and update the page. | 108 * Add it to audioStreams and update the page. |
| 87 * @param {Object} stream JSON representation of an audio stream. | 109 * @param {Object} stream JSON representation of an audio stream. |
| 88 */ | 110 */ |
| 89 addAudioStream = function(stream) { | 111 function addAudioStream(stream) { |
| 90 audioStreams.addItem(stream); | 112 audioStreams.addItem(stream); |
| 91 printAudioStreams(); | 113 printAudioStreams(); |
| 92 }; | 114 }; |
| 93 | 115 |
| 94 /** | 116 /** |
| 95 * Receiving all data. | 117 * Receiving all data. |
| 96 * Add it all to the appropriate stores and update the page. | 118 * Add it all to the appropriate stores and update the page. |
| 97 * @param {Object} stuff JSON containing lists of data. | 119 * @param {Object} stuff JSON containing lists of data. |
| 98 * @param {Object} stuff.audio_streams A dictionary of audio streams. | 120 * @param {Object} stuff.audio_streams A dictionary of audio streams. |
| 99 */ | 121 */ |
| 100 onReceiveEverything = function(stuff) { | 122 function onReceiveEverything(stuff) { |
| 101 audioStreams.addItems(stuff.audio_streams); | 123 audioStreams.addItems(stuff.audio_streams); |
| 102 printAudioStreams(); | 124 printAudioStreams(); |
| 103 }; | 125 }; |
| 104 | 126 |
| 105 /** | 127 /** |
| 106 * Removing an item from the appropriate store. | 128 * Removing an item from the appropriate store. |
| 107 * @param {string} id The id of the item to be removed, in the format | 129 * @param {string} id The id of the item to be removed, in the format |
| 108 * "item_type.identifying_info". | 130 * "item_type.identifying_info". |
| 109 */ | 131 */ |
| 110 onItemDeleted = function(id) { | 132 function onItemDeleted(id) { |
| 111 var type = id.split('.')[0]; | 133 var type = id.split('.')[0]; |
| 112 switch (type) { | 134 switch (type) { |
| 113 case 'audio_streams': | 135 case 'audio_streams': |
| 114 audioStreams.removeItem(id); | 136 audioStreams.removeItem(id); |
| 115 printAudioStreams(); | 137 printAudioStreams(); |
| 116 break; | 138 break; |
| 117 } | 139 } |
| 118 }; | 140 }; |
| 119 | 141 |
| 120 /** | 142 /** |
| 143 * A render process has ended, delete any media players associated with it. | |
| 144 * @param {int} renderer The id of the render process. | |
|
arv (Not doing code reviews)
2011/09/23 15:59:01
@param {number}
scherkus (not reviewing)
2011/09/23 17:43:23
Done.
| |
| 145 */ | |
| 146 function onRendererTerminated(renderer) { | |
| 147 for (var key in mediaPlayers) { | |
| 148 if (mediaPlayers[key].renderer == renderer) { | |
| 149 document.getElementById('media-players').removeChild(mediaPlayers[key]); | |
| 150 delete mediaPlayers[key]; | |
|
arv (Not doing code reviews)
2011/09/23 15:59:01
Maybe break out of loop here?
scherkus (not reviewing)
2011/09/23 17:43:23
Good catch - done.
| |
| 151 } | |
| 152 } | |
| 153 printMediaPlayers(); | |
| 154 }; | |
| 155 | |
| 156 /** | |
| 121 * Receiving net events. | 157 * Receiving net events. |
| 122 * Update cache information and update that section of the page. | 158 * Update cache information and update that section of the page. |
| 123 * @param {Array} updates A list of net events that have occurred. | 159 * @param {Array} updates A list of net events that have occurred. |
| 124 */ | 160 */ |
| 125 onNetUpdate = function(updates) { | 161 function onNetUpdate(updates) { |
| 126 updates.forEach(function(update) { | 162 updates.forEach(function(update) { |
| 127 var id = update.source.id; | 163 var id = update.source.id; |
| 128 if (!cacheEntries[id]) | 164 if (!cacheEntries[id]) |
| 129 cacheEntries[id] = new media.CacheEntry; | 165 cacheEntries[id] = new media.CacheEntry; |
| 130 | 166 |
| 131 switch (eventPhases[update.phase] + '.' + eventTypes[update.type]) { | 167 switch (eventPhases[update.phase] + '.' + eventTypes[update.type]) { |
| 132 case 'PHASE_BEGIN.DISK_CACHE_ENTRY_IMPL': | 168 case 'PHASE_BEGIN.DISK_CACHE_ENTRY_IMPL': |
| 133 var key = update.params.key; | 169 var key = update.params.key; |
| 134 | 170 |
| 135 // Merge this source with anything we already know about this key. | 171 // Merge this source with anything we already know about this key. |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 159 break; | 195 break; |
| 160 | 196 |
| 161 case 'PHASE_NONE.HTTP_TRANSACTION_READ_RESPONSE_HEADERS': | 197 case 'PHASE_NONE.HTTP_TRANSACTION_READ_RESPONSE_HEADERS': |
| 162 // Record the total size of the file if this was a range request. | 198 // Record the total size of the file if this was a range request. |
| 163 var range = /content-range:\s*bytes\s*\d+-\d+\/(\d+)/i.exec( | 199 var range = /content-range:\s*bytes\s*\d+-\d+\/(\d+)/i.exec( |
| 164 update.params.headers); | 200 update.params.headers); |
| 165 var key = requestURLs[update.source.id]; | 201 var key = requestURLs[update.source.id]; |
| 166 delete requestURLs[update.source.id]; | 202 delete requestURLs[update.source.id]; |
| 167 if (range && key) { | 203 if (range && key) { |
| 168 if (!cacheEntriesByKey[key]) { | 204 if (!cacheEntriesByKey[key]) { |
| 169 cacheEntriesByKey[key] = new CacheEntry; | 205 cacheEntriesByKey[key] = new media.CacheEntry; |
| 170 cacheEntriesByKey[key].key = key; | 206 cacheEntriesByKey[key].key = key; |
| 171 } | 207 } |
| 172 cacheEntriesByKey[key].size = range[1]; | 208 cacheEntriesByKey[key].size = range[1]; |
| 173 } | 209 } |
| 174 break; | 210 break; |
| 175 } | 211 } |
| 176 }); | 212 }); |
| 177 | 213 |
| 178 printSparseCacheEntries(); | 214 printSparseCacheEntries(); |
| 179 }; | 215 }; |
| 180 | 216 |
| 181 /** | 217 /** |
| 182 * Receiving values for constants. Store them for later use. | 218 * Receiving values for constants. Store them for later use. |
| 183 * @param {Object} constants A dictionary of constants. | 219 * @param {Object} constants A dictionary of constants. |
| 184 * @param {Object} constants.eventTypes A dictionary of event name -> int. | 220 * @param {Object} constants.eventTypes A dictionary of event name -> int. |
| 185 * @param {Object} constants.eventPhases A dictionary of event phase -> int. | 221 * @param {Object} constants.eventPhases A dictionary of event phase -> int. |
| 186 */ | 222 */ |
| 187 onReceiveConstants = function(constants) { | 223 function onReceiveConstants(constants) { |
| 188 var events = constants.eventTypes; | 224 var events = constants.eventTypes; |
| 189 for (var e in events) | 225 for (var e in events) { |
| 190 eventTypes[events[e]] = e; | 226 eventTypes[events[e]] = e; |
| 227 } | |
| 191 | 228 |
| 192 var phases = constants.eventPhases; | 229 var phases = constants.eventPhases; |
| 193 for (var p in phases) | 230 for (var p in phases) { |
| 194 eventPhases[phases[p]] = p; | 231 eventPhases[phases[p]] = p; |
| 232 } | |
| 233 }; | |
| 234 | |
| 235 /** | |
| 236 * Receiving notification of a media event. | |
| 237 * @param {Object} event The json representation of a MediaLogEvent. | |
| 238 */ | |
| 239 function onMediaEvent(event) { | |
| 240 // List everything in miliseconds. | |
| 241 event.time *= 1000; | |
|
arv (Not doing code reviews)
2011/09/23 15:59:01
It is kind of ugly to change the event object here
scherkus (not reviewing)
2011/09/23 17:43:23
Hmm... it looks like the event trickles through to
| |
| 242 | |
| 243 var source = event.renderer + ':' + event.player; | |
| 244 var item = mediaPlayers[source] || | |
| 245 new media.MediaPlayer({id: source, renderer: event.renderer}); | |
| 246 mediaPlayers[source] = item; | |
| 247 item.addEvent(event); | |
| 248 | |
| 249 // Both media and net events could provide the size of the file. | |
| 250 // Media takes priority, but keep the size in both places synchronized. | |
| 251 if (cacheEntriesByKey[item.properties.url]) { | |
| 252 item.properties.total_bytes = item.properties.total_bytes || | |
| 253 cacheEntriesByKey[item.properties.url].size; | |
| 254 cacheEntriesByKey[item.properties.url].size = item.properties.total_bytes; | |
| 255 } | |
| 256 | |
| 257 // Events tend to arrive in groups; don't redraw the page too often. | |
| 258 if (!redrawTimer) | |
| 259 redrawTimer = setTimeout(printMediaPlayers, 50); | |
| 195 }; | 260 }; |
| 196 | 261 |
| 197 return { | 262 return { |
| 198 initialize: initialize, | 263 initialize: initialize, |
| 199 addAudioStream: addAudioStream, | 264 addAudioStream: addAudioStream, |
| 265 cacheEntriesByKey: cacheEntriesByKey, | |
| 200 onReceiveEverything: onReceiveEverything, | 266 onReceiveEverything: onReceiveEverything, |
| 201 onItemDeleted: onItemDeleted, | 267 onItemDeleted: onItemDeleted, |
| 268 onRendererTerminated: onRendererTerminated, | |
| 202 onNetUpdate: onNetUpdate, | 269 onNetUpdate: onNetUpdate, |
| 203 onReceiveConstants: onReceiveConstants, | 270 onReceiveConstants: onReceiveConstants, |
| 271 onMediaEvent: onMediaEvent | |
| 204 }; | 272 }; |
| 205 }); | 273 }); |
| 206 | 274 |
| 207 /** | 275 /** |
| 208 * Initialize everything once we have access to the DOM. | 276 * Initialize everything once we have access to the DOM. |
| 209 */ | 277 */ |
| 210 window.onload = function() { | 278 window.onload = function() { |
|
arv (Not doing code reviews)
2011/09/23 15:59:01
Do you really have to wait for window.onload?
Can
scherkus (not reviewing)
2011/09/23 17:43:23
Done.
| |
| 211 media.initialize(); | 279 media.initialize(); |
| 212 }; | 280 }; |
| OLD | NEW |