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.
5 var USER_MEDIA_TAB_ID
= 'user-media-tab-id';
8 var ssrcInfoManager
= null;
9 var peerConnectionUpdateTable
= null;
10 var statsTable
= null;
11 var dumpCreator
= null;
12 /** A map from peer connection id to the PeerConnectionRecord. */
13 var peerConnectionDataStore
= {};
14 /** A list of getUserMedia requests. */
15 var userMediaRequests
= [];
17 /** A simple class to store the updates and stats data for a peer connection. */
18 var PeerConnectionRecord
= (function() {
20 function PeerConnectionRecord() {
31 PeerConnectionRecord
.prototype = {
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.
43 initialize: function(url
, rtcConfiguration
, constraints
) {
44 this.record_
.url
= url
;
45 this.record_
.rtcConfiguration
= rtcConfiguration
;
46 this.record_
.constraints
= constraints
;
50 * @param {string} dataSeriesId The TimelineDataSeries identifier.
51 * @return {!TimelineDataSeries}
53 getDataSeries: function(dataSeriesId
) {
54 return this.record_
.stats
[dataSeriesId
];
58 * @param {string} dataSeriesId The TimelineDataSeries identifier.
59 * @param {!TimelineDataSeries} dataSeries The TimelineDataSeries to set to.
61 setDataSeries: function(dataSeriesId
, dataSeries
) {
62 this.record_
.stats
[dataSeriesId
] = dataSeries
;
66 * @param {!Object} update The object contains keys "time", "type", and
69 addUpdate: function(update
) {
70 var time
= new Date(parseFloat(update
.time
));
71 this.record_
.updateLog
.push({
72 time
: time
.toLocaleString(),
79 return PeerConnectionRecord
;
82 // The maximum number of data points bufferred for each stats. Old data points
83 // will be shifted out when the buffer is full.
84 var MAX_STATS_DATA_POINT_BUFFER_SIZE
= 1000;
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"/>
95 function 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
);
102 chrome
.send('finishedDOMLoad');
104 // Requests stats from all peer connections every second.
105 window
.setInterval(requestStats
, 1000);
107 document
.addEventListener('DOMContentLoaded', initialize
);
110 /** Sends a request to the browser to get peer connection statistics. */
111 function requestStats() {
112 if (Object
.keys(peerConnectionDataStore
).length
> 0)
113 chrome
.send('getAllStats');
118 * A helper function for getting a peer connection element id.
120 * @param {!Object<number>} data The object containing the pid and lid of the
122 * @return {string} The peer connection element id.
124 function getPeerConnectionId(data
) {
125 return data
.pid
+ '-' + data
.lid
;
130 * Extracts ssrc info from a setLocal/setRemoteDescription update.
132 * @param {!PeerConnectionUpdateEntry} data The peer connection update data.
134 function extractSsrcInfo(data
) {
135 if (data
.type
== 'setLocalDescription' ||
136 data
.type
== 'setRemoteDescription') {
137 ssrcInfoManager
.addSsrcStreamInfo(data
.value
);
143 * A helper function for appending a child element to |parent|.
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.
150 function appendChildWithText(parent
, tag
, text
) {
151 var child
= document
.createElement(tag
);
152 child
.textContent
= text
;
153 parent
.appendChild(child
);
158 * Helper for adding a peer connection update.
160 * @param {Element} peerConnectionElement
161 * @param {!PeerConnectionUpdateEntry} update The peer connection update data.
163 function addPeerConnectionUpdate(peerConnectionElement
, update
) {
164 peerConnectionUpdateTable
.addPeerConnectionUpdate(peerConnectionElement
,
166 extractSsrcInfo(update
);
167 peerConnectionDataStore
[peerConnectionElement
.id
].addUpdate(update
);
171 /** Browser message handlers. */
175 * Removes all information about a peer connection.
177 * @param {!Object<number>} data The object containing the pid and lid of a peer
180 function removePeerConnection(data
) {
181 var element
= $(getPeerConnectionId(data
));
183 delete peerConnectionDataStore
[element
.id
];
184 tabView
.removeTab(element
.id
);
190 * Adds a peer connection.
192 * @param {!Object} data The object containing the pid, lid, url,
193 * rtcConfiguration, and constraints of a peer connection.
195 function addPeerConnection(data
) {
196 var id
= getPeerConnectionId(data
);
198 if (!peerConnectionDataStore
[id
]) {
199 peerConnectionDataStore
[id
] = new PeerConnectionRecord();
201 peerConnectionDataStore
[id
].initialize(
202 data
.url
, data
.rtcConfiguration
, data
.constraints
);
204 var peerConnectionElement
= $(id
);
205 if (!peerConnectionElement
) {
206 peerConnectionElement
= tabView
.addTab(id
, data
.url
+ ' [' + id
+ ']');
209 var p
= document
.createElement('p');
210 p
.textContent
= data
.url
+ ', ' + data
.rtcConfiguration
+ ', ' +
212 peerConnectionElement
.appendChild(p
);
214 return peerConnectionElement
;
219 * Adds a peer connection update.
221 * @param {!PeerConnectionUpdateEntry} data The peer connection update data.
223 function updatePeerConnection(data
) {
224 var peerConnectionElement
= $(getPeerConnectionId(data
));
225 addPeerConnectionUpdate(peerConnectionElement
, data
);
230 * Adds the information of all peer connections created so far.
232 * @param {Array<!Object>} data An array of the information of all peer
233 * connections. Each array item contains pid, lid, url, rtcConfiguration,
234 * constraints, and an array of updates as the log.
236 function updateAllPeerConnections(data
) {
237 for (var i
= 0; i
< data
.length
; ++i
) {
238 var peerConnection
= addPeerConnection(data
[i
]);
240 var log
= data
[i
].log
;
243 for (var j
= 0; j
< log
.length
; ++j
) {
244 addPeerConnectionUpdate(peerConnection
, log
[j
]);
252 * Handles the report of stats.
254 * @param {!Object} data The object containing pid, lid, and reports, where
255 * reports is an array of stats reports. Each report contains id, type,
256 * and stats, where stats is the object containing timestamp and values,
257 * which is an array of strings, whose even index entry is the name of the
258 * stat, and the odd index entry is the value.
260 function addStats(data
) {
261 var peerConnectionElement
= $(getPeerConnectionId(data
));
262 if (!peerConnectionElement
)
265 for (var i
= 0; i
< data
.reports
.length
; ++i
) {
266 var report
= data
.reports
[i
];
267 statsTable
.addStatsReport(peerConnectionElement
, report
);
268 drawSingleReport(peerConnectionElement
, report
);
274 * Adds a getUserMedia request.
276 * @param {!Object} data The object containing rid {number}, pid {number},
277 * origin {string}, audio {string}, video {string}.
279 function addGetUserMedia(data
) {
280 userMediaRequests
.push(data
);
282 if (!$(USER_MEDIA_TAB_ID
)) {
283 tabView
.addTab(USER_MEDIA_TAB_ID
, 'GetUserMedia Requests');
286 var requestDiv
= document
.createElement('div');
287 requestDiv
.className
= 'user-media-request-div-class';
288 requestDiv
.rid
= data
.rid
;
289 $(USER_MEDIA_TAB_ID
).appendChild(requestDiv
);
291 appendChildWithText(requestDiv
, 'div', 'Caller origin: ' + data
.origin
);
292 appendChildWithText(requestDiv
, 'div', 'Caller process id: ' + data
.pid
);
293 appendChildWithText(requestDiv
, 'span', 'Audio Constraints').style
.fontWeight
295 appendChildWithText(requestDiv
, 'div', data
.audio
);
297 appendChildWithText(requestDiv
, 'span', 'Video Constraints').style
.fontWeight
299 appendChildWithText(requestDiv
, 'div', data
.video
);
304 * Removes the getUserMedia requests from the specified |rid|.
306 * @param {!Object} data The object containing rid {number}, the render id.
308 function removeGetUserMediaForRenderer(data
) {
309 for (var i
= userMediaRequests
.length
- 1; i
>= 0; --i
) {
310 if (userMediaRequests
[i
].rid
== data
.rid
)
311 userMediaRequests
.splice(i
, 1);
314 var requests
= $(USER_MEDIA_TAB_ID
).childNodes
;
315 for (var i
= 0; i
< requests
.length
; ++i
) {
316 if (requests
[i
].rid
== data
.rid
)
317 $(USER_MEDIA_TAB_ID
).removeChild(requests
[i
]);
320 if ($(USER_MEDIA_TAB_ID
).childNodes
.length
== 0)
321 tabView
.removeTab(USER_MEDIA_TAB_ID
);
326 * Notification that the audio debug recordings file selection dialog was
327 * cancelled, i.e. recordings have not been enabled.
329 function audioDebugRecordingsFileSelectionCancelled() {
330 dumpCreator
.disableAudioDebugRecordings();
337 function enableAudioDebugRecordings() {
338 dumpCreator
.enableAudioDebugRecordings();