Home | History | Annotate | Download | only in audio_LeftRightInternalSpeaker
      1 # Copyright 2016 The Chromium OS Authors. All rights reserved.
      2 # Copyright 2016 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 
      6 """This is a server side internal speaker test using the Chameleon board,
      7 audio board and the audio box enclosure for sound isolation."""
      8 
      9 import logging
     10 import os
     11 import time
     12 
     13 from autotest_lib.server.cros.audio import audio_test
     14 from autotest_lib.client.cros.audio import audio_test_data
     15 from autotest_lib.client.cros.chameleon import audio_test_utils
     16 from autotest_lib.client.cros.chameleon import chameleon_audio_helper
     17 from autotest_lib.client.cros.chameleon import chameleon_audio_ids
     18 from autotest_lib.client.common_lib import error
     19 from autotest_lib.server.cros.multimedia import remote_facade_factory
     20 
     21 
     22 class audio_LeftRightInternalSpeaker(audio_test.AudioTest):
     23     """Server side left/right internal speaker audio test.
     24 
     25     This test verifies:
     26     1. When a file with audio on the left channel is played, that a sound is
     27        emitted from at least one speaker.
     28     2. When a file with audio on the right channel is played, that a sound
     29        is emitted from at least one speaker.
     30 
     31     This test cannot verify:
     32     1. If the speaker making the sound is not the one corresponding to the
     33        channel the audio was embedded in in the file.
     34 
     35     """
     36     version = 1
     37     DELAY_BEFORE_RECORD_SECONDS = 0.5
     38     DELAY_AFTER_BINDING = 0.5
     39     RECORD_SECONDS = 8
     40     RIGHT_WAV_FILE_URL = (
     41         'http://commondatastorage.googleapis.com/chromiumos-test-assets-'
     42         'public/audio_test/chameleon/Speaker/right_440_half.wav')
     43     LEFT_WAV_FILE_URL = (
     44         'http://commondatastorage.googleapis.com/chromiumos-test-assets-'
     45         'public/audio_test/chameleon/Speaker/left_440_half.wav')
     46 
     47     def run_once(self, host, player):
     48         """
     49 
     50         Entry point for test case.
     51 
     52         @param host: A reference to the DUT.
     53         @param player: A string representing what audio player to use. Could
     54                        be 'native' or 'browser'.
     55 
     56         """
     57 
     58         if not audio_test_utils.has_internal_speaker(host):
     59             return
     60 
     61         host.chameleon.setup_and_reset(self.outputdir)
     62 
     63         facade_factory = remote_facade_factory.RemoteFacadeFactory(
     64             host,
     65             results_dir=self.resultsdir)
     66         self.audio_facade = facade_factory.create_audio_facade()
     67         self.browser_facade = facade_factory.create_browser_facade()
     68 
     69         widget_factory = chameleon_audio_helper.AudioWidgetFactory(
     70             facade_factory,
     71             host)
     72         self.sound_source = widget_factory.create_widget(
     73             chameleon_audio_ids.CrosIds.SPEAKER)
     74         self.sound_recorder = widget_factory.create_widget(
     75             chameleon_audio_ids.ChameleonIds.MIC)
     76 
     77         self.play_and_record(
     78             host,
     79             player,
     80             'left')
     81         self.process_and_save_data(channel='left')
     82         self.validate_recorded_data(channel='left')
     83 
     84         self.play_and_record(
     85             host,
     86             player,
     87             'right')
     88         self.process_and_save_data(channel='right')
     89         self.validate_recorded_data(channel='right')
     90 
     91 
     92     def play_and_record(self, host, player, channel):
     93         """Play file using given details and record playback.
     94 
     95         The recording is accessible through the recorder object and doesn't
     96         need to be returned explicitly.
     97 
     98         @param host: The DUT.
     99         @param player: String name of audio player we intend to use.
    100         @param channel: Either 'left' or 'right'
    101 
    102         """
    103 
    104         #audio_facade = factory.create_audio_facade()
    105         audio_test_utils.dump_cros_audio_logs(
    106             host, self.audio_facade, self.resultsdir,
    107             'before_recording_' + channel)
    108 
    109         # Verify that output node is correct.
    110         output_nodes, _ = self.audio_facade.get_selected_node_types()
    111         if output_nodes != ['INTERNAL_SPEAKER']:
    112             raise error.TestFail(
    113                 '%s rather than internal speaker is selected on Cros '
    114                 'device' % output_nodes)
    115         self.audio_facade.set_selected_output_volume(80)
    116 
    117         if player == 'native':
    118             data_format=dict(file_type='raw',
    119                              sample_format='S16_LE',
    120                              channel=2,
    121                              rate=48000)
    122             if channel == 'left':
    123                 frequencies = [440, 0]
    124             else:
    125                 frequencies = [0, 440]
    126             sound_file = audio_test_data.GenerateAudioTestData(
    127                     data_format=data_format,
    128                     path=os.path.join(self.bindir, '440_half.raw'),
    129                     duration_secs=10,
    130                     frequencies=frequencies)
    131 
    132             logging.info('Going to use cras_test_client on CrOS')
    133             logging.info('Playing the file %s', sound_file)
    134             self.sound_source.set_playback_data(sound_file)
    135             self.sound_source.start_playback()
    136             time.sleep(self.DELAY_BEFORE_RECORD_SECONDS)
    137             self.sound_recorder.start_recording()
    138             time.sleep(self.RECORD_SECONDS)
    139             self.sound_recorder.stop_recording()
    140             self.sound_source.stop_playback()
    141             sound_file.delete()
    142             logging.info('Recording finished. Was done in format %s',
    143                          self.sound_recorder.data_format)
    144 
    145         elif player == 'browser':
    146             if channel == 'left':
    147                 sound_file = self.LEFT_WAV_FILE_URL
    148             else:
    149                 sound_file = self.RIGHT_WAV_FILE_URL
    150 
    151             tab_descriptor = self.browser_facade.new_tab(sound_file)
    152 
    153             time.sleep(self.DELAY_BEFORE_RECORD_SECONDS)
    154             logging.info('Start recording from Chameleon.')
    155             self.sound_recorder.start_recording()
    156 
    157             time.sleep(self.RECORD_SECONDS)
    158 
    159             self.sound_recorder.stop_recording()
    160             logging.info('Stopped recording from Chameleon.')
    161             self.browser_facade.close_tab(tab_descriptor)
    162 
    163         else:
    164             raise error.TestFail(
    165                 '%s is not in list of accepted audio players',
    166                 player)
    167 
    168         audio_test_utils.dump_cros_audio_logs(
    169             host, self.audio_facade, self.resultsdir,
    170             'after_recording_' + channel)
    171 
    172 
    173     def process_and_save_data(self, channel):
    174         """Save recorded data to files and process for analysis.
    175 
    176         @param channel: 'left' or 'right'.
    177 
    178         """
    179 
    180         self.sound_recorder.read_recorded_binary()
    181         file_name = 'recorded_' + channel + '.raw'
    182         unprocessed_file = os.path.join(self.resultsdir, file_name)
    183         logging.info('Saving raw unprocessed output to %s', unprocessed_file)
    184         self.sound_recorder.save_file(unprocessed_file)
    185 
    186         # Removes the beginning of recorded data. This is to avoid artifact
    187         # caused by Chameleon codec initialization in the beginning of
    188         # recording.
    189         self.sound_recorder.remove_head(1.0)
    190 
    191         # Reduce noise
    192         self.sound_recorder.lowpass_filter(1000)
    193         file_name = 'recorded_filtered_' + channel + '.raw'
    194         processsed_file = os.path.join(self.resultsdir, file_name)
    195         logging.info('Saving processed sound output to %s', processsed_file)
    196         self.sound_recorder.save_file(processsed_file)
    197 
    198 
    199     def validate_recorded_data(self, channel):
    200         """Read processed data and validate by comparing to golden file.
    201 
    202         @param channel: 'left' or 'right'.
    203 
    204         """
    205 
    206         # Compares data by frequency. Audio signal recorded by microphone has
    207         # gone through analog processing and through the air.
    208         # This suffers from codec artifacts and noise on the path.
    209         # Comparing data by frequency is more robust than comparing by
    210         # correlation, which is suitable for fully-digital audio path like USB
    211         # and HDMI.
    212         logging.info('Validating recorded output for channel %s', channel)
    213         audio_test_utils.check_recorded_frequency(
    214             audio_test_data.SIMPLE_FREQUENCY_SPEAKER_TEST_FILE,
    215             self.sound_recorder,
    216             second_peak_ratio=0.1,
    217             ignore_frequencies=[50, 60])
    218