desktopui_AudioFeedback.py revision 3ad68c37b8b52bcbeda37fea338d3f1122bdfe8e
1# Copyright (c) 2012 The Chromium 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 logging, tempfile 6 7from autotest_lib.client.bin import test 8from autotest_lib.client.common_lib import error 9from autotest_lib.client.cros import cros_ui_test, httpd 10from autotest_lib.client.cros.audio import audio_helper 11 12# Names of mixer controls. 13_CONTROL_MASTER = "'Master Playback Volume'" 14_CONTROL_HEADPHONE = "'Headphone Playback Volume'" 15_CONTROL_SPEAKER = "'Speaker Playback Volume'" 16_CONTROL_MIC_BOOST = "'Mic Boost Volume'" 17_CONTROL_MIC_CAPTURE = "'Mic Capture Volume'" 18_CONTROL_CAPTURE = "'Capture Volume'" 19_CONTROL_PCM = "'PCM Playback Volume'" 20_CONTROL_DIGITAL = "'Digital Capture Volume'" 21_CONTROL_CAPTURE_SWITCH = "'Capture Switch'" 22 23# Default test configuration. 24_DEFAULT_CARD = '0' 25_DEFAULT_MIXER_SETTINGS = [{'name': _CONTROL_MASTER, 'value': "100%"}, 26 {'name': _CONTROL_HEADPHONE, 'value': "100%"}, 27 {'name': _CONTROL_SPEAKER, 'value': "0%"}, 28 {'name': _CONTROL_MIC_BOOST, 'value': "50%"}, 29 {'name': _CONTROL_MIC_CAPTURE, 'value': "50%"}, 30 {'name': _CONTROL_PCM, 'value': "100%"}, 31 {'name': _CONTROL_DIGITAL, 'value': "100%"}, 32 {'name': _CONTROL_CAPTURE, 'value': "100%"}, 33 {'name': _CONTROL_CAPTURE_SWITCH, 'value': "on"}] 34 35_DEFAULT_NUM_CHANNELS = 2 36_DEFAULT_RECORD_DURATION = 15 37# Minimum RMS value to consider a "pass". 38_DEFAULT_SOX_RMS_THRESHOLD = 0.30 39 40 41class desktopui_AudioFeedback(cros_ui_test.UITest): 42 version = 1 43 44 def initialize(self, 45 card=_DEFAULT_CARD, 46 mixer_settings=_DEFAULT_MIXER_SETTINGS, 47 num_channels=_DEFAULT_NUM_CHANNELS, 48 record_duration=_DEFAULT_RECORD_DURATION, 49 sox_min_rms=_DEFAULT_SOX_RMS_THRESHOLD): 50 """Setup the deps for the test. 51 52 Args: 53 card: The index of the sound card to use. 54 mixer_settings: Alsa control settings to apply to the mixer before 55 starting the test. 56 num_channels: The number of channels on the device to test. 57 record_duration: How long of a sample to record. 58 sox_min_rms: The minimum RMS value to consider a pass. 59 60 Raises: 61 error.TestError if the deps can't be run. 62 """ 63 self._card = card 64 self._mixer_settings = mixer_settings 65 self._sox_min_rms = sox_min_rms 66 67 self._ah = audio_helper.AudioHelper(self, 68 record_duration=record_duration, 69 num_channels=num_channels) 70 self._ah.setup_deps(['sox']) 71 72 super(desktopui_AudioFeedback, self).initialize() 73 self._test_url = 'http://localhost:8000/youtube.html' 74 self._testServer = httpd.HTTPListener(8000, docroot=self.bindir) 75 self._testServer.run() 76 77 def run_once(self): 78 self._ah.set_mixer_controls(self._mixer_settings, self._card) 79 # Record a sample of "silence" to use as a noise profile. 80 with tempfile.NamedTemporaryFile(mode='w+t') as noise_file: 81 logging.info('Noise file: %s' % noise_file.name) 82 self._ah.record_sample(noise_file.name) 83 84 # Play the same video to test all channels. 85 self._ah.loopback_test_channels(noise_file, 86 lambda channel: self.play_video(), 87 self.check_recorded_audio) 88 89 def play_video(self): 90 """Plays a Youtube video to record audio samples. 91 92 Skipping initial 60 seconds so we can ignore initial silence 93 in the video. 94 """ 95 logging.info('Playing back youtube media file %s.' % self._test_url) 96 self.pyauto.NavigateToURL(self._test_url) 97 if not self.pyauto.WaitUntil(lambda: self.pyauto.ExecuteJavascript(""" 98 player_status = document.getElementById('player_status'); 99 window.domAutomationController.send(player_status.innerHTML); 100 """), expect_retval='player ready'): 101 raise error.TestError('Failed to load the Youtube player') 102 self.pyauto.ExecuteJavascript(""" 103 ytplayer.pauseVideo(); 104 ytplayer.seekTo(60, true); 105 ytplayer.playVideo(); 106 window.domAutomationController.send(''); 107 """) 108 109 def check_recorded_audio(self, rms_val, unused_media_file): 110 """Checks if the calculated RMS value is expected. 111 112 Args: 113 rms_val: The calculated RMS value. 114 unused_media_file: This value is unused in this function. 115 116 Raises: 117 error.TestFail if the RMS amplitude of the recording isn't above 118 the threshold. 119 """ 120 # In case sox didn't return an RMS value. 121 if rms_val is None: 122 raise error.TestError( 123 'Failed to generate an audio RMS value from playback.') 124 125 logging.info('Got audio RMS value of %f. Minimum pass is %f.' % 126 (rms_val, self._sox_min_rms)) 127 if rms_val < self._sox_min_rms: 128 raise error.TestError( 129 'Audio RMS value %f too low. Minimum pass is %f.' % 130 (rms_val, self._sox_min_rms)) 131