18581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold# Copyright 2016 The Chromium OS Authors. All rights reserved. 28581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold# Use of this source code is governed by a BSD-style license that can be 38581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold# found in the LICENSE file. 48581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 58581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnoldimport logging 671e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathanimport os 771e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathanimport subprocess 871e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathanimport tempfile 98581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnoldimport time 108581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 118581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnoldimport common 121aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathanfrom autotest_lib.client.common_lib import error 1371e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathanfrom autotest_lib.client.common_lib.feedback import client 148581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnoldfrom autotest_lib.server import test 158581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 168581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 1771e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan_BITS_PER_BYTE = 8 188581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold# The amount of time to wait when producing silence (i.e. no playback). 198581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold_SILENCE_DURATION_SECS = 5 208581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 2171e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan# Number of channels to generate. 2271e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan_DEFAULT_NUM_CHANNELS = 1 2371e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan# Sine wave sample rate (48kHz). 2471e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan_DEFAULT_SAMPLE_RATE = 48000 2571e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan# Sine wave default sample format is signed 16-bit PCM (two bytes). 2671e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan_DEFAULT_SAMPLE_WIDTH = 2 2771e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan# Default sine wave frequency. 2871e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan_DEFAULT_SINE_FREQUENCY = 440 2971e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan# Default duration of the sine wave in seconds. 3071e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan_DEFAULT_DURATION_SECS = 10 318581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 328581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnoldclass brillo_PlaybackAudioTest(test.test): 338581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold """Verify that basic audio playback works.""" 348581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold version = 1 358581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 368581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold def __init__(self, *args, **kwargs): 378581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold super(brillo_PlaybackAudioTest, self).__init__(*args, **kwargs) 388581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold self.host = None 398581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 408581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 4171e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan def _get_playback_cmd(self, method, dut_play_file): 421aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan """Get the playback command to execute based on the playback method. 431aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan 441aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan @param method: A string specifiying which method to use. 4571e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan @param dut_play_file: A string containing the path to the file to play 4671e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan on the DUT. 471aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan @return: A string containing the command to play audio using the 481aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan specified method. 491aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan 501aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan @raises TestError: Invalid playback method. 511aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan """ 5271e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan if dut_play_file: 5371e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan return 'su root slesTest_playFdPath %s 0' % dut_play_file 541aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan if method == 'libmedia': 55e21ca34c5e9edbf7f3744adffc57cb104bc6b0a7Ralph Nathan return 'brillo_audio_test --playback --libmedia --sine' 561aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan elif method == 'stagefright': 57e21ca34c5e9edbf7f3744adffc57cb104bc6b0a7Ralph Nathan return 'brillo_audio_test --playback --stagefright --sine' 581aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan elif method == 'opensles': 591aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan return 'slesTest_sawtoothBufferQueue' 601aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan else: 611aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan raise error.TestError('Test called with invalid playback method.') 621aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan 631aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan 6471e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan def test_playback(self, fb_query, playback_cmd, sample_width, sample_rate, 6571e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan duration_secs, num_channels, play_file_path=None): 668581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold """Performs a playback test. 678581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 688581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold @param fb_query: A feedback query. 698581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold @param playback_cmd: The playback generating command, or None for no-op. 7071e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan @param play_file_path: A string of the path to the file being played. 7171e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan @param sample_width: Sample width to test playback at. 7271e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan @param sample_rate: Sample rate to test playback at. 7371e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan @param num_channels: Number of channels to test playback with. 748581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold """ 7571e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan fb_query.prepare(sample_width=sample_width, 7671e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan sample_rate=sample_rate, 7771e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan duration_secs=duration_secs, 7871e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan num_channels=num_channels) 798581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold if playback_cmd: 808581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold self.host.run(playback_cmd) 818581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold else: 828581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold time.sleep(_SILENCE_DURATION_SECS) 8371e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan if play_file_path: 8471e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan fb_query.validate(audio_file=play_file_path) 8571e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan else: 8671e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan fb_query.validate() 878581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 888581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 8971e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan def run_once(self, host, fb_client, playback_method, use_file=False, 9071e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan sample_width=_DEFAULT_SAMPLE_WIDTH, 9171e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan sample_rate=_DEFAULT_SAMPLE_RATE, 9271e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan num_channels=_DEFAULT_NUM_CHANNELS, 9371e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan duration_secs=_DEFAULT_DURATION_SECS): 948581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold """Runs the test. 958581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 968581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold @param host: A host object representing the DUT. 978581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold @param fb_client: A feedback client implementation. 981aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan @param playback_method: A string representing a playback method to use. 991aaf403448c8d4e4a6aa0fbd9aa1950741a549d8Ralph Nathan Either 'opensles', 'libmedia', or 'stagefright'. 10071e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan @param use_file: Use a file to test audio. Must be used with 10171e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan playback_method 'opensles'. 10271e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan @param sample_width: Sample width to test playback at. 10371e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan @param sample_rate: Sample rate to test playback at. 10471e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan @param num_channels: Number of channels to test playback with. 10571e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan @param duration_secs: Duration to play file for. 1068581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold """ 1078581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold self.host = host 1088581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold with fb_client.initialize(self, host): 1098581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold logging.info('Testing silent playback') 1108581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold fb_query = fb_client.new_query(client.QUERY_AUDIO_PLAYBACK_SILENT) 11171e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan self.test_playback(fb_query=fb_query, 11271e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan playback_cmd=None, 11371e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan sample_rate=sample_rate, 11471e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan sample_width=sample_width, 11571e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan num_channels=num_channels, 11671e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan duration_secs=duration_secs) 11771e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan 11871e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan dut_play_file = None 11971e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan host_filename = None 12071e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan if use_file: 12171e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan _, host_filename = tempfile.mkstemp( 12271e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan prefix='sine-', suffix='.wav', 12371e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan dir=tempfile.mkdtemp(dir=fb_client.tmp_dir)) 12471e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan if sample_width == 1: 12571e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan sine_format = '-e unsigned' 12671e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan else: 12771e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan sine_format = '-e signed' 12871e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan gen_file_cmd = ('sox -n -t wav -c %d %s -b %d -r %d %s synth %d ' 12971e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan 'sine %d vol 0.9' % (num_channels, sine_format, 13071e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan sample_width * _BITS_PER_BYTE, 13171e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan sample_rate, host_filename, 13271e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan duration_secs, 13371e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan _DEFAULT_SINE_FREQUENCY)) 13471e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan logging.info('Command to generate sine wave: %s', gen_file_cmd) 13571e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan subprocess.call(gen_file_cmd, shell=True) 13671e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan logging.info('Send file to DUT.') 13771e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan dut_tmp_dir = '/data' 13871e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan dut_play_file = os.path.join(dut_tmp_dir, 'sine.wav') 13971e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan logging.info('dut_play_file %s', dut_play_file) 14071e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan host.send_file(host_filename, dut_play_file) 1418581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold 1428581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold logging.info('Testing audible playback') 1438581bf1f70afe8655c60005bfb9f7d19042c83a4Gilad Arnold fb_query = fb_client.new_query(client.QUERY_AUDIO_PLAYBACK_AUDIBLE) 14471e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan playback_cmd = self._get_playback_cmd(playback_method, dut_play_file) 14571e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan 14671e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan self.test_playback(fb_query=fb_query, 14771e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan playback_cmd=playback_cmd, 14871e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan sample_rate=sample_rate, 14971e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan sample_width=sample_width, 15071e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan num_channels=num_channels, 15171e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan duration_secs=duration_secs, 15271e94bd284ce7cb7c6feed21d85c120218aa1757Ralph Nathan play_file_path=host_filename) 153