Home | History | Annotate | Download | only in audio_lab
      1 #/usr/bin/env python3.4
      2 #
      3 # Copyright (C) 2016 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 """
     17 Test script to automate the Bluetooth Audio Funhaus.
     18 """
     19 from acts.keys import Config
     20 from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
     21 from acts.test_utils.bt.bt_test_utils import bluetooth_enabled_check
     22 from acts.utils import bypass_setup_wizard
     23 from acts.utils import create_dir
     24 from acts.utils import exe_cmd
     25 from acts.utils import sync_device_time
     26 from queue import Empty
     27 import json
     28 import time
     29 import os
     30 
     31 
     32 class BtFunhausTest(BluetoothBaseTest):
     33     music_file_to_play = ""
     34     device_fails_to_connect_list = []
     35 
     36     def __init__(self, controllers):
     37         BluetoothBaseTest.__init__(self, controllers)
     38 
     39     def on_fail(self, test_name, begin_time):
     40         self._collect_bluetooth_manager_dumpsys_logs(self.android_devices)
     41         super(BluetoothBaseTest, self).on_fail(test_name, begin_time)
     42 
     43     def setup_class(self):
     44         for ad in self.android_devices:
     45             sync_device_time(ad)
     46             # Disable Bluetooth HCI Snoop Logs for audio tests
     47             ad.droid.bluetoothConfigHciSnoopLog(False)
     48             if not bypass_setup_wizard(ad):
     49                 self.log.debug(
     50                     "Failed to bypass setup wizard, continuing test.")
     51         if not "bt_config" in self.user_params.keys():
     52             self.log.error("Missing mandatory user config \"bt_config\"!")
     53             return False
     54         bt_config_map_file = self.user_params["bt_config"]
     55         return self._setup_bt_config(bt_config_map_file)
     56 
     57     def _setup_bt_config(self, bt_config_map_file):
     58         bt_config_map = {}
     59         bt_conf_path = "/data/misc/bluedroid/bt_config.conf"
     60         if not os.path.isfile(bt_config_map_file):
     61             bt_config_map_file = os.path.join(
     62                 self.user_params[Config.key_config_path], bt_config_map_file)
     63             if not os.path.isfile(bt_config_map_file):
     64                 self.log.error("Unable to load bt_config file {}.".format(
     65                     bt_config_map_file))
     66                 return False
     67         try:
     68             f = open(bt_config_map_file, 'r')
     69             bt_config_map = json.load(f)
     70             f.close()
     71         except FileNotFoundError:
     72             self.log.error("File not found: {}.".format(bt_config_map_file))
     73             return False
     74         # Connected devices return all upper case mac addresses.
     75         # Make the peripheral_info address attribute upper case
     76         # in order to ensure the BT mac addresses match.
     77         for serial in bt_config_map.keys():
     78             mac_address = bt_config_map[serial]["peripheral_info"][
     79                 "address"].upper()
     80             bt_config_map[serial]["peripheral_info"]["address"] = mac_address
     81         for ad in self.android_devices:
     82             serial = ad.serial
     83 
     84             # Verify serial number in bt_config_map
     85             self.log.info("Verify serial number of Android device in config.")
     86             if serial not in bt_config_map.keys():
     87                 self.log.error(
     88                     "Missing android device serial {} in bt_config.".format(
     89                         serial))
     90                 return False
     91             # Push the bt_config.conf file to Android device
     92             self.log.info("Pushing bt_config.conf file to Android device.")
     93             config_path = bt_config_map[serial]["config_path"]
     94             if not os.path.isfile(config_path):
     95                 config_path = os.path.join(
     96                     self.user_params[Config.key_config_path], config_path)
     97                 if not os.path.isfile(config_path):
     98                     self.log.error("Unable to load bt_config file {}.".format(
     99                         config_path))
    100                     return False
    101             ad.adb.push("{} {}".format(config_path, bt_conf_path))
    102 
    103             # Add music to the Android device
    104             self.log.info("Pushing music to the Android device.")
    105             music_path_str = "music_path"
    106             android_music_path = "/sdcard/Music/"
    107             if music_path_str not in self.user_params:
    108                 self.log.error("Need music for audio testcases...")
    109                 return False
    110 
    111             music_path = self.user_params[music_path_str]
    112             if not os.path.isdir(music_path):
    113                 music_path = os.path.join(
    114                     self.user_params[Config.key_config_path], music_path)
    115                 if not os.path.isdir(music_path):
    116                     self.log.error("Unable to find music directory {}.".format(
    117                         music_path))
    118                     return False
    119             self._add_music_to_primary_android_device(ad, music_path,
    120                                                       android_music_path)
    121             ad.reboot()
    122 
    123             # Verify Bluetooth is enabled
    124             self.log.info("Verifying Bluetooth is enabled on Android Device.")
    125             if not bluetooth_enabled_check(ad):
    126                 self.log.error("Failed to toggle on Bluetooth on device {}".
    127                                format(serial))
    128                 return False
    129 
    130             # Verify Bluetooth device is connected
    131             self.log.info(
    132                 "Waiting up to 10 seconds for device to reconnect...")
    133             connected_devices = ad.droid.bluetoothGetConnectedDevices()
    134             start_time = time.time()
    135             wait_time = 10
    136             result = False
    137             while time.time() < start_time + wait_time:
    138                 connected_devices = ad.droid.bluetoothGetConnectedDevices()
    139                 if len(connected_devices) > 0:
    140                     if bt_config_map[serial]["peripheral_info"]["address"] in {
    141                             d['address']
    142                             for d in connected_devices
    143                     }:
    144                         result = True
    145                         break
    146                 else:
    147                     try:
    148                         ad.droid.bluetoothConnectBonded(bt_config_map[serial][
    149                             "peripheral_info"]["address"])
    150                     except Exception as err:
    151                         self.log.error(
    152                             "Failed to connect bonded. Err: {}".format(err))
    153             if not result:
    154                 self.log.info("Connected Devices: {}".format(
    155                     connected_devices))
    156                 self.log.info("Bonded Devices: {}".format(
    157                     ad.droid.bluetoothGetBondedDevices()))
    158                 self.log.error(
    159                     "Failed to connect to peripheral name: {}, address: {}".
    160                     format(bt_config_map[serial]["peripheral_info"]["name"],
    161                            bt_config_map[serial]["peripheral_info"][
    162                                "address"]))
    163                 self.device_fails_to_connect_list.append("{}:{}".format(
    164                     serial, bt_config_map[serial]["peripheral_info"]["name"]))
    165         if len(self.device_fails_to_connect_list) == len(self.android_devices):
    166             self.log.error("All devices failed to reconnect.")
    167             return False
    168         return True
    169 
    170     def _add_music_to_primary_android_device(self, ad, music_path,
    171                                              android_music_path):
    172         for dirname, dirnames, filenames in os.walk(music_path):
    173             for filename in filenames:
    174                 self.music_file_to_play = filename
    175                 file = os.path.join(dirname, filename)
    176                 #TODO: Handle file paths with spaces
    177                 ad.adb.push("{} {}".format(file, android_music_path))
    178         return True
    179 
    180     def _collect_bluetooth_manager_dumpsys_logs(self, ads):
    181         for ad in ads:
    182             serial = ad.serial
    183             out_name = "{}_{}".format(serial, "bluetooth_dumpsys.txt")
    184             dumpsys_path = ''.join((ad.log_path, "/BluetoothDumpsys"))
    185             create_dir(dumpsys_path)
    186             cmd = ''.join(
    187                 ("adb -s ", serial, " shell dumpsys bluetooth_manager > ",
    188                  dumpsys_path, "/", out_name))
    189             exe_cmd(cmd)
    190 
    191     @BluetoothBaseTest.bt_test_wrap
    192     def test_run_bt_audio_12_hours(self):
    193         """Test audio quality over 12 hours.
    194 
    195         This test is designed to run Bluetooth audio for 12 hours
    196         and collect relavant logs. If all devices disconnect during
    197         the test or Bluetooth is off on all devices, then fail the
    198         test.
    199 
    200         Steps:
    201         1. For each Android device connected run steps 2-5.
    202         2. Open and play media file of music pushed to device
    203         3. Set media to loop indefintely.
    204         4. After 12 hours collect bluetooth_manager dumpsys information
    205         5. Stop media player
    206 
    207         Expected Result:
    208         Audio plays for 12 hours over Bluetooth
    209 
    210         Returns:
    211           Pass if True
    212           Fail if False
    213 
    214         TAGS: Classic, A2DP
    215         Priority: 1
    216         """
    217         for ad in self.android_devices:
    218             ad.droid.mediaPlayOpen("file:///sdcard/Music/{}".format(
    219                 self.music_file_to_play))
    220             ad.droid.mediaPlaySetLooping(True)
    221             self.log.info("Music is now playing on device {}".format(
    222                 ad.serial))
    223 
    224         sleep_interval = 120
    225         twelve_hours_in_seconds = 43200
    226         end_time = time.time() + twelve_hours_in_seconds
    227         test_result = True
    228         bluetooth_off_list = []
    229         device_not_connected_list = []
    230         while time.time() < end_time:
    231             for ad in self.android_devices:
    232                 serial = ad.serial
    233                 if (not ad.droid.bluetoothCheckState() and
    234                         serial not in bluetooth_off_list):
    235                     self.log.error(
    236                         "Device {}'s Bluetooth state is off.".format(serial))
    237                     bluetooth_off_list.append(serial)
    238                 if (ad.droid.bluetoothGetConnectedDevices() == 0 and
    239                         serial not in device_not_connected_list):
    240                     self.log.error(
    241                         "Device {} not connected to any Bluetooth devices.".
    242                         format(serial))
    243                     device_not_connected_list.append(serial)
    244                 if len(bluetooth_off_list) == len(self.android_devices):
    245                     self.log.error(
    246                         "Bluetooth off on all Android devices. Ending Test")
    247                     return False
    248                 if len(device_not_connected_list) == len(self.android_devices):
    249                     self.log.error(
    250                         "Every Android device has no device connected.")
    251                     return False
    252             time.sleep(sleep_interval)
    253 
    254         self._collect_bluetooth_manager_dumpsys_logs(self.android_devices)
    255         for ad in self.android_devices:
    256             ad.droid.mediaPlayStopAll()
    257         if len(device_not_connected_list) > 0 or len(bluetooth_off_list) > 0:
    258             self.log.info("Devices reported as not connected: {}".format(
    259                 device_not_connected_list))
    260             self.log.info("Devices reported with Bluetooth state off: {}".
    261                           format(bluetooth_off_list))
    262             return False
    263         return True
    264 
    265     def test_setup_fail_if_devices_not_connected(self):
    266         """Test for devices connected or not during setup.
    267 
    268         This test is designed to fail if the number of devices having
    269         connection issues at time of setup is greater than 0. This lets
    270         the test runner know of the stability of the testbed.
    271 
    272         Steps:
    273         1. Check lenght of self.device_fails_to_connect_list
    274 
    275         Expected Result:
    276         No device should be in a disconnected state.
    277 
    278         Returns:
    279           Pass if True
    280           Fail if False
    281 
    282         TAGS: None
    283         Priority: 1
    284         """
    285         if len(self.device_fails_to_connect_list) > 0:
    286             self.log.error("Devices failed to reconnect:\n{}".format(
    287                 self.device_fails_to_connect_list))
    288             return False
    289         return True
    290