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( |
+ _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() |