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    def test_reverse(self):
329        for w in 1, 2, 4:
330            self.assertEqual(audioop.reverse(b'', w), b'')
331            self.assertEqual(audioop.reverse(packs[w](0, 1, 2), w),
332                             packs[w](2, 1, 0))
333
334    def test_tomono(self):
335        for w in 1, 2, 4:
336            data1 = datas[w]
337            data2 = bytearray(2 * len(data1))
338            for k in range(w):
339                data2[k::2*w] = data1[k::w]
340            self.assertEqual(audioop.tomono(str(data2), w, 1, 0), data1)
341            self.assertEqual(audioop.tomono(str(data2), w, 0, 1), b'\0' * len(data1))
342            for k in range(w):
343                data2[k+w::2*w] = data1[k::w]
344            self.assertEqual(audioop.tomono(str(data2), w, 0.5, 0.5), data1)
345
346    def test_tostereo(self):
347        for w in 1, 2, 4:
348            data1 = datas[w]
349            data2 = bytearray(2 * len(data1))
350            for k in range(w):
351                data2[k::2*w] = data1[k::w]
352            self.assertEqual(audioop.tostereo(data1, w, 1, 0), data2)
353            self.assertEqual(audioop.tostereo(data1, w, 0, 0), b'\0' * len(data2))
354            for k in range(w):
355                data2[k+w::2*w] = data1[k::w]
356            self.assertEqual(audioop.tostereo(data1, w, 1, 1), data2)
357
358    def test_findfactor(self):
359        self.assertEqual(audioop.findfactor(datas[2], datas[2]), 1.0)
360        self.assertEqual(audioop.findfactor(b'\0' * len(datas[2]), datas[2]),
361                         0.0)
362
363    def test_findfit(self):
364        self.assertEqual(audioop.findfit(datas[2], datas[2]), (0, 1.0))
365        self.assertEqual(audioop.findfit(datas[2], packs[2](1, 2, 0)),
366                         (1, 8038.8))
367        self.assertEqual(audioop.findfit(datas[2][:-2] * 5 + datas[2], datas[2]),
368                         (30, 1.0))
369
370    def test_findmax(self):
371        self.assertEqual(audioop.findmax(datas[2], 1), 5)
372
373    def test_getsample(self):
374        for w in 1, 2, 4:
375            data = packs[w](0, 1, -1, maxvalues[w], minvalues[w])
376            self.assertEqual(audioop.getsample(data, w, 0), 0)
377            self.assertEqual(audioop.getsample(data, w, 1), 1)
378            self.assertEqual(audioop.getsample(data, w, 2), -1)
379            self.assertEqual(audioop.getsample(data, w, 3), maxvalues[w])
380            self.assertEqual(audioop.getsample(data, w, 4), minvalues[w])
381
382    def test_negativelen(self):
383        # from issue 3306, previously it segfaulted
384        self.assertRaises(audioop.error,
385            audioop.findmax, ''.join( chr(x) for x in xrange(256)), -2392392)
386
387    def test_issue7673(self):
388        state = None
389        for data, size in INVALID_DATA:
390            size2 = size
391            self.assertRaises(audioop.error, audioop.getsample, data, size, 0)
392            self.assertRaises(audioop.error, audioop.max, data, size)
393            self.assertRaises(audioop.error, audioop.minmax, data, size)
394            self.assertRaises(audioop.error, audioop.avg, data, size)
395            self.assertRaises(audioop.error, audioop.rms, data, size)
396            self.assertRaises(audioop.error, audioop.avgpp, data, size)
397            self.assertRaises(audioop.error, audioop.maxpp, data, size)
398            self.assertRaises(audioop.error, audioop.cross, data, size)
399            self.assertRaises(audioop.error, audioop.mul, data, size, 1.0)
400            self.assertRaises(audioop.error, audioop.tomono, data, size, 0.5, 0.5)
401            self.assertRaises(audioop.error, audioop.tostereo, data, size, 0.5, 0.5)
402            self.assertRaises(audioop.error, audioop.add, data, data, size)
403            self.assertRaises(audioop.error, audioop.bias, data, size, 0)
404            self.assertRaises(audioop.error, audioop.reverse, data, size)
405            self.assertRaises(audioop.error, audioop.lin2lin, data, size, size2)
406            self.assertRaises(audioop.error, audioop.ratecv, data, size, 1, 1, 1, state)
407            self.assertRaises(audioop.error, audioop.lin2ulaw, data, size)
408            self.assertRaises(audioop.error, audioop.lin2alaw, data, size)
409            self.assertRaises(audioop.error, audioop.lin2adpcm, data, size, state)
410
411    def test_wrongsize(self):
412        data = b'abcdefgh'
413        state = None
414        for size in (-1, 0, 3, 5, 1024):
415            self.assertRaises(audioop.error, audioop.ulaw2lin, data, size)
416            self.assertRaises(audioop.error, audioop.alaw2lin, data, size)
417            self.assertRaises(audioop.error, audioop.adpcm2lin, data, size, state)
418
419def test_main():
420    run_unittest(TestAudioop)
421
422if __name__ == '__main__':
423    test_main()
424