1# Copyright (c) 2012 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 logging
6import os
7import tempfile
8
9from autotest_lib.client.bin import utils
10from autotest_lib.client.common_lib import error
11from autotest_lib.client.cros.audio import audio_helper
12from autotest_lib.client.cros.audio import cmd_utils
13from autotest_lib.client.cros.audio import cras_utils
14from autotest_lib.client.cros.audio import sox_utils
15
16
17class desktopui_MediaAudioFeedback(audio_helper.chrome_rms_test):
18    """Verifies if media playback can be captured."""
19
20    version = 1
21
22    def run_once(self, test_files, test_duration):
23        self._rms_values = {}
24        noise_file = os.path.join(self.resultsdir, 'noise.wav')
25        noiseprof_file = tempfile.NamedTemporaryFile()
26
27        # Record a sample of "silence" to use as a noise profile.
28        cras_utils.capture(noise_file, duration=2)
29        sox_utils.noise_profile(noise_file, noiseprof_file.name)
30
31        # Open the test page
32        self.chrome.browser.platform.SetHTTPServerDirectories(self.bindir)
33        tab = self.chrome.browser.tabs[0]
34        tab.Navigate(self.chrome.browser.platform.http_server.UrlOf(
35                os.path.join(self.bindir, 'play.html')))
36        tab.WaitForDocumentReadyStateToBeComplete()
37
38        # Test each media file for all channels.
39        for media_file in test_files:
40            self.rms_test(tab, media_file, noiseprof_file.name, test_duration)
41        self.write_perf_keyval(self._rms_values)
42
43
44    def rms_test(self, tab, media_file, noiseprof_file, test_duration):
45        logging.info('rms test on media file %s.', media_file)
46        recorded_file = os.path.join(self.resultsdir, 'recorded.wav')
47        loopback_file = os.path.join(self.resultsdir, 'loopback.wav')
48
49        # Plays the media_file in the browser.
50        self.play_media(tab, media_file)
51
52        # Record the audio output and also the CRAS loopback output.
53        p1 = cmd_utils.popen(cras_utils.capture_cmd(
54                recorded_file, duration=test_duration))
55        p2 = cmd_utils.popen(cras_utils.loopback_cmd(
56                loopback_file, duration=test_duration))
57        cmd_utils.wait_and_check_returncode(p1, p2)
58
59        # See if we recorded something.
60
61        # We captured two channels of audio in the CRAS loopback.
62        # The RMS values are for debugging only.
63        loopback_stats = [audio_helper.get_channel_sox_stat(
64                loopback_file, i) for i in (1, 2)]
65        logging.info('loopback stats: %s', [str(s) for s in loopback_stats])
66
67        reduced_file = tempfile.NamedTemporaryFile()
68        sox_utils.noise_reduce(
69                recorded_file, reduced_file.name, noiseprof_file)
70        rms = audio_helper.get_rms(reduced_file.name)[0]
71
72        self._rms_values['%s_rms_value' % media_file.replace('.', '_')] = rms
73
74        # Make sure the audio can be played to the end.
75        self.wait_player_end(tab)
76
77
78    def wait_player_end(self, tab):
79        """Wait for player ends playing."""
80        utils.poll_for_condition(
81            condition=lambda: tab.EvaluateJavaScript('player.ended'),
82            exception=error.TestError('Player never end until timeout.'))
83
84
85    def play_media(self, tab, media_file):
86        """Plays a media file in Chromium.
87
88        @param media_file: Media file to test.
89        """
90        tab.EvaluateJavaScript('play("%s")' % media_file)
91
92        def get_current_time():
93            return tab.EvaluateJavaScript('player.currentTime')
94
95        # Make sure the audio is being played
96        old_time = get_current_time()
97        utils.poll_for_condition(
98            condition=lambda: get_current_time() > old_time,
99            exception=error.TestError('Player never start until timeout.'))
100