Home | History | Annotate | Download | only in cros
      1 # Copyright (c) 2017 The Chromium OS 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.
      4 
      5 import json
      6 
      7 from autotest_lib.server.cros import cfm_jmidata_helper_base
      8 
      9 # Start index in the JSON object that contains Audio/Video streams related info.
     10 AV_INDEX = 4
     11 
     12 SSRC = u'ssrc'
     13 GLOBAL = u'global'
     14 
     15 AUDIO_INPUT = u'audioInputLevel'
     16 AUDIO_OUTPUT = u'audioOutputLevel'
     17 BYTES_RECEIVED = u'bytesReceived'
     18 BYTES_SENT = u'bytesSent'
     19 ADAPTATION_CHANGES = u'googAdaptationChanges'
     20 AVERAGE_ENCODE_TIME = u'googAvgEncodeMs'
     21 BANDWIDTH_LIMITED_RESOLUTION = u'googBandwidthLimitedResolution'
     22 CPU_LIMITED_RESOLUTION = u'googCpuLimitedResolution'
     23 VIDEO_ENCODE_CPU_USAGE = u'googEncodeUsagePercent'
     24 VIDEO_RECEIVED_FRAME_HEIGHT = u'googFrameHeightReceived'
     25 VIDEO_RECEIVED_FRAME_WIDTH = u'googFrameWidthReceived'
     26 FRAMERATE_OUTGOING = u'googFrameRateInput'
     27 FRAMERATE_RECEIVED = u'googFrameRateReceived'
     28 FRAMERATE_SENT = u'googFrameRateSent'
     29 FRAMERATE_DECODED = u'googFrameRateDecoded'
     30 FRAMERATE_OUTPUT = u'googFrameRateOutput'
     31 FRAME_WIDTH_SENT = u'googFrameWidthSent'
     32 FRAME_HEIGHT_SENT = u'googFrameHeightSent'
     33 FRAMES_DECODED = u'framesDecoded'
     34 FRAMES_ENCODED = u'framesEncoded'
     35 VIDEO_PACKETS_LOST = u'packetsLost'
     36 VIDEO_PACKETS_SENT = u'packetsSent'
     37 
     38 BROWSER_CPU = u'browserCpuUsage'
     39 GPU_CPU = u'gpuCpuUsage'
     40 NUM_PROCESSORS = u'numOfProcessors'
     41 NACL_EFFECTS_CPU = u'pluginCpuUsage'
     42 RENDERER_CPU = u'tabCpuUsage'
     43 TOTAL_CPU = u'totalCpuUsage'
     44 
     45 
     46 class JMIDataV3Helper(cfm_jmidata_helper_base.JMIDataHelperBase):
     47     """Helper class for JMI data v3 parsing. This class helps in extracting
     48     relevant JMI data from javascript log.
     49 
     50     The class takes javascript file as input and extracts jmidata elements from
     51     the file that is internally stored as a list. Whenever we need to extract
     52     data i.e. audio received bytes we call a method such as
     53     getAudioReceivedDataList. This method converts each string element in the
     54     internal list to a json object and retrieves the relevant info from it which
     55     is then stored and returned as a list.
     56     """
     57 
     58     def __init__(self, log_file_content):
     59         super(JMIDataV3Helper, self).__init__(log_file_content, 'jmidatav3')
     60 
     61     def _ExtractAllJMIDataPointsWithKey(self, jmi_type, is_audio, key):
     62         """Extracts all values from the data points with the given key."""
     63         data_list = []
     64         for jmi_data_point in self._jmi_list:
     65             json_arr = json.loads(jmi_data_point)
     66             for i in range(AV_INDEX, len(json_arr)):
     67                 if json_arr[i] and jmi_type in json_arr[i]:
     68                     jmi_obj = json_arr[i][jmi_type]
     69                     this_is_audio = (AUDIO_INPUT in jmi_obj or
     70                                      AUDIO_OUTPUT in jmi_obj)
     71                     if this_is_audio == is_audio and key in jmi_obj:
     72                         if (not isinstance(jmi_obj[key], int) and
     73                                 (jmi_obj[key] == 'false' or
     74                                  jmi_obj[key] == 'true')):
     75                             jmi_obj[key] = 1 if jmi_obj[key] == 'true' else 0
     76                         data_list.append(jmi_obj[key])
     77         if not data_list:
     78             data_list = [0]
     79         return data_list
     80 
     81     def GetAudioReceivedBytesList(self):
     82         return self._ExtractAllJMIDataPointsWithKey(
     83                 jmi_type=SSRC, is_audio=True, key=BYTES_RECEIVED)
     84 
     85     def GetAudioSentBytesList(self):
     86         return self._ExtractAllJMIDataPointsWithKey(
     87                 jmi_type=SSRC, is_audio=True, key=BYTES_SENT)
     88 
     89     def GetAudioReceivedEnergyList(self):
     90         return self._ExtractAllJMIDataPointsWithKey(
     91                 jmi_type=SSRC, is_audio=True, key=AUDIO_OUTPUT)
     92 
     93     def GetAudioSentEnergyList(self):
     94         return self._ExtractAllJMIDataPointsWithKey(
     95                 jmi_type=SSRC, is_audio=True, key=AUDIO_INPUT)
     96 
     97     def GetVideoSentBytesList(self):
     98         return self._ExtractAllJMIDataPointsWithKey(
     99                 jmi_type=SSRC, is_audio=False, key=BYTES_SENT)
    100 
    101     def GetVideoReceivedBytesList(self):
    102         return self._ExtractAllJMIDataPointsWithKey(
    103                 jmi_type=SSRC, is_audio=False, key=BYTES_RECEIVED)
    104 
    105     def GetVideoIncomingFramerateReceivedList(self):
    106         return self._ExtractAllJMIDataPointsWithKey(
    107                 jmi_type=SSRC, is_audio=False, key=FRAMERATE_RECEIVED)
    108 
    109     def GetVideoOutgoingFramerateSentList(self):
    110         return self._ExtractAllJMIDataPointsWithKey(
    111                 jmi_type=SSRC, is_audio=False, key=FRAMERATE_SENT)
    112 
    113     def GetVideoIncomingFramerateDecodedList(self):
    114         return self._ExtractAllJMIDataPointsWithKey(
    115                 jmi_type=SSRC, is_audio=False, key=FRAMERATE_DECODED)
    116 
    117     def GetVideoIncomingFramerateList(self):
    118         return self._ExtractAllJMIDataPointsWithKey(
    119                 jmi_type=SSRC, is_audio=False, key=FRAMERATE_OUTPUT)
    120 
    121     def GetVideoSentFrameWidthList(self):
    122         return self._ExtractAllJMIDataPointsWithKey(
    123                 jmi_type=SSRC, is_audio=False, key=FRAME_WIDTH_SENT)
    124 
    125     def GetVideoSentFrameHeightList(self):
    126         return self._ExtractAllJMIDataPointsWithKey(
    127                 jmi_type=SSRC, is_audio=False, key=FRAME_HEIGHT_SENT)
    128 
    129     def GetCPULimitedResolutionList(self):
    130         return self._ExtractAllJMIDataPointsWithKey(
    131                 jmi_type=SSRC, is_audio=False, key=CPU_LIMITED_RESOLUTION)
    132 
    133     def GetVideoPacketsSentList(self):
    134         return self._ExtractAllJMIDataPointsWithKey(
    135                 jmi_type=SSRC, is_audio=False, key=VIDEO_PACKETS_SENT)
    136 
    137     def GetVideoPacketsLostList(self):
    138         return self._ExtractAllJMIDataPointsWithKey(
    139                 jmi_type=SSRC, is_audio=False, key=VIDEO_PACKETS_LOST)
    140 
    141     def GetVideoIncomingFramesDecodedList(self):
    142         return self._ExtractAllJMIDataPointsWithKey(
    143                 jmi_type=SSRC, is_audio=False, key=FRAMES_DECODED)
    144 
    145     def GetVideoOutgoingFramesEncodedList(self):
    146         return self._ExtractAllJMIDataPointsWithKey(
    147                 jmi_type=SSRC, is_audio=False, key=FRAMES_ENCODED)
    148 
    149     def GetVideoAdaptationChangeList(self):
    150         return self._ExtractAllJMIDataPointsWithKey(
    151                 jmi_type=SSRC, is_audio=False, key=ADAPTATION_CHANGES)
    152 
    153     def GetVideoEncodeTimeList(self):
    154         return self._ExtractAllJMIDataPointsWithKey(
    155                 jmi_type=SSRC, is_audio=False, key=AVERAGE_ENCODE_TIME)
    156 
    157     def GetBandwidthLimitedResolutionList(self):
    158         return self._ExtractAllJMIDataPointsWithKey(
    159                 jmi_type=SSRC, is_audio=False, key=BANDWIDTH_LIMITED_RESOLUTION)
    160 
    161     def GetVideoReceivedFrameHeightList(self):
    162         return self._ExtractAllJMIDataPointsWithKey(
    163                 jmi_type=SSRC, is_audio=False, key=VIDEO_RECEIVED_FRAME_HEIGHT)
    164 
    165     def GetVideoOutgoingFramerateInputList(self):
    166         return self._ExtractAllJMIDataPointsWithKey(
    167                 jmi_type=SSRC, is_audio=False, key=FRAMERATE_OUTGOING)
    168 
    169     def GetVideoReceivedFrameWidthList(self):
    170         return self._ExtractAllJMIDataPointsWithKey(
    171                 jmi_type=SSRC, is_audio=False, key=VIDEO_RECEIVED_FRAME_WIDTH)
    172 
    173     def GetVideoEncodeCpuUsagePercentList(self):
    174         return self._ExtractAllJMIDataPointsWithKey(
    175                 jmi_type=SSRC, is_audio=False, key=VIDEO_ENCODE_CPU_USAGE)
    176 
    177     def GetNumberOfActiveIncomingVideoStreams(self):
    178         """Retrieve number of active incoming video streams."""
    179         if not self._jmi_list:
    180             # JMI data hasn't started populating yet.
    181             return 0
    182 
    183         num_video_streams = []
    184 
    185         # If JMI data has started getting populated and has video stream data.
    186         for jmi_data_point in self._jmi_list:
    187             json_arr = json.loads(jmi_data_point)
    188             video_streams = 0
    189             for i in range(AV_INDEX, len(json_arr)):
    190                 if json_arr[i] and SSRC in json_arr[i]:
    191                     ssrc_obj = json_arr[i][SSRC]
    192                     is_audio = ('audioInputLevel' in ssrc_obj or
    193                             'audioOutputLevel' in ssrc_obj)
    194                     is_incoming = 'bytesReceived' in ssrc_obj
    195                     frame_rate_received = 'googFrameRateReceived' in ssrc_obj
    196                     if ssrc_obj['mediaType'] == 'video' and \
    197                             frame_rate_received:
    198                         frame_rate = ssrc_obj['googFrameRateReceived']
    199                         if (is_incoming and not is_audio) and \
    200                                 frame_rate != 0:
    201                             video_streams += 1
    202             num_video_streams.append(video_streams)
    203         if not num_video_streams:
    204             num_video_streams = [0]
    205         return num_video_streams
    206 
    207     def GetCpuUsageList(self, cpu_type):
    208         """Retrieves cpu usage data from JMI data.
    209 
    210         @param cpu_type: Cpu usage type.
    211         @returns List containing CPU usage data.
    212         """
    213         data_list = []
    214         for jmi_data_point in self._jmi_list:
    215             json_arr = json.loads(jmi_data_point)
    216             for i in range(AV_INDEX, len(json_arr)):
    217                 if json_arr[i] and GLOBAL in json_arr[i]:
    218                     global_obj = json_arr[i][GLOBAL]
    219                     # Some values in JMIDataV3 are set to 'null'.
    220                     if cpu_type == u'numOfProcessors':
    221                         return global_obj[cpu_type]
    222                     elif (cpu_type in global_obj and
    223                             self.IsFloat(global_obj[cpu_type])):
    224                         data_list.append(float(global_obj[cpu_type]))
    225         if not data_list:
    226             data_list = [0]
    227         return data_list
    228 
    229     def GetNumOfProcessors(self):
    230         return self.GetCpuUsageList(NUM_PROCESSORS)
    231 
    232     def GetTotalCpuPercentage(self):
    233         return self.GetCpuUsageList(TOTAL_CPU)
    234 
    235     def GetBrowserCpuPercentage(self):
    236         return self.GetCpuUsageList(BROWSER_CPU)
    237 
    238     def GetGpuCpuPercentage(self):
    239         return self.GetCpuUsageList(GPU_CPU)
    240 
    241     def GetNaclEffectsCpuPercentage(self):
    242         return self.GetCpuUsageList(NACL_EFFECTS_CPU)
    243 
    244     def GetRendererCpuPercentage(self):
    245         return self.GetCpuUsageList(RENDERER_CPU)
    246 
    247     def IsFloat(self, value):
    248         try:
    249             float(value)
    250             return True
    251         except TypeError:
    252             return False
    253