blob: 1e7672964af6f73dab90289770fc238c45839b3f [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""
Test script to automate the Bluetooth audio testing and analysis.
Quick way to generate necessary audio files:
sudo apt-get install sox
sox -b 16 -r 48000 -c 2 -n audio_file_2k1k_10_sec.wav synth 10 sine 2000 sine 3000
sox -b 16 -r 48000 -c 2 -n audio_file_2k1k_300_sec.wav synth 300 sine 2000 sine 3000
"""
import os
import subprocess
import time
from acts.test_decorators import test_tracker_info
from acts.test_utils.audio_analysis_lib.check_quality import quality_analysis
from acts.test_utils.bt.BtFunhausBaseTest import BtFunhausBaseTest
from acts.test_utils.bt.bt_constants import audio_bits_per_sample_32
from acts.test_utils.bt.bt_constants import audio_channel_mode_8
from acts.test_utils.bt.bt_constants import audio_sample_rate_48000
from acts.test_utils.bt.bt_constants import delay_after_binding_seconds
from acts.test_utils.bt.bt_constants import delay_before_record_seconds
from acts.test_utils.bt.bt_constants import fpga_linein_bus_endpoint
from acts.test_utils.bt.bt_constants import headphone_bus_endpoint
from acts.test_utils.bt.bt_constants import silence_wait_seconds
class BtChameleonTest(BtFunhausBaseTest):
audio_file_2k1k_10_sec = "audio_file_2k1k_10_sec.wav"
audio_file_2k1k_300_sec = "audio_file_2k1k_300_sec.wav"
android_sdcard_music_path = "/sdcard/Music"
def setup_class(self):
super().setup_class()
self.chameleon = self.chameleon_devices[0]
self.dut = self.android_devices[0]
self.raw_audio_dest = "{}/{}".format(self.android_devices[0].log_path,
"Chameleon_audio")
os.makedirs(self.raw_audio_dest, exist_ok=True)
self.chameleon.audio_board_connect(1, headphone_bus_endpoint)
self.chameleon.audio_board_connect(1, fpga_linein_bus_endpoint)
time.sleep(delay_after_binding_seconds)
def _orchestrate_audio_quality_test(self, output_file_prefix_name,
bits_per_sample, rate, record_seconds,
channel, audio_to_play):
audio_analysis_filename = "{}_audio_analysis.txt".format(
output_file_prefix_name)
bluetooth_bind_time_seconds = 5
port_id = 6
has_file = True
# Additional sleep to allow full connection of Bluetooth device
# from test setup.
time.sleep(bluetooth_bind_time_seconds)
self.chameleon.start_capturing_audio(port_id, has_file)
time.sleep(delay_before_record_seconds)
self.dut.droid.mediaPlayOpen("file://{}".format(audio_to_play))
time.sleep(record_seconds + silence_wait_seconds)
raw_audio_info = self.chameleon_devices[0].stop_capturing_audio(
port_id)
self.ad.droid.mediaPlayStopAll()
raw_audio_path = raw_audio_info[0]
dest_file_path = "{}/{}_recording.raw".format(self.raw_audio_dest,
output_file_prefix_name)
self.chameleon.scp(raw_audio_path, dest_file_path)
self._collect_bluetooth_manager_dumpsys_logs(self.android_devices)
self.collect_bluetooth_manager_metrics_logs(self.android_devices)
analysis_path = "{}/{}".format(self.raw_audio_dest,
audio_analysis_filename)
try:
quality_analysis(
filename=dest_file_path,
output_file=analysis_path,
bit_width=bits_per_sample,
rate=rate,
channel=channel,
spectral_only=False)
except Exception as err:
self.log.exception("Failed to analyze raw audio: {}".format(err))
return False
# TODO: Log results to proto
return True
@test_tracker_info(uuid='b808fed6-5cb0-4e40-9522-c0f410cd77e8')
def test_run_bt_audio_quality_2k1k_10_sec_sine_wave(self):
"""Measure audio quality over Bluetooth by playing a 1k2k sine wave.
Play a sine wave and measure the analysis of 1kHz and 2kHz on two
different channels for 10 seconds:
1. Delays during playback.
2. Noise before playback.
3. Noise after playback.
4. Bursts during playback.
5. Volume changes.
Steps:
1. Connect Chameleon headphone audio bus endpoint.
2. Connect FPGA line-in bus endpoint.
3. Clear audio routes on the Chameleon device.
4. Start capturing audio on the Chameleon device.
5. Start playing the sine wave on the Android device.
6. Record for record_seconds + silence_wait_seconds.
7. Stop recording audio on the Chameleon device.
8. Stop playing audio on the Android Device.
9. Pull raw recorded audio from the Chameleon device.
10. Analyze raw audio and log results.
Expected Result:
Audio is recorded and processed successfully.
Returns:
True if Pass
False if Fail
TAGS: Classic, A2DP, Chameleon
Priority: 2
"""
sox_call = "{}{}".format("sox -b 16 -r 48000 -c 2 -n {}".format(
self.audio_file_2k1k_10_sec), " synth 10 sine 2000 sine 3000")
subprocess.call(sox_call, shell=True)
sox_audio_path = "{}/{}".format(
os.path.dirname(os.path.realpath(self.audio_file_2k1k_10_sec)),
self.audio_file_2k1k_10_sec)
sox_audio_path = os.path.join(
os.path.dirname(os.path.realpath(self.audio_file_2k1k_10_sec)),
self.audio_file_2k1k_10_sec)
self.dut.adb.push("{} {}".format(sox_audio_path,
self.android_sdcard_music_path))
output_file_prefix_name = "{}_{}".format("test_2k1k_10_sec",
time.time())
bits_per_sample = audio_bits_per_sample_32
rate = audio_sample_rate_48000
record_seconds = 10 # The length in seconds for how long to record
channel = audio_channel_mode_8
audio_to_play = "{}/{}".format(self.android_sdcard_music_path,
self.audio_file_2k1k_10_sec)
audio_to_play = os.path.join(self.android_sdcard_music_path,
self.audio_file_2k1k_10_sec)
return self._orchestrate_audio_quality_test(
output_file_prefix_name=output_file_prefix_name,
bits_per_sample=bits_per_sample,
rate=rate,
record_seconds=record_seconds,
channel=channel,
audio_to_play=audio_to_play)
@test_tracker_info(uuid='7e971cef-6637-4198-929a-7ecc712121d7')
def test_run_bt_audio_quality_2k1k_300_sec_sine_wave(self):
"""Measure audio quality over Bluetooth by playing a 1k2k sine wave.
Play a sine wave and measure the analysis of 1kHz and 2kHz on two
different channels for 300 seconds:
1. Delays during playback.
2. Noise before playback.
3. Noise after playback.
4. Bursts during playback.
5. Volume changes.
Steps:
1. Connect Chameleon headphone audio bus endpoint.
2. Connect FPGA line-in bus endpoint.
3. Clear audio routes on the Chameleon device.
4. Start capturing audio on the Chameleon device.
5. Start playing the sine wave on the Android device.
6. Record for record_seconds + silence_wait_seconds.
7. Stop recording audio on the Chameleon device.
8. Stop playing audio on the Android Device.
9. Pull raw recorded audio from the Chameleon device.
10. Analyze raw audio and log results.
Expected Result:
Audio is recorded and processed successfully.
Returns:
True if Pass
False if Fail
TAGS: Classic, A2DP, Chameleon
Priority: 2
"""
sox_call = "{}{}".format("sox -b 16 -r 48000 -c 2 -n {}".format(
self.audio_file_2k1k_300_sec), " synth 300 sine 2000 sine 3000")
subprocess.call(sox_call, shell=True)
sox_audio_path = os.path.join(
os.path.dirname(os.path.realpath(self.audio_file_2k1k_300_sec)),
self.audio_file_2k1k_300_sec)
self.dut.adb.push("{} {}".format(sox_audio_path,
self.android_sdcard_music_path))
output_file_prefix_name = "{}_{}".format("test_2k1k_300_sec.wav",
time.time())
bits_per_sample = audio_bits_per_sample_32
rate = audio_sample_rate_48000
record_seconds = 300 # The length in seconds for how long to record
channel = audio_channel_mode_8
audio_to_play = os.path.join(self.android_sdcard_music_path,
self.audio_file_2k1k_300_sec)
return self._orchestrate_audio_quality_test(
output_file_prefix_name=output_file_prefix_name,
bits_per_sample=bits_per_sample,
rate=rate,
record_seconds=record_seconds,
channel=channel,
audio_to_play=audio_to_play)