Chromium Code Reviews| Index: webrtc/audio/test/low_bandwidth_audio_test.py |
| diff --git a/webrtc/audio/test/low_bandwidth_audio_test.py b/webrtc/audio/test/low_bandwidth_audio_test.py |
| index 8f4068199be7342e521eeb2e27f5bbe1b4083610..379a2d3ebea014dd2b500d1ad301f1e38196f0cc 100755 |
| --- a/webrtc/audio/test/low_bandwidth_audio_test.py |
| +++ b/webrtc/audio/test/low_bandwidth_audio_test.py |
| @@ -15,6 +15,7 @@ output files will be performed. |
| """ |
| import argparse |
| +import collections |
| import logging |
| import os |
| import re |
| @@ -59,13 +60,14 @@ def _DownloadTools(): |
| tools_dir = os.path.join(SRC_DIR, 'tools-webrtc') |
| toolchain_dir = os.path.join(tools_dir, 'audio_quality') |
| - # Download pesq. |
| + # Download PESQ and POLQA. |
| download_script = os.path.join(tools_dir, 'download_tools.py') |
| command = [sys.executable, download_script, toolchain_dir] |
| subprocess.check_call(_LogCommand(command)) |
| pesq_path = os.path.join(toolchain_dir, _GetPlatform(), 'pesq') |
| - return pesq_path |
| + polqa_path = os.path.join(toolchain_dir, _GetPlatform(), 'PolqaOem64') |
| + return pesq_path, polqa_path |
| def ExtractTestRuns(lines, echo=False): |
| @@ -108,13 +110,74 @@ def _GetFile(file_path, out_dir, move=False, |
| return out_file_path |
| +def _RunPesq(executable_path, reference_file, degraded_file, |
| + sampling_frequency_hz=16000): |
| + directory = os.path.dirname(reference_file) |
| + assert os.path.dirname(degraded_file) == directory |
| + |
| + # Analyze audio. |
| + command = [executable_path, '+%d' % sampling_frequency_hz, |
| + os.path.basename(reference_file), |
| + os.path.basename(degraded_file)] |
| + # Need to provide paths in the current directory due to a bug in PESQ: |
| + # On Mac, for some 'path/to/file.wav', if 'file.wav' is longer than |
| + # 'path/to', PESQ crashes. |
| + out = subprocess.check_output(_LogCommand(command), |
| + cwd=directory, stderr=subprocess.STDOUT) |
| + |
| + # Find the scores in stdout of PESQ. |
| + match = re.search( |
| + r'Prediction \(Raw MOS, MOS-LQO\):\s+=\s+([\d.]+)\s+([\d.]+)', out) |
| + if match: |
| + raw_mos, _ = match.groups() |
| + |
| + return {'pesq_mos': (raw_mos, 'score')} |
| + else: |
| + logging.error('PESQ: %s', out.splitlines()[-1]) |
| + return {} |
| + |
| + |
| +def _RunPolqa(executable_path, reference_file, degraded_file): |
| + # Analyze audio. |
| + command = [executable_path, '-q', '-LC', 'NB', |
| + '-Ref', reference_file, '-Test', degraded_file] |
| + try: |
| + process = subprocess.Popen(_LogCommand(command), |
| + stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| + except OSError as e: |
| + if e.errno == os.errno.ENOENT: |
| + logging.warning('POLQA executable missing, skipping test.') |
| + return {} |
| + else: |
| + raise |
| + out, err = process.communicate() |
| + |
| + # Find the scores in stdout of POLQA. |
| + match = re.search(r'\bMOS-LQO:\s+([\d.]+)', out) |
| + |
| + if process.returncode != 0 or not match: |
| + if process.returncode == 2: |
| + logging.warning('%s (2)', err.strip()) |
| + logging.warning('POLQA license error, skipping test.') |
| + else: |
| + logging.error('%s (%d)', err.strip(), process.returncode) |
| + return {} |
| + |
| + mos_lqo, = match.groups() |
| + return {'polqa_mos_lqo': (mos_lqo, 'score')} |
| + |
| + |
| +Analyzer = collections.namedtuple('Analyzer', ['func', 'executable', |
| + 'sampling_frequency_hz']) |
| + |
| + |
| def main(): |
| # pylint: disable=W0101 |
| logging.basicConfig(level=logging.INFO) |
| args = _ParseArgs() |
| - pesq_path = _DownloadTools() |
| + pesq_path, polqa_path = _DownloadTools() |
| out_dir = os.path.join(args.build_dir, '..') |
| if args.android: |
| @@ -123,51 +186,44 @@ def main(): |
| else: |
| test_command = [os.path.join(args.build_dir, 'low_bandwidth_audio_test')] |
| - # Start the test executable that produces audio files. |
| - test_process = subprocess.Popen(_LogCommand(test_command), |
| - stdout=subprocess.PIPE) |
| - |
| - try: |
| - lines = iter(test_process.stdout.readline, '') |
| - for result in ExtractTestRuns(lines, echo=True): |
| - (android_device, test_name, reference_file, degraded_file) = result |
| - |
| - adb_prefix = (args.adb_path,) |
| - if android_device: |
| - adb_prefix += ('-s', android_device) |
| - |
| - reference_file = _GetFile(reference_file, out_dir, |
| - android=args.android, adb_prefix=adb_prefix) |
| - degraded_file = _GetFile(degraded_file, out_dir, move=True, |
| - android=args.android, adb_prefix=adb_prefix) |
| - |
| - # Analyze audio. |
| - pesq_command = [pesq_path, '+16000', |
| - os.path.basename(reference_file), |
| - os.path.basename(degraded_file)] |
| - # Need to provide paths in the current directory due to a bug in PESQ: |
| - # On Mac, for some 'path/to/file.wav', if 'file.wav' is longer than |
| - # 'path/to', PESQ crashes. |
| - pesq_output = subprocess.check_output(_LogCommand(pesq_command), |
| - cwd=out_dir) |
| - |
| - # Find the scores in stdout of pesq. |
| - match = re.search( |
| - r'Prediction \(Raw MOS, MOS-LQO\):\s+=\s+([\d.]+)\s+([\d.]+)', |
| - pesq_output) |
| - if match: |
| - raw_mos, _ = match.groups() |
| - |
| - # Output a result for the perf dashboard. |
| - print 'RESULT pesq_mos: %s= %s score' % (test_name, raw_mos) |
| - else: |
| - logging.error('PESQ: %s', pesq_output.splitlines()[-1]) |
| - |
| - if args.remove: |
| - os.remove(reference_file) |
| - os.remove(degraded_file) |
| - finally: |
| - test_process.terminate() |
| + analyzers = [Analyzer(_RunPesq, pesq_path, 16000)] |
| + # Check if POLQA can run at all, or skip the 48 kHz tests entirely. |
| + example_path = os.path.join(SRC_DIR, 'resources', |
| + 'voice_engine', 'audio_tiny48.wav') |
| + if _RunPolqa(polqa_path, example_path, example_path): |
| + analyzers.append(Analyzer(_RunPolqa, polqa_path, 48000)) |
| + |
| + for analyzer in analyzers: |
| + # Start the test executable that produces audio files. |
| + test_process = subprocess.Popen( |
|
kjellander_webrtc
2017/04/10 12:30:02
What happens in the case where we get a really bad
oprypin_webrtc
2017/04/10 12:36:51
I don't quite understand.
The executed command is
kjellander_webrtc
2017/04/10 12:49:33
You're right - this is fine. I didn't pay enough a
|
| + _LogCommand(test_command + ['--sampling_frequency=%d' % |
| + analyzer.sampling_frequency_hz]), |
| + stdout=subprocess.PIPE) |
| + try: |
| + lines = iter(test_process.stdout.readline, '') |
| + for result in ExtractTestRuns(lines, echo=True): |
| + (android_device, test_name, reference_file, degraded_file) = result |
| + |
| + adb_prefix = (args.adb_path,) |
| + if android_device: |
| + adb_prefix += ('-s', android_device) |
| + |
| + reference_file = _GetFile(reference_file, out_dir, |
| + android=args.android, adb_prefix=adb_prefix) |
| + degraded_file = _GetFile(degraded_file, out_dir, move=True, |
| + android=args.android, adb_prefix=adb_prefix) |
| + |
| + analyzer_results = analyzer.func(analyzer.executable, |
| + reference_file, degraded_file) |
| + for metric, (value, units) in analyzer_results.items(): |
| + # Output a result for the perf dashboard. |
| + print 'RESULT %s: %s= %s %s' % (metric, test_name, value, units) |
| + |
| + if args.remove: |
| + os.remove(reference_file) |
| + os.remove(degraded_file) |
| + finally: |
| + test_process.terminate() |
| return test_process.wait() |