1import audioop
2import sys
3import unittest
4import struct
5from test.test_support import run_unittest
6
7
8formats = {
9    1: 'b',
10    2: 'h',
11    4: 'i',
12}
13
14def pack(width, data):
15    return struct.pack('=%d%s' % (len(data), formats[width]), *data)
16
17packs = {
18    1: lambda *data: pack(1, data),
19    2: lambda *data: pack(2, data),
20    4: lambda *data: pack(4, data),
21}
22maxvalues = {w: (1 << (8 * w - 1)) - 1 for w in (1, 2, 4)}
23minvalues = {w: -1 << (8 * w - 1) for w in (1, 2, 4)}
24
25datas = {
26    1: b'\x00\x12\x45\xbb\x7f\x80\xff',
27    2: packs[2](0, 0x1234, 0x4567, -0x4567, 0x7fff, -0x8000, -1),
28    4: packs[4](0, 0x12345678, 0x456789ab, -0x456789ab,
29                0x7fffffff, -0x80000000, -1),
30}
31
32INVALID_DATA = [
33    (b'abc', 0),
34    (b'abc', 2),
35    (b'abc', 4),
36]
37
38
39class TestAudioop(unittest.TestCase):
40
41    def test_max(self):
42        for w in 1, 2, 4:
43            self.assertEqual(audioop.max(b'', w), 0)
44            p = packs[w]
45            self.assertEqual(audioop.max(p(5), w), 5)
46            self.assertEqual(audioop.max(p(5, -8, -1), w), 8)
47            self.assertEqual(audioop.max(p(maxvalues[w]), w), maxvalues[w])
48            self.assertEqual(audioop.max(p(minvalues[w]), w), -minvalues[w])
49            self.assertEqual(audioop.max(datas[w], w), -minvalues[w])
50
51    def test_minmax(self):
52        for w in 1, 2, 4:
53            self.assertEqual(audioop.minmax(b'', w),
54                             (0x7fffffff, -0x80000000))
55            p = packs[w]
56            self.assertEqual(audioop.minmax(p(5), w), (5, 5))
57            self.assertEqual(audioop.minmax(p(5, -8, -1), w), (-8, 5))
58            self.assertEqual(audioop.minmax(p(maxvalues[w]), w),
59                             (maxvalues[w], maxvalues[w]))
60            self.assertEqual(audioop.minmax(p(minvalues[w]), w),
61                             (minvalues[w], minvalues[w]))
62            self.assertEqual(audioop.minmax(datas[w], w),
63                             (minvalues[w], maxvalues[w]))
64
65    def test_maxpp(self):
66        for w in 1, 2, 4:
67            self.assertEqual(audioop.maxpp(b'', w), 0)
68            self.assertEqual(audioop.maxpp(packs[w](*range(100)), w), 0)
69            self.assertEqual(audioop.maxpp(packs[w](9, 10, 5, 5, 0, 1), w), 10)
70            self.assertEqual(audioop.maxpp(datas[w], w),
71                             maxvalues[w] - minvalues[w])
72
73    def test_avg(self):
74        for w in 1, 2, 4:
75            self.assertEqual(audioop.avg(b'', w), 0)
76            p = packs[w]
77            self.assertEqual(audioop.avg(p(5), w), 5)
78            self .assertEqual(audioop.avg(p(5, 8), w), 6)
79            self.assertEqual(audioop.avg(p(5, -8), w), -2)
80            self.assertEqual(audioop.avg(p(maxvalues[w], maxvalues[w]), w),
81                             maxvalues[w])
82            self.assertEqual(audioop.avg(p(minvalues[w], minvalues[w]), w),
83                             minvalues[w])
84        self.assertEqual(audioop.avg(packs[4](0x50000000, 0x70000000), 4),
85                         0x60000000)
86        self.assertEqual(audioop.avg(packs[4](-0x50000000, -0x70000000), 4),
87                         -0x60000000)
88
89    def test_avgpp(self):
90        for w in 1, 2, 4:
91            self.assertEqual(audioop.avgpp(b'', w), 0)
92            self.assertEqual(audioop.avgpp(packs[w](*range(100)), w), 0)
93            self.assertEqual(audioop.avgpp(packs[w](9, 10, 5, 5, 0, 1), w), 10)
94        self.assertEqual(audioop.avgpp(datas[1], 1), 196)
95        self.assertEqual(audioop.avgpp(datas[2], 2), 50534)
96        self.assertEqual(audioop.avgpp(datas[4], 4), 3311897002)
97
98    def test_rms(self):
99        for w in 1, 2, 4:
100            self.assertEqual(audioop.rms(b'', w), 0)
101            p = packs[w]
102            self.assertEqual(audioop.rms(p(*range(100)), w), 57)
103            self.assertAlmostEqual(audioop.rms(p(maxvalues[w]) * 5, w),
104                                   maxvalues[w], delta=1)
105            self.assertAlmostEqual(audioop.rms(p(minvalues[w]) * 5, w),
106                                   -minvalues[w], delta=1)
107        self.assertEqual(audioop.rms(datas[1], 1), 77)
108        self.assertEqual(audioop.rms(datas[2], 2), 20001)
109        self.assertEqual(audioop.rms(datas[4], 4), 1310854152)
110
111    def test_cross(self):
112        for w in 1, 2, 4:
113            self.assertEqual(audioop.cross(b'', w), -1)
114            p = packs[w]
115            self.assertEqual(audioop.cross(p(0, 1, 2), w), 0)
116            self.assertEqual(audioop.cross(p(1, 2, -3, -4), w), 1)
117            self.assertEqual(audioop.cross(p(-1, -2, 3, 4), w), 1)
118            self.assertEqual(audioop.cross(p(0, minvalues[w]), w), 1)
119            self.assertEqual(audioop.cross(p(minvalues[w], maxvalues[w]), w), 1)
120
121    def test_add(self):
122        for w in 1, 2, 4:
123            self.assertEqual(audioop.add(b'', b'', w), b'')
124            self.assertEqual(audioop.add(datas[w], b'\0' * len(datas[w]), w),
125                             datas[w])
126        self.assertEqual(audioop.add(datas[1], datas[1], 1),
127                         b'\x00\x24\x7f\x80\x7f\x80\xfe')
128        self.assertEqual(audioop.add(datas[2], datas[2], 2),
129                packs[2](0, 0x2468, 0x7fff, -0x8000, 0x7fff, -0x8000, -2))
130        self.assertEqual(audioop.add(datas[4], datas[4], 4),
131                packs[4](0, 0x2468acf0, 0x7fffffff, -0x80000000,
132                       0x7fffffff, -0x80000000, -2))
133
134    def test_bias(self):
135        for w in 1, 2, 4:
136            for bias in 0, 1, -1, 127, -128, 0x7fffffff, -0x80000000:
137                self.assertEqual(audioop.bias(b'', w, bias), b'')
138        self.assertEqual(audioop.bias(datas[1], 1, 1),
139                         b'\x01\x13\x46\xbc\x80\x81\x00')
140        self.assertEqual(audioop.bias(datas[1], 1, -1),
141                         b'\xff\x11\x44\xba\x7e\x7f\xfe')
142        self.assertEqual(audioop.bias(datas[1], 1, 0x7fffffff),
143                         b'\xff\x11\x44\xba\x7e\x7f\xfe')
144        self.assertEqual(audioop.bias(datas[1], 1, -0x80000000),
145                         datas[1])
146        self.assertEqual(audioop.bias(datas[2], 2, 1),
147                packs[2](1, 0x1235, 0x4568, -0x4566, -0x8000, -0x7fff, 0))
148        self.assertEqual(audioop.bias(datas[2], 2, -1),
149                packs[2](-1, 0x1233, 0x4566, -0x4568, 0x7ffe, 0x7fff, -2))
150        self.assertEqual(audioop.bias(datas[2], 2, 0x7fffffff),
151                packs[2](-1, 0x1233, 0x4566, -0x4568, 0x7ffe, 0x7fff, -2))
152        self.assertEqual(audioop.bias(datas[2], 2, -0x80000000),
153                datas[2])
154        self.assertEqual(audioop.bias(datas[4], 4, 1),
155                packs[4](1, 0x12345679, 0x456789ac, -0x456789aa,
156                         -0x80000000, -0x7fffffff, 0))
157        self.assertEqual(audioop.bias(datas[4], 4, -1),
158                packs[4](-1, 0x12345677, 0x456789aa, -0x456789ac,
159                         0x7ffffffe, 0x7fffffff, -2))
160        self.assertEqual(audioop.bias(datas[4], 4, 0x7fffffff),
161                packs[4](0x7fffffff, -0x6dcba989, -0x3a987656, 0x3a987654,
162                         -2, -1, 0x7ffffffe))
163        self.assertEqual(audioop.bias(datas[4], 4, -0x80000000),
164                packs[4](-0x80000000, -0x6dcba988, -0x3a987655, 0x3a987655,
165                         -1, 0, 0x7fffffff))
166
167    def test_lin2lin(self):
168        for w in 1, 2, 4:
169            self.assertEqual(audioop.lin2lin(datas[w], w, w), datas[w])
170
171        self.assertEqual(audioop.lin2lin(datas[1], 1, 2),
172            packs[2](0, 0x1200, 0x4500, -0x4500, 0x7f00, -0x8000, -0x100))
173        self.assertEqual(audioop.lin2lin(datas[1], 1, 4),
174            packs[4](0, 0x12000000, 0x45000000, -0x45000000,
175                     0x7f000000, -0x80000000, -0x1000000))
176        self.assertEqual(audioop.lin2lin(datas[2], 2, 1),
177            b'\x00\x12\x45\xba\x7f\x80\xff')
178        self.assertEqual(audioop.lin2lin(datas[2], 2, 4),
179            packs[4](0, 0x12340000, 0x45670000, -0x45670000,
180                     0x7fff0000, -0x80000000, -0x10000))
181        self.assertEqual(audioop.lin2lin(datas[4], 4, 1),
182            b'\x00\x12\x45\xba\x7f\x80\xff')
183        self.assertEqual(audioop.lin2lin(datas[4], 4, 2),
184            packs[2](0, 0x1234, 0x4567, -0x4568, 0x7fff, -0x8000, -1))
185
186    def test_adpcm2lin(self):
187        self.assertEqual(audioop.adpcm2lin(b'\x07\x7f\x7f', 1, None),
188                         (b'\x00\x00\x00\xff\x00\xff', (-179, 40)))
189        self.assertEqual(audioop.adpcm2lin(b'\x07\x7f\x7f', 2, None),
190                         (packs[2](0, 0xb, 0x29, -0x16, 0x72, -0xb3), (-179, 40)))
191        self.assertEqual(audioop.adpcm2lin(b'\x07\x7f\x7f', 4, None),
192                         (packs[4](0, 0xb0000, 0x290000, -0x160000, 0x720000,
193                                   -0xb30000), (-179, 40)))
194
195        # Very cursory test
196        for w in 1, 2, 4:
197            self.assertEqual(audioop.adpcm2lin(b'\0' * 5, w, None),
198                             (b'\0' * w * 10, (0, 0)))
199
200    def test_lin2adpcm(self):
201        self.assertEqual(audioop.lin2adpcm(datas[1], 1, None),
202                         (b'\x07\x7f\x7f', (-221, 39)))
203        self.assertEqual(audioop.lin2adpcm(datas[2], 2, None),
204                         (b'\x07\x7f\x7f', (31, 39)))
205        self.assertEqual(audioop.lin2adpcm(datas[4], 4, None),
206                         (b'\x07\x7f\x7f', (31, 39)))
207
208        # Very cursory test
209        for w in 1, 2, 4:
210            self.assertEqual(audioop.lin2adpcm(b'\0' * w * 10, w, None),
211                             (b'\0' * 5, (0, 0)))
212
213    def test_invalid_adpcm_state(self):
214        # state must be a tuple or None, not an integer
215        self.assertRaises(TypeError, audioop.adpcm2lin, b'\0', 1, 555)
216        self.assertRaises(TypeError, audioop.lin2adpcm, b'\0', 1, 555)
217        # Issues #24456, #24457: index out of range
218        self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (0, -1))
219        self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (0, 89))
220        self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (0, -1))
221        self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (0, 89))
222        # value out of range
223        self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (-0x8001, 0))
224        self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (0x8000, 0))
225        self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (-0x8001, 0))
226        self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (0x8000, 0))
227
228    def test_lin2alaw(self):
229        self.assertEqual(audioop.lin2alaw(datas[1], 1),
230                         b'\xd5\x87\xa4\x24\xaa\x2a\x5a')
231        self.assertEqual(audioop.lin2alaw(datas[2], 2),
232                         b'\xd5\x87\xa4\x24\xaa\x2a\x55')
233        self.assertEqual(audioop.lin2alaw(datas[4], 4),
234                         b'\xd5\x87\xa4\x24\xaa\x2a\x55')
235
236    def test_alaw2lin(self):
237        encoded = b'\x00\x03\x24\x2a\x51\x54\x55\x58\x6b\x71\x7f'\
238                  b'\x80\x83\xa4\xaa\xd1\xd4\xd5\xd8\xeb\xf1\xff'
239        src = [-688, -720, -2240, -4032, -9, -3, -1, -27, -244, -82, -106,
240               688, 720, 2240, 4032, 9, 3, 1, 27, 244, 82, 106]
241        for w in 1, 2, 4:
242            self.assertEqual(audioop.alaw2lin(encoded, w),
243                             packs[w](*(x << (w * 8) >> 13 for x in src)))
244
245        encoded = ''.join(chr(x) for x in xrange(256))
246        for w in 2, 4:
247            decoded = audioop.alaw2lin(encoded, w)
248            self.assertEqual(audioop.lin2alaw(decoded, w), encoded)
249
250    def test_lin2ulaw(self):
251        self.assertEqual(audioop.lin2ulaw(datas[1], 1),
252                         b'\xff\xad\x8e\x0e\x80\x00\x67')
253        self.assertEqual(audioop.lin2ulaw(datas[2], 2),
254                         b'\xff\xad\x8e\x0e\x80\x00\x7e')
255        self.assertEqual(audioop.lin2ulaw(datas[4], 4),
256                         b'\xff\xad\x8e\x0e\x80\x00\x7e')
257
258    def test_ulaw2lin(self):
259        encoded = b'\x00\x0e\x28\x3f\x57\x6a\x76\x7c\x7e\x7f'\
260                  b'\x80\x8e\xa8\xbf\xd7\xea\xf6\xfc\xfe\xff'
261        src = [-8031, -4447, -1471, -495, -163, -53, -18, -6, -2, 0,
262               8031, 4447, 1471, 495, 163, 53, 18, 6, 2, 0]
263        for w in 1, 2, 4:
264            self.assertEqual(audioop.ulaw2lin(encoded, w),
265                             packs[w](*(x << (w * 8) >> 14 for x in src)))
266
267        # Current u-law implementation has two codes fo 0: 0x7f and 0xff.
268        encoded = ''.join(chr(x) for x in range(127) + range(128, 256))
269        for w in 2, 4:
270            decoded = audioop.ulaw2lin(encoded, w)
271            self.assertEqual(audioop.lin2ulaw(decoded, w), encoded)
272
273    def test_mul(self):
274        for w in 1, 2, 4:
275            self.assertEqual(audioop.mul(b'', w, 2), b'')
276            self.assertEqual(audioop.mul(datas[w], w, 0),
277                             b'\0' * len(datas[w]))
278            self.assertEqual(audioop.mul(datas[w], w, 1),
279                             datas[w])
280        self.assertEqual(audioop.mul(datas[1], 1, 2),
281                         b'\x00\x24\x7f\x80\x7f\x80\xfe')
282        self.assertEqual(audioop.mul(datas[2], 2, 2),
283                packs[2](0, 0x2468, 0x7fff, -0x8000, 0x7fff, -0x8000, -2))
284        self.assertEqual(audioop.mul(datas[4], 4, 2),
285                packs[4](0, 0x2468acf0, 0x7fffffff, -0x80000000,
286                         0x7fffffff, -0x80000000, -2))
287
288    def test_ratecv(self):
289        for w in 1, 2, 4:
290            self.assertEqual(audioop.ratecv(b'', w, 1, 8000, 8000, None),
291                             (b'', (-1, ((0, 0),))))
292            self.assertEqual(audioop.ratecv(b'', w, 5, 8000, 8000, None),
293                             (b'', (-1, ((0, 0),) * 5)))
294            self.assertEqual(audioop.ratecv(b'', w, 1, 8000, 16000, None),
295                             (b'', (-2, ((0, 0),))))
296            self.assertEqual(audioop.ratecv(datas[w], w, 1, 8000, 8000, None)[0],
297                             datas[w])
298            self.assertEqual(audioop.ratecv(datas[w], w, 1, 8000, 8000, None, 1, 0)[0],
299                             datas[w])
300
301        state = None
302        d1, state = audioop.ratecv(b'\x00\x01\x02', 1, 1, 8000, 16000, state)
303        d2, state = audioop.ratecv(b'\x00\x01\x02', 1, 1, 8000, 16000, state)
304        self.assertEqual(d1 + d2, b'\000\000\001\001\002\001\000\000\001\001\002')
305
306        for w in 1, 2, 4:
307            d0, state0 = audioop.ratecv(datas[w], w, 1, 8000, 16000, None)
308            d, state = b'', None
309            for i in range(0, len(datas[w]), w):
310                d1, state = audioop.ratecv(datas[w][i:i + w], w, 1,
311                                           8000, 16000, state)
312                d += d1
313            self.assertEqual(d, d0)
314            self.assertEqual(state, state0)
315
316        expected = {
317            1: packs[1](0, 0x0d, 0x37, -0x26, 0x55, -0x4b, -0x14),
318            2: packs[2](0, 0x0da7, 0x3777, -0x2630, 0x5673, -0x4a64, -0x129a),
319            4: packs[4](0, 0x0da740da, 0x37777776, -0x262fc962,
320                        0x56740da6, -0x4a62fc96, -0x1298bf26),
321        }
322        for w in 1, 2, 4:
323            self.assertEqual(audioop.ratecv(datas[w], w, 1, 8000, 8000, None, 3, 1)[0],
324                             expected[w])
325            self.assertEqual(audioop.ratecv(datas[w], w, 1, 8000, 8000, None, 30, 10)[0],
326                             expected[w])
327
328        self.assertRaises(TypeError, audioop.ratecv, b'', 1, 1, 8000, 8000, 42)
329        self.assertRaises(TypeError, audioop.ratecv,
330                          b'', 1, 1, 8000, 8000, (1, (42,)))
331
332    def test_reverse(self):
333        for w in 1, 2, 4:
334            self.assertEqual(audioop.reverse(b'', w), b'')
335            self.assertEqual(audioop.reverse(packs[w](0, 1, 2), w),
336                             packs[w](2, 1, 0))
337
338    def test_tomono(self):
339        for w in 1, 2, 4:
340            data1 = datas[w]
341            data2 = bytearray(2 * len(data1))
342            for k in range(w):
343                data2[k::2*w] = data1[k::w]
344            self.assertEqual(audioop.tomono(str(data2), w, 1, 0), data1)
345            self.assertEqual(audioop.tomono(str(data2), w, 0, 1), b'\0' * len(data1))
346            for k in range(w):
347                data2[k+w::2*w] = data1[k::w]
348            self.assertEqual(audioop.tomono(str(data2), w, 0.5, 0.5), data1)
349
350    def test_tostereo(self):
351        for w in 1, 2, 4:
352            data1 = datas[w]
353            data2 = bytearray(2 * len(data1))
354            for k in range(w):
355                data2[k::2*w] = data1[k::w]
356            self.assertEqual(audioop.tostereo(data1, w, 1, 0), data2)
357            self.assertEqual(audioop.tostereo(data1, w, 0, 0), b'\0' * len(data2))
358            for k in range(w):
359                data2[k+w::2*w] = data1[k::w]
360            self.assertEqual(audioop.tostereo(data1, w, 1, 1), data2)
361
362    def test_findfactor(self):
363        self.assertEqual(audioop.findfactor(datas[2], datas[2]), 1.0)
364        self.assertEqual(audioop.findfactor(b'\0' * len(datas[2]), datas[2]),
365                         0.0)
366
367    def test_findfit(self):
368        self.assertEqual(audioop.findfit(datas[2], datas[2]), (0, 1.0))
369        self.assertEqual(audioop.findfit(datas[2], packs[2](1, 2, 0)),
370                         (1, 8038.8))
371        self.assertEqual(audioop.findfit(datas[2][:-2] * 5 + datas[2], datas[2]),
372                         (30, 1.0))
373
374    def test_findmax(self):
375        self.assertEqual(audioop.findmax(datas[2], 1), 5)
376
377    def test_getsample(self):
378        for w in 1, 2, 4:
379            data = packs[w](0, 1, -1, maxvalues[w], minvalues[w])
380            self.assertEqual(audioop.getsample(data, w, 0), 0)
381            self.assertEqual(audioop.getsample(data, w, 1), 1)
382            self.assertEqual(audioop.getsample(data, w, 2), -1)
383            self.assertEqual(audioop.getsample(data, w, 3), maxvalues[w])
384            self.assertEqual(audioop.getsample(data, w, 4), minvalues[w])
385
386    def test_negativelen(self):
387        # from issue 3306, previously it segfaulted
388        self.assertRaises(audioop.error,
389            audioop.findmax, ''.join( chr(x) for x in xrange(256)), -2392392)
390
391    def test_issue7673(self):
392        state = None
393        for data, size in INVALID_DATA:
394            size2 = size
395            self.assertRaises(audioop.error, audioop.getsample, data, size, 0)
396            self.assertRaises(audioop.error, audioop.max, data, size)
397            self.assertRaises(audioop.error, audioop.minmax, data, size)
398            self.assertRaises(audioop.error, audioop.avg, data, size)
399            self.assertRaises(audioop.error, audioop.rms, data, size)
400            self.assertRaises(audioop.error, audioop.avgpp, data, size)
401            self.assertRaises(audioop.error, audioop.maxpp, data, size)
402            self.assertRaises(audioop.error, audioop.cross, data, size)
403            self.assertRaises(audioop.error, audioop.mul, data, size, 1.0)
404            self.assertRaises(audioop.error, audioop.tomono, data, size, 0.5, 0.5)
405            self.assertRaises(audioop.error, audioop.tostereo, data, size, 0.5, 0.5)
406            self.assertRaises(audioop.error, audioop.add, data, data, size)
407            self.assertRaises(audioop.error, audioop.bias, data, size, 0)
408            self.assertRaises(audioop.error, audioop.reverse, data, size)
409            self.assertRaises(audioop.error, audioop.lin2lin, data, size, size2)
410            self.assertRaises(audioop.error, audioop.ratecv, data, size, 1, 1, 1, state)
411            self.assertRaises(audioop.error, audioop.lin2ulaw, data, size)
412            self.assertRaises(audioop.error, audioop.lin2alaw, data, size)
413            self.assertRaises(audioop.error, audioop.lin2adpcm, data, size, state)
414
415    def test_wrongsize(self):
416        data = b'abcdefgh'
417        state = None
418        for size in (-1, 0, 3, 5, 1024):
419            self.assertRaises(audioop.error, audioop.ulaw2lin, data, size)
420            self.assertRaises(audioop.error, audioop.alaw2lin, data, size)
421            self.assertRaises(audioop.error, audioop.adpcm2lin, data, size, state)
422
423def test_main():
424    run_unittest(TestAudioop)
425
426if __name__ == '__main__':
427    test_main()
428