• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 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
5"""This is a server side audio volume 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.chameleon import audio_test_utils
13from autotest_lib.client.cros.chameleon import chameleon_audio_ids
14from autotest_lib.client.cros.chameleon import chameleon_audio_helper
15from autotest_lib.server.cros.audio import audio_test
16from autotest_lib.server.cros.multimedia import remote_facade_factory
17
18
19class audio_AudioVolume(audio_test.AudioTest):
20    """Server side audio volume test.
21
22    This test talks to a Chameleon board and a Cros device to verify
23    audio volume function of the Cros device.
24
25    """
26    version = 1
27    RECORD_SECONDS = 5
28    DELAY_AFTER_BINDING = 0.5
29
30    def run_once(self, host, source_id, sink_id, recorder_id, volume_spec,
31                 golden_file, switch_hsp=False):
32        """Running audio volume test.
33
34        @param host: device under test CrosHost
35        @param source_id: An ID defined in chameleon_audio_ids for source.
36        @param sink_id: An ID defined in chameleon_audio_ids for sink if needed.
37                        Currently this is only used on bluetooth.
38        @param recorder: An ID defined in chameleon_audio_ids for recording.
39        @param volume_spec: A tuple (low_volume, high_volume, highest_ratio).
40                            Low volume and high volume specifies the two volumes
41                            used in the test, and highest_ratio speficies the
42                            highest acceptable value for
43                            recorded_volume_low / recorded_volume_high.
44                            For example, (50, 100, 0.2) asserts that
45                            (recorded magnitude at volume 50) should be lower
46                            than (recorded magnitude at volume 100) * 0.2.
47        @param golden_file: A test file defined in audio_test_data.
48        @param switch_hsp: Run a recording process on Cros device. This is
49                           to trigger Cros switching from A2DP to HSP.
50
51        """
52        if (source_id == chameleon_audio_ids.CrosIds.SPEAKER and
53            not audio_test_utils.has_internal_speaker(host)):
54            return
55
56        chameleon_board = host.chameleon
57        factory = remote_facade_factory.RemoteFacadeFactory(
58                host, results_dir=self.resultsdir)
59
60        chameleon_board.setup_and_reset(self.outputdir)
61
62        widget_factory = chameleon_audio_helper.AudioWidgetFactory(
63                factory, host)
64
65        source = widget_factory.create_widget(source_id)
66        recorder = widget_factory.create_widget(recorder_id)
67
68        # Chameleon Mic does not need binding.
69        binding = (recorder_id != chameleon_audio_ids.ChameleonIds.MIC)
70
71        binder = None
72
73        if binding:
74            if sink_id:
75                sink = widget_factory.create_widget(sink_id)
76                binder = widget_factory.create_binder(source, sink, recorder)
77            else:
78                binder = widget_factory.create_binder(source, recorder)
79
80        low_volume, high_volume, highest_ratio = volume_spec
81        ignore_frequencies = [50, 60]
82
83        second_peak_ratio = audio_test_utils.get_second_peak_ratio(
84                source_id=source_id,
85                recorder_id=recorder_id,
86                is_hsp=switch_hsp)
87
88        with chameleon_audio_helper.bind_widgets(binder):
89            # Checks the node selected by cras is correct.
90            time.sleep(self.DELAY_AFTER_BINDING)
91            audio_facade = factory.create_audio_facade()
92
93            audio_test_utils.dump_cros_audio_logs(
94                    host, audio_facade, self.resultsdir, 'after_binding')
95
96            audio_test_utils.check_output_port(audio_facade, source.port_id)
97
98            if switch_hsp:
99                audio_test_utils.switch_to_hsp(audio_facade)
100
101            logging.info('Setting playback data on Cros device')
102            source.set_playback_data(golden_file)
103
104            def playback_record(tag):
105                """Playback and record.
106
107                @param tag: file name tag.
108
109                """
110                logging.info('Start recording from Chameleon.')
111                recorder.start_recording()
112
113                logging.info('Start playing %s on Cros device',
114                             golden_file.path)
115                source.start_playback()
116
117                time.sleep(self.RECORD_SECONDS)
118
119                recorder.stop_recording()
120                logging.info('Stopped recording from Chameleon.')
121
122                audio_test_utils.dump_cros_audio_logs(
123                        host, audio_facade, self.resultsdir,
124                        'after_recording_' + 'tag')
125
126                source.stop_playback()
127
128                recorder.read_recorded_binary()
129                logging.info('Read recorded binary from Chameleon.')
130
131                recorded_file = os.path.join(
132                        self.resultsdir, "recorded_%s.raw" % tag)
133                logging.info('Saving recorded data to %s', recorded_file)
134                recorder.save_file(recorded_file)
135                recorder.remove_head(0.5)
136
137            audio_facade.set_chrome_active_volume(low_volume)
138            playback_record('low')
139            low_dominant_spectrals = audio_test_utils.check_recorded_frequency(
140                    golden_file, recorder,
141                    second_peak_ratio=second_peak_ratio,
142                    ignore_frequencies=ignore_frequencies)
143
144            audio_facade.set_chrome_active_volume(high_volume)
145            playback_record('high')
146            high_dominant_spectrals = audio_test_utils.check_recorded_frequency(
147                    golden_file, recorder,
148                    second_peak_ratio=second_peak_ratio,
149                    ignore_frequencies=ignore_frequencies)
150
151            error_messages = []
152            logging.info('low_dominant_spectrals: %s', low_dominant_spectrals)
153            logging.info('high_dominant_spectrals: %s', high_dominant_spectrals)
154
155            for channel in xrange(len(low_dominant_spectrals)):
156                _, low_coeff  = low_dominant_spectrals[channel]
157                _, high_coeff  = high_dominant_spectrals[channel]
158                ratio = low_coeff / high_coeff
159                logging.info('Channel %d volume(at %f) / volume(at %f) = %f',
160                             channel, low_volume, high_volume, ratio)
161                if ratio > highest_ratio:
162                    error_messages.append(
163                            'Channel %d volume ratio: %f is incorrect.' % (
164                                    channel, ratio))
165            if error_messages:
166                raise error.TestFail(
167                        'Failed volume check: %s' % ' '.join(error_messages))
168