Add comparison to e2e and clean up.

BUG=issue502
TEST=manual

Review URL: https://webrtc-codereview.appspot.com/577006

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2274 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
andrew@webrtc.org
2012-05-23 02:47:58 +00:00
parent a1a34d675f
commit 2b004655b5
2 changed files with 81 additions and 49 deletions

View File

@ -18,7 +18,9 @@
#include "src/voice_engine/main/interface/voe_audio_processing.h" #include "src/voice_engine/main/interface/voe_audio_processing.h"
#include "src/voice_engine/main/interface/voe_base.h" #include "src/voice_engine/main/interface/voe_base.h"
#include "src/voice_engine/main/interface/voe_codec.h" #include "src/voice_engine/main/interface/voe_codec.h"
#include "src/voice_engine/main/interface/voe_hardware.h"
DEFINE_string(render, "render", "render device name");
DEFINE_string(codec, "ISAC", "codec name"); DEFINE_string(codec, "ISAC", "codec name");
DEFINE_int32(rate, 16000, "codec sample rate in Hz"); DEFINE_int32(rate, 16000, "codec sample rate in Hz");
@ -34,6 +36,8 @@ void RunHarness() {
ASSERT_TRUE(base != NULL); ASSERT_TRUE(base != NULL);
VoECodec* codec = VoECodec::GetInterface(voe); VoECodec* codec = VoECodec::GetInterface(voe);
ASSERT_TRUE(codec != NULL); ASSERT_TRUE(codec != NULL);
VoEHardware* hardware = VoEHardware::GetInterface(voe);
ASSERT_TRUE(hardware != NULL);
ASSERT_EQ(0, base->Init()); ASSERT_EQ(0, base->Init());
int channel = base->CreateChannel(); int channel = base->CreateChannel();
@ -54,6 +58,23 @@ void RunHarness() {
ASSERT_TRUE(codec_found); ASSERT_TRUE(codec_found);
ASSERT_EQ(0, codec->SetSendCodec(channel, codec_params)); ASSERT_EQ(0, codec->SetSendCodec(channel, codec_params));
int num_devices = 0;
ASSERT_EQ(0, hardware->GetNumOfPlayoutDevices(num_devices));
char device_name[128] = {0};
char guid[128] = {0};
bool device_found = false;
int device_index;
for (device_index = 0; device_index < num_devices; device_index++) {
ASSERT_EQ(0, hardware->GetPlayoutDeviceName(device_index, device_name,
guid));
if (FLAGS_render.compare(device_name) == 0) {
device_found = true;
break;
}
}
ASSERT_TRUE(device_found);
ASSERT_EQ(0, hardware->SetPlayoutDevice(device_index));
// Disable all audio processing. // Disable all audio processing.
ASSERT_EQ(0, audio->SetAgcStatus(false)); ASSERT_EQ(0, audio->SetAgcStatus(false));
ASSERT_EQ(0, audio->SetEcStatus(false)); ASSERT_EQ(0, audio->SetEcStatus(false));

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
#
# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. # Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
# #
# Use of this source code is governed by a BSD-style license # Use of this source code is governed by a BSD-style license
@ -7,16 +8,6 @@
# in the file PATENTS. All contributing project authors may # in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree. # be found in the AUTHORS file in the root of the source tree.
__author__ = 'andrew@webrtc.org (Andrew MacDonald)'
import optparse
import os
import shlex
import subprocess
import sys
import threading
import time
"""Runs an end-to-end audio quality test on Linux. """Runs an end-to-end audio quality test on Linux.
Expects the presence of PulseAudio virtual devices (null sinks). These are Expects the presence of PulseAudio virtual devices (null sinks). These are
@ -26,18 +17,14 @@ utility (pacat) is used to play to and record from the virtual devices.
The input reference file is then compared to the output file. The input reference file is then compared to the output file.
""" """
def popen_and_call(popen_args, call_on_exit): import optparse
"""Executes the arguments, and triggers the callback when finished.""" import os
import re
def run_in_thread(popen_args, call_on_exit): import shlex
proc = subprocess.Popen(popen_args) import subprocess
proc.wait() import sys
call_on_exit() import threading
return import time
thread = threading.Thread(target=run_in_thread,
args=(popen_args, call_on_exit))
thread.start()
return thread
def main(argv): def main(argv):
parser = optparse.OptionParser() parser = optparse.OptionParser()
@ -53,42 +40,66 @@ def main(argv):
parser.add_option('--rec_sink', default='render', parser.add_option('--rec_sink', default='render',
help='name of PulseAudio sink whose monitor will be recorded') help='name of PulseAudio sink whose monitor will be recorded')
parser.add_option('--harness', parser.add_option('--harness',
default=os.path.dirname(sys.argv[0]) + default=os.path.abspath(os.path.dirname(sys.argv[0]) +
'/../../../out/Debug/audio_e2e_harness', '/../../../out/Debug/audio_e2e_harness'),
help='path to audio harness executable') help='path to audio harness executable')
parser.add_option('--compare',
help='command-line arguments for comparison tool')
parser.add_option('--regexp',
help='regular expression to extract the comparison metric')
(options, args) = parser.parse_args(argv[1:]) (options, args) = parser.parse_args(argv[1:])
# Set default devices to be used by VoiceEngine. # Set the default capture device to be used by VoiceEngine. We unfortunately
subprocess.call(['pacmd', 'set-default-sink', options.rec_sink]); # need to do this rather than select the devices directly through the harness
subprocess.call(['pacmd', 'set-default-source', # because monitor sources don't appear in VoiceEngine except as defaults.
options.play_sink + '.monitor']); #
# We pass the render device for VoiceEngine to select because (for unknown
# reasons) the virtual device is sometimes not used when the default.
retcode = subprocess.call(['pacmd', 'set-default-source',
options.play_sink + '.monitor'], stdout=subprocess.PIPE);
if retcode != 0:
return retcode
print 'Start an audio call' command = [options.harness, '--render=' + options.rec_sink,
print options.harness '--codec=' + options.codec, '--rate=' + options.rate]
voe_proc = subprocess.Popen([options.harness, print ' '.join(command)
'--codec=' + options.codec, '--rate=' + options.rate]); voe_proc = subprocess.Popen(command)
print 'Start recording to ' + options.output format_args = ['-n', '--format=s16le', '--rate=' + options.rate,
format_args = ('-n --format=s16le --rate=' + options.rate + ' --channels=' + '--channels=' + options.channels, '--raw']
options.channels + ' --raw') command = (['pacat', '-p', '-d', options.play_sink] + format_args +
command = ('pacat -r -d ' + options.rec_sink + '.monitor ' + format_args + [options.input])
' ' + options.output) print ' '.join(command)
record_proc = subprocess.Popen(shlex.split(command)) play_proc = subprocess.Popen(command)
def stop_recording():
# If recording starts before there is data available, pacat sometimes
# inexplicably adds a large delay to the start of the file. We wait here in
# an attempt to prevent that.
time.sleep(0.2)
command = (['pacat', '-r', '-d', options.rec_sink + '.monitor'] +
format_args + [options.output])
print ' '.join(command)
record_proc = subprocess.Popen(command)
retcode = play_proc.wait()
# If these ended early, an exception will be thrown here.
record_proc.kill() record_proc.kill()
print 'Start playing from ' + options.input
command = ('pacat -p -d ' + options.play_sink + ' ' + format_args + ' ' +
options.input)
popen_and_call(shlex.split(command), stop_recording)
# record_proc will be killed after playout finishes.
record_proc.wait()
print 'Shutdown audio call'
voe_proc.kill() voe_proc.kill()
if retcode != 0:
return retcode
# TODO(andrew): compare files. if options.compare and options.regexp:
command = shlex.split(options.compare) + [options.input, options.output]
print ' '.join(command)
compare_proc = subprocess.Popen(command, stdout=subprocess.PIPE)
compare_output = compare_proc.communicate()[0]
if compare_proc.returncode != 0:
return compare_proc.returncode
# The list should only contain one item.
print ''.join(re.findall(options.regexp, compare_output))
return 0
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main(sys.argv)) sys.exit(main(sys.argv))