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 |
Nanang Izzuddin | 9eac547 | 2008-06-26 18:52:16 +0000 | [diff] [blame] | 18 | import wave |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 19 | import inc_const as const |
| 20 | |
| 21 | from inc_cfg import * |
| 22 | |
| 23 | # Load configuration |
| 24 | cfg_file = imp.load_source("cfg_file", sys.argv[2]) |
| 25 | |
| 26 | # PESQ configs |
| 27 | # PESQ_THRESHOLD specifies the minimum acceptable PESQ MOS value, so test can be declared successful |
| 28 | PESQ = "tools/pesq.exe" |
Nanang Izzuddin | 9eac547 | 2008-06-26 18:52:16 +0000 | [diff] [blame] | 29 | PESQ_DEFAULT_THRESHOLD = 3.4 |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 30 | |
| 31 | # UserData |
| 32 | class mod_pesq_user_data: |
| 33 | # Sample rate option for PESQ |
| 34 | pesq_sample_rate_opt = "" |
| 35 | # Input/Reference filename |
| 36 | input_filename = "" |
| 37 | # Output/Degraded filename |
| 38 | output_filename = "" |
| 39 | |
| 40 | # Test body function |
| 41 | def test_func(t, user_data): |
Nanang Izzuddin | 6ee166d | 2008-06-26 12:26:52 +0000 | [diff] [blame] | 42 | |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 43 | ua1 = t.process[0] |
| 44 | ua2 = t.process[1] |
| 45 | |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 46 | # Get input file name |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 47 | 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] | 48 | |
| 49 | # Get output file name |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 50 | 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] | 51 | |
| 52 | # Find appropriate clock rate for the input file |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 53 | mo_clock_rate = re.compile("\.(\d+)\.wav").search(user_data.output_filename) |
| 54 | if (mo_clock_rate==None): |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 55 | raise TestError("Cannot compare input & output, incorrect output filename format") |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 56 | clock_rate = mo_clock_rate.group(1) |
| 57 | 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] | 58 | |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 59 | if (clock_rate != "8") & (clock_rate != "16"): |
| 60 | raise TestError("PESQ only works on clock rate 8kHz or 16kHz, clock rate used = "+clock_rate+ "kHz") |
| 61 | |
| 62 | # Get conference clock rate of UA2 for PESQ sample rate option |
| 63 | user_data.pesq_sample_rate_opt = "+" + clock_rate + "000" |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 64 | |
Nanang Izzuddin | 9eac547 | 2008-06-26 18:52:16 +0000 | [diff] [blame] | 65 | # Get WAV input length, in seconds |
| 66 | fin = wave.open(user_data.input_filename, "r") |
| 67 | if fin == None: |
| 68 | raise TestError("Failed opening input WAV file") |
| 69 | inwavlen = fin.getnframes() // fin.getframerate() |
| 70 | if (fin.getnframes() % fin.getframerate()) > 0: |
| 71 | inwavlen = inwavlen + 1 |
| 72 | fin.close() |
| 73 | |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 74 | # UA1 making call |
| 75 | ua1.send("m") |
| 76 | ua1.send(t.inst_params[1].uri) |
| 77 | ua1.expect(const.STATE_CALLING) |
Nanang Izzuddin | 9eac547 | 2008-06-26 18:52:16 +0000 | [diff] [blame] | 78 | |
| 79 | # UA2 wait until call established |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 80 | ua2.expect(const.STATE_CONFIRMED) |
| 81 | |
Nanang Izzuddin | 9eac547 | 2008-06-26 18:52:16 +0000 | [diff] [blame] | 82 | # Disconnect mic -> rec file, to avoid echo recorded when using sound device |
| 83 | # Disconnect stream -> spk, make it silent |
| 84 | # Connect stream -> rec file, start recording |
| 85 | ua2.send("cd 0 1\ncd 4 0\ncc 4 1") |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 86 | |
Nanang Izzuddin | 9eac547 | 2008-06-26 18:52:16 +0000 | [diff] [blame] | 87 | # Disconnect mic -> stream, make stream purely sending from file |
| 88 | # Disconnect stream -> spk, make it silent |
| 89 | # Connect file -> stream, start sending |
| 90 | ua1.send("cd 0 4\ncd 4 0\ncc 1 4") |
Nanang Izzuddin | acb3e32 | 2008-06-25 18:18:32 +0000 | [diff] [blame] | 91 | |
Nanang Izzuddin | 9eac547 | 2008-06-26 18:52:16 +0000 | [diff] [blame] | 92 | time.sleep(inwavlen) |
| 93 | |
| 94 | # Disconnect files from bridge |
| 95 | ua2.send("cd 4 1") |
| 96 | ua2.expect(const.MEDIA_DISCONN_PORT_SUCCESS) |
| 97 | ua1.send("cd 1 4") |
| 98 | ua1.expect(const.MEDIA_DISCONN_PORT_SUCCESS) |
| 99 | |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 100 | |
| 101 | # Post body function |
| 102 | def post_func(t, user_data): |
| 103 | endpt = t.process[0] |
| 104 | |
| 105 | # Execute PESQ |
| 106 | fullcmd = PESQ + " " + user_data.pesq_sample_rate_opt + " " + user_data.input_filename + " " + user_data.output_filename |
| 107 | endpt.trace("Popen " + fullcmd) |
| 108 | pesq_proc = subprocess.Popen(fullcmd, stdout=subprocess.PIPE, universal_newlines=True) |
| 109 | pesq_out = pesq_proc.communicate() |
| 110 | |
| 111 | # Parse ouput |
Nanang Izzuddin | 6ee166d | 2008-06-26 12:26:52 +0000 | [diff] [blame] | 112 | 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] | 113 | if (mo_pesq_out == None): |
| 114 | raise TestError("Failed to fetch PESQ result") |
| 115 | |
Nanang Izzuddin | 9eac547 | 2008-06-26 18:52:16 +0000 | [diff] [blame] | 116 | # Get threshold |
| 117 | if (cfg_file.pesq_threshold != None) | (cfg_file.pesq_threshold > -0.5 ): |
| 118 | threshold = cfg_file.pesq_threshold |
| 119 | else: |
| 120 | threshold = PESQ_DEFAULT_THRESHOLD |
| 121 | |
| 122 | # Evaluate the PESQ MOS value |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 123 | pesq_res = mo_pesq_out.group(1) |
Nanang Izzuddin | 9eac547 | 2008-06-26 18:52:16 +0000 | [diff] [blame] | 124 | if (float(pesq_res) >= threshold): |
Nanang Izzuddin | 6ee166d | 2008-06-26 12:26:52 +0000 | [diff] [blame] | 125 | endpt.trace("Success, PESQ result = " + pesq_res) |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 126 | else: |
Nanang Izzuddin | 6ee166d | 2008-06-26 12:26:52 +0000 | [diff] [blame] | 127 | endpt.trace("Failed, PESQ result = " + pesq_res) |
Nanang Izzuddin | b6133fb | 2008-06-20 21:45:50 +0000 | [diff] [blame] | 128 | raise TestError("WAV seems to be degraded badly") |
| 129 | |
| 130 | |
| 131 | # Here where it all comes together |
| 132 | test = cfg_file.test_param |
| 133 | test.test_func = test_func |
| 134 | test.post_func = post_func |
| 135 | test.user_data = mod_pesq_user_data() |
| 136 | |