| /** |
| * 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())); |
| } |