Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 1 | # $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 | |
| 13 | import time |
| 14 | import imp |
| 15 | import sys |
| 16 | import re |
| 17 | import subprocess |
| 18 | import inc_const as const |
| 19 | |
| 20 | from inc_cfg import * |
| 21 | |
| 22 | # Load configuration |
| 23 | cfg_file = imp.load_source("cfg_file", sys.argv[2]) |
| 24 | |
| 25 | # PESQ configs |
| 26 | # PESQ_THRESHOLD specifies the minimum acceptable PESQ MOS value, so test can be declared successful |
| 27 | PESQ = "tools/pesq.exe" |
Nanang Izzuddin | 6ee166d | 2008-06-26 12:26:52 +0000 | [diff] [blame^] | 28 | PESQ_THRESHOLD = 3.0 |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 29 | |
| 30 | # UserData |
| 31 | class mod_pesq_user_data: |
| 32 | # Sample rate option for PESQ |
| 33 | pesq_sample_rate_opt = "" |
| 34 | # Input/Reference filename |
| 35 | input_filename = "" |
| 36 | # Output/Degraded filename |
| 37 | output_filename = "" |
| 38 | |
| 39 | # Test body function |
| 40 | def test_func(t, user_data): |
Nanang Izzuddin | 6ee166d | 2008-06-26 12:26:52 +0000 | [diff] [blame^] | 41 | |
| 42 | if len(t.process) == 0: |
| 43 | return |
| 44 | |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 45 | ua1 = t.process[0] |
| 46 | ua2 = t.process[1] |
| 47 | |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 48 | # Get input file name |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 49 | user_data.input_filename = re.compile(const.MEDIA_PLAY_FILE).search(ua1.inst_param.arg).group(1) |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 50 | |
| 51 | # Get output file name |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 52 | user_data.output_filename = re.compile(const.MEDIA_REC_FILE).search(ua2.inst_param.arg).group(1) |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 53 | |
| 54 | # Find appropriate clock rate for the input file |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 55 | mo_clock_rate = re.compile("\.(\d+)\.wav").search(user_data.output_filename) |
| 56 | if (mo_clock_rate==None): |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 57 | raise TestError("Cannot compare input & output, incorrect output filename format") |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 58 | clock_rate = mo_clock_rate.group(1) |
| 59 | user_data.input_filename = re.sub("\.\d+\.wav", "."+clock_rate+".wav", user_data.input_filename) |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 60 | |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 61 | if (clock_rate != "8") & (clock_rate != "16"): |
| 62 | raise TestError("PESQ only works on clock rate 8kHz or 16kHz, clock rate used = "+clock_rate+ "kHz") |
| 63 | |
| 64 | # Get conference clock rate of UA2 for PESQ sample rate option |
| 65 | user_data.pesq_sample_rate_opt = "+" + clock_rate + "000" |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 66 | |
| 67 | # UA1 making call |
| 68 | ua1.send("m") |
| 69 | ua1.send(t.inst_params[1].uri) |
| 70 | ua1.expect(const.STATE_CALLING) |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 71 | ua2.expect(const.STATE_CONFIRMED) |
| 72 | |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 73 | # Disconnect mic -> rec file to avoid echo recorded when using sound device |
| 74 | ua2.send("cd 0 1") |
| 75 | |
| 76 | # Auto answer, auto play, auto hangup |
| 77 | # Just wait for call disconnected |
| 78 | # Assumed WAV input is no more than 30 secs |
| 79 | while 1: |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 80 | line = ua2.proc.stdout.readline() |
| 81 | if line == "": |
| 82 | raise TestError(ua2.name + ": Premature EOF") |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 83 | |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 84 | # Search for disconnected text |
| 85 | if re.search(const.STATE_DISCONNECTED, line) != None: |
| 86 | break |
| 87 | |
| 88 | |
| 89 | # Post body function |
| 90 | def post_func(t, user_data): |
| 91 | endpt = t.process[0] |
| 92 | |
| 93 | # Execute PESQ |
| 94 | fullcmd = PESQ + " " + user_data.pesq_sample_rate_opt + " " + user_data.input_filename + " " + user_data.output_filename |
| 95 | endpt.trace("Popen " + fullcmd) |
| 96 | pesq_proc = subprocess.Popen(fullcmd, stdout=subprocess.PIPE, universal_newlines=True) |
| 97 | pesq_out = pesq_proc.communicate() |
| 98 | |
| 99 | # Parse ouput |
Nanang Izzuddin | 6ee166d | 2008-06-26 12:26:52 +0000 | [diff] [blame^] | 100 | mo_pesq_out = re.compile("Prediction[^=]+=\s+([\d\.]+)\s*").search(pesq_out[0]) |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 101 | if (mo_pesq_out == None): |
| 102 | raise TestError("Failed to fetch PESQ result") |
| 103 | |
| 104 | # Evaluate the similarity value |
| 105 | pesq_res = mo_pesq_out.group(1) |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 106 | if (float(pesq_res) >= PESQ_THRESHOLD): |
Nanang Izzuddin | 6ee166d | 2008-06-26 12:26:52 +0000 | [diff] [blame^] | 107 | endpt.trace("Success, PESQ result = " + pesq_res) |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 108 | else: |
Nanang Izzuddin | 6ee166d | 2008-06-26 12:26:52 +0000 | [diff] [blame^] | 109 | endpt.trace("Failed, PESQ result = " + pesq_res) |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 110 | raise TestError("WAV seems to be degraded badly") |
| 111 | |
| 112 | |
| 113 | # Here where it all comes together |
| 114 | test = cfg_file.test_param |
| 115 | test.test_func = test_func |
| 116 | test.post_func = post_func |
| 117 | test.user_data = mod_pesq_user_data() |
| 118 | |