blob: 3ce45c300b9164e5b746cd2af183e9cef3dc1bbb [file] [log] [blame]
# Copyright (c) 2012 The Chromium 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 os
import subprocess
import tempfile
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from import audio_helper
from import cmd_utils
from import cras_utils
from import sox_utils
class audio_CRASFormatConversion(audio_helper.cras_rms_test):
"""Checks that sample rate conversion works in CRAS."""
version = 1
def play_sine_tone(self, frequency, rate):
"""Plays a sine tone by cras and returns the processes.
@param frequency: the frequency of the sine wave.
@param rate: the sampling rate.
p1 = cmd_utils.popen(
filename='-', rate=rate, frequencies=frequency, gain=-6),
p2 = cmd_utils.popen(
cras_utils.playback_cmd(playback_file='-', rate=rate),
return [p1, p2]
def wait_for_active_stream_count(self, expected_count):
"""Waits until the number of active streams matches the requested
number or until a timeout occurs.
@param expected_count: the exact number of streams required to
be active for execution to continue.
@raise TestError: if a timeout occurs.
lambda: cras_utils.get_active_stream_count() == expected_count,
'Timeout waiting active stream count to become %d' %
timeout=1, sleep_interval=0.05)
def loopback(self, noise_profile, primary, secondary):
"""Gets the rms value of the recorded audio of playing two different
tones (the 440 and 523 Hz sine wave) at the specified sampling rate.
@param noise_profile: The noise profile which is used to reduce the
noise of the recored audio.
@param primary: The first sample rate, HW will be set to this.
@param secondary: The second sample rate, will be SRC'd to the first.
popens = []
record_file = os.path.join(self.resultsdir,
'record-%s-%s.wav' % (primary, secondary))
# There should be no other active streams.
# Start with the primary sample rate, then add the secondary. This
# causes the secondary to be SRC'd to the primary rate.
# Play the first audio stream and make sure it has been played
popens += self.play_sine_tone(_TEST_TONE_ONE, primary)
# Play the second audio stream and make sure it has been played
popens += self.play_sine_tone(_TEST_TONE_TWO, secondary)
cras_utils.capture(record_file, duration=1, rate=44100)
# Make sure the playback is still in good shape
if any(p.poll() is not None for p in popens):
# We will log more details later in finally.
raise error.TestFail('process unexpectly stopped')
reduced_file = tempfile.NamedTemporaryFile()
record_file,, noise_profile, rate=44100)
sox_stat = sox_utils.get_stat(, rate=44100)'The sox stat of (%d, %d) is %s',
primary, secondary, str(sox_stat))
return sox_stat.rms
def run_once(self, test_sample_rates):
"""Runs the format conversion test.
rms_values = {}
# Record silence to use as the noise profile.
noise_file = os.path.join(self.resultsdir, "noise.wav")
noise_profile = tempfile.NamedTemporaryFile()
cras_utils.capture(noise_file, duration=1)
# Try all sample rate pairs.
for primary in test_sample_rates:
for secondary in test_sample_rates:
key = 'rms_value_%d_%d' % (primary, secondary)
rms_values[key] = self.loopback(, primary, secondary)
# Record at all sample rates
record_file = tempfile.NamedTemporaryFile()
for rate in test_sample_rates:
cras_utils.capture(, duration=1, rate=rate)
# Add min_rms_value to the result
rms_values['min_rms_value'] = min(rms_values.values())