blob: 272d0715bf7e1f1cceb485238690d6eef830f74d [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
Benny Prijono459a0ff2009-01-05 15:31:25 +000015import os
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000016import sys
17import re
18import subprocess
Nanang Izzuddin9eac5472008-06-26 18:52:16 +000019import wave
Nanang Izzuddinffa18c92008-06-28 00:52:20 +000020import shutil
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000021import inc_const as const
22
23from inc_cfg import *
24
25# Load configuration
Nanang Izzuddina680bd62008-06-27 21:12:12 +000026cfg_file = imp.load_source("cfg_file", ARGS[1])
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000027
28# PESQ configs
Benny Prijonof84081d2009-01-04 21:28:10 +000029PESQ = "tools/pesq" # PESQ executable path
Nanang Izzuddina680bd62008-06-27 21:12:12 +000030PESQ_DEFAULT_THRESHOLD = 3.4 # Default minimum acceptable PESQ MOS value
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000031
Nanang Izzuddina680bd62008-06-27 21:12:12 +000032# PESQ params
33pesq_sample_rate_opt = "" # Sample rate option for PESQ
34input_filename = "" # Input/Reference filename
35output_filename = "" # Output/Degraded filename
36
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000037
38# Test body function
Nanang Izzuddina680bd62008-06-27 21:12:12 +000039def test_func(t):
40 global pesq_sample_rate_opt
41 global input_filename
42 global output_filename
Nanang Izzuddin6ee166d2008-06-26 12:26:52 +000043
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000044 ua1 = t.process[0]
45 ua2 = t.process[1]
46
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000047 # Get input file name
Nanang Izzuddina680bd62008-06-27 21:12:12 +000048 input_filename = re.compile(const.MEDIA_PLAY_FILE).search(ua1.inst_param.arg).group(1)
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000049
50 # Get output file name
Nanang Izzuddina680bd62008-06-27 21:12:12 +000051 output_filename = re.compile(const.MEDIA_REC_FILE).search(ua2.inst_param.arg).group(1)
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000052
Nanang Izzuddin9869cb52008-06-27 16:18:13 +000053 # Get WAV input length, in seconds
Nanang Izzuddina680bd62008-06-27 21:12:12 +000054 fin = wave.open(input_filename, "r")
Nanang Izzuddin9869cb52008-06-27 16:18:13 +000055 if fin == None:
56 raise TestError("Failed opening input WAV file")
57 inwavlen = fin.getnframes() * 1.0 / fin.getframerate()
58 inwavlen += 0.2
59 fin.close()
60 print "WAV input len = " + str(inwavlen) + "s"
61
62 # Get clock rate of the output
Nanang Izzuddina680bd62008-06-27 21:12:12 +000063 mo_clock_rate = re.compile("\.(\d+)\.wav").search(output_filename)
Nanang Izzuddinacb3e322008-06-25 18:18:32 +000064 if (mo_clock_rate==None):
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000065 raise TestError("Cannot compare input & output, incorrect output filename format")
Nanang Izzuddinacb3e322008-06-25 18:18:32 +000066 clock_rate = mo_clock_rate.group(1)
Nanang Izzuddin9869cb52008-06-27 16:18:13 +000067
68 # Get channel count of the output
69 channel_count = 1
70 if re.search("--stereo", ua2.inst_param.arg) != None:
71 channel_count = 2
72
73 # Get matched input file from output file
74 # (PESQ evaluates only files whose same clock rate & channel count)
75 if channel_count == 2:
Nanang Izzuddina680bd62008-06-27 21:12:12 +000076 if re.search("\.\d+\.\d+\.wav", input_filename) != None:
77 input_filename = re.sub("\.\d+\.\d+\.wav", "." + str(channel_count) + "."+clock_rate+".wav", input_filename)
Nanang Izzuddin9869cb52008-06-27 16:18:13 +000078 else:
Nanang Izzuddina680bd62008-06-27 21:12:12 +000079 input_filename = re.sub("\.\d+\.wav", "." + str(channel_count) + "."+clock_rate+".wav", input_filename)
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000080
Nanang Izzuddinacb3e322008-06-25 18:18:32 +000081 if (clock_rate != "8") & (clock_rate != "16"):
82 raise TestError("PESQ only works on clock rate 8kHz or 16kHz, clock rate used = "+clock_rate+ "kHz")
83
84 # Get conference clock rate of UA2 for PESQ sample rate option
Nanang Izzuddina680bd62008-06-27 21:12:12 +000085 pesq_sample_rate_opt = "+" + clock_rate + "000"
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000086
87 # UA1 making call
88 ua1.send("m")
89 ua1.send(t.inst_params[1].uri)
90 ua1.expect(const.STATE_CALLING)
Nanang Izzuddin9eac5472008-06-26 18:52:16 +000091
92 # UA2 wait until call established
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +000093 ua2.expect(const.STATE_CONFIRMED)
94
Benny Prijonob9760d92008-08-26 12:15:31 +000095 ua1.sync_stdout()
96 ua2.sync_stdout()
97 time.sleep(2)
98
Nanang Izzuddin9eac5472008-06-26 18:52:16 +000099 # Disconnect mic -> rec file, to avoid echo recorded when using sound device
100 # Disconnect stream -> spk, make it silent
101 # Connect stream -> rec file, start recording
102 ua2.send("cd 0 1\ncd 4 0\ncc 4 1")
Nanang Izzuddinacb3e322008-06-25 18:18:32 +0000103
Nanang Izzuddin9eac5472008-06-26 18:52:16 +0000104 # Disconnect mic -> stream, make stream purely sending from file
105 # Disconnect stream -> spk, make it silent
106 # Connect file -> stream, start sending
107 ua1.send("cd 0 4\ncd 4 0\ncc 1 4")
Nanang Izzuddinacb3e322008-06-25 18:18:32 +0000108
Nanang Izzuddin9eac5472008-06-26 18:52:16 +0000109 time.sleep(inwavlen)
110
111 # Disconnect files from bridge
112 ua2.send("cd 4 1")
113 ua2.expect(const.MEDIA_DISCONN_PORT_SUCCESS)
114 ua1.send("cd 1 4")
115 ua1.expect(const.MEDIA_DISCONN_PORT_SUCCESS)
116
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000117
118# Post body function
Nanang Izzuddina680bd62008-06-27 21:12:12 +0000119def post_func(t):
120 global pesq_sample_rate_opt
121 global input_filename
122 global output_filename
123
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000124 endpt = t.process[0]
125
126 # Execute PESQ
Benny Prijono459a0ff2009-01-05 15:31:25 +0000127 fullcmd = os.path.normpath(PESQ) + " " + pesq_sample_rate_opt + " " + input_filename + " " + output_filename
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000128 endpt.trace("Popen " + fullcmd)
Benny Prijonof84081d2009-01-04 21:28:10 +0000129 pesq_proc = subprocess.Popen(fullcmd, shell=True, stdout=subprocess.PIPE, universal_newlines=True)
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000130 pesq_out = pesq_proc.communicate()
131
132 # Parse ouput
Nanang Izzuddin9869cb52008-06-27 16:18:13 +0000133 mo_pesq_out = re.compile("Prediction[^=]+=\s+([\-\d\.]+)\s*").search(pesq_out[0])
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000134 if (mo_pesq_out == None):
135 raise TestError("Failed to fetch PESQ result")
136
Nanang Izzuddin9eac5472008-06-26 18:52:16 +0000137 # Get threshold
138 if (cfg_file.pesq_threshold != None) | (cfg_file.pesq_threshold > -0.5 ):
139 threshold = cfg_file.pesq_threshold
140 else:
141 threshold = PESQ_DEFAULT_THRESHOLD
142
143 # Evaluate the PESQ MOS value
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000144 pesq_res = mo_pesq_out.group(1)
Nanang Izzuddin9eac5472008-06-26 18:52:16 +0000145 if (float(pesq_res) >= threshold):
Nanang Izzuddinffa18c92008-06-28 00:52:20 +0000146 endpt.trace("Success, PESQ result = " + pesq_res + " (target=" + str(threshold) + ").")
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000147 else:
Nanang Izzuddinffa18c92008-06-28 00:52:20 +0000148 endpt.trace("Failed, PESQ result = " + pesq_res + " (target=" + str(threshold) + ").")
149 # Save the wav file
150 wavoutname = ARGS[1]
151 wavoutname = re.sub("[\\\/]", "_", wavoutname)
152 wavoutname = re.sub("\.py$", ".wav", wavoutname)
153 wavoutname = "logs/" + wavoutname
154 try:
155 shutil.copyfile(output_filename, wavoutname)
156 print "Output WAV is copied to " + wavoutname
157 except:
158 print "Couldn't copy output WAV, please check if 'logs' directory exists."
159
160 raise TestError("WAV seems to be degraded badly, PESQ = "+ pesq_res + " (target=" + str(threshold) + ").")
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000161
162
163# Here where it all comes together
164test = cfg_file.test_param
165test.test_func = test_func
166test.post_func = post_func
Nanang Izzuddinb6133fb2008-06-20 21:45:50 +0000167