1# Lint as: python2, python3
2# Copyright 2015 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5"""This is a server side external microphone test using the Chameleon board."""
6
7import logging
8import os
9import time
10
11from autotest_lib.client.common_lib import error
12from autotest_lib.client.cros.audio import audio_test_data
13from autotest_lib.client.cros.chameleon import audio_test_utils
14from autotest_lib.client.cros.chameleon import chameleon_audio_ids
15from autotest_lib.client.cros.chameleon import chameleon_audio_helper
16from autotest_lib.server.cros.audio import audio_test
17
18
19class audio_AudioBasicExternalMicrophone(audio_test.AudioTest):
20    """Server side external microphone audio test.
21
22    This test talks to a Chameleon board and a Cros device to verify
23    external mic audio function of the Cros device.
24
25    """
26    version = 1
27    DELAY_BEFORE_RECORD_SECONDS = 0.5
28    RECORD_SECONDS = 9
29    DELAY_AFTER_BINDING = 0.5
30
31    def run_once(self, check_quality=False, blocked_boards=[]):
32        """Running basic headphone audio tests.
33
34        @param check_quality: flag to check audio quality.
35        @blocked_boards: boards to ignore and exit.
36
37        """
38        if self.host.get_board().split(':')[1] in blocked_boards:
39            raise error.TestNAError('Board NOT APPLICABLE to test!')
40        if not audio_test_utils.has_audio_jack(self.host):
41            raise error.TestNAError(
42                    'No audio jack for the DUT.'
43                    'Please check label of the host and control file.'
44                    'Please check the host label and test dependency.')
45
46        golden_file = audio_test_data.GenerateAudioTestData(
47                path=os.path.join(self.bindir, 'fix_1330_16.raw'),
48                duration_secs=10,
49                frequencies=[1330, 1330],
50                volume_scale=0.1)
51
52        source = self.widget_factory.create_widget(
53                chameleon_audio_ids.ChameleonIds.LINEOUT)
54        recorder = self.widget_factory.create_widget(
55                chameleon_audio_ids.CrosIds.EXTERNAL_MIC)
56        binder = self.widget_factory.create_binder(source, recorder)
57
58        with chameleon_audio_helper.bind_widgets(binder):
59            # Checks the node selected by cras is correct.
60            time.sleep(self.DELAY_AFTER_BINDING)
61
62            audio_test_utils.dump_cros_audio_logs(
63                    self.host, self.facade, self.resultsdir, 'after_binding')
64
65            # Selects and checks the node selected by cras is correct.
66            audio_test_utils.check_and_set_chrome_active_node_types(
67                    self.facade, None, 'MIC')
68
69            logging.info('Setting playback data on Chameleon')
70            source.set_playback_data(golden_file)
71
72            # Starts playing, waits for some time, and then starts recording.
73            # This is to avoid artifact caused by chameleon codec initialization
74            # in the beginning of playback.
75            logging.info('Start playing %s from Chameleon', golden_file.path)
76            source.start_playback()
77
78            time.sleep(self.DELAY_BEFORE_RECORD_SECONDS)
79            logging.info('Start recording from Cros device.')
80            recorder.start_recording()
81
82            time.sleep(self.RECORD_SECONDS)
83
84            recorder.stop_recording()
85            logging.info('Stopped recording from Cros device.')
86
87            audio_test_utils.dump_cros_audio_logs(
88                    self.host, self.facade, self.resultsdir, 'after_recording')
89
90            recorder.read_recorded_binary()
91            logging.info('Read recorded binary from Cros device.')
92
93        recorded_file = os.path.join(self.resultsdir, "recorded.raw")
94        logging.info('Saving recorded data to %s', recorded_file)
95        recorder.save_file(recorded_file)
96
97        # Removes the beginning of recorded data. This is to avoid artifact
98        # caused by Cros device codec initialization in the beginning of
99        # recording.
100        recorder.remove_head(4.5)
101
102        recorded_file = os.path.join(self.resultsdir, "recorded_clipped.raw")
103        logging.info('Saving clipped data to %s', recorded_file)
104        recorder.save_file(recorded_file)
105
106        # Compares data by frequency. Audio signal from Chameleon Line-Out to
107        # Cros device external microphone has gone through analog processing.
108        # This suffers from codec artifacts and noise on the path.
109        # Comparing data by frequency is more robust than comparing them by
110        # correlation, which is suitable for fully-digital audio path like USB
111        # and HDMI.
112        audio_test_utils.check_recorded_frequency(
113                golden_file,
114                recorder,
115                check_artifacts=check_quality,
116                ignore_frequencies=[50, 60])
117