blob: 2a78ae7c2b0ed80360f9773d978dcb7aad3d17b6 [file] [log] [blame]
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import logging
import re
from telemetry.internal.util import camel_case
from telemetry.value import list_of_scalar_values
from metrics import Metric
INTERESTING_METRICS = {
'packetsReceived': {
'units': 'packets',
'description': 'Packets received by the peer connection',
},
'packetsSent': {
'units': 'packets',
'description': 'Packets sent by the peer connection',
},
'googDecodeMs': {
'units': 'ms',
'description': 'Time spent decoding.',
},
'googMaxDecodeMs': {
'units': 'ms',
'description': 'Maximum time spent decoding one frame.',
},
'googRtt': {
'units': 'ms',
'description': 'Measured round-trip time.',
},
'googJitterReceived': {
'units': 'ms',
'description': 'Receive-side jitter in milliseconds.',
},
'googCaptureJitterMs': {
'units': 'ms',
'description': 'Capture device (audio/video) jitter.',
},
'googTargetDelayMs': {
'units': 'ms',
'description': 'The delay we are targeting.',
},
'googExpandRate': {
'units': '%',
'description': 'How much we have NetEQ-expanded the audio (0-100%)',
},
'googFrameRateReceived': {
'units': 'fps',
'description': 'Receive-side frames per second (video)',
},
'googFrameRateSent': {
'units': 'fps',
'description': 'Send-side frames per second (video)',
},
# Bandwidth estimation stats.
'googAvailableSendBandwidth': {
'units': 'bit/s',
'description': 'How much send bandwidth we estimate we have.'
},
'googAvailableReceiveBandwidth': {
'units': 'bit/s',
'description': 'How much receive bandwidth we estimate we have.'
},
'googTargetEncBitrate': {
'units': 'bit/s',
'description': ('The target encoding bitrate we estimate is good to '
'aim for given our bandwidth estimates.')
},
'googTransmitBitrate': {
'units': 'bit/s',
'description': 'The actual transmit bitrate.'
},
}
def GetReportKind(report):
if 'audioInputLevel' in report or 'audioOutputLevel' in report:
return 'audio'
if 'googFrameRateSent' in report or 'googFrameRateReceived' in report:
return 'video'
if 'googAvailableSendBandwidth' in report:
return 'bwe'
logging.debug('Did not recognize report batch: %s.', report.keys())
# There are other kinds of reports, such as transport types, which we don't
# care about here. For these cases just return 'unknown' which will ignore the
# report.
return 'unknown'
def DistinguishAudioVideoOrBwe(report, stat_name):
return GetReportKind(report) + '_' + stat_name
def StripAudioVideoBweDistinction(stat_name):
return re.sub('^(audio|video|bwe)_', '', stat_name)
def SortStatsIntoTimeSeries(report_batches):
time_series = {}
for report_batch in report_batches:
for report in report_batch:
for stat_name, value in report.iteritems():
if stat_name not in INTERESTING_METRICS:
continue
if GetReportKind(report) == 'unknown':
continue
full_stat_name = DistinguishAudioVideoOrBwe(report, stat_name)
time_series.setdefault(full_stat_name, []).append(float(value))
return time_series
class WebRtcStatisticsMetric(Metric):
"""Makes it possible to measure stats from peer connections."""
def __init__(self):
super(WebRtcStatisticsMetric, self).__init__()
self._all_reports = None
def Start(self, page, tab):
pass
def Stop(self, page, tab):
"""Digs out stats from data populated by the javascript in webrtc_cases."""
self._all_reports = tab.EvaluateJavaScript(
'JSON.stringify(window.peerConnectionReports)')
def AddResults(self, tab, results):
if not self._all_reports:
return
reports = json.loads(self._all_reports)
for i, report in enumerate(reports):
time_series = SortStatsIntoTimeSeries(report)
for stat_name, values in time_series.iteritems():
stat_name_underscored = camel_case.ToUnderscore(stat_name)
trace_name = 'peer_connection_%d_%s' % (i, stat_name_underscored)
general_name = StripAudioVideoBweDistinction(stat_name)
results.AddValue(list_of_scalar_values.ListOfScalarValues(
results.current_page, trace_name,
INTERESTING_METRICS[general_name]['units'], values,
description=INTERESTING_METRICS[general_name]['description'],
important=False))