]> code.delx.au - pulseaudio/blob - src/tests/mix-special-test.c
sink-input, source-output: Add hooks for mute changes
[pulseaudio] / 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 #include "runtime-test-util.h"
36
37 static void acquire_mix_streams(pa_mix_info streams[], unsigned nstreams) {
38 unsigned i;
39
40 for (i = 0; i < nstreams; i++)
41 streams[i].ptr = pa_memblock_acquire_chunk(&streams[i].chunk);
42 }
43
44 static void release_mix_streams(pa_mix_info streams[], unsigned nstreams) {
45 unsigned i;
46
47 for (i = 0; i < nstreams; i++)
48 pa_memblock_release(streams[i].chunk.memblock);
49 }
50
51 /* special case: mix 2 s16ne streams, 1 channel each */
52 static void pa_mix2_ch1_s16ne(pa_mix_info streams[], int16_t *data, unsigned length) {
53 const int16_t *ptr0 = streams[0].ptr;
54 const int16_t *ptr1 = streams[1].ptr;
55
56 const int32_t cv0 = streams[0].linear[0].i;
57 const int32_t cv1 = streams[1].linear[0].i;
58
59 length /= sizeof(int16_t);
60
61 for (; length > 0; length--) {
62 int32_t sum;
63
64 sum = pa_mult_s16_volume(*ptr0++, cv0);
65 sum += pa_mult_s16_volume(*ptr1++, cv1);
66
67 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
68 *data++ = sum;
69 }
70 }
71
72 /* special case: mix 2 s16ne streams, 2 channels each */
73 static void pa_mix2_ch2_s16ne(pa_mix_info streams[], int16_t *data, unsigned length) {
74 const int16_t *ptr0 = streams[0].ptr;
75 const int16_t *ptr1 = streams[1].ptr;
76
77 length /= sizeof(int16_t) * 2;
78
79 for (; length > 0; length--) {
80 int32_t sum;
81
82 sum = pa_mult_s16_volume(*ptr0++, streams[0].linear[0].i);
83 sum += pa_mult_s16_volume(*ptr1++, streams[1].linear[0].i);
84
85 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
86 *data++ = sum;
87
88 sum = pa_mult_s16_volume(*ptr0++, streams[0].linear[1].i);
89 sum += pa_mult_s16_volume(*ptr1++, streams[1].linear[1].i);
90
91 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
92 *data++ = sum;
93 }
94 }
95
96 /* special case: mix 2 s16ne streams */
97 static void pa_mix2_s16ne(pa_mix_info streams[], unsigned channels, int16_t *data, unsigned length) {
98 const int16_t *ptr0 = streams[0].ptr;
99 const int16_t *ptr1 = streams[1].ptr;
100 unsigned channel = 0;
101
102 length /= sizeof(int16_t);
103
104 for (; length > 0; length--) {
105 int32_t sum;
106
107 sum = pa_mult_s16_volume(*ptr0++, streams[0].linear[channel].i);
108 sum += pa_mult_s16_volume(*ptr1++, streams[1].linear[channel].i);
109
110 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
111 *data++ = sum;
112
113 if (PA_UNLIKELY(++channel >= channels))
114 channel = 0;
115 }
116 }
117
118 /* special case: mix s16ne streams, 2 channels each */
119 static void pa_mix_ch2_s16ne(pa_mix_info streams[], unsigned nstreams, int16_t *data, unsigned length) {
120
121 length /= sizeof(int16_t) * 2;
122
123 for (; length > 0; length--) {
124 int32_t sum0 = 0, sum1 = 0;
125 unsigned i;
126
127 for (i = 0; i < nstreams; i++) {
128 pa_mix_info *m = streams + i;
129 int32_t cv0 = m->linear[0].i;
130 int32_t cv1 = m->linear[1].i;
131
132 sum0 += pa_mult_s16_volume(*((int16_t*) m->ptr), cv0);
133 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
134
135 sum1 += pa_mult_s16_volume(*((int16_t*) m->ptr), cv1);
136 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
137 }
138
139 *data++ = PA_CLAMP_UNLIKELY(sum0, -0x8000, 0x7FFF);
140 *data++ = PA_CLAMP_UNLIKELY(sum1, -0x8000, 0x7FFF);
141 }
142 }
143
144 static void pa_mix_generic_s16ne(pa_mix_info streams[], unsigned nstreams, unsigned channels, int16_t *data, unsigned length) {
145 unsigned channel = 0;
146
147 length /= sizeof(int16_t);
148
149 for (; length > 0; length--) {
150 int32_t sum = 0;
151 unsigned i;
152
153 for (i = 0; i < nstreams; i++) {
154 pa_mix_info *m = streams + i;
155 int32_t cv = m->linear[channel].i;
156
157 if (PA_LIKELY(cv > 0))
158 sum += pa_mult_s16_volume(*((int16_t*) m->ptr), cv);
159 m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
160 }
161
162 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
163 *data++ = sum;
164
165 if (PA_UNLIKELY(++channel >= channels))
166 channel = 0;
167 }
168 }
169
170 #define SAMPLES 1028
171 #define TIMES 1000
172 #define TIMES2 100
173
174 START_TEST (mix_special_1ch_test) {
175 int16_t samples0[SAMPLES];
176 int16_t samples1[SAMPLES];
177 int16_t out[SAMPLES];
178 int16_t out_ref[SAMPLES];
179 pa_mempool *pool;
180 pa_memchunk c0, c1;
181 pa_mix_info m[2];
182 unsigned nsamples = SAMPLES;
183
184 fail_unless((pool = pa_mempool_new(false, 0)) != NULL, NULL);
185
186 pa_random(samples0, nsamples * sizeof(int16_t));
187 c0.memblock = pa_memblock_new_fixed(pool, samples0, nsamples * sizeof(int16_t), false);
188 c0.length = pa_memblock_get_length(c0.memblock);
189 c0.index = 0;
190
191 pa_random(samples1, nsamples * sizeof(int16_t));
192 c1.memblock = pa_memblock_new_fixed(pool, samples1, nsamples * sizeof(int16_t), false);
193 c1.length = pa_memblock_get_length(c1.memblock);
194 c1.index = 0;
195
196 m[0].chunk = c0;
197 m[0].volume.channels = 1;
198 m[0].volume.values[0] = PA_VOLUME_NORM;
199 m[0].linear[0].i = 0x5555;
200
201 m[1].chunk = c1;
202 m[1].volume.channels = 1;
203 m[1].volume.values[0] = PA_VOLUME_NORM;
204 m[1].linear[0].i = 0x6789;
205
206 PA_RUNTIME_TEST_RUN_START("mix s16 generic 1 channel", TIMES, TIMES2) {
207 acquire_mix_streams(m, 2);
208 pa_mix_generic_s16ne(m, 2, 1, out_ref, nsamples * sizeof(int16_t));
209 release_mix_streams(m, 2);
210 } PA_RUNTIME_TEST_RUN_STOP
211
212 PA_RUNTIME_TEST_RUN_START("mix s16 2 streams 1 channel", TIMES, TIMES2) {
213 acquire_mix_streams(m, 2);
214 pa_mix2_ch1_s16ne(m, out, nsamples * sizeof(int16_t));
215 release_mix_streams(m, 2);
216 } PA_RUNTIME_TEST_RUN_STOP
217
218 fail_unless(memcmp(out, out_ref, nsamples * sizeof(int16_t)) == 0);
219
220 pa_memblock_unref(c0.memblock);
221 pa_memblock_unref(c1.memblock);
222
223 pa_mempool_free(pool);
224 }
225 END_TEST
226
227 START_TEST (mix_special_2ch_test) {
228 int16_t samples0[SAMPLES*2];
229 int16_t samples1[SAMPLES*2];
230 int16_t out[SAMPLES*2];
231 int16_t out_ref[SAMPLES*2];
232 int i;
233 pa_mempool *pool;
234 pa_memchunk c0, c1;
235 pa_mix_info m[2];
236 unsigned nsamples = SAMPLES * 2;
237
238 fail_unless((pool = pa_mempool_new(false, 0)) != NULL, NULL);
239
240 pa_random(samples0, nsamples * sizeof(int16_t));
241 c0.memblock = pa_memblock_new_fixed(pool, samples0, nsamples * sizeof(int16_t), false);
242 c0.length = pa_memblock_get_length(c0.memblock);
243 c0.index = 0;
244
245 pa_random(samples1, nsamples * sizeof(int16_t));
246 c1.memblock = pa_memblock_new_fixed(pool, samples1, nsamples * sizeof(int16_t), false);
247 c1.length = pa_memblock_get_length(c1.memblock);
248 c1.index = 0;
249
250 m[0].chunk = c0;
251 m[0].volume.channels = 2;
252 for (i = 0; i < m[0].volume.channels; i++) {
253 m[0].volume.values[i] = PA_VOLUME_NORM;
254 m[0].linear[i].i = 0x5555;
255 }
256
257 m[1].chunk = c1;
258 m[1].volume.channels = 2;
259 for (i = 0; i < m[1].volume.channels; i++) {
260 m[1].volume.values[i] = PA_VOLUME_NORM;
261 m[1].linear[i].i = 0x6789;
262 }
263
264 PA_RUNTIME_TEST_RUN_START("mix s16 generic 2 channels", TIMES, TIMES2) {
265 acquire_mix_streams(m, 2);
266 pa_mix_generic_s16ne(m, 2, 2, out_ref, nsamples * sizeof(int16_t));
267 release_mix_streams(m, 2);
268 } PA_RUNTIME_TEST_RUN_STOP
269
270 PA_RUNTIME_TEST_RUN_START("mix s16 2 channels", TIMES, TIMES2) {
271 acquire_mix_streams(m, 2);
272 pa_mix_ch2_s16ne(m, 2, out, nsamples * sizeof(int16_t));
273 release_mix_streams(m, 2);
274 } PA_RUNTIME_TEST_RUN_STOP
275
276 fail_unless(memcmp(out, out_ref, nsamples * sizeof(int16_t)) == 0);
277
278 PA_RUNTIME_TEST_RUN_START("mix s16 2 streams", TIMES, TIMES2) {
279 acquire_mix_streams(m, 2);
280 pa_mix2_s16ne(m, 2, out, nsamples * sizeof(int16_t));
281 release_mix_streams(m, 2);
282 } PA_RUNTIME_TEST_RUN_STOP
283
284 fail_unless(memcmp(out, out_ref, nsamples * sizeof(int16_t)) == 0);
285
286 PA_RUNTIME_TEST_RUN_START("mix s16 2 streams 2 channels", TIMES, TIMES2) {
287 acquire_mix_streams(m, 2);
288 pa_mix2_ch2_s16ne(m, out, nsamples * sizeof(int16_t));
289 release_mix_streams(m, 2);
290 } PA_RUNTIME_TEST_RUN_STOP
291
292 fail_unless(memcmp(out, out_ref, nsamples * sizeof(int16_t)) == 0);
293
294 pa_memblock_unref(c0.memblock);
295 pa_memblock_unref(c1.memblock);
296
297 pa_mempool_free(pool);
298 }
299 END_TEST
300
301 int main(int argc, char *argv[]) {
302 int failed = 0;
303 Suite *s;
304 TCase *tc;
305 SRunner *sr;
306
307 if (!getenv("MAKE_CHECK"))
308 pa_log_set_level(PA_LOG_DEBUG);
309
310 s = suite_create("Mix-special");
311 tc = tcase_create("mix-special 1ch");
312 tcase_add_test(tc, mix_special_1ch_test);
313 tcase_set_timeout(tc, 120);
314 suite_add_tcase(s, tc);
315 tc = tcase_create("mix-special 2ch");
316 tcase_add_test(tc, mix_special_2ch_test);
317 tcase_set_timeout(tc, 120);
318 suite_add_tcase(s, tc);
319
320 sr = srunner_create(s);
321 srunner_run_all(sr, CK_NORMAL);
322 failed = srunner_ntests_failed(sr);
323 srunner_free(sr);
324
325 return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
326 }