1# Copyright (c) 2014 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 5import os 6import logging 7import time 8 9from autotest_lib.client.common_lib import error 10from autotest_lib.client.common_lib.cros import chrome 11from autotest_lib.client.cros.a11y import a11y_test_base 12from autotest_lib.client.cros.audio import cras_utils 13from autotest_lib.client.cros.audio import sox_utils 14 15 16class accessibility_ChromeVoxSound(a11y_test_base.a11y_test_base): 17 """Check whether ChromeVox makes noise on real hardware.""" 18 version = 1 19 20 _audio_chunk_size = 1 # Length of chunk size in seconds. 21 _detect_time = 40 # Max length of time to spend detecting audio in seconds. 22 23 24 def _detect_audio(self, name, min_time): 25 """Detects whether audio was heard and returns the approximate time. 26 27 Runs for at most self._detect_time, checking each chunk for sound. 28 After first detecting a chunk that has audio, counts the subsequent 29 chunks that also do. 30 31 Finally, check whether the found audio matches the expected length. 32 33 @param name: a string representing which sound is expected. 34 @param min_time: the minimum allowed sound length in seconds. 35 36 @raises: error.TestFail if the observed behavior doesn't match 37 expected: either no sound or sound of bad length. 38 39 """ 40 count = 0 41 counting = False 42 saw_sound_end = False 43 44 for i in xrange(self._detect_time / self._audio_chunk_size): 45 rms = self._rms_of_next_audio_chunk() 46 if rms > 0: 47 logging.info('Found passing chunk: %d.', i) 48 if not counting: 49 start_time = time.time() 50 counting = True 51 count += 1 52 elif counting: 53 audio_length = time.time() - start_time 54 saw_sound_end = True 55 break 56 if not counting: 57 raise error.TestFail('No audio for %s was found!' % name) 58 if not saw_sound_end: 59 raise error.TestFail('Audio for %s was more than % seconds!' % ( 60 name, self._detect_time)) 61 62 logging.info('Time taken - %s: %f', name, audio_length) 63 if audio_length < min_time: 64 raise error.TestFail( 65 '%s audio was only %f seconds long!' % (name, audio_length)) 66 return 67 68 69 def _rms_of_next_audio_chunk(self): 70 """Finds the sox_stats values of the next chunk of audio.""" 71 cras_utils.loopback(self._loopback_file, channels=1, 72 duration=self._audio_chunk_size) 73 stat_output = sox_utils.get_stat(self._loopback_file) 74 logging.info(stat_output) 75 return vars(stat_output)['rms'] 76 77 78 def _check_chromevox_sound(self, cr): 79 """Test contents. 80 81 Enable ChromeVox, navigate to a new page, and open a new tab. Check 82 the audio output at each point. 83 84 @param cr: the chrome.Chrome() object 85 86 """ 87 chromevox_start_time = time.time() 88 self._toggle_chromevox() 89 self._confirm_chromevox_state(True) 90 91 # TODO: this sound doesn't play for Telemetry user. crbug.com/590403 92 # Welcome ding 93 # self._detect_audio('enable ChromeVox ding', 1) 94 95 # "ChromeVox Spoken Feedback is ready!" 96 self._detect_audio('welcome message', 2) 97 chromevox_open_time = time.time() - chromevox_start_time 98 logging.info('ChromeVox took %f seconds to start.') 99 100 # New tab sound. 101 tab = cr.browser.tabs.New() 102 self._detect_audio('new tab ding', 2) 103 104 # Page navigation sound. 105 tab.Navigate('chrome://version') 106 self._detect_audio('page navigation sound', 2) 107 108 109 def run_once(self): 110 """Entry point of this test.""" 111 self._loopback_file = os.path.join(self.bindir, 'cras_loopback.wav') 112 extension_path = self._get_extension_path() 113 114 with chrome.Chrome(extension_paths=[extension_path]) as cr: 115 self._extension = cr.get_extension(extension_path) 116 cr.browser.tabs[0].WaitForDocumentReadyStateToBeComplete() 117 self._confirm_chromevox_state(False) 118 self._check_chromevox_sound(cr) 119 120 121 def _child_test_cleanup(self): 122 try: 123 os.remove(self._loopback_file) 124 except OSError: 125 pass 126