blob: d616230b90fb73cffe7107d111f07d8ddfcf95f4 [file] [log] [blame]
Qi36ec56f2020-01-02 11:02:41 -08001#!/usr/bin/env python3
2#
3# Copyright (C) 2019 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16
Xianyuan Jia24299b72020-10-21 13:52:47 -070017import acts_contrib.test_utils.bt.bt_test_utils as btutils
Qi36ec56f2020-01-02 11:02:41 -080018from acts import asserts
19from acts.signals import TestPass
Xianyuan Jia24299b72020-10-21 13:52:47 -070020from acts_contrib.test_utils.bt import bt_constants
21from acts_contrib.test_utils.bt import BtEnum
22from acts_contrib.test_utils.bt.A2dpBaseTest import A2dpBaseTest
23from acts_contrib.test_utils.bt.loggers import bluetooth_metric_logger as log
24from acts_contrib.test_utils.power.PowerBTBaseTest import ramp_attenuation
Qi36ec56f2020-01-02 11:02:41 -080025
26
27class BtA2dpRangeTest(A2dpBaseTest):
28 def __init__(self, configs):
29 super().__init__(configs)
30 self.bt_logger = log.BluetoothMetricLogger.for_test_case()
31 req_params = ['attenuation_vector', 'codecs']
32 #'attenuation_vector' is a dict containing: start, stop and step of
33 #attenuation changes
34 #'codecs' is a list containing all codecs required in the tests
35 self.unpack_userparams(req_params)
36 for codec_config in self.codecs:
37 self.generate_test_case(codec_config)
38
39 def setup_class(self):
40 super().setup_class()
41 # Enable BQR on all android devices
42 btutils.enable_bqr(self.android_devices)
43
44 def generate_test_case(self, codec_config):
45 def test_case_fn():
46 self.run_a2dp_to_max_range(codec_config)
47
48 test_case_name = 'test_bt_a2dp_range_codec_{}'.format(
49 codec_config['codec_type'])
50 setattr(self, test_case_name, test_case_fn)
51
Qi36ec56f2020-01-02 11:02:41 -080052 def generate_proto(self, data_points, codec_type, sample_rate,
53 bits_per_sample, channel_mode):
54 """Generate a results protobuf.
55
56 Args:
57 data_points: list of dicts representing info to go into
58 AudioTestDataPoint protobuffer message.
59 codec_type: The codec type config to store in the proto.
60 sample_rate: The sample rate config to store in the proto.
61 bits_per_sample: The bits per sample config to store in the proto.
62 channel_mode: The channel mode config to store in the proto.
63 Returns:
64 dict: Dictionary with key 'proto' mapping to serialized protobuf,
65 'proto_ascii' mapping to human readable protobuf info, and 'test'
66 mapping to the test class name that generated the results.
67 """
68
69 # Populate protobuf
70 test_case_proto = self.bt_logger.proto_module.BluetoothAudioTestResult(
71 )
72
73 for data_point in data_points:
74 audio_data_proto = test_case_proto.data_points.add()
75 log.recursive_assign(audio_data_proto, data_point)
76
77 codec_proto = test_case_proto.a2dp_codec_config
78 codec_proto.codec_type = bt_constants.codec_types[codec_type]
79 codec_proto.sample_rate = int(sample_rate)
80 codec_proto.bits_per_sample = int(bits_per_sample)
81 codec_proto.channel_mode = bt_constants.channel_modes[channel_mode]
82
83 self.bt_logger.add_config_data_to_proto(test_case_proto, self.dut,
84 self.bt_device)
85
86 self.bt_logger.add_proto_to_results(test_case_proto,
87 self.__class__.__name__)
88
89 proto_dict = self.bt_logger.get_proto_dict(self.__class__.__name__,
90 test_case_proto)
91 del proto_dict["proto_ascii"]
92 return proto_dict
93
94 def run_a2dp_to_max_range(self, codec_config):
95 attenuation_range = range(self.attenuation_vector['start'],
96 self.attenuation_vector['stop'] + 1,
97 self.attenuation_vector['step'])
98
99 data_points = []
100
101 # Set Codec if needed
102 current_codec = self.dut.droid.bluetoothA2dpGetCurrentCodecConfig()
103 current_codec_type = BtEnum.BluetoothA2dpCodecType(
104 current_codec['codecType']).name
105 if current_codec_type != codec_config['codec_type']:
106 codec_set = btutils.set_bluetooth_codec(self.dut, **codec_config)
107 asserts.assert_true(codec_set, 'Codec configuration failed.')
108 else:
109 self.log.info('Current codec is {}, no need to change'.format(
110 current_codec_type))
111
112 #loop RSSI with the same codec setting
113 for atten in attenuation_range:
114 ramp_attenuation(self.attenuator, atten)
115 self.log.info('Set attenuation to %d dB', atten)
116
117 tag = 'codec_{}_attenuation_{}dB_'.format(
118 codec_config['codec_type'], atten)
119 recorded_file = self.play_and_record_audio(
120 self.audio_params['duration'])
121 [rssi_master, pwl_master, rssi_slave] = self._get_bt_link_metrics()
122 thdns = self.run_thdn_analysis(recorded_file, tag)
123 # Collect Metrics for dashboard
124 data_point = {
125 'attenuation_db': int(self.attenuator.get_atten()),
126 'rssi_master': rssi_master[self.dut.serial],
127 'tx_power_level_master': pwl_master[self.dut.serial],
128 'rssi_slave': rssi_slave[self.bt_device_controller.serial],
129 'total_harmonic_distortion_plus_noise_percent': thdns[0] * 100
130 }
131 data_points.append(data_point)
132 self.log.info(data_point)
133 # Check thdn for glitches, stop if max range reached
134 for thdn in thdns:
135 if thdn >= self.audio_params['thdn_threshold']:
136 self.log.info(
137 'Max range at attenuation {} dB'.format(atten))
138 self.log.info(
139 'master rssi {} dBm, master tx power level {}, '
140 'slave rssi {} dBm'
141 .format(rssi_master, pwl_master, rssi_slave))
142 proto_dict = self.generate_proto(data_points,
143 **codec_config)
144 raise TestPass('Max range reached and move to next codec',
145 extras=proto_dict)
146
147 proto_dict = self.generate_proto(data_points, **codec_config)
148 raise TestPass('Could not reach max range, need extra attenuation.',
149 extras=proto_dict)