1/** 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11// StatTracker is a helper class to keep track of stats on a RTCPeerConnection 12// object. It uses google visualization datatables to keep the recorded samples 13// and simplify plugging them into graphs later. 14// 15// Usage example: 16// var tracker = new StatTracker(pc, pollInterval); 17// tracker.recordStat("EstimatedSendBitrate", 18// "bweforvideo", "googAvailableSendBandwidth"); 19// ... 20// tracker.stop(); 21// tracker.dataTable(); // returns the recorded values. In this case 22// a table with 2 columns { Time, EstimatedSendBitrate } and a row for each 23// sample taken until stop() was called. 24// 25function StatTracker(pc, pollInterval) { 26 pollInterval = pollInterval || 250; 27 28 var dataTable = new google.visualization.DataTable(); 29 var timeColumnIndex = dataTable.addColumn('datetime', 'Time'); 30 var recording = true; 31 32 // Set of sampling functions. Functions registered here are called 33 // once per getStats with the given report and a rowIndex for the 34 // sample period so they can extract and record the tracked variables. 35 var samplingFunctions = {}; 36 37 // Accessor to the current recorded stats. 38 this.dataTable = function() { return dataTable; } 39 40 // recordStat(varName, recordName, statName) adds a samplingFunction that 41 // records namedItem(recordName).stat(statName) from RTCStatsReport for each 42 // sample into a column named varName in the dataTable. 43 this.recordStat = function (varName, recordName, statName) { 44 var columnIndex = dataTable.addColumn('number', varName); 45 samplingFunctions[varName] = function (report, rowIndex) { 46 var sample; 47 var record = report.namedItem(recordName); 48 if (record) sample = record.stat(statName); 49 dataTable.setCell(rowIndex, columnIndex, sample); 50 } 51 } 52 53 // Stops the polling of stats from the peer connection. 54 this.stop = function() { 55 recording = false; 56 } 57 58 // RTCPeerConnection.getStats is asynchronous. In order to avoid having 59 // too many pending getStats requests going, this code only queues the 60 // next getStats with setTimeout after the previous one returns, instead 61 // of using setInterval. 62 function poll() { 63 pc.getStats(function (report) { 64 if (!recording) return; 65 setTimeout(poll, pollInterval); 66 var result = report.result(); 67 if (result.length < 1) return; 68 69 var rowIndex = dataTable.addRow(); 70 dataTable.setCell(rowIndex, timeColumnIndex, result[0].timestamp); 71 for (var v in samplingFunctions) 72 samplingFunctions[v](report, rowIndex); 73 }); 74 } 75 setTimeout(poll, pollInterval); 76} 77 78/** 79 * Utility method to perform a full join between data tables from StatTracker. 80 */ 81function mergeDataTable(dataTable1, dataTable2) { 82 function allColumns(cols) { 83 var a = []; 84 for (var i = 1; i < cols; ++i) a.push(i); 85 return a; 86 } 87 return google.visualization.data.join( 88 dataTable1, 89 dataTable2, 90 'full', 91 [[0, 0]], 92 allColumns(dataTable1.getNumberOfColumns()), 93 allColumns(dataTable2.getNumberOfColumns())); 94} 95