OLD | NEW |
(Empty) | |
| 1 import unittest |
| 2 |
| 3 import mock |
| 4 |
| 5 import numpy |
| 6 |
| 7 from telemetry.web_perf.metrics import webrtc_rendering_stats as stats_helper |
| 8 |
| 9 |
| 10 class FakeEvent(object): |
| 11 """Fake event class to mock rendering events.""" |
| 12 |
| 13 def __init__(self, **kwargs): |
| 14 """Initializer for the fake WebMediaPlayerMS::UpdateCurrentFrame events. |
| 15 |
| 16 The WebMediaPlayerMsRenderingStats only cares about actual render begin, |
| 17 actual render end, ideal render instant and serial fields of the events. |
| 18 So we only define these four fields here in this fake event class. |
| 19 This method is written so as to take whatever valid parameters from the |
| 20 event definition. It can also be used to craft incomplete events. |
| 21 |
| 22 Args: |
| 23 kwargs::= dict('actual_begin', 'actual_end', 'ideal_instant', 'serial'). |
| 24 """ |
| 25 self.args = {} |
| 26 name_map = { |
| 27 'Actual Render Begin': 'actual_begin', |
| 28 'Actual Render End': 'actual_end', |
| 29 'Ideal Render Instant': 'ideal_instant', |
| 30 'Serial': 'serial'} |
| 31 for internal_name, external_name in name_map.iteritems(): |
| 32 if external_name in kwargs: |
| 33 self.args[internal_name] = kwargs[external_name] |
| 34 |
| 35 |
| 36 class WebMediaPlayerMsRenderingStatsTest(unittest.TestCase): |
| 37 |
| 38 def setUp(self): |
| 39 # A local stream id always has an even number. |
| 40 # A remote stream id always has an odd number. |
| 41 self.local_stream = 136390988 |
| 42 self.remote_stream = 118626165 |
| 43 |
| 44 def testInitialization(self): |
| 45 event_local_stream = FakeEvent(actual_begin=1655987203306, |
| 46 actual_end=1655987219972, ideal_instant=1655987154324, |
| 47 serial=self.local_stream) |
| 48 |
| 49 event_remote_stream = FakeEvent(actual_begin=1655987203306, |
| 50 actual_end=1655987219972, ideal_instant=1655987167999, |
| 51 serial=self.remote_stream) |
| 52 |
| 53 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats( |
| 54 [event_local_stream, event_remote_stream]) |
| 55 |
| 56 self.assertEqual(2, len(stats_parser.stream_to_events)) |
| 57 |
| 58 self.assertEqual(event_local_stream.args, |
| 59 stats_parser.stream_to_events[self.local_stream][0].args) |
| 60 |
| 61 self.assertEqual(event_remote_stream.args, |
| 62 stats_parser.stream_to_events[self.remote_stream][0].args) |
| 63 |
| 64 def testInvalidEvents(self): |
| 65 event_missing_serial = FakeEvent(actual_begin=1655987244074, |
| 66 actual_end=1655987260740, ideal_instant=1655987204839) |
| 67 |
| 68 event_missing_actual_begin = FakeEvent(actual_end=1655987260740, |
| 69 ideal_instant=1655987217999, serial=self.local_stream) |
| 70 |
| 71 event_missing_actual_end = FakeEvent(actual_end=1655987260740, |
| 72 ideal_instant=1655987217999, serial=self.remote_stream) |
| 73 |
| 74 event_missing_ideal_instant = FakeEvent(actual_begin=1655987260740, |
| 75 actual_end=1655987277406, serial=self.remote_stream) |
| 76 |
| 77 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats( |
| 78 [event_missing_serial, event_missing_actual_begin, |
| 79 event_missing_actual_end, event_missing_ideal_instant]) |
| 80 |
| 81 self.assertEqual(0, len(stats_parser.stream_to_events)) |
| 82 |
| 83 def _GetFakeEvents(self): |
| 84 fake_events = [ |
| 85 FakeEvent(actual_begin=1663780195583, actual_end=1663780212249, |
| 86 ideal_instant=1663780179998, serial=self.remote_stream), |
| 87 FakeEvent(actual_begin=1663780212249, actual_end=1663780228915, |
| 88 ideal_instant=1663780179998, serial=self.remote_stream), |
| 89 FakeEvent(actual_begin=1663780228915, actual_end=1663780245581, |
| 90 ideal_instant=1663780197998, serial=self.remote_stream), |
| 91 FakeEvent(actual_begin=1663780245581, actual_end=1663780262247, |
| 92 ideal_instant=1663780215998, serial=self.remote_stream), |
| 93 FakeEvent(actual_begin=1663780262247, actual_end=1663780278913, |
| 94 ideal_instant=1663780215998, serial=self.remote_stream), |
| 95 FakeEvent(actual_begin=1663780278913, actual_end=1663780295579, |
| 96 ideal_instant=1663780254998, serial=self.remote_stream), |
| 97 FakeEvent(actual_begin=1663780295579, actual_end=1663780312245, |
| 98 ideal_instant=1663780254998, serial=self.remote_stream), |
| 99 FakeEvent(actual_begin=1663780312245, actual_end=1663780328911, |
| 100 ideal_instant=1663780254998, serial=self.remote_stream), |
| 101 FakeEvent(actual_begin=1663780328911, actual_end=1663780345577, |
| 102 ideal_instant=1663780310998, serial=self.remote_stream), |
| 103 FakeEvent(actual_begin=1663780345577, actual_end=1663780362243, |
| 104 ideal_instant=1663780310998, serial=self.remote_stream), |
| 105 FakeEvent(actual_begin=1663780362243, actual_end=1663780378909, |
| 106 ideal_instant=1663780310998, serial=self.remote_stream), |
| 107 FakeEvent(actual_begin=1663780378909, actual_end=1663780395575, |
| 108 ideal_instant=1663780361998, serial=self.remote_stream), |
| 109 FakeEvent(actual_begin=1663780395575, actual_end=1663780412241, |
| 110 ideal_instant=1663780361998, serial=self.remote_stream), |
| 111 FakeEvent(actual_begin=1663780412241, actual_end=1663780428907, |
| 112 ideal_instant=1663780361998, serial=self.remote_stream), |
| 113 FakeEvent(actual_begin=1663780428907, actual_end=1663780445573, |
| 114 ideal_instant=1663780412998, serial=self.remote_stream)] |
| 115 |
| 116 return fake_events |
| 117 |
| 118 def testGetCadence(self): |
| 119 fake_events = self._GetFakeEvents() |
| 120 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats(fake_events) |
| 121 # The events defined in _GetFakeEvents above show that the first source |
| 122 # framee of ideal_instant=1663780179998 is rendered twice, then |
| 123 # the second source frame of ideal_instant=1663780197998 is rendered once |
| 124 # the third source frame of ideal_instant=1663780215998 is rendered twice |
| 125 # and so on. The expected cadence will therefore be [2 1 2 etc..] |
| 126 expected_cadence = [2, 1, 2, 3, 3, 3, 1] |
| 127 self.assertEqual(expected_cadence, stats_parser._GetCadence(fake_events)) |
| 128 |
| 129 def testGetSourceToOutputDistribution(self): |
| 130 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats([]) |
| 131 cadence = [2, 1, 2, 3, 3, 3, 1] |
| 132 expected_frame_distribution = {1: 2, 2: 2, 3: 3} |
| 133 self.assertEqual(expected_frame_distribution, |
| 134 stats_parser._GetSourceToOutputDistribution(cadence)) |
| 135 |
| 136 def testGetFpsFromCadence(self): |
| 137 frame_distribution = {1: 2, 2: 2, 3: 3} |
| 138 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats([]) |
| 139 expected_frame_rate = 28.0 |
| 140 self.assertEqual(expected_frame_rate, |
| 141 stats_parser._GetFpsFromCadence(frame_distribution)) |
| 142 |
| 143 def testGetFrozenFramesReports(self): |
| 144 frame_distribution = {1: 2, 2: 2, 3: 569, 6: 1} |
| 145 expected_frozen_reports = [{'frozen_frames': 5, 'occurrences': 1}] |
| 146 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats([]) |
| 147 self.assertEqual(expected_frozen_reports, |
| 148 stats_parser._GetFrozenFramesReports(frame_distribution)) |
| 149 |
| 150 def testIsRemoteStream(self): |
| 151 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats([]) |
| 152 self.assertTrue(stats_parser._IsRemoteStream(self.remote_stream)) |
| 153 |
| 154 def testGetDrifTimeStats(self): |
| 155 fake_events = self._GetFakeEvents() |
| 156 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats([]) |
| 157 cadence = stats_parser._GetCadence(fake_events) |
| 158 expected_drift_time = [15585, 30917, 29583, 23915, 17913, 16911, 15909] |
| 159 expected_rendering_length_error = 29.613733905579398 |
| 160 |
| 161 self.assertEqual((expected_drift_time, expected_rendering_length_error), |
| 162 stats_parser._GetDrifTimeStats(fake_events, cadence)) |
| 163 |
| 164 def testGetSmoothnessStats(self): |
| 165 norm_drift_time = [5948.2857142857138, 9383.7142857142862, |
| 166 8049.7142857142862, 2381.7142857142862, 3620.2857142857138, |
| 167 4622.2857142857138, 5624.2857142857138] |
| 168 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats([]) |
| 169 expected_percent_badly_oos = 0.0 |
| 170 expected_percent_out_of_sync = 0.0 |
| 171 expected_smoothness_score = 100.0 |
| 172 expected_smoothness_stats = (expected_percent_badly_oos, |
| 173 expected_percent_out_of_sync, expected_smoothness_score) |
| 174 |
| 175 self.assertEqual(expected_smoothness_stats, |
| 176 stats_parser._GetSmoothnessStats(norm_drift_time)) |
| 177 |
| 178 def testNegativeSmoothnessScoreChangedToZero(self): |
| 179 norm_drift_time = [15948.285714285714, 9383.714285714286, |
| 180 28049.714285714286, 72381.71428571429, 3620.2857142857138, |
| 181 4622.285714285714, 35624.28571428572] |
| 182 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats([]) |
| 183 expected_percent_badly_oos = 28.571428571428573 |
| 184 expected_percent_out_of_sync = 42.857142857142854 |
| 185 expected_smoothness_score = 0.0 |
| 186 expected_smoothness_stats = (expected_percent_badly_oos, |
| 187 expected_percent_out_of_sync, expected_smoothness_score) |
| 188 |
| 189 self.assertEqual(expected_smoothness_stats, |
| 190 stats_parser._GetSmoothnessStats(norm_drift_time)) |
| 191 |
| 192 def testGetFreezingScore(self): |
| 193 frame_distribution = {1: 2, 2: 2, 3: 569, 6: 1} |
| 194 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats([]) |
| 195 expected_freezing_score = 99.94182664339732 |
| 196 self.assertEqual(expected_freezing_score, |
| 197 stats_parser._GetFreezingScore(frame_distribution)) |
| 198 |
| 199 def testNegativeFrezingScoreChangedToZero(self): |
| 200 frame_distribution = {1: 2, 2: 2, 3: 2, 8:100} |
| 201 stats_parser = stats_helper.WebMediaPlayerMsRenderingStats([]) |
| 202 self.assertEqual(0.0, stats_parser._GetFreezingScore(frame_distribution)) |
| 203 |
| 204 def testGetTimeStats(self): |
| 205 fake_events = self._GetFakeEvents() |
| 206 expected_cadence = [2, 1, 2, 3, 3, 3, 1] |
| 207 expected_frame_dist = {1: 2, 2: 2, 3: 569, 6: 1} |
| 208 expected_frame_rate = 28.0 |
| 209 expected_drift_time = [15585, 30917, 29583, 23915, 17913, 16911, 15909] |
| 210 expected_rendering_length_error = 29.613733905579398 |
| 211 expected_percent_badly_oos = 0.0 |
| 212 expected_percent_out_of_sync = 0.0 |
| 213 expected_smoothness_score = 100.0 |
| 214 expected_freezing_score = 99.94182664339732 |
| 215 |
| 216 stats_cls = stats_helper.WebMediaPlayerMsRenderingStats |
| 217 stats_cls._GetCadence = mock.Mock() |
| 218 stats_cls._GetCadence.return_value = expected_cadence |
| 219 stats_cls._GetSourceToOutputDistribution = mock.Mock() |
| 220 stats_cls._GetSourceToOutputDistribution.return_value = expected_frame_dist |
| 221 stats_cls._GetFpsFromCadence = mock.Mock() |
| 222 stats_cls._GetFpsFromCadence.return_value = expected_frame_rate |
| 223 stats_cls._GetDrifTimeStats = mock.Mock() |
| 224 stats_cls._GetDrifTimeStats.return_value = (expected_drift_time, |
| 225 expected_rendering_length_error) |
| 226 stats_cls._GetSmoothnessStats = mock.Mock() |
| 227 stats_cls._GetSmoothnessStats.return_value = (expected_percent_badly_oos, |
| 228 expected_percent_out_of_sync, expected_smoothness_score) |
| 229 stats_cls._GetFreezingScore = mock.Mock() |
| 230 stats_cls._GetFreezingScore.return_value = expected_freezing_score |
| 231 |
| 232 stats_parser = stats_cls(fake_events) |
| 233 |
| 234 expected_stats = { |
| 235 'drift_time': expected_drift_time, |
| 236 'mean_drift_time': numpy.mean(expected_drift_time), |
| 237 'std_dev_drift_time': numpy.std(expected_drift_time), |
| 238 'percent_badly_out_of_sync': expected_percent_badly_oos, |
| 239 'percent_out_of_sync': expected_percent_out_of_sync, |
| 240 'smoothness_score': expected_smoothness_score, |
| 241 'freezing_score': expected_freezing_score, |
| 242 'rendering_length_error': expected_rendering_length_error, |
| 243 'fps': expected_frame_rate, |
| 244 'frame_distribution': expected_frame_dist} |
| 245 |
| 246 self.assertEqual(expected_stats, stats_parser.GetTimeStats()) |
OLD | NEW |