Home | History | Annotate | Download | only in media
      1 // Copyright 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 /**
      6  * A global object that gets used by the C++ interface.
      7  */
      8 var media = (function() {
      9   'use strict';
     10 
     11   var manager = null;
     12 
     13   // A number->string mapping that is populated through the backend that
     14   // describes the phase that the network entity is in.
     15   var eventPhases = {};
     16 
     17   // A number->string mapping that is populated through the backend that
     18   // describes the type of event sent from the network.
     19   var eventTypes = {};
     20 
     21   // A mapping of number->CacheEntry where the number is a unique id for that
     22   // network request.
     23   var cacheEntries = {};
     24 
     25   // A mapping of url->CacheEntity where the url is the url of the resource.
     26   var cacheEntriesByKey = {};
     27 
     28   var requrestURLs = {};
     29 
     30   var media = {
     31     BAR_WIDTH: 200,
     32     BAR_HEIGHT: 25
     33   };
     34 
     35   /**
     36    * Users of |media| must call initialize prior to calling other methods.
     37    */
     38   media.initialize = function(theManager) {
     39     manager = theManager;
     40   };
     41 
     42   media.onReceiveEverything = function(everything) {
     43     for (var component in everything) {
     44       media.updateAudioComponent(everything[component]);
     45     }
     46   };
     47 
     48   media.onReceiveConstants = function(constants) {
     49     for (var key in constants.eventTypes) {
     50       var value = constants.eventTypes[key];
     51       eventTypes[value] = key;
     52     }
     53 
     54     for (var key in constants.eventPhases) {
     55       var value = constants.eventPhases[key];
     56       eventPhases[value] = key;
     57     }
     58   };
     59 
     60   media.cacheForUrl = function(url) {
     61     return cacheEntriesByKey[url];
     62   };
     63 
     64   media.onNetUpdate = function(updates) {
     65     updates.forEach(function(update) {
     66       var id = update.source.id;
     67       if (!cacheEntries[id])
     68         cacheEntries[id] = new media.CacheEntry;
     69 
     70       switch (eventPhases[update.phase] + '.' + eventTypes[update.type]) {
     71         case 'PHASE_BEGIN.DISK_CACHE_ENTRY_IMPL':
     72           var key = update.params.key;
     73 
     74           // Merge this source with anything we already know about this key.
     75           if (cacheEntriesByKey[key]) {
     76             cacheEntriesByKey[key].merge(cacheEntries[id]);
     77             cacheEntries[id] = cacheEntriesByKey[key];
     78           } else {
     79             cacheEntriesByKey[key] = cacheEntries[id];
     80           }
     81           cacheEntriesByKey[key].key = key;
     82           break;
     83 
     84         case 'PHASE_BEGIN.SPARSE_READ':
     85           cacheEntries[id].readBytes(update.params.offset,
     86                                       update.params.buff_len);
     87           cacheEntries[id].sparse = true;
     88           break;
     89 
     90         case 'PHASE_BEGIN.SPARSE_WRITE':
     91           cacheEntries[id].writeBytes(update.params.offset,
     92                                        update.params.buff_len);
     93           cacheEntries[id].sparse = true;
     94           break;
     95 
     96         case 'PHASE_BEGIN.URL_REQUEST_START_JOB':
     97           requrestURLs[update.source.id] = update.params.url;
     98           break;
     99 
    100         case 'PHASE_NONE.HTTP_TRANSACTION_READ_RESPONSE_HEADERS':
    101           // Record the total size of the file if this was a range request.
    102           var range = /content-range:\s*bytes\s*\d+-\d+\/(\d+)/i.exec(
    103               update.params.headers);
    104           var key = requrestURLs[update.source.id];
    105           delete requrestURLs[update.source.id];
    106           if (range && key) {
    107             if (!cacheEntriesByKey[key]) {
    108               cacheEntriesByKey[key] = new media.CacheEntry;
    109               cacheEntriesByKey[key].key = key;
    110             }
    111             cacheEntriesByKey[key].size = range[1];
    112           }
    113           break;
    114       }
    115     });
    116   };
    117 
    118   media.onRendererTerminated = function(renderId) {
    119     util.object.forEach(manager.players_, function(playerInfo, id) {
    120       if (playerInfo.properties['render_id'] == renderId) {
    121         manager.removePlayer(id);
    122       }
    123     });
    124   };
    125 
    126   media.updateAudioComponent = function(component) {
    127     var uniqueComponentId = component.owner_id + ':' + component.component_id;
    128     switch (component.status) {
    129       case 'closed':
    130         manager.removeAudioComponent(
    131             component.component_type, uniqueComponentId);
    132         break;
    133       default:
    134         manager.updateAudioComponent(
    135             component.component_type, uniqueComponentId, component);
    136         break;
    137     }
    138   };
    139 
    140   media.onPlayerOpen = function(id, timestamp) {
    141     manager.addPlayer(id, timestamp);
    142   };
    143 
    144   media.onMediaEvent = function(event) {
    145     var source = event.renderer + ':' + event.player;
    146 
    147     // Although this gets called on every event, there is nothing we can do
    148     // because there is no onOpen event.
    149     media.onPlayerOpen(source);
    150     manager.updatePlayerInfoNoRecord(
    151         source, event.ticksMillis, 'render_id', event.renderer);
    152     manager.updatePlayerInfoNoRecord(
    153         source, event.ticksMillis, 'player_id', event.player);
    154 
    155     var propertyCount = 0;
    156     util.object.forEach(event.params, function(value, key) {
    157       key = key.trim();
    158 
    159       // These keys get spammed *a lot*, so put them on the display
    160       // but don't log list.
    161       if (key === 'buffer_start' ||
    162           key === 'buffer_end' ||
    163           key === 'buffer_current' ||
    164           key === 'is_downloading_data') {
    165         manager.updatePlayerInfoNoRecord(
    166             source, event.ticksMillis, key, value);
    167       } else {
    168         manager.updatePlayerInfo(source, event.ticksMillis, key, value);
    169       }
    170       propertyCount += 1;
    171     });
    172 
    173     if (propertyCount === 0) {
    174       manager.updatePlayerInfo(
    175           source, event.ticksMillis, 'EVENT', event.type);
    176     }
    177   };
    178 
    179   // |chrome| is not defined during tests.
    180   if (window.chrome && window.chrome.send) {
    181     chrome.send('getEverything');
    182   }
    183   return media;
    184 }());
    185