Home | History | Annotate | Download | only in audio_AudioVolume
      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 
      7 import logging
      8 import os
      9 import time
     10 
     11 from autotest_lib.client.common_lib import error
     12 from autotest_lib.client.cros.chameleon import audio_test_utils
     13 from autotest_lib.client.cros.chameleon import chameleon_audio_ids
     14 from autotest_lib.client.cros.chameleon import chameleon_audio_helper
     15 from autotest_lib.server.cros.audio import audio_test
     16 from autotest_lib.server.cros.multimedia import remote_facade_factory
     17 
     18 
     19 class 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