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