| # Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import os |
| import logging |
| import time |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.common_lib.cros import chrome |
| from autotest_lib.client.cros.a11y import a11y_test_base |
| from autotest_lib.client.cros.audio import cras_utils |
| from autotest_lib.client.cros.audio import sox_utils |
| |
| |
| class accessibility_ChromeVoxSound(a11y_test_base.a11y_test_base): |
| """Check whether ChromeVox makes noise on real hardware.""" |
| version = 1 |
| |
| _audio_chunk_size = 1 # Length of chunk size in seconds. |
| _detect_time = 40 # Max length of time to spend detecting audio in seconds. |
| |
| |
| def _detect_audio(self, name, min_time, max_time): |
| """Detects whether audio was heard and returns the approximate time. |
| |
| Runs for at most self._detect_time, checking each chunk for sound. |
| After first detecting a chunk that has audio, counts the subsequent |
| chunks that also do. |
| |
| Finally, check whether the found audio matches the expected length. |
| |
| @param name: a string representing which sound is expected. |
| @param min_time: the minimum allowed sound length in seconds. |
| @param max_time: the maximum allowed sound length in seconds. |
| |
| @raises: error.TestFail if the observed behavior doesn't match |
| expected: either no sound or sound of bad length. |
| |
| """ |
| count = 0 |
| counting = False |
| |
| for i in xrange(self._detect_time / self._audio_chunk_size): |
| rms = self._rms_of_next_audio_chunk() |
| if rms > 0: |
| logging.info('Found passing chunk: %d.', i) |
| if not counting: |
| start_time = time.time() |
| counting = True |
| count += 1 |
| elif counting: |
| audio_length = time.time() - start_time |
| break |
| if not counting: |
| raise error.TestFail('No audio for %s was found!' % name) |
| |
| logging.info('Time taken - %s: %f', name, audio_length) |
| if audio_length < min_time: |
| raise error.TestFail( |
| '%s audio was only %f seconds long!' % (name, audio_length)) |
| elif audio_length > max_time: |
| raise error.TestFail( |
| '%s audio was too long: %f seconds!' % (name, audio_length)) |
| return |
| |
| |
| def _rms_of_next_audio_chunk(self): |
| """Finds the sox_stats values of the next chunk of audio.""" |
| cras_utils.loopback(self._loopback_file, channels=1, |
| duration=self._audio_chunk_size) |
| stat_output = sox_utils.get_stat(self._loopback_file) |
| logging.info(stat_output) |
| return vars(stat_output)['rms'] |
| |
| |
| def _check_chromevox_sound(self, cr): |
| """Test contents. |
| |
| Enable ChromeVox, navigate to a new page, and open a new tab. Check |
| the audio output at each point. |
| |
| @param cr: the chrome.Chrome() object |
| |
| """ |
| chromevox_start_time = time.time() |
| self._toggle_chromevox() |
| self._confirm_chromevox_state(True) |
| |
| # TODO: this sound doesn't play for Telemetry user. crbug.com/590403 |
| # Welcome ding |
| # self._detect_audio('enable ChromeVox ding', 1, 2) |
| |
| # "ChromeVox Spoken Feedback is ready!" |
| self._detect_audio('welcome message', 2, 6) |
| chromevox_open_time = time.time() - chromevox_start_time |
| logging.info('ChromeVox took %f seconds to start.') |
| |
| # Page navigation sound. |
| cr.browser.tabs[0].Navigate('chrome://version') |
| self._detect_audio('page navigation sound', 2, 6) |
| |
| # New tab sound |
| tab = cr.browser.tabs.New() |
| self._detect_audio('new tab ding', 2, 6) |
| |
| |
| def run_once(self): |
| """Entry point of this test.""" |
| self._loopback_file = os.path.join(self.bindir, 'cras_loopback.wav') |
| extension_path = self._get_extension_path() |
| |
| with chrome.Chrome(extension_paths=[extension_path], |
| is_component=False) as cr: |
| self._extension = cr.get_extension(extension_path) |
| cr.browser.tabs[0].WaitForDocumentReadyStateToBeComplete() |
| self._confirm_chromevox_state(False) |
| self._check_chromevox_sound(cr) |
| |
| |
| def _child_test_cleanup(self): |
| try: |
| os.remove(self._loopback_file) |
| except OSError: |
| pass |