sink, source: Really set the fixed latency in set_fixed_latency_within_thread(),...
[platform/upstream/pulseaudio.git] / src / tests / mix-special-test.c
1 /***
2   This file is part of PulseAudio.
3
4   PulseAudio is free software; you can redistribute it and/or modify
5   it under the terms of the GNU Lesser General Public License as published
6   by the Free Software Foundation; either version 2.1 of the License,
7   or (at your option) any later version.
8
9   PulseAudio is distributed in the hope that it will be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   General Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public License
15   along with PulseAudio; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17   USA.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <check.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <math.h>
28
29 #include <pulse/rtclock.h>
30 #include <pulsecore/random.h>
31 #include <pulsecore/macro.h>
32 #include <pulsecore/mix.h>
33 #include <pulsecore/sample-util.h>
34
35 #define PA_CPU_TEST_RUN_START(l, t1, t2)                        \
36 {                                                               \
37     int _j, _k;                                                 \
38     int _times = (t1), _times2 = (t2);                          \
39     pa_usec_t _start, _stop;                                    \
40     pa_usec_t _min = INT_MAX, _max = 0;                         \
41     double _s1 = 0, _s2 = 0;                                    \
42     const char *_label = (l);                                   \
43                                                                 \
44     for (_k = 0; _k < _times2; _k++) {                          \
45         _start = pa_rtclock_now();                              \
46         for (_j = 0; _j < _times; _j++)
47
48 #define PA_CPU_TEST_RUN_STOP                                    \
49         _stop = pa_rtclock_now();                               \
50                                                                 \
51         if (_min > (_stop - _start)) _min = _stop - _start;     \
52         if (_max < (_stop - _start)) _max = _stop - _start;     \
53         _s1 += _stop - _start;                                  \
54         _s2 += (_stop - _start) * (_stop - _start);             \
55     }                                                           \
56     pa_log_debug("%s: %llu usec (avg: %g, min = %llu, max = %llu, stddev = %g).", _label, \
57             (long long unsigned int)_s1,                        \
58             ((double)_s1 / _times2),                            \
59             (long long unsigned int)_min,                       \
60             (long long unsigned int)_max,                       \
61             sqrt(_times2 * _s2 - _s1 * _s1) / _times2);         \
62 }
63
64 static void acquire_mix_streams(pa_mix_info streams[], unsigned nstreams) {
65     unsigned i;
66
67     for (i = 0; i < nstreams; i++)
68         streams[i].ptr = pa_memblock_acquire_chunk(&streams[i].chunk);
69 }
70
71 static void release_mix_streams(pa_mix_info streams[], unsigned nstreams) {
72     unsigned i;
73
74     for (i = 0; i < nstreams; i++)
75         pa_memblock_release(streams[i].chunk.memblock);
76 }
77
78 /* special case: mix 2 s16ne streams, 1 channel each */
79 static void pa_mix2_ch1_s16ne(pa_mix_info streams[], int16_t *data, unsigned length) {
80     const int16_t *ptr0 = streams[0].ptr;
81     const int16_t *ptr1 = streams[1].ptr;
82
83     const int32_t cv0 = streams[0].linear[0].i;
84     const int32_t cv1 = streams[1].linear[0].i;
85
86     length /= sizeof(int16_t);
87
88     for (; length > 0; length--) {
89         int32_t sum;
90
91         sum = pa_mult_s16_volume(*ptr0++, cv0);
92         sum += pa_mult_s16_volume(*ptr1++, cv1);
93
94         sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
95         *data++ = sum;
96     }
97 }
98
99 /* special case: mix 2 s16ne streams, 2 channels each */
100 static void pa_mix2_ch2_s16ne(pa_mix_info streams[], int16_t *data, unsigned length) {
101     const int16_t *ptr0 = streams[0].ptr;
102     const int16_t *ptr1 = streams[1].ptr;
103
104     length /= sizeof(int16_t) * 2;
105
106     for (; length > 0; length--) {
107         int32_t sum;
108
109         sum = pa_mult_s16_volume(*ptr0++, streams[0].linear[0].i);
110         sum += pa_mult_s16_volume(*ptr1++, streams[1].linear[0].i);
111
112         sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
113         *data++ = sum;
114
115         sum = pa_mult_s16_volume(*ptr0++, streams[0].linear[1].i);
116         sum += pa_mult_s16_volume(*ptr1++, streams[1].linear[1].i);
117
118         sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
119         *data++ = sum;
120     }
121 }
122
123 /* special case: mix 2 s16ne streams */
124 static void pa_mix2_s16ne(pa_mix_info streams[], unsigned channels, int16_t *data, unsigned length) {
125     const int16_t *ptr0 = streams[0].ptr;
126     const int16_t *ptr1 = streams[1].ptr;
127     unsigned channel = 0;
128
129     length /= sizeof(int16_t);
130
131     for (; length > 0; length--) {
132         int32_t sum;
133
134         sum = pa_mult_s16_volume(*ptr0++, streams[0].linear[channel].i);
135         sum += pa_mult_s16_volume(*ptr1++, streams[1].linear[channel].i);
136
137         sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
138         *data++ = sum;
139
140         if (PA_UNLIKELY(++channel >= channels))
141             channel = 0;
142     }
143 }
144
145 /* special case: mix s16ne streams, 2 channels each */
146 static void pa_mix_ch2_s16ne(pa_mix_info streams[], unsigned nstreams, int16_t *data, unsigned length) {
147
148     length /= sizeof(int16_t) * 2;
149
150     for (; length > 0; length--) {
151         int32_t sum0 = 0, sum1 = 0;
152         unsigned i;
153
154         for (i = 0; i < nstreams; i++) {
155             pa_mix_info *m = streams + i;
156             int32_t cv0 = m->linear[0].i;
157             int32_t cv1 = m->linear[1].i;
158
159             sum0 += pa_mult_s16_volume(*((int16_t*) m->ptr), cv0);
160             m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
161
162             sum1 += pa_mult_s16_volume(*((int16_t*) m->ptr), cv1);
163             m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
164         }
165
166         *data++ = PA_CLAMP_UNLIKELY(sum0, -0x8000, 0x7FFF);
167         *data++ = PA_CLAMP_UNLIKELY(sum1, -0x8000, 0x7FFF);
168     }
169 }
170
171 static void pa_mix_generic_s16ne(pa_mix_info streams[], unsigned nstreams, unsigned channels, int16_t *data, unsigned length) {
172     unsigned channel = 0;
173
174     length /= sizeof(int16_t);
175
176     for (; length > 0; length--) {
177         int32_t sum = 0;
178         unsigned i;
179
180         for (i = 0; i < nstreams; i++) {
181             pa_mix_info *m = streams + i;
182             int32_t cv = m->linear[channel].i;
183
184             if (PA_LIKELY(cv > 0))
185                 sum += pa_mult_s16_volume(*((int16_t*) m->ptr), cv);
186             m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
187         }
188
189         sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
190         *data++ = sum;
191
192         if (PA_UNLIKELY(++channel >= channels))
193             channel = 0;
194     }
195 }
196
197
198 #define SAMPLES 1028
199 #define TIMES 1000
200 #define TIMES2 100
201
202 START_TEST (mix_special_1ch_test) {
203     int16_t samples0[SAMPLES];
204     int16_t samples1[SAMPLES];
205     int16_t out[SAMPLES];
206     int16_t out_ref[SAMPLES];
207     pa_mempool *pool;
208     pa_memchunk c0, c1;
209     pa_mix_info m[2];
210     unsigned nsamples = SAMPLES;
211
212     fail_unless((pool = pa_mempool_new(FALSE, 0)) != NULL, NULL);
213
214     pa_random(samples0, nsamples * sizeof(int16_t));
215     c0.memblock = pa_memblock_new_fixed(pool, samples0, nsamples * sizeof(int16_t), FALSE);
216     c0.length = pa_memblock_get_length(c0.memblock);
217     c0.index = 0;
218
219     pa_random(samples1, nsamples * sizeof(int16_t));
220     c1.memblock = pa_memblock_new_fixed(pool, samples1, nsamples * sizeof(int16_t), FALSE);
221     c1.length = pa_memblock_get_length(c1.memblock);
222     c1.index = 0;
223
224     m[0].chunk = c0;
225     m[0].volume.channels = 1;
226     m[0].volume.values[0] = PA_VOLUME_NORM;
227     m[0].linear[0].i = 0x5555;
228
229     m[1].chunk = c1;
230     m[1].volume.channels = 1;
231     m[1].volume.values[0] = PA_VOLUME_NORM;
232     m[1].linear[0].i = 0x6789;
233
234     PA_CPU_TEST_RUN_START("mix s16 generic 1 channel", TIMES, TIMES2) {
235         acquire_mix_streams(m, 2);
236         pa_mix_generic_s16ne(m, 2, 1, out_ref, nsamples * sizeof(int16_t));
237         release_mix_streams(m, 2);
238     } PA_CPU_TEST_RUN_STOP
239
240     PA_CPU_TEST_RUN_START("mix s16 2 streams 1 channel", TIMES, TIMES2) {
241         acquire_mix_streams(m, 2);
242         pa_mix2_ch1_s16ne(m, out, nsamples * sizeof(int16_t));
243         release_mix_streams(m, 2);
244     } PA_CPU_TEST_RUN_STOP
245
246     fail_unless(memcmp(out, out_ref, nsamples * sizeof(int16_t)) == 0);
247
248     pa_memblock_unref(c0.memblock);
249     pa_memblock_unref(c1.memblock);
250
251     pa_mempool_free(pool);
252 }
253 END_TEST
254
255 START_TEST (mix_special_2ch_test) {
256     int16_t samples0[SAMPLES*2];
257     int16_t samples1[SAMPLES*2];
258     int16_t out[SAMPLES*2];
259     int16_t out_ref[SAMPLES*2];
260     int i;
261     pa_mempool *pool;
262     pa_memchunk c0, c1;
263     pa_mix_info m[2];
264     unsigned nsamples = SAMPLES * 2;
265
266     fail_unless((pool = pa_mempool_new(FALSE, 0)) != NULL, NULL);
267
268     pa_random(samples0, nsamples * sizeof(int16_t));
269     c0.memblock = pa_memblock_new_fixed(pool, samples0, nsamples * sizeof(int16_t), FALSE);
270     c0.length = pa_memblock_get_length(c0.memblock);
271     c0.index = 0;
272
273     pa_random(samples1, nsamples * sizeof(int16_t));
274     c1.memblock = pa_memblock_new_fixed(pool, samples1, nsamples * sizeof(int16_t), FALSE);
275     c1.length = pa_memblock_get_length(c1.memblock);
276     c1.index = 0;
277
278     m[0].chunk = c0;
279     m[0].volume.channels = 2;
280     for (i = 0; i < m[0].volume.channels; i++) {
281         m[0].volume.values[i] = PA_VOLUME_NORM;
282         m[0].linear[i].i = 0x5555;
283     }
284
285     m[1].chunk = c1;
286     m[1].volume.channels = 2;
287     for (i = 0; i < m[1].volume.channels; i++) {
288         m[1].volume.values[i] = PA_VOLUME_NORM;
289         m[1].linear[i].i = 0x6789;
290     }
291
292     PA_CPU_TEST_RUN_START("mix s16 generic 2 channels", TIMES, TIMES2) {
293         acquire_mix_streams(m, 2);
294         pa_mix_generic_s16ne(m, 2, 2, out_ref, nsamples * sizeof(int16_t));
295         release_mix_streams(m, 2);
296     } PA_CPU_TEST_RUN_STOP
297
298     PA_CPU_TEST_RUN_START("mix s16 2 channels", TIMES, TIMES2) {
299         acquire_mix_streams(m, 2);
300         pa_mix_ch2_s16ne(m, 2, out, nsamples * sizeof(int16_t));
301         release_mix_streams(m, 2);
302     } PA_CPU_TEST_RUN_STOP
303
304     fail_unless(memcmp(out, out_ref, nsamples * sizeof(int16_t)) == 0);
305
306     PA_CPU_TEST_RUN_START("mix s16 2 streams", TIMES, TIMES2) {
307         acquire_mix_streams(m, 2);
308         pa_mix2_s16ne(m, 2, out, nsamples * sizeof(int16_t));
309         release_mix_streams(m, 2);
310     } PA_CPU_TEST_RUN_STOP
311
312     fail_unless(memcmp(out, out_ref, nsamples * sizeof(int16_t)) == 0);
313
314     PA_CPU_TEST_RUN_START("mix s16 2 streams 2 channels", TIMES, TIMES2) {
315         acquire_mix_streams(m, 2);
316         pa_mix2_ch2_s16ne(m, out, nsamples * sizeof(int16_t));
317         release_mix_streams(m, 2);
318     } PA_CPU_TEST_RUN_STOP
319
320     fail_unless(memcmp(out, out_ref, nsamples * sizeof(int16_t)) == 0);
321
322     pa_memblock_unref(c0.memblock);
323     pa_memblock_unref(c1.memblock);
324
325     pa_mempool_free(pool);
326 }
327 END_TEST
328
329 int main(int argc, char *argv[]) {
330     int failed = 0;
331     Suite *s;
332     TCase *tc;
333     SRunner *sr;
334
335     if (!getenv("MAKE_CHECK"))
336         pa_log_set_level(PA_LOG_DEBUG);
337
338     s = suite_create("Mix-special");
339     tc = tcase_create("mix-special 1ch");
340     tcase_add_test(tc, mix_special_1ch_test);
341     tcase_set_timeout(tc, 120);
342     suite_add_tcase(s, tc);
343     tc = tcase_create("mix-special 2ch");
344     tcase_add_test(tc, mix_special_2ch_test);
345     tcase_set_timeout(tc, 120);
346     suite_add_tcase(s, tc);
347
348     sr = srunner_create(s);
349     srunner_run_all(sr, CK_NORMAL);
350     failed = srunner_ntests_failed(sr);
351     srunner_free(sr);
352
353     return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
354 }