blob: 081c528f35f9c9d8ccbdbaebbaedc8a7869e1e36 [file] [log] [blame]
Hsinyu Chao4b8300e2011-11-15 13:07:32 -08001#!/usr/bin/python
2# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import logging
7import os
Hsinyu Chaof80337a2012-04-07 18:02:29 +08008import re
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +08009import threading
Hsin-Yu Chaof272d8e2013-04-05 03:28:50 +080010import time
Hsinyu Chao4b8300e2011-11-15 13:07:32 -080011
Hsin-Yu Chao084e9da2012-11-07 15:56:26 +080012from glob import glob
13
Hsinyu Chao4b8300e2011-11-15 13:07:32 -080014from autotest_lib.client.bin import utils
Hsin-Yu Chao084e9da2012-11-07 15:56:26 +080015from autotest_lib.client.bin.input.input_device import *
Hsinyu Chao4b8300e2011-11-15 13:07:32 -080016from autotest_lib.client.common_lib import error
17
18LD_LIBRARY_PATH = 'LD_LIBRARY_PATH'
19
Hsinyu Chaof80337a2012-04-07 18:02:29 +080020_DEFAULT_NUM_CHANNELS = 2
Dylan Reidbf9a5d42012-11-06 16:27:20 -080021_DEFAULT_REC_COMMAND = 'arecord -D hw:0,0 -d 10 -f dat'
Hsinyu Chaof80337a2012-04-07 18:02:29 +080022_DEFAULT_SOX_FORMAT = '-t raw -b 16 -e signed -r 48000 -L'
Hsin-Yu Chao4be6d182013-04-19 14:07:56 +080023
24# Minimum RMS value to pass when checking recorded file.
25_DEFAULT_SOX_RMS_THRESHOLD = 0.08
Hsinyu Chaof80337a2012-04-07 18:02:29 +080026
Hsin-Yu Chao8d093f42012-11-05 18:43:22 +080027_JACK_VALUE_ON_RE = re.compile('.*values=on')
28_HP_JACK_CONTROL_RE = re.compile('numid=(\d+).*Headphone\sJack')
29_MIC_JACK_CONTROL_RE = re.compile('numid=(\d+).*Mic\sJack')
30
Hsinyu Chaof80337a2012-04-07 18:02:29 +080031_SOX_RMS_AMPLITUDE_RE = re.compile('RMS\s+amplitude:\s+(.+)')
Hsinyu Chao2d64e1f2012-05-21 11:18:53 +080032_SOX_ROUGH_FREQ_RE = re.compile('Rough\s+frequency:\s+(.+)')
Hsinyu Chaof80337a2012-04-07 18:02:29 +080033_SOX_FORMAT = '-t raw -b 16 -e signed -r 48000 -L'
34
Hsin-Yu Chao95ee3512012-11-05 20:43:10 +080035_AUDIO_NOT_FOUND_RE = r'Audio\snot\sdetected'
36_MEASURED_LATENCY_RE = r'Measured\sLatency:\s(\d+)\suS'
37_REPORTED_LATENCY_RE = r'Reported\sLatency:\s(\d+)\suS'
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +080038
Hsin-Yu Chaof6bbc6c2013-08-20 19:22:05 +080039# Tools from platform/audiotest
40AUDIOFUNTEST_PATH = 'audiofuntest'
41AUDIOLOOP_PATH = 'looptest'
42LOOPBACK_LATENCY_PATH = 'loopback_latency'
43SOX_PATH = 'sox'
44TEST_TONES_PATH = 'test_tones'
45
46
Hsin-Yu Chao30561af2013-09-06 14:03:56 +080047def set_mixer_controls(mixer_settings={}, card='0'):
48 '''
49 Sets all mixer controls listed in the mixer settings on card.
50
51 @param mixer_settings: Mixer settings to set.
52 @param card: Index of audio card to set mixer settings for.
53 '''
54 logging.info('Setting mixer control values on %s', card)
55 for item in mixer_settings:
56 logging.info('Setting %s to %s on card %s',
57 item['name'], item['value'], card)
58 cmd = 'amixer -c %s cset name=%s %s'
59 cmd = cmd % (card, item['name'], item['value'])
60 try:
61 utils.system(cmd)
62 except error.CmdError:
63 # A card is allowed not to support all the controls, so don't
64 # fail the test here if we get an error.
65 logging.info('amixer command failed: %s', cmd)
66
67def set_volume_levels(volume, capture):
68 '''
69 Sets the volume and capture gain through cras_test_client
70
71 @param volume: The playback volume to set.
72 @param capture: The capture gain to set.
73 '''
74 logging.info('Setting volume level to %d', volume)
75 utils.system('/usr/bin/cras_test_client --volume %d' % volume)
76 logging.info('Setting capture gain to %d', capture)
77 utils.system('/usr/bin/cras_test_client --capture_gain %d' % capture)
78 utils.system('/usr/bin/cras_test_client --dump_server_info')
79 utils.system('/usr/bin/cras_test_client --mute 0')
80 utils.system('amixer -c 0 contents')
81
82def loopback_latency_check(**args):
83 '''
84 Checks loopback latency.
85
86 @param args: additional arguments for loopback_latency.
87
88 @return A tuple containing measured and reported latency in uS.
89 Return None if no audio detected.
90 '''
91 noise_threshold = str(args['n']) if args.has_key('n') else '400'
92
93 cmd = '%s -n %s' % (LOOPBACK_LATENCY_PATH, noise_threshold)
94
95 output = utils.system_output(cmd, retain_output=True)
96
97 # Sleep for a short while to make sure device is not busy anymore
98 # after called loopback_latency.
99 time.sleep(.1)
100
101 measured_latency = None
102 reported_latency = None
103 for line in output.split('\n'):
104 match = re.search(_MEASURED_LATENCY_RE, line, re.I)
105 if match:
106 measured_latency = int(match.group(1))
107 continue
108 match = re.search(_REPORTED_LATENCY_RE, line, re.I)
109 if match:
110 reported_latency = int(match.group(1))
111 continue
112 if re.search(_AUDIO_NOT_FOUND_RE, line, re.I):
113 return None
114 if measured_latency and reported_latency:
115 return (measured_latency, reported_latency)
116 else:
117 # Should not reach here, just in case.
118 return None
119
120def get_mixer_jack_status(jack_reg_exp):
121 '''
122 Gets the mixer jack status.
123
124 @param jack_reg_exp: The regular expression to match jack control name.
125
126 @return None if the control does not exist, return True if jack control
127 is detected plugged, return False otherwise.
128 '''
129 output = utils.system_output('amixer -c0 controls', retain_output=True)
130 numid = None
131 for line in output.split('\n'):
132 m = jack_reg_exp.match(line)
133 if m:
134 numid = m.group(1)
135 break
136
137 # Proceed only when matched numid is not empty.
138 if numid:
139 output = utils.system_output('amixer -c0 cget numid=%s' % numid)
140 for line in output.split('\n'):
141 if _JACK_VALUE_ON_RE.match(line):
142 return True
143 return False
144 else:
145 return None
146
147def get_hp_jack_status():
148 '''Gets the status of headphone jack'''
149 status = get_mixer_jack_status(_HP_JACK_CONTROL_RE)
150 if status is not None:
151 return status
152
153 # When headphone jack is not found in amixer, lookup input devices
154 # instead.
155 #
156 # TODO(hychao): Check hp/mic jack status dynamically from evdev. And
157 # possibly replace the existing check using amixer.
158 for evdev in glob('/dev/input/event*'):
159 device = InputDevice(evdev)
160 if device.is_hp_jack():
161 return device.get_headphone_insert()
162 else:
163 return None
164
165def get_mic_jack_status():
166 '''Gets the status of mic jack'''
167 status = get_mixer_jack_status(_MIC_JACK_CONTROL_RE)
168 if status is not None:
169 return status
170
171 # When mic jack is not found in amixer, lookup input devices instead.
172 for evdev in glob('/dev/input/event*'):
173 device = InputDevice(evdev)
174 if device.is_mic_jack():
175 return device.get_microphone_insert()
176 else:
177 return None
178
179def check_loopback_dongle():
180 '''
181 Checks if loopback dongle is equipped correctly.
182 '''
183 # Check Mic Jack
184 mic_jack_status = get_mic_jack_status()
185 if mic_jack_status is None:
186 logging.warning('Found no Mic Jack control, skip check.')
187 elif not mic_jack_status:
188 logging.info('Mic jack is not plugged.')
189 return False
190 else:
191 logging.info('Mic jack is plugged.')
192
193 # Check Headphone Jack
194 hp_jack_status = get_hp_jack_status()
195 if hp_jack_status is None:
196 logging.warning('Found no Headphone Jack control, skip check.')
197 elif not hp_jack_status:
198 logging.info('Headphone jack is not plugged.')
199 return False
200 else:
201 logging.info('Headphone jack is plugged.')
202
203 # Use latency check to test if audio can be captured through dongle.
204 # We only want to know the basic function of dongle, so no need to
205 # assert the latency accuracy here.
206 latency = loopback_latency_check(n=4000)
207 if latency:
208 logging.info('Got latency measured %d, reported %d',
209 latency[0], latency[1])
210 else:
211 logging.warning('Latency check fail.')
212 return False
213
214 return True
215
216# Functions to test audio palyback.
217def play_sound(duration_seconds=None, audio_file_path=None):
218 '''
219 Plays a sound file found at |audio_file_path| for |duration_seconds|.
220
221 If |audio_file_path|=None, plays a default audio file.
222 If |duration_seconds|=None, plays audio file in its entirety.
223
224 @param duration_seconds: Duration to play sound.
225 @param audio_file_path: Path to the audio file.
226 '''
227 if not audio_file_path:
228 audio_file_path = '/usr/local/autotest/cros/audio/sine440.wav'
229 duration_arg = ('-d %d' % duration_seconds) if duration_seconds else ''
230 utils.system('aplay %s %s' % (duration_arg, audio_file_path))
231
232def get_play_sine_args(channel, odev='default', freq=1000, duration=10,
233 sample_size=16):
234 '''Gets the command args to generate a sine wav to play to odev.
235
236 @param channel: 0 for left, 1 for right; otherwize, mono.
237 @param odev: alsa output device.
238 @param freq: frequency of the generated sine tone.
239 @param duration: duration of the generated sine tone.
240 @param sample_size: output audio sample size. Default to 16.
241 '''
242 cmdargs = [SOX_PATH, '-b', str(sample_size), '-n', '-t', 'alsa',
243 odev, 'synth', str(duration)]
244 if channel == 0:
245 cmdargs += ['sine', str(freq), 'sine', '0']
246 elif channel == 1:
247 cmdargs += ['sine', '0', 'sine', str(freq)]
248 else:
249 cmdargs += ['sine', str(freq)]
250
251 return cmdargs
252
253def play_sine(channel, odev='default', freq=1000, duration=10,
254 sample_size=16):
255 '''Generates a sine wave and plays to odev.
256
257 @param channel: 0 for left, 1 for right; otherwize, mono.
258 @param odev: alsa output device.
259 @param freq: frequency of the generated sine tone.
260 @param duration: duration of the generated sine tone.
261 @param sample_size: output audio sample size. Default to 16.
262 '''
263 cmdargs = get_play_sine_args(channel, odev, freq, duration, sample_size)
264 utils.system(' '.join(cmdargs))
265
266
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +0800267class RecordSampleThread(threading.Thread):
268 '''Wraps the execution of arecord in a thread.'''
269 def __init__(self, audio, recordfile):
270 threading.Thread.__init__(self)
271 self._audio = audio
272 self._recordfile = recordfile
273
274 def run(self):
275 self._audio.record_sample(self._recordfile)
276
277
Adrian Li689d3ff2013-07-15 15:11:06 -0700278class RecordMixThread(threading.Thread):
279 '''
280 Wraps the execution of recording the mixed loopback stream in
281 cras_test_client in a thread.
282 '''
283 def __init__(self, audio, recordfile):
284 threading.Thread.__init__(self)
285 self._audio = audio
286 self._recordfile = recordfile
287
288 def run(self):
289 self._audio.record_mix(self._recordfile)
290
291
Hsinyu Chao4b8300e2011-11-15 13:07:32 -0800292class AudioHelper(object):
293 '''
294 A helper class contains audio related utility functions.
295 '''
Dylan Reidbf9a5d42012-11-06 16:27:20 -0800296 def __init__(self, test,
297 sox_format = _DEFAULT_SOX_FORMAT,
Dylan Reid51f289c2012-11-06 17:16:24 -0800298 sox_threshold = _DEFAULT_SOX_RMS_THRESHOLD,
Dylan Reidbf9a5d42012-11-06 16:27:20 -0800299 record_command = _DEFAULT_REC_COMMAND,
Adrian Li689d3ff2013-07-15 15:11:06 -0700300 num_channels = _DEFAULT_NUM_CHANNELS,
301 mix_command = None):
Hsinyu Chao4b8300e2011-11-15 13:07:32 -0800302 self._test = test
Dylan Reid51f289c2012-11-06 17:16:24 -0800303 self._sox_threshold = sox_threshold
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800304 self._sox_format = sox_format
Dylan Reidbf9a5d42012-11-06 16:27:20 -0800305 self._rec_cmd = record_command
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +0800306 self._num_channels = num_channels
Adrian Li689d3ff2013-07-15 15:11:06 -0700307 self._mix_cmd = mix_command
Hsinyu Chao4b8300e2011-11-15 13:07:32 -0800308
Hsinyu Chao2d64e1f2012-05-21 11:18:53 +0800309 def sox_stat_output(self, infile, channel):
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800310 '''Executes sox stat command.
311
312 @param infile: Input file name.
313 @param channel: The selected channel.
314
315 @return The output of sox stat command
316 '''
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800317 sox_mixer_cmd = self.get_sox_mixer_cmd(infile, channel)
Hsin-Yu Chaof6bbc6c2013-08-20 19:22:05 +0800318 stat_cmd = '%s -c 1 %s - -n stat 2>&1' % (SOX_PATH,
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800319 self._sox_format)
320 sox_cmd = '%s | %s' % (sox_mixer_cmd, stat_cmd)
Hsinyu Chao2d64e1f2012-05-21 11:18:53 +0800321 return utils.system_output(sox_cmd, retain_output=True)
322
323 def get_audio_rms(self, sox_output):
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800324 '''Gets the audio RMS value from sox stat output
325
326 @param sox_output: Output of sox stat command.
327
328 @return The RMS value parsed from sox stat output.
329 '''
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800330 for rms_line in sox_output.split('\n'):
331 m = _SOX_RMS_AMPLITUDE_RE.match(rms_line)
332 if m is not None:
333 return float(m.group(1))
334
Hsinyu Chao2d64e1f2012-05-21 11:18:53 +0800335 def get_rough_freq(self, sox_output):
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800336 '''Gets the rough audio frequency from sox stat output
337
338 @param sox_output: Output of sox stat command.
339
340 @return The rough frequency value parsed from sox stat output.
341 '''
342
Hsinyu Chao2d64e1f2012-05-21 11:18:53 +0800343 for rms_line in sox_output.split('\n'):
344 m = _SOX_ROUGH_FREQ_RE.match(rms_line)
345 if m is not None:
346 return int(m.group(1))
347
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800348 def get_sox_mixer_cmd(self, infile, channel):
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800349 '''Gets sox mixer command to reduce channel.
350
351 @param infile: Input file name.
352 @param channel: The selected channel to take effect.
353 '''
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800354 # Build up a pan value string for the sox command.
355 if channel == 0:
356 pan_values = '1'
357 else:
358 pan_values = '0'
359 for pan_index in range(1, self._num_channels):
360 if channel == pan_index:
361 pan_values = '%s%s' % (pan_values, ',1')
362 else:
363 pan_values = '%s%s' % (pan_values, ',0')
364
Hsin-Yu Chaof6bbc6c2013-08-20 19:22:05 +0800365 return '%s -c 2 %s %s -c 1 %s - mixer %s' % (SOX_PATH,
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800366 self._sox_format, infile, self._sox_format, pan_values)
367
368 def noise_reduce_file(self, in_file, noise_file, out_file):
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +0800369 '''Runs the sox command to noise-reduce in_file using
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800370 the noise profile from noise_file.
371
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800372 @param in_file: The file to noise reduce.
373 @param noise_file: The file containing the noise profile.
374 This can be created by recording silence.
375 @param out_file: The file contains the noise reduced sound.
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800376
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800377 @return The name of the file containing the noise-reduced data.
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +0800378 '''
Hsin-Yu Chaof6bbc6c2013-08-20 19:22:05 +0800379 prof_cmd = '%s -c 2 %s %s -n noiseprof' % (SOX_PATH,
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800380 _SOX_FORMAT, noise_file)
381 reduce_cmd = ('%s -c 2 %s %s -c 2 %s %s noisered' %
Hsin-Yu Chaof6bbc6c2013-08-20 19:22:05 +0800382 (SOX_PATH, _SOX_FORMAT, in_file, _SOX_FORMAT, out_file))
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800383 utils.system('%s | %s' % (prof_cmd, reduce_cmd))
384
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +0800385 def record_sample(self, tmpfile):
386 '''Records a sample from the default input device.
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800387
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800388 @param tmpfile: The file to record to.
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +0800389 '''
Dylan Reidbf9a5d42012-11-06 16:27:20 -0800390 cmd_rec = self._rec_cmd + ' %s' % tmpfile
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800391 logging.info('Command %s recording now', cmd_rec)
Hsinyu Chaof80337a2012-04-07 18:02:29 +0800392 utils.system(cmd_rec)
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +0800393
Adrian Li689d3ff2013-07-15 15:11:06 -0700394 def record_mix(self, tmpfile):
395 '''Records a sample from the mixed loopback stream in cras_test_client.
396
397 @param tmpfile: The file to record to.
398 '''
399 cmd_mix = self._mix_cmd + ' %s' % tmpfile
400 logging.info('Command %s recording now', cmd_mix)
401 utils.system(cmd_mix)
402
Rohit Makasana8ef9e292013-05-02 19:02:15 -0700403 def loopback_test_channels(self, noise_file_name,
404 loopback_callback=None,
405 check_recorded_callback=None,
406 preserve_test_file=True):
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +0800407 '''Tests loopback on all channels.
408
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800409 @param noise_file_name: Name of the file contains pre-recorded noise.
410 @param loopback_callback: The callback to do the loopback for
411 one channel.
412 @param check_recorded_callback: The callback to check recorded file.
Rohit Makasana8ef9e292013-05-02 19:02:15 -0700413 @param preserve_test_file: Retain the recorded files for future debugging.
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +0800414 '''
415 for channel in xrange(self._num_channels):
Hsin-Yu Chao78c44b22013-04-06 05:33:58 +0800416 reduced_file_name = self.create_wav_file("reduced-%d" % channel)
417 record_file_name = self.create_wav_file("record-%d" % channel)
Hsin-Yu Chao78c44b22013-04-06 05:33:58 +0800418 record_thread = RecordSampleThread(self, record_file_name)
419 record_thread.start()
Adrian Li689d3ff2013-07-15 15:11:06 -0700420
421 if self._mix_cmd != None:
422 mix_file_name = self.create_wav_file("mix-%d" % channel)
423 mix_thread = RecordMixThread(self, mix_file_name)
424 mix_thread.start()
425
Hsin-Yu Chao78c44b22013-04-06 05:33:58 +0800426 if loopback_callback:
427 loopback_callback(channel)
Adrian Li689d3ff2013-07-15 15:11:06 -0700428
429 if self._mix_cmd != None:
430 mix_thread.join()
431 sox_output_mix = self.sox_stat_output(mix_file_name, channel)
432 rms_val_mix = self.get_audio_rms(sox_output_mix)
433 logging.info('Got mixed audio RMS value of %f.', rms_val_mix)
434
Hsin-Yu Chao78c44b22013-04-06 05:33:58 +0800435 record_thread.join()
Adrian Li689d3ff2013-07-15 15:11:06 -0700436 sox_output_record = self.sox_stat_output(record_file_name, channel)
437 rms_val_record = self.get_audio_rms(sox_output_record)
438 logging.info('Got recorded audio RMS value of %f.', rms_val_record)
Hsinyu Chao2a7e2f22012-04-18 16:46:43 +0800439
Hsin-Yu Chao78c44b22013-04-06 05:33:58 +0800440 self.noise_reduce_file(record_file_name, noise_file_name,
Adrian Li689d3ff2013-07-15 15:11:06 -0700441 reduced_file_name)
Hsin-Yu Chao11041d32012-11-13 15:46:13 +0800442
Adrian Li689d3ff2013-07-15 15:11:06 -0700443 sox_output_reduced = self.sox_stat_output(reduced_file_name,
444 channel)
Hsin-Yu Chao78c44b22013-04-06 05:33:58 +0800445
Rohit Makasana8ef9e292013-05-02 19:02:15 -0700446 if not preserve_test_file:
447 os.unlink(reduced_file_name)
448 os.unlink(record_file_name)
Adrian Li689d3ff2013-07-15 15:11:06 -0700449 if self._mix_cmd != None:
450 os.unlink(mix_file_name)
Hsin-Yu Chao78c44b22013-04-06 05:33:58 +0800451 # Use injected check recorded callback if any.
452 if check_recorded_callback:
Adrian Li689d3ff2013-07-15 15:11:06 -0700453 check_recorded_callback(sox_output_reduced)
Hsin-Yu Chao78c44b22013-04-06 05:33:58 +0800454 else:
Adrian Li689d3ff2013-07-15 15:11:06 -0700455 self.check_recorded(sox_output_reduced)
Dylan Reid51f289c2012-11-06 17:16:24 -0800456
457 def check_recorded(self, sox_output):
458 """Checks if the calculated RMS value is expected.
459
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800460 @param sox_output: The output from sox stat command.
Dylan Reid51f289c2012-11-06 17:16:24 -0800461
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800462 @raises error.TestError if RMS amplitude can't be parsed.
463 @raises error.TestFail if the RMS amplitude of the recording isn't above
Dylan Reid51f289c2012-11-06 17:16:24 -0800464 the threshold.
465 """
466 rms_val = self.get_audio_rms(sox_output)
467
468 # In case we don't get a valid RMS value.
469 if rms_val is None:
470 raise error.TestError(
471 'Failed to generate an audio RMS value from playback.')
472
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800473 logging.info('Got audio RMS value of %f. Minimum pass is %f.',
474 rms_val, self._sox_threshold)
Dylan Reid51f289c2012-11-06 17:16:24 -0800475 if rms_val < self._sox_threshold:
Hsin-Yu Chao84e86d22013-04-03 00:43:01 +0800476 raise error.TestFail(
Dylan Reid51f289c2012-11-06 17:16:24 -0800477 'Audio RMS value %f too low. Minimum pass is %f.' %
478 (rms_val, self._sox_threshold))
Hsin-Yu Chao95ee3512012-11-05 20:43:10 +0800479
Hsin-Yu Chao78c44b22013-04-06 05:33:58 +0800480 def create_wav_file(self, prefix=""):
481 '''Creates a unique name for wav file.
482
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800483 The created file name will be preserved in autotest result directory
484 for future analysis.
Hsin-Yu Chao78c44b22013-04-06 05:33:58 +0800485
Hsin-Yu Chao2ecbfe62013-04-06 05:49:27 +0800486 @param prefix: specified file name prefix.
Hsin-Yu Chao78c44b22013-04-06 05:33:58 +0800487 '''
488 filename = "%s-%s.wav" % (prefix, time.time())
489 return os.path.join(self._test.resultsdir, filename)