webrtc_internals.js revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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
5var USER_MEDIA_TAB_ID = 'user-media-tab-id';
6
7var tabView = null;
8var ssrcInfoManager = null;
9var peerConnectionUpdateTable = null;
10var statsTable = null;
11var dumpCreator = null;
12/** A map from peer connection id to the PeerConnectionRecord. */
13var peerConnectionDataStore = {};
14/** A list of getUserMedia requests. */
15var userMediaRequests = [];
16
17/** A simple class to store the updates and stats data for a peer connection. */
18var PeerConnectionRecord = (function() {
19  /** @constructor */
20  function PeerConnectionRecord() {
21    /** @private */
22    this.record_ = {
23      constraints: {},
24      rtcConfiguration: [],
25      stats: {},
26      updateLog: [],
27      url: '',
28    };
29  };
30
31  PeerConnectionRecord.prototype = {
32    /** @override */
33    toJSON: function() {
34      return this.record_;
35    },
36
37    /**
38     * Adds the initilization info of the peer connection.
39     * @param {string} url The URL of the web page owning the peer connection.
40     * @param {Array} rtcConfiguration
41     * @param {!Object} constraints Media constraints.
42     */
43    initialize: function(url, rtcConfiguration, constraints) {
44      this.record_.url = url;
45      this.record_.rtcConfiguration = rtcConfiguration;
46      this.record_.constraints = constraints;
47    },
48
49    /**
50     * @param {string} dataSeriesId The TimelineDataSeries identifier.
51     * @return {!TimelineDataSeries}
52     */
53    getDataSeries: function(dataSeriesId) {
54      return this.record_.stats[dataSeriesId];
55    },
56
57    /**
58     * @param {string} dataSeriesId The TimelineDataSeries identifier.
59     * @param {!TimelineDataSeries} dataSeries The TimelineDataSeries to set to.
60     */
61    setDataSeries: function(dataSeriesId, dataSeries) {
62      this.record_.stats[dataSeriesId] = dataSeries;
63    },
64
65    /**
66     * @param {!Object} update The object contains keys "time", "type", and
67     *   "value".
68     */
69    addUpdate: function(update) {
70      var time = new Date(parseFloat(update.time));
71      this.record_.updateLog.push({
72        time: time.toLocaleString(),
73        type: update.type,
74        value: update.value,
75      });
76    },
77  };
78
79  return PeerConnectionRecord;
80})();
81
82// The maximum number of data points bufferred for each stats. Old data points
83// will be shifted out when the buffer is full.
84var MAX_STATS_DATA_POINT_BUFFER_SIZE = 1000;
85
86<include src="tab_view.js"/>
87<include src="data_series.js"/>
88<include src="ssrc_info_manager.js"/>
89<include src="stats_graph_helper.js"/>
90<include src="stats_table.js"/>
91<include src="peer_connection_update_table.js"/>
92<include src="dump_creator.js"/>
93
94
95function initialize() {
96  dumpCreator = new DumpCreator($('content-root'));
97  tabView = new TabView($('content-root'));
98  ssrcInfoManager = new SsrcInfoManager();
99  peerConnectionUpdateTable = new PeerConnectionUpdateTable();
100  statsTable = new StatsTable(ssrcInfoManager);
101
102  chrome.send('finishedDOMLoad');
103
104  // Requests stats from all peer connections every second.
105  window.setInterval(requestStats, 1000);
106}
107document.addEventListener('DOMContentLoaded', initialize);
108
109
110/** Sends a request to the browser to get peer connection statistics. */
111function requestStats() {
112  if (Object.keys(peerConnectionDataStore).length > 0)
113    chrome.send('getAllStats');
114}
115
116
117/**
118 * A helper function for getting a peer connection element id.
119 *
120 * @param {!Object.<string, number>} data The object containing the pid and lid
121 *     of the peer connection.
122 * @return {string} The peer connection element id.
123 */
124function getPeerConnectionId(data) {
125  return data.pid + '-' + data.lid;
126}
127
128
129/**
130 * Extracts ssrc info from a setLocal/setRemoteDescription update.
131 *
132 * @param {!PeerConnectionUpdateEntry} data The peer connection update data.
133 */
134function extractSsrcInfo(data) {
135  if (data.type == 'setLocalDescription' ||
136      data.type == 'setRemoteDescription') {
137    ssrcInfoManager.addSsrcStreamInfo(data.value);
138  }
139}
140
141
142/**
143 * A helper function for appending a child element to |parent|.
144 *
145 * @param {!Element} parent The parent element.
146 * @param {string} tag The child element tag.
147 * @param {string} text The textContent of the new DIV.
148 * @return {!Element} the new DIV element.
149 */
150function appendChildWithText(parent, tag, text) {
151  var child = document.createElement(tag);
152  child.textContent = text;
153  parent.appendChild(child);
154  return child;
155}
156
157/**
158 * Helper for adding a peer connection update.
159 *
160 * @param {Element} peerConnectionElement
161 * @param {!PeerConnectionUpdateEntry} update The peer connection update data.
162 */
163function addPeerConnectionUpdate(peerConnectionElement, update) {
164  peerConnectionUpdateTable.addPeerConnectionUpdate(peerConnectionElement,
165                                                    update);
166  extractSsrcInfo(update);
167  peerConnectionDataStore[peerConnectionElement.id].addUpdate(update);
168}
169
170
171/** Browser message handlers. */
172
173
174/**
175 * Removes all information about a peer connection.
176 *
177 * @param {!Object.<string, number>} data The object containing the pid and lid
178 *     of a peer connection.
179 */
180function removePeerConnection(data) {
181  var element = $(getPeerConnectionId(data));
182  if (element) {
183    delete peerConnectionDataStore[element.id];
184    tabView.removeTab(element.id);
185  }
186}
187
188
189/**
190 * Adds a peer connection.
191 *
192 * @param {!Object} data The object containing the pid, lid, url,
193 *     rtcConfiguration, and constraints of a peer connection.
194 */
195function addPeerConnection(data) {
196  var id = getPeerConnectionId(data);
197
198  if (!peerConnectionDataStore[id]) {
199    peerConnectionDataStore[id] = new PeerConnectionRecord();
200  }
201  peerConnectionDataStore[id].initialize(
202      data.url, data.rtcConfiguration, data.constraints);
203
204  var peerConnectionElement = $(id);
205  if (!peerConnectionElement) {
206    peerConnectionElement = tabView.addTab(id, data.url + ' [' + id + ']');
207  }
208  peerConnectionElement.innerHTML =
209      '<p>' + data.url + ' ' + data.rtcConfiguration + ' ' + data.constraints +
210      '</p>';
211
212  return peerConnectionElement;
213}
214
215
216/**
217 * Adds a peer connection update.
218 *
219 * @param {!PeerConnectionUpdateEntry} data The peer connection update data.
220 */
221function updatePeerConnection(data) {
222  var peerConnectionElement = $(getPeerConnectionId(data));
223  addPeerConnectionUpdate(peerConnectionElement, data);
224}
225
226
227/**
228 * Adds the information of all peer connections created so far.
229 *
230 * @param {Array.<!Object>} data An array of the information of all peer
231 *     connections. Each array item contains pid, lid, url, rtcConfiguration,
232 *     constraints, and an array of updates as the log.
233 */
234function updateAllPeerConnections(data) {
235  for (var i = 0; i < data.length; ++i) {
236    var peerConnection = addPeerConnection(data[i]);
237
238    var log = data[i].log;
239    if (!log)
240      continue;
241    for (var j = 0; j < log.length; ++j) {
242      addPeerConnectionUpdate(peerConnection, log[j]);
243    }
244  }
245  requestStats();
246}
247
248
249/**
250 * Handles the report of stats.
251 *
252 * @param {!Object} data The object containing pid, lid, and reports, where
253 *     reports is an array of stats reports. Each report contains id, type,
254 *     and stats, where stats is the object containing timestamp and values,
255 *     which is an array of strings, whose even index entry is the name of the
256 *     stat, and the odd index entry is the value.
257 */
258function addStats(data) {
259  var peerConnectionElement = $(getPeerConnectionId(data));
260  if (!peerConnectionElement)
261    return;
262
263  for (var i = 0; i < data.reports.length; ++i) {
264    var report = data.reports[i];
265    statsTable.addStatsReport(peerConnectionElement, report);
266    drawSingleReport(peerConnectionElement, report);
267  }
268}
269
270
271/**
272 * Adds a getUserMedia request.
273 *
274 * @param {!Object} data The object containing rid {number}, pid {number},
275 *     origin {string}, audio {string}, video {string}.
276 */
277function addGetUserMedia(data) {
278  userMediaRequests.push(data);
279
280  if (!$(USER_MEDIA_TAB_ID)) {
281    tabView.addTab(USER_MEDIA_TAB_ID, 'GetUserMedia Requests');
282  }
283
284  var requestDiv = document.createElement('div');
285  requestDiv.className = 'user-media-request-div-class';
286  requestDiv.rid = data.rid;
287  $(USER_MEDIA_TAB_ID).appendChild(requestDiv);
288
289  appendChildWithText(requestDiv, 'div', 'Caller origin: ' + data.origin);
290  appendChildWithText(requestDiv, 'div', 'Caller process id: ' + data.pid);
291  appendChildWithText(requestDiv, 'span', 'Audio Constraints').style.fontWeight
292      = 'bold';
293  appendChildWithText(requestDiv, 'div', data.audio);
294
295  appendChildWithText(requestDiv, 'span', 'Video Constraints').style.fontWeight
296      = 'bold';
297  appendChildWithText(requestDiv, 'div', data.video);
298}
299
300
301/**
302 * Removes the getUserMedia requests from the specified |rid|.
303 *
304 * @param {!Object} data The object containing rid {number}, the render id.
305 */
306function removeGetUserMediaForRenderer(data) {
307  for (var i = userMediaRequests.length - 1; i >= 0; --i) {
308    if (userMediaRequests[i].rid == data.rid)
309      userMediaRequests.splice(i, 1);
310  }
311
312  var requests = $(USER_MEDIA_TAB_ID).childNodes;
313  for (var i = 0; i < requests.length; ++i) {
314    if (requests[i].rid == data.rid)
315      $(USER_MEDIA_TAB_ID).removeChild(requests[i]);
316
317  }
318  if ($(USER_MEDIA_TAB_ID).childNodes.length == 0)
319    tabView.removeTab(USER_MEDIA_TAB_ID);
320}
321
322
323/**
324 * Notification that the AEC recording file selection dialog was cancelled,
325 * i.e. AEC has not been enabled.
326 */
327function aecRecordingFileSelectionCancelled() {
328  dumpCreator.disableAecRecording();
329}
330
331
332/**
333 * Set
334 */
335function enableAecRecording() {
336  dumpCreator.enableAecRecording();
337}
338