1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | Lib/test/test_ossaudiodev.py
from test import test_support test_support.requires('audio') from test.test_support import findfile ossaudiodev = test_support.import_module('ossaudiodev') import errno import sys import sunau import time import audioop import unittest # Arggh, AFMT_S16_NE not defined on all platforms -- seems to be a # fairly recent addition to OSS. try: from ossaudiodev import AFMT_S16_NE except ImportError: if sys.byteorder == "little": AFMT_S16_NE = ossaudiodev.AFMT_S16_LE else: AFMT_S16_NE = ossaudiodev.AFMT_S16_BE def read_sound_file(path): with open(path, 'rb') as fp: au = sunau.open(fp) rate = au.getframerate() nchannels = au.getnchannels() encoding = au._encoding fp.seek(0) data = fp.read() if encoding != sunau.AUDIO_FILE_ENCODING_MULAW_8: raise RuntimeError("Expect .au file with 8-bit mu-law samples") # Convert the data to 16-bit signed. data = audioop.ulaw2lin(data, 2) return (data, rate, 16, nchannels) class OSSAudioDevTests(unittest.TestCase): def play_sound_file(self, data, rate, ssize, nchannels): try: dsp = ossaudiodev.open('w') except IOError, msg: if msg.args[0] in (errno.EACCES, errno.ENOENT, errno.ENODEV, errno.EBUSY): raise unittest.SkipTest(msg) raise # at least check that these methods can be invoked dsp.bufsize() dsp.obufcount() dsp.obuffree() dsp.getptr() dsp.fileno() # Make sure the read-only attributes work. self.assertFalse(dsp.closed) self.assertEqual(dsp.name, "/dev/dsp") self.assertEqual(dsp.mode, "w", "bad dsp.mode: %r" % dsp.mode) # And make sure they're really read-only. for attr in ('closed', 'name', 'mode'): try: setattr(dsp, attr, 42) except TypeError: pass else: self.fail("dsp.%s not read-only" % attr) # Compute expected running time of sound sample (in seconds). expected_time = float(len(data)) / (ssize//8) / nchannels / rate # set parameters based on .au file headers dsp.setparameters(AFMT_S16_NE, nchannels, rate) self.assertTrue(abs(expected_time - 3.51) < 1e-2, expected_time) t1 = time.time() dsp.write(data) dsp.close() t2 = time.time() elapsed_time = t2 - t1 percent_diff = (abs(elapsed_time - expected_time) / expected_time) * 100 self.assertTrue(percent_diff <= 10.0, "elapsed time > 10% off of expected time") def set_parameters(self, dsp): # Two configurations for testing: # config1 (8-bit, mono, 8 kHz) should work on even the most # ancient and crufty sound card, but maybe not on special- # purpose high-end hardware # config2 (16-bit, stereo, 44.1kHz) should work on all but the # most ancient and crufty hardware config1 = (ossaudiodev.AFMT_U8, 1, 8000) config2 = (AFMT_S16_NE, 2, 44100) for config in [config1, config2]: (fmt, channels, rate) = config if (dsp.setfmt(fmt) == fmt and dsp.channels(channels) == channels and dsp.speed(rate) == rate): break else: raise RuntimeError("unable to set audio sampling parameters: " "you must have really weird audio hardware") # setparameters() should be able to set this configuration in # either strict or non-strict mode. result = dsp.setparameters(fmt, channels, rate, False) self.assertEqual(result, (fmt, channels, rate), "setparameters%r: returned %r" % (config, result)) result = dsp.setparameters(fmt, channels, rate, True) self.assertEqual(result, (fmt, channels, rate), "setparameters%r: returned %r" % (config, result)) def set_bad_parameters(self, dsp): # Now try some configurations that are presumably bogus: eg. 300 # channels currently exceeds even Hollywood's ambitions, and # negative sampling rate is utter nonsense. setparameters() should # accept these in non-strict mode, returning something other than # was requested, but should barf in strict mode. fmt = AFMT_S16_NE rate = 44100 channels = 2 for config in [(fmt, 300, rate), # ridiculous nchannels (fmt, -5, rate), # impossible nchannels (fmt, channels, -50), # impossible rate ]: (fmt, channels, rate) = config result = dsp.setparameters(fmt, channels, rate, False) self.assertNotEqual(result, config, "unexpectedly got requested configuration") try: result = dsp.setparameters(fmt, channels, rate, True) except ossaudiodev.OSSAudioError, err: pass else: self.fail("expected OSSAudioError") def test_playback(self): sound_info = read_sound_file(findfile('audiotest.au')) self.play_sound_file(*sound_info) def test_set_parameters(self): dsp = ossaudiodev.open("w") try: self.set_parameters(dsp) # Disabled because it fails under Linux 2.6 with ALSA's OSS # emulation layer. #self.set_bad_parameters(dsp) finally: dsp.close() self.assertTrue(dsp.closed) def test_main(): try: dsp = ossaudiodev.open('w') except (ossaudiodev.error, IOError), msg: if msg.args[0] in (errno.EACCES, errno.ENOENT, errno.ENODEV, errno.EBUSY): raise unittest.SkipTest(msg) raise dsp.close() test_support.run_unittest(__name__) if __name__ == "__main__": test_main() |