/** * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // StatTracker is a helper class to keep track of stats on a RTCPeerConnection // object. It uses google visualization datatables to keep the recorded samples // and simplify plugging them into graphs later. // // Usage example: // var tracker = new StatTracker(pc, pollInterval); // tracker.recordStat("EstimatedSendBitrate", // "bweforvideo", "googAvailableSendBandwidth"); // ... // tracker.stop(); // tracker.dataTable(); // returns the recorded values. In this case // a table with 2 columns { Time, EstimatedSendBitrate } and a row for each // sample taken until stop() was called. // function StatTracker(pc, pollInterval) { pollInterval = pollInterval || 250; var dataTable = new google.visualization.DataTable(); var timeColumnIndex = dataTable.addColumn('datetime', 'Time'); var recording = true; // Set of sampling functions. Functions registered here are called // once per getStats with the given report and a rowIndex for the // sample period so they can extract and record the tracked variables. var samplingFunctions = {}; // Accessor to the current recorded stats. this.dataTable = function() { return dataTable; } // recordStat(varName, recordName, statName) adds a samplingFunction that // records namedItem(recordName).stat(statName) from RTCStatsReport for each // sample into a column named varName in the dataTable. this.recordStat = function (varName, recordName, statName) { var columnIndex = dataTable.addColumn('number', varName); samplingFunctions[varName] = function (report, rowIndex) { var sample; var record = report.namedItem(recordName); if (record) sample = record.stat(statName); dataTable.setCell(rowIndex, columnIndex, sample); } } // Stops the polling of stats from the peer connection. this.stop = function() { recording = false; } // RTCPeerConnection.getStats is asynchronous. In order to avoid having // too many pending getStats requests going, this code only queues the // next getStats with setTimeout after the previous one returns, instead // of using setInterval. function poll() { pc.getStats(function (report) { if (!recording) return; setTimeout(poll, pollInterval); var result = report.result(); if (result.length < 1) return; var rowIndex = dataTable.addRow(); dataTable.setCell(rowIndex, timeColumnIndex, result[0].timestamp); for (var v in samplingFunctions) samplingFunctions[v](report, rowIndex); }); } setTimeout(poll, pollInterval); } /** * Utility method to perform a full join between data tables from StatTracker. */ function mergeDataTable(dataTable1, dataTable2) { function allColumns(cols) { var a = []; for (var i = 1; i < cols; ++i) a.push(i); return a; } return google.visualization.data.join( dataTable1, dataTable2, 'full', [[0, 0]], allColumns(dataTable1.getNumberOfColumns()), allColumns(dataTable2.getNumberOfColumns())); }