• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright (C) 2017 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"""
17Test script to automate the Bluetooth audio testing and analysis.
18
19Quick way to generate necessary audio files:
20sudo apt-get install sox
21sox -b 16 -r 48000 -c 2 -n audio_file_2k1k_10_sec.wav synth 10 sine 2000 sine 3000
22sox -b 16 -r 48000 -c 2 -n audio_file_2k1k_300_sec.wav synth 300 sine 2000 sine 3000
23
24"""
25import os
26import subprocess
27import time
28
29from acts.test_decorators import test_tracker_info
30from acts.test_utils.audio_analysis_lib.check_quality import quality_analysis
31from acts.test_utils.bt.BtFunhausBaseTest import BtFunhausBaseTest
32from acts.test_utils.bt.bt_constants import audio_bits_per_sample_32
33from acts.test_utils.bt.bt_constants import audio_channel_mode_8
34from acts.test_utils.bt.bt_constants import audio_sample_rate_48000
35from acts.test_utils.bt.bt_constants import delay_after_binding_seconds
36from acts.test_utils.bt.bt_constants import delay_before_record_seconds
37from acts.test_utils.bt.bt_constants import fpga_linein_bus_endpoint
38from acts.test_utils.bt.bt_constants import headphone_bus_endpoint
39from acts.test_utils.bt.bt_constants import silence_wait_seconds
40
41from acts import utils
42
43
44class BtChameleonTest(BtFunhausBaseTest):
45
46    audio_file_2k1k_10_sec = "audio_file_2k1k_10_sec.wav"
47    audio_file_2k1k_300_sec = "audio_file_2k1k_300_sec.wav"
48    android_sdcard_music_path = "/sdcard/Music"
49
50    def __init__(self, controllers):
51        BtFunhausBaseTest.__init__(self, controllers)
52        self.chameleon = self.chameleon_devices[0]
53        self.dut = self.android_devices[0]
54        self.raw_audio_dest = "{}/{}".format(self.android_devices[0].log_path,
55                                             "Chameleon_audio")
56        utils.create_dir(self.raw_audio_dest)
57        self.chameleon.audio_board_connect(1, headphone_bus_endpoint)
58        self.chameleon.audio_board_connect(1, fpga_linein_bus_endpoint)
59        time.sleep(delay_after_binding_seconds)
60
61    def _orchestrate_audio_quality_test(self, output_file_prefix_name,
62                                        bits_per_sample, rate, record_seconds,
63                                        channel, audio_to_play):
64        audio_analysis_filename = "{}_audio_analysis.txt".format(
65            output_file_prefix_name)
66        bluetooth_bind_time_seconds = 5
67        port_id = 6
68        has_file = True
69        # Additional sleep to allow full connection of Bluetooth device
70        # from test setup.
71        time.sleep(bluetooth_bind_time_seconds)
72        self.chameleon.start_capturing_audio(port_id, has_file)
73        time.sleep(delay_before_record_seconds)
74        self.dut.droid.mediaPlayOpen("file://{}".format(audio_to_play))
75        time.sleep(record_seconds + silence_wait_seconds)
76        raw_audio_info = self.chameleon_devices[0].stop_capturing_audio(
77            port_id)
78        self.ad.droid.mediaPlayStopAll()
79        raw_audio_path = raw_audio_info[0]
80        dest_file_path = "{}/{}_recording.raw".format(self.raw_audio_dest,
81                                                      output_file_prefix_name)
82        self.chameleon.scp(raw_audio_path, dest_file_path)
83        self._collect_bluetooth_manager_dumpsys_logs(self.android_devices)
84        self.collect_bluetooth_manager_metrics_logs(self.android_devices)
85        analysis_path = "{}/{}".format(self.raw_audio_dest,
86                                       audio_analysis_filename)
87        try:
88            quality_analysis(
89                filename=dest_file_path,
90                output_file=analysis_path,
91                bit_width=bits_per_sample,
92                rate=rate,
93                channel=channel,
94                spectral_only=False)
95        except Exception as err:
96            self.log.exception("Failed to analyze raw audio: {}".format(err))
97            return False
98        # TODO: Log results to proto
99        return True
100
101    @test_tracker_info(uuid='b808fed6-5cb0-4e40-9522-c0f410cd77e8')
102    def test_run_bt_audio_quality_2k1k_10_sec_sine_wave(self):
103        """Measure audio quality over Bluetooth by playing a 1k2k sine wave.
104
105        Play a sine wave and measure the analysis of 1kHz and 2kHz on two
106            different channels for 10 seconds:
107        1. Delays during playback.
108        2. Noise before playback.
109        3. Noise after playback.
110        4. Bursts during playback.
111        5. Volume changes.
112
113        Steps:
114        1. Connect Chameleon headphone audio bus endpoint.
115        2. Connect FPGA line-in bus endpoint.
116        3. Clear audio routes on the Chameleon device.
117        4. Start capturing audio on the Chameleon device.
118        5. Start playing the sine wave on the Android device.
119        6. Record for record_seconds + silence_wait_seconds.
120        7. Stop recording audio on the Chameleon device.
121        8. Stop playing audio on the Android Device.
122        9. Pull raw recorded audio from the Chameleon device.
123        10. Analyze raw audio and log results.
124
125
126        Expected Result:
127        Audio is recorded and processed successfully.
128
129        Returns:
130          True if Pass
131          False if Fail
132
133        TAGS: Classic, A2DP, Chameleon
134        Priority: 2
135        """
136        sox_call = "{}{}".format("sox -b 16 -r 48000 -c 2 -n {}".format(
137            self.audio_file_2k1k_10_sec), " synth 10 sine 2000 sine 3000")
138        subprocess.call(sox_call, shell=True)
139        sox_audio_path = "{}/{}".format(
140            os.path.dirname(os.path.realpath(self.audio_file_2k1k_10_sec)),
141            self.audio_file_2k1k_10_sec)
142        sox_audio_path = os.path.join(
143            os.path.dirname(os.path.realpath(self.audio_file_2k1k_10_sec)),
144            self.audio_file_2k1k_10_sec)
145        self.dut.adb.push("{} {}".format(sox_audio_path,
146                                         self.android_sdcard_music_path))
147        output_file_prefix_name = "{}_{}".format("test_2k1k_10_sec",
148                                                 time.time())
149        bits_per_sample = audio_bits_per_sample_32
150        rate = audio_sample_rate_48000
151        record_seconds = 10  # The length in seconds for how long to record
152        channel = audio_channel_mode_8
153        audio_to_play = "{}/{}".format(self.android_sdcard_music_path,
154                                       self.audio_file_2k1k_10_sec)
155        audio_to_play = os.path.join(self.android_sdcard_music_path,
156                                     self.audio_file_2k1k_10_sec)
157        return self._orchestrate_audio_quality_test(
158            output_file_prefix_name=output_file_prefix_name,
159            bits_per_sample=bits_per_sample,
160            rate=rate,
161            record_seconds=record_seconds,
162            channel=channel,
163            audio_to_play=audio_to_play)
164
165    @test_tracker_info(uuid='7e971cef-6637-4198-929a-7ecc712121d7')
166    def test_run_bt_audio_quality_2k1k_300_sec_sine_wave(self):
167        """Measure audio quality over Bluetooth by playing a 1k2k sine wave.
168
169        Play a sine wave and measure the analysis of 1kHz and 2kHz on two
170            different channels for 300 seconds:
171        1. Delays during playback.
172        2. Noise before playback.
173        3. Noise after playback.
174        4. Bursts during playback.
175        5. Volume changes.
176
177        Steps:
178        1. Connect Chameleon headphone audio bus endpoint.
179        2. Connect FPGA line-in bus endpoint.
180        3. Clear audio routes on the Chameleon device.
181        4. Start capturing audio on the Chameleon device.
182        5. Start playing the sine wave on the Android device.
183        6. Record for record_seconds + silence_wait_seconds.
184        7. Stop recording audio on the Chameleon device.
185        8. Stop playing audio on the Android Device.
186        9. Pull raw recorded audio from the Chameleon device.
187        10. Analyze raw audio and log results.
188
189
190        Expected Result:
191        Audio is recorded and processed successfully.
192
193        Returns:
194          True if Pass
195          False if Fail
196
197        TAGS: Classic, A2DP, Chameleon
198        Priority: 2
199        """
200        sox_call = "{}{}".format("sox -b 16 -r 48000 -c 2 -n {}".format(
201            self.audio_file_2k1k_300_sec), " synth 300 sine 2000 sine 3000")
202        subprocess.call(sox_call, shell=True)
203        sox_audio_path = os.path.join(
204            os.path.dirname(os.path.realpath(self.audio_file_2k1k_300_sec)),
205            self.audio_file_2k1k_300_sec)
206        self.dut.adb.push("{} {}".format(sox_audio_path,
207                                         self.android_sdcard_music_path))
208        output_file_prefix_name = "{}_{}".format("test_2k1k_300_sec.wav",
209                                                 time.time())
210        bits_per_sample = audio_bits_per_sample_32
211        rate = audio_sample_rate_48000
212        record_seconds = 300  # The length in seconds for how long to record
213        channel = audio_channel_mode_8
214        audio_to_play = os.path.join(self.android_sdcard_music_path,
215                                     self.audio_file_2k1k_300_sec)
216
217        return self._orchestrate_audio_quality_test(
218            output_file_prefix_name=output_file_prefix_name,
219            bits_per_sample=bits_per_sample,
220            rate=rate,
221            record_seconds=record_seconds,
222            channel=channel,
223            audio_to_play=audio_to_play)
224