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_lin2alaw(self):
214        self.assertEqual(audioop.lin2alaw(datas[1], 1),
215                         b'\xd5\x87\xa4\x24\xaa\x2a\x5a')
216        self.assertEqual(audioop.lin2alaw(datas[2], 2),
217                         b'\xd5\x87\xa4\x24\xaa\x2a\x55')
218        self.assertEqual(audioop.lin2alaw(datas[4], 4),
219                         b'\xd5\x87\xa4\x24\xaa\x2a\x55')
220
221    def test_alaw2lin(self):
222        encoded = b'\x00\x03\x24\x2a\x51\x54\x55\x58\x6b\x71\x7f'\
223                  b'\x80\x83\xa4\xaa\xd1\xd4\xd5\xd8\xeb\xf1\xff'
224        src = [-688, -720, -2240, -4032, -9, -3, -1, -27, -244, -82, -106,
225               688, 720, 2240, 4032, 9, 3, 1, 27, 244, 82, 106]
226        for w in 1, 2, 4:
227            self.assertEqual(audioop.alaw2lin(encoded, w),
228                             packs[w](*(x << (w * 8) >> 13 for x in src)))
229
230        encoded = ''.join(chr(x) for x in xrange(256))
231        for w in 2, 4:
232            decoded = audioop.alaw2lin(encoded, w)
233            self.assertEqual(audioop.lin2alaw(decoded, w), encoded)
234
235    def test_lin2ulaw(self):
236        self.assertEqual(audioop.lin2ulaw(datas[1], 1),
237                         b'\xff\xad\x8e\x0e\x80\x00\x67')
238        self.assertEqual(audioop.lin2ulaw(datas[2], 2),
239                         b'\xff\xad\x8e\x0e\x80\x00\x7e')
240        self.assertEqual(audioop.lin2ulaw(datas[4], 4),
241                         b'\xff\xad\x8e\x0e\x80\x00\x7e')
242
243    def test_ulaw2lin(self):
244        encoded = b'\x00\x0e\x28\x3f\x57\x6a\x76\x7c\x7e\x7f'\
245                  b'\x80\x8e\xa8\xbf\xd7\xea\xf6\xfc\xfe\xff'
246        src = [-8031, -4447, -1471, -495, -163, -53, -18, -6, -2, 0,
247               8031, 4447, 1471, 495, 163, 53, 18, 6, 2, 0]
248        for w in 1, 2, 4:
249            self.assertEqual(audioop.ulaw2lin(encoded, w),
250                             packs[w](*(x << (w * 8) >> 14 for x in src)))
251
252        # Current u-law implementation has two codes fo 0: 0x7f and 0xff.
253        encoded = ''.join(chr(x) for x in range(127) + range(128, 256))
254        for w in 2, 4:
255            decoded = audioop.ulaw2lin(encoded, w)
256            self.assertEqual(audioop.lin2ulaw(decoded, w), encoded)
257
258    def test_mul(self):
259        for w in 1, 2, 4:
260            self.assertEqual(audioop.mul(b'', w, 2), b'')
261            self.assertEqual(audioop.mul(datas[w], w, 0),
262                             b'\0' * len(datas[w]))
263            self.assertEqual(audioop.mul(datas[w], w, 1),
264                             datas[w])
265        self.assertEqual(audioop.mul(datas[1], 1, 2),
266                         b'\x00\x24\x7f\x80\x7f\x80\xfe')
267        self.assertEqual(audioop.mul(datas[2], 2, 2),
268                packs[2](0, 0x2468, 0x7fff, -0x8000, 0x7fff, -0x8000, -2))
269        self.assertEqual(audioop.mul(datas[4], 4, 2),
270                packs[4](0, 0x2468acf0, 0x7fffffff, -0x80000000,
271                         0x7fffffff, -0x80000000, -2))
272
273    def test_ratecv(self):
274        for w in 1, 2, 4:
275            self.assertEqual(audioop.ratecv(b'', w, 1, 8000, 8000, None),
276                             (b'', (-1, ((0, 0),))))
277            self.assertEqual(audioop.ratecv(b'', w, 5, 8000, 8000, None),
278                             (b'', (-1, ((0, 0),) * 5)))
279            self.assertEqual(audioop.ratecv(b'', w, 1, 8000, 16000, None),
280                             (b'', (-2, ((0, 0),))))
281            self.assertEqual(audioop.ratecv(datas[w], w, 1, 8000, 8000, None)[0],
282                             datas[w])
283        state = None
284        d1, state = audioop.ratecv(b'\x00\x01\x02', 1, 1, 8000, 16000, state)
285        d2, state = audioop.ratecv(b'\x00\x01\x02', 1, 1, 8000, 16000, state)
286        self.assertEqual(d1 + d2, b'\000\000\001\001\002\001\000\000\001\001\002')
287
288        for w in 1, 2, 4:
289            d0, state0 = audioop.ratecv(datas[w], w, 1, 8000, 16000, None)
290            d, state = b'', None
291            for i in range(0, len(datas[w]), w):
292                d1, state = audioop.ratecv(datas[w][i:i + w], w, 1,
293                                           8000, 16000, state)
294                d += d1
295            self.assertEqual(d, d0)
296            self.assertEqual(state, state0)
297
298    def test_reverse(self):
299        for w in 1, 2, 4:
300            self.assertEqual(audioop.reverse(b'', w), b'')
301            self.assertEqual(audioop.reverse(packs[w](0, 1, 2), w),
302                             packs[w](2, 1, 0))
303
304    def test_tomono(self):
305        for w in 1, 2, 4:
306            data1 = datas[w]
307            data2 = bytearray(2 * len(data1))
308            for k in range(w):
309                data2[k::2*w] = data1[k::w]
310            self.assertEqual(audioop.tomono(str(data2), w, 1, 0), data1)
311            self.assertEqual(audioop.tomono(str(data2), w, 0, 1), b'\0' * len(data1))
312            for k in range(w):
313                data2[k+w::2*w] = data1[k::w]
314            self.assertEqual(audioop.tomono(str(data2), w, 0.5, 0.5), data1)
315
316    def test_tostereo(self):
317        for w in 1, 2, 4:
318            data1 = datas[w]
319            data2 = bytearray(2 * len(data1))
320            for k in range(w):
321                data2[k::2*w] = data1[k::w]
322            self.assertEqual(audioop.tostereo(data1, w, 1, 0), data2)
323            self.assertEqual(audioop.tostereo(data1, w, 0, 0), b'\0' * len(data2))
324            for k in range(w):
325                data2[k+w::2*w] = data1[k::w]
326            self.assertEqual(audioop.tostereo(data1, w, 1, 1), data2)
327
328    def test_findfactor(self):
329        self.assertEqual(audioop.findfactor(datas[2], datas[2]), 1.0)
330        self.assertEqual(audioop.findfactor(b'\0' * len(datas[2]), datas[2]),
331                         0.0)
332
333    def test_findfit(self):
334        self.assertEqual(audioop.findfit(datas[2], datas[2]), (0, 1.0))
335        self.assertEqual(audioop.findfit(datas[2], packs[2](1, 2, 0)),
336                         (1, 8038.8))
337        self.assertEqual(audioop.findfit(datas[2][:-2] * 5 + datas[2], datas[2]),
338                         (30, 1.0))
339
340    def test_findmax(self):
341        self.assertEqual(audioop.findmax(datas[2], 1), 5)
342
343    def test_getsample(self):
344        for w in 1, 2, 4:
345            data = packs[w](0, 1, -1, maxvalues[w], minvalues[w])
346            self.assertEqual(audioop.getsample(data, w, 0), 0)
347            self.assertEqual(audioop.getsample(data, w, 1), 1)
348            self.assertEqual(audioop.getsample(data, w, 2), -1)
349            self.assertEqual(audioop.getsample(data, w, 3), maxvalues[w])
350            self.assertEqual(audioop.getsample(data, w, 4), minvalues[w])
351
352    def test_negativelen(self):
353        # from issue 3306, previously it segfaulted
354        self.assertRaises(audioop.error,
355            audioop.findmax, ''.join( chr(x) for x in xrange(256)), -2392392)
356
357    def test_issue7673(self):
358        state = None
359        for data, size in INVALID_DATA:
360            size2 = size
361            self.assertRaises(audioop.error, audioop.getsample, data, size, 0)
362            self.assertRaises(audioop.error, audioop.max, data, size)
363            self.assertRaises(audioop.error, audioop.minmax, data, size)
364            self.assertRaises(audioop.error, audioop.avg, data, size)
365            self.assertRaises(audioop.error, audioop.rms, data, size)
366            self.assertRaises(audioop.error, audioop.avgpp, data, size)
367            self.assertRaises(audioop.error, audioop.maxpp, data, size)
368            self.assertRaises(audioop.error, audioop.cross, data, size)
369            self.assertRaises(audioop.error, audioop.mul, data, size, 1.0)
370            self.assertRaises(audioop.error, audioop.tomono, data, size, 0.5, 0.5)
371            self.assertRaises(audioop.error, audioop.tostereo, data, size, 0.5, 0.5)
372            self.assertRaises(audioop.error, audioop.add, data, data, size)
373            self.assertRaises(audioop.error, audioop.bias, data, size, 0)
374            self.assertRaises(audioop.error, audioop.reverse, data, size)
375            self.assertRaises(audioop.error, audioop.lin2lin, data, size, size2)
376            self.assertRaises(audioop.error, audioop.ratecv, data, size, 1, 1, 1, state)
377            self.assertRaises(audioop.error, audioop.lin2ulaw, data, size)
378            self.assertRaises(audioop.error, audioop.lin2alaw, data, size)
379            self.assertRaises(audioop.error, audioop.lin2adpcm, data, size, state)
380
381    def test_wrongsize(self):
382        data = b'abcdefgh'
383        state = None
384        for size in (-1, 0, 3, 5, 1024):
385            self.assertRaises(audioop.error, audioop.ulaw2lin, data, size)
386            self.assertRaises(audioop.error, audioop.alaw2lin, data, size)
387            self.assertRaises(audioop.error, audioop.adpcm2lin, data, size, state)
388
389def test_main():
390    run_unittest(TestAudioop)
391
392if __name__ == '__main__':
393    test_main()
394