1# Copyright 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.
4import logging
5import os
6
7from metrics import Metric
8from telemetry.value import list_of_scalar_values
9from telemetry.value import scalar
10
11
12class MediaMetric(Metric):
13  """MediaMetric class injects and calls JS responsible for recording metrics.
14
15  Default media metrics are collected for every media element in the page,
16  such as decoded_frame_count, dropped_frame_count, decoded_video_bytes, and
17  decoded_audio_bytes.
18  """
19
20  def __init__(self, tab):
21    super(MediaMetric, self).__init__()
22    with open(os.path.join(os.path.dirname(__file__), 'media.js')) as f:
23      js = f.read()
24      tab.ExecuteJavaScript(js)
25    self._results = None
26    self._skip_basic_metrics = False
27
28  def Start(self, page, tab):
29    """Create the media metrics for all media elements in the document."""
30    if hasattr(page, 'skip_basic_metrics'):
31      self._skip_basic_metrics = page.skip_basic_metrics
32    tab.ExecuteJavaScript('window.__createMediaMetricsForDocument()')
33
34  def Stop(self, page, tab):
35    self._results = tab.EvaluateJavaScript('window.__getAllMetrics()')
36
37  def AddResults(self, tab, results):
38    """Reports all recorded metrics as Telemetry perf results."""
39    trace_names = []
40    for media_metric in self._results:
41      trace_names.append(self._AddResultsForMediaElement(media_metric, results))
42
43    return '_'.join(trace_names) or tab.url
44
45  def _AddResultsForMediaElement(self, media_metric, results):
46    """Reports metrics for one media element.
47
48    Media metrics contain an ID identifying the media element and values:
49    media_metric = {
50      'id': 'video_1',
51      'metrics': {
52          'time_to_play': 120,
53          'decoded_bytes': 13233,
54          ...
55      }
56    }
57    """
58    def AddOneResult(metric, unit):
59      metrics = media_metric['metrics']
60      for m in metrics:
61        if m.startswith(metric):
62          special_label = m[len(metric):]
63          trace_name = '%s.%s%s' % (metric, trace, special_label)
64          if isinstance(metrics[m], list):
65            results.AddValue(list_of_scalar_values.ListOfScalarValues(
66                results.current_page, trace_name, unit,
67                values=[float(v) for v in metrics[m]],
68                important=True))
69          else:
70            results.AddValue(scalar.ScalarValue(
71                results.current_page, trace_name, unit, value=float(metrics[m]),
72                important=True))
73
74    trace = media_metric['id']
75    if not trace:
76      logging.error('Metrics ID is missing in results.')
77      return
78
79    if not self._skip_basic_metrics:
80      AddOneResult('buffering_time', 'ms')
81      AddOneResult('decoded_audio_bytes', 'bytes')
82      AddOneResult('decoded_video_bytes', 'bytes')
83      AddOneResult('decoded_frame_count', 'frames')
84      AddOneResult('dropped_frame_count', 'frames')
85      AddOneResult('time_to_play', 'ms')
86
87    AddOneResult('avg_loop_time', 'ms')
88    AddOneResult('seek', 'ms')
89    return trace
90