blob: 109674ef6b7cbb00b06c541d623f1cb8595be4c4 [file] [log] [blame]
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +00001# $Id$
2
3# Quality test of media calls.
4# - UA1 calls UA2
5# - UA1 plays a file until finished to be streamed to UA2
6# - UA2 records from stream
7# - Apply PESQ to played file (reference) and recorded file (degraded)
8#
9# File should be:
10# - naming: xxxxxx.CLOCK_RATE.wav, e.g: test1.8.wav
11# - clock-rate of those files can only be 8khz or 16khz
12
13import time
14import imp
15import sys
16import re
17import subprocess
Nanang Izzuddin9eac5472008-06-26 18:52:16 +000018import wave
Nanang Izzuddinffa18c92008-06-28 00:52:20 +000019import shutil
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000020import inc_const as const
21
22from inc_cfg import *
23
24# Load configuration
Nanang Izzuddina680bd62008-06-27 21:12:12 +000025cfg_file = imp.load_source("cfg_file", ARGS[1])
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000026
27# PESQ configs
Nanang Izzuddina680bd62008-06-27 21:12:12 +000028PESQ = "tools/pesq.exe" # PESQ executable path
29PESQ_DEFAULT_THRESHOLD = 3.4 # Default minimum acceptable PESQ MOS value
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000030
Nanang Izzuddina680bd62008-06-27 21:12:12 +000031# PESQ params
32pesq_sample_rate_opt = "" # Sample rate option for PESQ
33input_filename = "" # Input/Reference filename
34output_filename = "" # Output/Degraded filename
35
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000036
37# Test body function
Nanang Izzuddina680bd62008-06-27 21:12:12 +000038def test_func(t):
39 global pesq_sample_rate_opt
40 global input_filename
41 global output_filename
Nanang Izzuddin6ee166d2008-06-26 12:26:52 +000042
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000043 ua1 = t.process[0]
44 ua2 = t.process[1]
45
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000046 # Get input file name
Nanang Izzuddina680bd62008-06-27 21:12:12 +000047 input_filename = re.compile(const.MEDIA_PLAY_FILE).search(ua1.inst_param.arg).group(1)
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000048
49 # Get output file name
Nanang Izzuddina680bd62008-06-27 21:12:12 +000050 output_filename = re.compile(const.MEDIA_REC_FILE).search(ua2.inst_param.arg).group(1)
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000051
Nanang Izzuddin9869cb52008-06-27 16:18:13 +000052 # Get WAV input length, in seconds
Nanang Izzuddina680bd62008-06-27 21:12:12 +000053 fin = wave.open(input_filename, "r")
Nanang Izzuddin9869cb52008-06-27 16:18:13 +000054 if fin == None:
55 raise TestError("Failed opening input WAV file")
56 inwavlen = fin.getnframes() * 1.0 / fin.getframerate()
57 inwavlen += 0.2
58 fin.close()
59 print "WAV input len = " + str(inwavlen) + "s"
60
61 # Get clock rate of the output
Nanang Izzuddina680bd62008-06-27 21:12:12 +000062 mo_clock_rate = re.compile("\.(\d+)\.wav").search(output_filename)
Nanang Izzuddinacb3e322008-06-25 18:18:32 +000063 if (mo_clock_rate==None):
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000064 raise TestError("Cannot compare input & output, incorrect output filename format")
Nanang Izzuddinacb3e322008-06-25 18:18:32 +000065 clock_rate = mo_clock_rate.group(1)
Nanang Izzuddin9869cb52008-06-27 16:18:13 +000066
67 # Get channel count of the output
68 channel_count = 1
69 if re.search("--stereo", ua2.inst_param.arg) != None:
70 channel_count = 2
71
72 # Get matched input file from output file
73 # (PESQ evaluates only files whose same clock rate & channel count)
74 if channel_count == 2:
Nanang Izzuddina680bd62008-06-27 21:12:12 +000075 if re.search("\.\d+\.\d+\.wav", input_filename) != None:
76 input_filename = re.sub("\.\d+\.\d+\.wav", "." + str(channel_count) + "."+clock_rate+".wav", input_filename)
Nanang Izzuddin9869cb52008-06-27 16:18:13 +000077 else:
Nanang Izzuddina680bd62008-06-27 21:12:12 +000078 input_filename = re.sub("\.\d+\.wav", "." + str(channel_count) + "."+clock_rate+".wav", input_filename)
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000079
Nanang Izzuddinacb3e322008-06-25 18:18:32 +000080 if (clock_rate != "8") & (clock_rate != "16"):
81 raise TestError("PESQ only works on clock rate 8kHz or 16kHz, clock rate used = "+clock_rate+ "kHz")
82
83 # Get conference clock rate of UA2 for PESQ sample rate option
Nanang Izzuddina680bd62008-06-27 21:12:12 +000084 pesq_sample_rate_opt = "+" + clock_rate + "000"
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000085
86 # UA1 making call
87 ua1.send("m")
88 ua1.send(t.inst_params[1].uri)
89 ua1.expect(const.STATE_CALLING)
Nanang Izzuddin9eac5472008-06-26 18:52:16 +000090
91 # UA2 wait until call established
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000092 ua2.expect(const.STATE_CONFIRMED)
93
Nanang Izzuddin9eac5472008-06-26 18:52:16 +000094 # Disconnect mic -> rec file, to avoid echo recorded when using sound device
95 # Disconnect stream -> spk, make it silent
96 # Connect stream -> rec file, start recording
97 ua2.send("cd 0 1\ncd 4 0\ncc 4 1")
Nanang Izzuddinacb3e322008-06-25 18:18:32 +000098
Nanang Izzuddin9eac5472008-06-26 18:52:16 +000099 # Disconnect mic -> stream, make stream purely sending from file
100 # Disconnect stream -> spk, make it silent
101 # Connect file -> stream, start sending
102 ua1.send("cd 0 4\ncd 4 0\ncc 1 4")
Nanang Izzuddinacb3e322008-06-25 18:18:32 +0000103
Nanang Izzuddin9eac5472008-06-26 18:52:16 +0000104 time.sleep(inwavlen)
105
106 # Disconnect files from bridge
107 ua2.send("cd 4 1")
108 ua2.expect(const.MEDIA_DISCONN_PORT_SUCCESS)
109 ua1.send("cd 1 4")
110 ua1.expect(const.MEDIA_DISCONN_PORT_SUCCESS)
111
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000112
113# Post body function
Nanang Izzuddina680bd62008-06-27 21:12:12 +0000114def post_func(t):
115 global pesq_sample_rate_opt
116 global input_filename
117 global output_filename
118
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000119 endpt = t.process[0]
120
121 # Execute PESQ
Nanang Izzuddina680bd62008-06-27 21:12:12 +0000122 fullcmd = PESQ + " " + pesq_sample_rate_opt + " " + input_filename + " " + output_filename
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000123 endpt.trace("Popen " + fullcmd)
124 pesq_proc = subprocess.Popen(fullcmd, stdout=subprocess.PIPE, universal_newlines=True)
125 pesq_out = pesq_proc.communicate()
126
127 # Parse ouput
Nanang Izzuddin9869cb52008-06-27 16:18:13 +0000128 mo_pesq_out = re.compile("Prediction[^=]+=\s+([\-\d\.]+)\s*").search(pesq_out[0])
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000129 if (mo_pesq_out == None):
130 raise TestError("Failed to fetch PESQ result")
131
Nanang Izzuddin9eac5472008-06-26 18:52:16 +0000132 # Get threshold
133 if (cfg_file.pesq_threshold != None) | (cfg_file.pesq_threshold > -0.5 ):
134 threshold = cfg_file.pesq_threshold
135 else:
136 threshold = PESQ_DEFAULT_THRESHOLD
137
138 # Evaluate the PESQ MOS value
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000139 pesq_res = mo_pesq_out.group(1)
Nanang Izzuddin9eac5472008-06-26 18:52:16 +0000140 if (float(pesq_res) >= threshold):
Nanang Izzuddinffa18c92008-06-28 00:52:20 +0000141 endpt.trace("Success, PESQ result = " + pesq_res + " (target=" + str(threshold) + ").")
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000142 else:
Nanang Izzuddinffa18c92008-06-28 00:52:20 +0000143 endpt.trace("Failed, PESQ result = " + pesq_res + " (target=" + str(threshold) + ").")
144 # Save the wav file
145 wavoutname = ARGS[1]
146 wavoutname = re.sub("[\\\/]", "_", wavoutname)
147 wavoutname = re.sub("\.py$", ".wav", wavoutname)
148 wavoutname = "logs/" + wavoutname
149 try:
150 shutil.copyfile(output_filename, wavoutname)
151 print "Output WAV is copied to " + wavoutname
152 except:
153 print "Couldn't copy output WAV, please check if 'logs' directory exists."
154
155 raise TestError("WAV seems to be degraded badly, PESQ = "+ pesq_res + " (target=" + str(threshold) + ").")
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000156
157
158# Here where it all comes together
159test = cfg_file.test_param
160test.test_func = test_func
161test.post_func = post_func
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000162