desktopui_AudioFeedback.py revision 78c44b20a094313d388a2f12536384178b2c339f
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
6
7from autotest_lib.client.common_lib import error
8from autotest_lib.client.cros import cros_ui_test, httpd
9from autotest_lib.client.cros.audio import audio_helper
10
11# Names of mixer controls.
12_CONTROL_MASTER = "'Master Playback Volume'"
13_CONTROL_HEADPHONE = "'Headphone Playback Volume'"
14_CONTROL_SPEAKER = "'Speaker Playback Volume'"
15_CONTROL_MIC_BOOST = "'Mic Boost Volume'"
16_CONTROL_MIC_CAPTURE = "'Mic Capture Volume'"
17_CONTROL_CAPTURE = "'Capture Volume'"
18_CONTROL_PCM = "'PCM Playback Volume'"
19_CONTROL_DIGITAL = "'Digital Capture Volume'"
20_CONTROL_CAPTURE_SWITCH = "'Capture Switch'"
21
22# Default test configuration.
23_DEFAULT_CARD = '0'
24_DEFAULT_MIXER_SETTINGS = [{'name': _CONTROL_MASTER, 'value': "100%"},
25                           {'name': _CONTROL_HEADPHONE, 'value': "100%"},
26                           {'name': _CONTROL_SPEAKER, 'value': "0%"},
27                           {'name': _CONTROL_MIC_BOOST, 'value': "50%"},
28                           {'name': _CONTROL_MIC_CAPTURE, 'value': "50%"},
29                           {'name': _CONTROL_PCM, 'value': "100%"},
30                           {'name': _CONTROL_DIGITAL, 'value': "100%"},
31                           {'name': _CONTROL_CAPTURE, 'value': "100%"},
32                           {'name': _CONTROL_CAPTURE_SWITCH, 'value': "on"}]
33
34_DEFAULT_NUM_CHANNELS = 2
35_DEFAULT_RECORD_DURATION = 15
36# Minimum RMS value to consider a "pass".
37_DEFAULT_SOX_RMS_THRESHOLD = 0.25
38_DEFAULT_VOLUME_LEVEL = 100
39_DEFAULT_CAPTURE_GAIN = 2500
40
41
42class desktopui_AudioFeedback(cros_ui_test.UITest):
43    """Verifies if youtube playback can be captured."""
44    version = 1
45
46    def initialize(self,
47                   card=_DEFAULT_CARD,
48                   mixer_settings=_DEFAULT_MIXER_SETTINGS,
49                   num_channels=_DEFAULT_NUM_CHANNELS,
50                   record_duration=_DEFAULT_RECORD_DURATION,
51                   sox_min_rms=_DEFAULT_SOX_RMS_THRESHOLD,
52                   volume_level=_DEFAULT_VOLUME_LEVEL,
53                   capture_gain=_DEFAULT_CAPTURE_GAIN):
54        """Setup the deps for the test.
55
56        Args:
57            card: The index of the sound card to use.
58            mixer_settings: Alsa control settings to apply to the mixer before
59                starting the test.
60            num_channels: The number of channels on the device to test.
61            record_duration: How long of a sample to record.
62            sox_min_rms: The minimum RMS value to consider a pass.
63
64        Raises:
65            error.TestError if the deps can't be run.
66        """
67        self._card = card
68        self._mixer_settings = mixer_settings
69        self._volume_level = volume_level
70        self._capture_gain = capture_gain
71
72        cmd_rec = 'arecord -d %f -f dat' % record_duration
73        self._ah = audio_helper.AudioHelper(self,
74                record_command=cmd_rec,
75                sox_threshold=sox_min_rms,
76                num_channels=num_channels)
77        self._ah.setup_deps(['audioloop', 'sox'])
78
79        super(desktopui_AudioFeedback, self).initialize()
80        self._test_url = 'http://localhost:8000/youtube.html'
81        self._testServer = httpd.HTTPListener(8000, docroot=self.bindir)
82        self._testServer.run()
83
84    def run_once(self):
85        """Entry point of this test."""
86        self._ah.set_volume_levels(self._volume_level, self._capture_gain)
87        if not self._ah.check_loopback_dongle():
88            raise error.TestError('Audio loopback dongle is in bad state.')
89
90        # Record a sample of "silence" to use as a noise profile.
91        noise_file_name = self._ah.create_wav_file("noise")
92        self._ah.record_sample(noise_file_name)
93
94        # Play the same video to test all channels.
95        self.play_video(lambda: self._ah.loopback_test_channels(
96                noise_file_name))
97
98    def play_video(self, player_ready_callback):
99        """Plays a Youtube video to record audio samples.
100
101           Skipping initial 60 seconds so we can ignore initial silence
102           in the video.
103
104           @param player_ready_callback: callback when yt player is ready.
105        """
106        logging.info('Playing back youtube media file %s.', self._test_url)
107        self.pyauto.NavigateToURL(self._test_url)
108
109        # Default automation timeout is 45 seconds.
110        if not self.pyauto.WaitUntil(lambda: self.pyauto.ExecuteJavascript("""
111                    player_status = document.getElementById('player_status');
112                    window.domAutomationController.send(player_status.innerHTML);
113               """), expect_retval='player ready'):
114            raise error.TestError('Failed to load the Youtube player')
115        self.pyauto.ExecuteJavascript("""
116            ytplayer.pauseVideo();
117            ytplayer.seekTo(60, true);
118            ytplayer.playVideo();
119            window.domAutomationController.send('');
120        """)
121        if player_ready_callback:
122            player_ready_callback()
123