# Copyright 2016 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging import tempfile import time import common from autotest_lib.client.common_lib import error from autotest_lib.client.common_lib.feedback import client from autotest_lib.server import test from autotest_lib.server.brillo import audio_utils # The amount of time to wait when producing silence (i.e. no playback). _SILENCE_DURATION_SECS = 5 # Number of channels to generate. _DEFAULT_NUM_CHANNELS = 1 # Sine wave sample rate (48kHz). _DEFAULT_SAMPLE_RATE = 48000 # Sine wave default sample format is signed 16-bit PCM (two bytes). _DEFAULT_SAMPLE_WIDTH = 2 # Default sine wave frequency. _DEFAULT_SINE_FREQUENCY = 440 # Default duration of the sine wave in seconds. _DEFAULT_DURATION_SECS = 10 class brillo_PlaybackAudioTest(test.test): """Verify that basic audio playback works.""" version = 1 def __init__(self, *args, **kwargs): super(brillo_PlaybackAudioTest, self).__init__(*args, **kwargs) self.host = None def _get_playback_cmd(self, method, dut_play_file): """Get the playback command to execute based on the playback method. @param method: A string specifiying which method to use. @param dut_play_file: A string containing the path to the file to play on the DUT. @return: A string containing the command to play audio using the specified method. @raises TestError: Invalid playback method. """ if dut_play_file: if method == 'libmedia': return ('brillo_audio_test --playback --libmedia ' '--filename=%s' % dut_play_file) elif method == 'stagefright': return ('brillo_audio_test --playback --stagefright ' '--filename=%s' % dut_play_file) elif method == 'opensles': return 'slesTest_playFdPath %s 0' % dut_play_file else: if method == 'libmedia': return 'brillo_audio_test --playback --libmedia --sine' elif method == 'stagefright': return 'brillo_audio_test --playback --stagefright --sine' elif method == 'opensles': return 'slesTest_sawtoothBufferQueue' raise error.TestError('Test called with invalid playback method.') def test_playback(self, fb_query, playback_cmd, sample_width, sample_rate, num_channels, play_file_path=None): """Performs a playback test. @param fb_query: A feedback query. @param playback_cmd: The playback generating command, or None for no-op. @param play_file_path: A string of the path to the file being played. @param sample_width: Sample width to test playback at. @param sample_rate: Sample rate to test playback at. @param num_channels: Number of channels to test playback with. """ fb_query.prepare(sample_width=sample_width, sample_rate=sample_rate, duration_secs=self.duration_secs, num_channels=num_channels) if playback_cmd: self.host.run(playback_cmd) else: time.sleep(_SILENCE_DURATION_SECS) if play_file_path: fb_query.validate(audio_file=play_file_path) else: fb_query.validate() def test_audio(self, fb_client, playback_method, sample_rate, sample_width, num_channels): """Test audio playback with the given parameters. @param fb_client: A feedback client implementation. @param playback_method: A string representing a playback method to use. Either 'opensles', 'libmedia', or 'stagefright'. @param sample_rate: Sample rate to test playback at. @param sample_width: Sample width to test playback at. @param num_channels: Number of channels to test playback with. """ logging.info('Testing silent playback') fb_query = fb_client.new_query(client.QUERY_AUDIO_PLAYBACK_SILENT) self.test_playback(fb_query=fb_query, playback_cmd=None, sample_rate=sample_rate, sample_width=sample_width, num_channels=num_channels) dut_play_file = None host_filename = None if self.use_file: host_filename, dut_play_file = audio_utils.generate_sine_file( self.host, num_channels, sample_rate, sample_width, self.duration_secs, _DEFAULT_SINE_FREQUENCY, self.temp_dir) logging.info('Testing audible playback') fb_query = fb_client.new_query(client.QUERY_AUDIO_PLAYBACK_AUDIBLE) playback_cmd = self._get_playback_cmd(playback_method, dut_play_file) self.test_playback(fb_query=fb_query, playback_cmd=playback_cmd, sample_rate=sample_rate, sample_width=sample_width, num_channels=num_channels, play_file_path=host_filename) def run_once(self, host, fb_client, playback_method, use_file=False, sample_widths_arr=[_DEFAULT_SAMPLE_WIDTH], sample_rates_arr=[_DEFAULT_SAMPLE_RATE], num_channels_arr=[_DEFAULT_NUM_CHANNELS], duration_secs=_DEFAULT_DURATION_SECS): """Runs the test. @param host: A host object representing the DUT. @param fb_client: A feedback client implementation. @param playback_method: A string representing a playback method to use. Either 'opensles', 'libmedia', or 'stagefright'. @param use_file: Use a file to test audio. Must be used with playback_method 'opensles'. @param sample_widths_arr: Array of sample widths to test playback at. @param sample_rates_arr: Array of sample rates to test playback at. @param num_channels_arr: Array of number of channels to test playback with. @param duration_secs: Duration to play file for. """ self.host = host self.duration_secs = duration_secs self.use_file = use_file self.temp_dir = tempfile.mkdtemp(dir=fb_client.tmp_dir) failed_params = [] with fb_client.initialize(self, host): for sample_rate in sample_rates_arr: for sample_width in sample_widths_arr: for num_channels in num_channels_arr: logging.info('Running test with the following params:') logging.info('Sample rate: %d', sample_rate) logging.info('Sample width: %d', sample_width) logging.info('Number of channels: %d', num_channels) try: self.test_audio(fb_client=fb_client, playback_method=playback_method, sample_rate=sample_rate, sample_width=sample_width, num_channels=num_channels) except error.TestFail: logging.info('Test failed.') failed_params.append((sample_rate, sample_width, num_channels)) finally: # Sleep to avoid conflict between different tests. time.sleep(duration_secs) if failed_params == []: logging.info('All tests successfully passed.') else: logging.error('The following combinations failed:') for param in failed_params: logging.error('Sample rate: %i, Sample width: %i, Num Channels ' '%i', param[0], param[1], param[2]) raise error.TestFail('Some of the tests failed to pass.')