1# Copyright 2020 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"""A Batch of Bluetooth AUdio Health tests""" 6 7import time 8 9from autotest_lib.client.common_lib import error 10from autotest_lib.client.cros.bluetooth.bluetooth_audio_test_data import ( 11 A2DP, A2DP_LONG, AVRCP, HFP_WBS, HFP_NBS) 12from autotest_lib.server.cros.bluetooth.bluetooth_adapter_audio_tests import ( 13 BluetoothAdapterAudioTests) 14from autotest_lib.server.cros.bluetooth.bluetooth_adapter_quick_tests import ( 15 BluetoothAdapterQuickTests) 16 17 18class bluetooth_AdapterAUHealth(BluetoothAdapterQuickTests, 19 BluetoothAdapterAudioTests): 20 """A Batch of Bluetooth audio health tests.""" 21 22 test_wrapper = BluetoothAdapterQuickTests.quick_test_test_decorator 23 batch_wrapper = BluetoothAdapterQuickTests.quick_test_batch_decorator 24 25 26 def au_run_method(self, device, test_method, test_profile): 27 """audio procedure of running a specified test method. 28 29 @param device: the bt peer device 30 @param test_method: the audio test method to run 31 @param test_profile: which test profile is used, 32 A2DP, HFP_WBS or HFP_NBS 33 """ 34 self.test_reset_on_adapter() 35 self.test_bluetoothd_running() 36 self.initialize_bluetooth_audio(device, test_profile) 37 self.test_device_set_discoverable(device, True) 38 self.test_discover_device(device.address) 39 self.test_pairing(device.address, device.pin, trusted=True) 40 self.test_connection_by_adapter(device.address) 41 test_method() 42 self.test_disconnection_by_adapter(device.address) 43 self.cleanup_bluetooth_audio(device, test_profile) 44 45 46 def _au_a2dp_test(self, test_profile, duration=0): 47 """A2DP test with sinewaves on the two channels. 48 49 @param test_profile: which test profile is used, A2DP or A2DP_LONG. 50 @param duration: the duration to test a2dp. The unit is in seconds. 51 if duration is 0, use the default duration in test_profile. 52 """ 53 device = self.devices['BLUETOOTH_AUDIO'][0] 54 self.au_run_method(device, 55 lambda: self.test_a2dp_sinewaves( 56 device, test_profile, duration), 57 test_profile) 58 59 60 @test_wrapper('A2DP sinewave test', devices={'BLUETOOTH_AUDIO':1}) 61 def au_a2dp_test(self): 62 """A2DP test with sinewaves on the two channels.""" 63 self._au_a2dp_test(A2DP) 64 65 # The A2DP long test is a stress test. Exclude it from the AVL. 66 @test_wrapper('A2DP sinewave long test', devices={'BLUETOOTH_AUDIO':1}, 67 flags=['Quick Health']) 68 def au_a2dp_long_test(self, duration=600): 69 """A2DP long test with sinewaves on the two channels. 70 71 @param duration: the duration to test a2dp. The unit is in seconds. 72 """ 73 self._au_a2dp_test(A2DP_LONG, duration=duration) 74 75 76 def check_wbs_capability(self): 77 """Check if the DUT supports WBS capability. 78 79 @raises: TestNAError if the dut does not support wbs. 80 """ 81 capabilities, err = self.bluetooth_facade.get_supported_capabilities() 82 return err is None and bool(capabilities.get('wide band speech')) 83 84 85 def au_hfp_run_method(self, device, test_method, test_profile): 86 """Run an HFP test with the specified test method. 87 88 @param device: the bt peer device 89 @param test_method: the specific HFP WBS test method 90 @param test_profile: which test profile is used, HFP_WBS or HFP_NBS 91 """ 92 if self.check_wbs_capability(): 93 if test_profile == HFP_WBS: 94 # Restart cras to ensure that cras goes back to the default 95 # selection of either WBS or NBS. 96 # Any board that supports WBS should use WBS by default, unless 97 # it's overridden by CRAS' config. 98 # Do not enable WBS explicitly in the test so we can catch if 99 # the default selection goes wrong. 100 self.restart_cras() 101 # The audio team suggests a simple 2-second sleep. 102 time.sleep(2) 103 elif test_profile == HFP_NBS: 104 # Cras may be in either WBS or NBS mode. Disable WBS explicitly. 105 if not self.bluetooth_facade.enable_wbs(False): 106 raise error.TestError('failed to disable wbs') 107 else: 108 if test_profile == HFP_WBS: 109 # Skip the WBS test on a board that does not support WBS. 110 raise error.TestNAError( 111 'The DUT does not support WBS. Skip the test.') 112 elif test_profile == HFP_NBS: 113 # Restart cras to ensure that cras goes back to the default 114 # selection of either WBS or NBS. 115 # Any board that does not support WBS should use NBS by default. 116 # Do not enable NBS explicitly in the test so we can catch if 117 # the default selection goes wrong. 118 self.restart_cras() 119 # The audio team suggests a simple 2-second sleep. 120 time.sleep(2) 121 122 self.au_run_method( 123 device, lambda: test_method(device, test_profile), test_profile) 124 125 126 # TODO(b/163284498) Realtek not ready for WBS yet pending on cras patches. 127 @test_wrapper('HFP WBS sinewave test with dut as source', 128 skip_chipsets=['Realtek-RTL8822C-USB'], 129 devices={'BLUETOOTH_AUDIO':1}) 130 def au_hfp_wbs_dut_as_source_test(self): 131 """HFP WBS test with sinewave streaming from dut to peer.""" 132 device = self.devices['BLUETOOTH_AUDIO'][0] 133 self.au_hfp_run_method(device, self.test_hfp_dut_as_source, HFP_WBS) 134 135 136 # TODO(b/163284498) Realtek not ready for WBS yet pending on cras patches. 137 @test_wrapper('HFP WBS sinewave test with dut as sink', 138 skip_chipsets=['Realtek-RTL8822C-USB'], 139 devices={'BLUETOOTH_AUDIO':1}) 140 def au_hfp_wbs_dut_as_sink_test(self): 141 """HFP WBS test with sinewave streaming from peer to dut.""" 142 device = self.devices['BLUETOOTH_AUDIO'][0] 143 self.au_hfp_run_method(device, self.test_hfp_dut_as_sink, HFP_WBS) 144 145 146 @test_wrapper('HFP NBS sinewave test with dut as source', 147 devices={'BLUETOOTH_AUDIO':1}) 148 def au_hfp_nbs_dut_as_source_test(self): 149 """HFP NBS test with sinewave streaming from dut to peer.""" 150 device = self.devices['BLUETOOTH_AUDIO'][0] 151 self.au_hfp_run_method(device, self.test_hfp_dut_as_source, HFP_NBS) 152 153 154 @test_wrapper('HFP NBS sinewave test with dut as sink', 155 devices={'BLUETOOTH_AUDIO':1}) 156 def au_hfp_nbs_dut_as_sink_test(self): 157 """HFP NBS test with sinewave streaming from peer to dut.""" 158 device = self.devices['BLUETOOTH_AUDIO'][0] 159 self.au_hfp_run_method(device, self.test_hfp_dut_as_sink, HFP_NBS) 160 161 162 @test_wrapper('HFP WBS VISQOL test with dut as sink', 163 devices={'BLUETOOTH_AUDIO':1}) 164 def au_hfp_wbs_dut_as_sink_visqol_test(self): 165 """HFP WBS VISQOL test with audio streaming from peer to dut""" 166 device = self.devices['BLUETOOTH_AUDIO'][0] 167 self.au_hfp_run_method(device, self.test_hfp_dut_as_sink_visqol_score, 168 HFP_WBS) 169 170 171 @test_wrapper('HFP WBS VISQOL test with dut as source', 172 devices={'BLUETOOTH_AUDIO':1}) 173 def au_hfp_wbs_dut_as_source_visqol_test(self): 174 """HFP WBS VISQOL test with audio streaming from dut to peer""" 175 device = self.devices['BLUETOOTH_AUDIO'][0] 176 self.au_hfp_run_method(device, self.test_hfp_dut_as_source_visqol_score, 177 HFP_WBS) 178 179 @test_wrapper('HFP NBS VISQOL test with dut as sink', 180 devices={'BLUETOOTH_AUDIO':1}) 181 def au_hfp_nbs_dut_as_sink_visqol_test(self): 182 """HFP NBS VISQOL test with audio streaming from peer to dut""" 183 device = self.devices['BLUETOOTH_AUDIO'][0] 184 self.au_hfp_run_method(device, self.test_hfp_dut_as_sink_visqol_score, 185 HFP_NBS) 186 187 188 @test_wrapper('HFP NBS VISQOL test with dut as source', 189 devices={'BLUETOOTH_AUDIO':1}) 190 def au_hfp_nbs_dut_as_source_visqol_test(self): 191 """HFP NBS VISQOL test with audio streaming from dut to peer""" 192 device = self.devices['BLUETOOTH_AUDIO'][0] 193 self.au_hfp_run_method(device, self.test_hfp_dut_as_source_visqol_score, 194 HFP_NBS) 195 196 197 def au_run_avrcp_method(self, device, test_method): 198 """avrcp procedure of running a specified test method. 199 200 @param device: the bt peer device 201 @param test_method: the avrcp test method to run 202 """ 203 def wrapped_test_method(device): 204 """A wrapper method to initialize and cleanup avrcp tests. 205 206 @param device: the bt peer device 207 """ 208 self.initialize_bluetooth_player(device) 209 test_method(device) 210 self.cleanup_bluetooth_player(device) 211 212 self.au_run_method( 213 device, lambda: wrapped_test_method(device), AVRCP) 214 215 216 @test_wrapper('avrcp command test', devices={'BLUETOOTH_AUDIO':1}) 217 def au_avrcp_command_test(self): 218 """AVRCP test to examine commands reception.""" 219 device = self.devices['BLUETOOTH_AUDIO'][0] 220 self.au_run_avrcp_method(device, self.test_avrcp_commands) 221 222 223 # Add 'Quick Health' to flags to exclude the test from AVL. 224 # When this test is stable enough later, remove the flags here. 225 @test_wrapper('avrcp media info test', devices={'BLUETOOTH_AUDIO':1}, 226 flags=['Quick Health']) 227 def au_avrcp_media_info_test(self): 228 """AVRCP test to examine metadata propgation.""" 229 device = self.devices['BLUETOOTH_AUDIO'][0] 230 self.au_run_avrcp_method(device, self.test_avrcp_media_info) 231 232 233 @batch_wrapper('Bluetooth Audio Batch Health Tests') 234 def au_health_batch_run(self, num_iterations=1, test_name=None): 235 """Run the bluetooth audio health test batch or a specific given test. 236 237 @param num_iterations: how many iterations to run 238 @param test_name: specific test to run otherwise None to run the 239 whole batch 240 """ 241 self.au_a2dp_test() 242 self.au_a2dp_long_test() 243 self.au_hfp_nbs_dut_as_source_test() 244 self.au_hfp_nbs_dut_as_sink_test() 245 self.au_hfp_wbs_dut_as_source_test() 246 self.au_hfp_wbs_dut_as_sink_test() 247 self.au_hfp_wbs_dut_as_source_visqol_test() 248 self.au_hfp_wbs_dut_as_sink_visqol_test() 249 self.au_hfp_nbs_dut_as_source_visqol_test() 250 self.au_hfp_nbs_dut_as_sink_visqol_test() 251 self.au_avrcp_command_test() 252 self.au_avrcp_media_info_test() 253 254 255 def run_once(self, 256 host, 257 num_iterations=1, 258 args_dict=None, 259 test_name=None, 260 flag='Quick Health'): 261 """Run the batch of Bluetooth stand health tests 262 263 @param host: the DUT, usually a chromebook 264 @param num_iterations: the number of rounds to execute the test 265 @param test_name: the test to run, or None for all tests 266 """ 267 self.host = host 268 269 self.quick_test_init(host, 270 use_btpeer=True, 271 flag=flag, 272 args_dict=args_dict) 273 self.au_health_batch_run(num_iterations, test_name) 274 self.quick_test_cleanup() 275