Home | History | Annotate | Download | only in brillo_PlaybackAudioTest
      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 import logging
      6 import tempfile
      7 import time
      8 
      9 import common
     10 from autotest_lib.client.common_lib import error
     11 from autotest_lib.client.common_lib.feedback import client
     12 from autotest_lib.server import test
     13 from autotest_lib.server.brillo import audio_utils
     14 
     15 
     16 # The amount of time to wait when producing silence (i.e. no playback).
     17 _SILENCE_DURATION_SECS = 5
     18 
     19 # Number of channels to generate.
     20 _DEFAULT_NUM_CHANNELS = 1
     21 # Sine wave sample rate (48kHz).
     22 _DEFAULT_SAMPLE_RATE = 48000
     23 # Sine wave default sample format is signed 16-bit PCM (two bytes).
     24 _DEFAULT_SAMPLE_WIDTH = 2
     25 # Default sine wave frequency.
     26 _DEFAULT_SINE_FREQUENCY = 440
     27 # Default duration of the sine wave in seconds.
     28 _DEFAULT_DURATION_SECS = 10
     29 
     30 class brillo_PlaybackAudioTest(test.test):
     31     """Verify that basic audio playback works."""
     32     version = 1
     33 
     34     def __init__(self, *args, **kwargs):
     35         super(brillo_PlaybackAudioTest, self).__init__(*args, **kwargs)
     36         self.host = None
     37 
     38 
     39     def _get_playback_cmd(self, method, dut_play_file):
     40         """Get the playback command to execute based on the playback method.
     41 
     42         @param method: A string specifiying which method to use.
     43         @param dut_play_file: A string containing the path to the file to play
     44                               on the DUT.
     45         @return: A string containing the command to play audio using the
     46                  specified method.
     47 
     48         @raises TestError: Invalid playback method.
     49         """
     50         if dut_play_file:
     51             if method == 'libmedia':
     52                 return ('brillo_audio_test --playback --libmedia '
     53                         '--filename=%s' % dut_play_file)
     54             elif method == 'stagefright':
     55                 return ('brillo_audio_test --playback --stagefright '
     56                         '--filename=%s' % dut_play_file)
     57             elif method == 'opensles':
     58                 return 'slesTest_playFdPath %s 0' % dut_play_file
     59         else:
     60             if method == 'libmedia':
     61                 return 'brillo_audio_test --playback --libmedia --sine'
     62             elif method == 'stagefright':
     63                 return 'brillo_audio_test --playback --stagefright --sine'
     64             elif method == 'opensles':
     65                 return 'slesTest_sawtoothBufferQueue'
     66         raise error.TestError('Test called with invalid playback method.')
     67 
     68 
     69     def test_playback(self, fb_query, playback_cmd, sample_width, sample_rate,
     70                       num_channels, play_file_path=None):
     71         """Performs a playback test.
     72 
     73         @param fb_query: A feedback query.
     74         @param playback_cmd: The playback generating command, or None for no-op.
     75         @param play_file_path: A string of the path to the file being played.
     76         @param sample_width: Sample width to test playback at.
     77         @param sample_rate: Sample rate to test playback at.
     78         @param num_channels: Number of channels to test playback with.
     79         """
     80         fb_query.prepare(sample_width=sample_width,
     81                          sample_rate=sample_rate,
     82                          duration_secs=self.duration_secs,
     83                          num_channels=num_channels)
     84         if playback_cmd:
     85             self.host.run(playback_cmd)
     86         else:
     87             time.sleep(_SILENCE_DURATION_SECS)
     88         if play_file_path:
     89             fb_query.validate(audio_file=play_file_path)
     90         else:
     91             fb_query.validate()
     92 
     93 
     94     def test_audio(self, fb_client, playback_method, sample_rate, sample_width,
     95                    num_channels):
     96         """Test audio playback with the given parameters.
     97 
     98         @param fb_client: A feedback client implementation.
     99         @param playback_method: A string representing a playback method to use.
    100                                 Either 'opensles', 'libmedia', or 'stagefright'.
    101         @param sample_rate: Sample rate to test playback at.
    102         @param sample_width: Sample width to test playback at.
    103         @param num_channels: Number of channels to test playback with.
    104         """
    105         logging.info('Testing silent playback')
    106         fb_query = fb_client.new_query(client.QUERY_AUDIO_PLAYBACK_SILENT)
    107         self.test_playback(fb_query=fb_query,
    108                            playback_cmd=None,
    109                            sample_rate=sample_rate,
    110                            sample_width=sample_width,
    111                            num_channels=num_channels)
    112 
    113         dut_play_file = None
    114         host_filename = None
    115         if self.use_file:
    116            host_filename, dut_play_file = audio_utils.generate_sine_file(
    117                    self.host, num_channels, sample_rate, sample_width,
    118                    self.duration_secs, _DEFAULT_SINE_FREQUENCY, self.temp_dir)
    119 
    120         logging.info('Testing audible playback')
    121         fb_query = fb_client.new_query(client.QUERY_AUDIO_PLAYBACK_AUDIBLE)
    122         playback_cmd = self._get_playback_cmd(playback_method, dut_play_file)
    123 
    124         self.test_playback(fb_query=fb_query,
    125                            playback_cmd=playback_cmd,
    126                            sample_rate=sample_rate,
    127                            sample_width=sample_width,
    128                            num_channels=num_channels,
    129                            play_file_path=host_filename)
    130 
    131 
    132     def run_once(self, host, fb_client, playback_method, use_file=False,
    133                  sample_widths_arr=[_DEFAULT_SAMPLE_WIDTH],
    134                  sample_rates_arr=[_DEFAULT_SAMPLE_RATE],
    135                  num_channels_arr=[_DEFAULT_NUM_CHANNELS],
    136                  duration_secs=_DEFAULT_DURATION_SECS):
    137         """Runs the test.
    138 
    139         @param host: A host object representing the DUT.
    140         @param fb_client: A feedback client implementation.
    141         @param playback_method: A string representing a playback method to use.
    142                                 Either 'opensles', 'libmedia', or 'stagefright'.
    143         @param use_file: Use a file to test audio. Must be used with
    144                          playback_method 'opensles'.
    145         @param sample_widths_arr: Array of sample widths to test playback at.
    146         @param sample_rates_arr: Array of sample rates to test playback at.
    147         @param num_channels_arr: Array of number of channels to test playback
    148                                  with.
    149         @param duration_secs: Duration to play file for.
    150         """
    151         self.host = host
    152         self.duration_secs = duration_secs
    153         self.use_file = use_file
    154         self.temp_dir = tempfile.mkdtemp(dir=fb_client.tmp_dir)
    155         failed_params = []
    156         with fb_client.initialize(self, host):
    157             for sample_rate in sample_rates_arr:
    158                 for sample_width in sample_widths_arr:
    159                     for num_channels in num_channels_arr:
    160                         logging.info('Running test with the following params:')
    161                         logging.info('Sample rate: %d', sample_rate)
    162                         logging.info('Sample width: %d', sample_width)
    163                         logging.info('Number of channels: %d', num_channels)
    164 
    165                         try:
    166                             self.test_audio(fb_client=fb_client,
    167                                             playback_method=playback_method,
    168                                             sample_rate=sample_rate,
    169                                             sample_width=sample_width,
    170                                             num_channels=num_channels)
    171                         except error.TestFail:
    172                             logging.info('Test failed.')
    173                             failed_params.append((sample_rate, sample_width,
    174                                                   num_channels))
    175                         finally:
    176                             # Sleep to avoid conflict between different tests.
    177                             time.sleep(duration_secs)
    178 
    179         if failed_params == []:
    180             logging.info('All tests successfully passed.')
    181         else:
    182             logging.error('The following combinations failed:')
    183             for param in failed_params:
    184                 logging.error('Sample rate: %i, Sample width: %i, Num Channels '
    185                               '%i', param[0], param[1], param[2])
    186             raise error.TestFail('Some of the tests failed to pass.')
    187