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