/src/opus/src/opus_multistream_decoder.c
Line | Count | Source |
1 | | /* Copyright (c) 2011 Xiph.Org Foundation |
2 | | Written by Jean-Marc Valin */ |
3 | | /* |
4 | | Redistribution and use in source and binary forms, with or without |
5 | | modification, are permitted provided that the following conditions |
6 | | are met: |
7 | | |
8 | | - Redistributions of source code must retain the above copyright |
9 | | notice, this list of conditions and the following disclaimer. |
10 | | |
11 | | - Redistributions in binary form must reproduce the above copyright |
12 | | notice, this list of conditions and the following disclaimer in the |
13 | | documentation and/or other materials provided with the distribution. |
14 | | |
15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
16 | | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
17 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
18 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER |
19 | | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
20 | | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
21 | | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
22 | | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
23 | | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
24 | | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | | */ |
27 | | |
28 | | #ifdef HAVE_CONFIG_H |
29 | | #include "config.h" |
30 | | #endif |
31 | | |
32 | | #include "opus_multistream.h" |
33 | | #include "opus.h" |
34 | | #include "opus_private.h" |
35 | | #include "stack_alloc.h" |
36 | | #include <stdarg.h> |
37 | | #include "float_cast.h" |
38 | | #include "os_support.h" |
39 | | |
40 | | /* DECODER */ |
41 | | |
42 | | #if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) |
43 | | static void validate_ms_decoder(OpusMSDecoder *st) |
44 | 316k | { |
45 | 316k | validate_layout(&st->layout); |
46 | 316k | } |
47 | 316k | #define VALIDATE_MS_DECODER(st) validate_ms_decoder(st) |
48 | | #else |
49 | | #define VALIDATE_MS_DECODER(st) |
50 | | #endif |
51 | | |
52 | | |
53 | | opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams) |
54 | 6.67k | { |
55 | 6.67k | int coupled_size; |
56 | 6.67k | int mono_size; |
57 | | |
58 | 6.67k | if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; |
59 | 6.67k | coupled_size = opus_decoder_get_size(2); |
60 | 6.67k | mono_size = opus_decoder_get_size(1); |
61 | 6.67k | return align(sizeof(OpusMSDecoder)) |
62 | 6.67k | + nb_coupled_streams * align(coupled_size) |
63 | 6.67k | + (nb_streams-nb_coupled_streams) * align(mono_size); |
64 | 6.67k | } |
65 | | |
66 | | int opus_multistream_decoder_init( |
67 | | OpusMSDecoder *st, |
68 | | opus_int32 Fs, |
69 | | int channels, |
70 | | int streams, |
71 | | int coupled_streams, |
72 | | const unsigned char *mapping |
73 | | ) |
74 | 6.67k | { |
75 | 6.67k | int coupled_size; |
76 | 6.67k | int mono_size; |
77 | 6.67k | int i, ret; |
78 | 6.67k | char *ptr; |
79 | | |
80 | 6.67k | if ((channels>255) || (channels<1) || (coupled_streams>streams) || |
81 | 6.67k | (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) |
82 | 0 | return OPUS_BAD_ARG; |
83 | | |
84 | 6.67k | st->layout.nb_channels = channels; |
85 | 6.67k | st->layout.nb_streams = streams; |
86 | 6.67k | st->layout.nb_coupled_streams = coupled_streams; |
87 | | |
88 | 41.7k | for (i=0;i<st->layout.nb_channels;i++) |
89 | 35.0k | st->layout.mapping[i] = mapping[i]; |
90 | 6.67k | if (!validate_layout(&st->layout)) |
91 | 6 | return OPUS_BAD_ARG; |
92 | | |
93 | 6.67k | ptr = (char*)st + align(sizeof(OpusMSDecoder)); |
94 | 6.67k | coupled_size = opus_decoder_get_size(2); |
95 | 6.67k | mono_size = opus_decoder_get_size(1); |
96 | | |
97 | 20.7k | for (i=0;i<st->layout.nb_coupled_streams;i++) |
98 | 14.0k | { |
99 | 14.0k | ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2); |
100 | 14.0k | if(ret!=OPUS_OK)return ret; |
101 | 14.0k | ptr += align(coupled_size); |
102 | 14.0k | } |
103 | 53.4k | for (;i<st->layout.nb_streams;i++) |
104 | 46.7k | { |
105 | 46.7k | ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1); |
106 | 46.7k | if(ret!=OPUS_OK)return ret; |
107 | 46.7k | ptr += align(mono_size); |
108 | 46.7k | } |
109 | 6.67k | return OPUS_OK; |
110 | 6.67k | } |
111 | | |
112 | | |
113 | | OpusMSDecoder *opus_multistream_decoder_create( |
114 | | opus_int32 Fs, |
115 | | int channels, |
116 | | int streams, |
117 | | int coupled_streams, |
118 | | const unsigned char *mapping, |
119 | | int *error |
120 | | ) |
121 | 6.70k | { |
122 | 6.70k | int ret; |
123 | 6.70k | OpusMSDecoder *st; |
124 | 6.70k | if ((channels>255) || (channels<1) || (coupled_streams>streams) || |
125 | 6.70k | (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) |
126 | 28 | { |
127 | 28 | if (error) |
128 | 28 | *error = OPUS_BAD_ARG; |
129 | 28 | return NULL; |
130 | 28 | } |
131 | 6.67k | st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams)); |
132 | 6.67k | if (st==NULL) |
133 | 0 | { |
134 | 0 | if (error) |
135 | 0 | *error = OPUS_ALLOC_FAIL; |
136 | 0 | return NULL; |
137 | 0 | } |
138 | 6.67k | ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping); |
139 | 6.67k | if (error) |
140 | 6.67k | *error = ret; |
141 | 6.67k | if (ret != OPUS_OK) |
142 | 6 | { |
143 | 6 | opus_free(st); |
144 | 6 | st = NULL; |
145 | 6 | } |
146 | 6.67k | return st; |
147 | 6.67k | } |
148 | | |
149 | | static int opus_multistream_packet_validate(const unsigned char *data, |
150 | | opus_int32 len, int nb_streams, opus_int32 Fs) |
151 | 270k | { |
152 | 270k | int s; |
153 | 270k | int count; |
154 | 270k | unsigned char toc; |
155 | 270k | opus_int16 size[48]; |
156 | 270k | int samples=0; |
157 | 270k | opus_int32 packet_offset; |
158 | | |
159 | 523k | for (s=0;s<nb_streams;s++) |
160 | 285k | { |
161 | 285k | int tmp_samples; |
162 | 285k | if (len<=0) |
163 | 238 | return OPUS_INVALID_PACKET; |
164 | 285k | count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL, |
165 | 285k | size, NULL, &packet_offset, NULL, NULL); |
166 | 285k | if (count<0) |
167 | 31.5k | return count; |
168 | 254k | tmp_samples = opus_packet_get_nb_samples(data, packet_offset, Fs); |
169 | 254k | if (s!=0 && samples != tmp_samples) |
170 | 1.31k | return OPUS_INVALID_PACKET; |
171 | 252k | samples = tmp_samples; |
172 | 252k | data += packet_offset; |
173 | 252k | len -= packet_offset; |
174 | 252k | } |
175 | 237k | return samples; |
176 | 270k | } |
177 | | |
178 | | int opus_multistream_decode_native( |
179 | | OpusMSDecoder *st, |
180 | | const unsigned char *data, |
181 | | opus_int32 len, |
182 | | void *pcm, |
183 | | opus_copy_channel_out_func copy_channel_out, |
184 | | int frame_size, |
185 | | int decode_fec, |
186 | | int soft_clip, |
187 | | void *user_data |
188 | | ) |
189 | 316k | { |
190 | 316k | opus_int32 Fs; |
191 | 316k | int coupled_size; |
192 | 316k | int mono_size; |
193 | 316k | int s, c; |
194 | 316k | char *ptr; |
195 | 316k | int do_plc=0; |
196 | 316k | VARDECL(opus_res, buf); |
197 | 316k | ALLOC_STACK; |
198 | | |
199 | 316k | VALIDATE_MS_DECODER(st); |
200 | 316k | if (frame_size <= 0) |
201 | 0 | { |
202 | 0 | RESTORE_STACK; |
203 | 0 | return OPUS_BAD_ARG; |
204 | 0 | } |
205 | | /* Limit frame_size to avoid excessive stack allocations. */ |
206 | 316k | MUST_SUCCEED(opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs))); |
207 | 316k | frame_size = IMIN(frame_size, Fs/25*3); |
208 | 316k | ALLOC(buf, 2*frame_size, opus_res); |
209 | 316k | ptr = (char*)st + align(sizeof(OpusMSDecoder)); |
210 | 316k | coupled_size = opus_decoder_get_size(2); |
211 | 316k | mono_size = opus_decoder_get_size(1); |
212 | | |
213 | 316k | if (len==0) |
214 | 0 | do_plc = 1; |
215 | 316k | if (len < 0) |
216 | 0 | { |
217 | 0 | RESTORE_STACK; |
218 | 0 | return OPUS_BAD_ARG; |
219 | 0 | } |
220 | 316k | if (!do_plc && len < 2*st->layout.nb_streams-1) |
221 | 45.5k | { |
222 | 45.5k | RESTORE_STACK; |
223 | 45.5k | return OPUS_INVALID_PACKET; |
224 | 45.5k | } |
225 | 270k | if (!do_plc) |
226 | 270k | { |
227 | 270k | int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs); |
228 | 270k | if (ret < 0) |
229 | 33.1k | { |
230 | 33.1k | RESTORE_STACK; |
231 | 33.1k | return ret; |
232 | 237k | } else if (ret > frame_size) |
233 | 0 | { |
234 | 0 | RESTORE_STACK; |
235 | 0 | return OPUS_BUFFER_TOO_SMALL; |
236 | 0 | } |
237 | 270k | } |
238 | 478k | for (s=0;s<st->layout.nb_streams;s++) |
239 | 241k | { |
240 | 241k | OpusDecoder *dec; |
241 | 241k | opus_int32 packet_offset; |
242 | 241k | int ret; |
243 | | |
244 | 241k | dec = (OpusDecoder*)ptr; |
245 | 241k | ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); |
246 | | |
247 | 241k | if (!do_plc && len<=0) |
248 | 0 | { |
249 | 0 | RESTORE_STACK; |
250 | 0 | return OPUS_INTERNAL_ERROR; |
251 | 0 | } |
252 | 241k | packet_offset = 0; |
253 | 241k | ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip, NULL, 0); |
254 | 241k | if (!do_plc) |
255 | 241k | { |
256 | 241k | data += packet_offset; |
257 | 241k | len -= packet_offset; |
258 | 241k | } |
259 | 241k | if (ret <= 0) |
260 | 0 | { |
261 | 0 | RESTORE_STACK; |
262 | 0 | return ret; |
263 | 0 | } |
264 | 241k | frame_size = ret; |
265 | 241k | if (s < st->layout.nb_coupled_streams) |
266 | 220k | { |
267 | 220k | int chan, prev; |
268 | 220k | prev = -1; |
269 | | /* Copy "left" audio to the channel(s) where it belongs */ |
270 | 435k | while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) |
271 | 215k | { |
272 | 215k | (*copy_channel_out)(pcm, st->layout.nb_channels, chan, |
273 | 215k | buf, 2, frame_size, user_data); |
274 | 215k | prev = chan; |
275 | 215k | } |
276 | 220k | prev = -1; |
277 | | /* Copy "right" audio to the channel(s) where it belongs */ |
278 | 446k | while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) |
279 | 225k | { |
280 | 225k | (*copy_channel_out)(pcm, st->layout.nb_channels, chan, |
281 | 225k | buf+1, 2, frame_size, user_data); |
282 | 225k | prev = chan; |
283 | 225k | } |
284 | 220k | } else { |
285 | 20.3k | int chan, prev; |
286 | 20.3k | prev = -1; |
287 | | /* Copy audio to the channel(s) where it belongs */ |
288 | 39.7k | while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) |
289 | 19.3k | { |
290 | 19.3k | (*copy_channel_out)(pcm, st->layout.nb_channels, chan, |
291 | 19.3k | buf, 1, frame_size, user_data); |
292 | 19.3k | prev = chan; |
293 | 19.3k | } |
294 | 20.3k | } |
295 | 241k | } |
296 | | /* Handle muted channels */ |
297 | 699k | for (c=0;c<st->layout.nb_channels;c++) |
298 | 461k | { |
299 | 461k | if (st->layout.mapping[c] == 255) |
300 | 1.73k | { |
301 | 1.73k | (*copy_channel_out)(pcm, st->layout.nb_channels, c, |
302 | 1.73k | NULL, 0, frame_size, user_data); |
303 | 1.73k | } |
304 | 461k | } |
305 | 237k | RESTORE_STACK; |
306 | 237k | return frame_size; |
307 | 237k | } |
308 | | |
309 | | #if !defined(DISABLE_FLOAT_API) |
310 | | static void opus_copy_channel_out_float( |
311 | | void *dst, |
312 | | int dst_stride, |
313 | | int dst_channel, |
314 | | const opus_res *src, |
315 | | int src_stride, |
316 | | int frame_size, |
317 | | void *user_data |
318 | | ) |
319 | 0 | { |
320 | 0 | float *float_dst; |
321 | 0 | opus_int32 i; |
322 | 0 | (void)user_data; |
323 | 0 | float_dst = (float*)dst; |
324 | 0 | if (src != NULL) |
325 | 0 | { |
326 | 0 | for (i=0;i<frame_size;i++) |
327 | 0 | float_dst[i*dst_stride+dst_channel] = RES2FLOAT(src[i*src_stride]); |
328 | 0 | } |
329 | 0 | else |
330 | 0 | { |
331 | 0 | for (i=0;i<frame_size;i++) |
332 | 0 | float_dst[i*dst_stride+dst_channel] = 0; |
333 | 0 | } |
334 | 0 | } |
335 | | #endif |
336 | | |
337 | | static void opus_copy_channel_out_short( |
338 | | void *dst, |
339 | | int dst_stride, |
340 | | int dst_channel, |
341 | | const opus_res *src, |
342 | | int src_stride, |
343 | | int frame_size, |
344 | | void *user_data |
345 | | ) |
346 | 461k | { |
347 | 461k | opus_int16 *short_dst; |
348 | 461k | opus_int32 i; |
349 | 461k | (void)user_data; |
350 | 461k | short_dst = (opus_int16*)dst; |
351 | 461k | if (src != NULL) |
352 | 460k | { |
353 | 553M | for (i=0;i<frame_size;i++) |
354 | 552M | short_dst[i*dst_stride+dst_channel] = RES2INT16(src[i*src_stride]); |
355 | 460k | } |
356 | 1.73k | else |
357 | 1.73k | { |
358 | 1.72M | for (i=0;i<frame_size;i++) |
359 | 1.72M | short_dst[i*dst_stride+dst_channel] = 0; |
360 | 1.73k | } |
361 | 461k | } |
362 | | |
363 | | static void opus_copy_channel_out_int24( |
364 | | void *dst, |
365 | | int dst_stride, |
366 | | int dst_channel, |
367 | | const opus_res *src, |
368 | | int src_stride, |
369 | | int frame_size, |
370 | | void *user_data |
371 | | ) |
372 | 0 | { |
373 | 0 | opus_int32 *short_dst; |
374 | 0 | opus_int32 i; |
375 | 0 | (void)user_data; |
376 | 0 | short_dst = (opus_int32*)dst; |
377 | 0 | if (src != NULL) |
378 | 0 | { |
379 | 0 | for (i=0;i<frame_size;i++) |
380 | 0 | short_dst[i*dst_stride+dst_channel] = RES2INT24(src[i*src_stride]); |
381 | 0 | } |
382 | 0 | else |
383 | 0 | { |
384 | 0 | for (i=0;i<frame_size;i++) |
385 | 0 | short_dst[i*dst_stride+dst_channel] = 0; |
386 | 0 | } |
387 | 0 | } |
388 | | |
389 | | #ifdef FIXED_POINT |
390 | | #define OPTIONAL_CLIP 0 |
391 | | #else |
392 | 316k | #define OPTIONAL_CLIP 1 |
393 | | #endif |
394 | | |
395 | | int opus_multistream_decode( |
396 | | OpusMSDecoder *st, |
397 | | const unsigned char *data, |
398 | | opus_int32 len, |
399 | | opus_int16 *pcm, |
400 | | int frame_size, |
401 | | int decode_fec |
402 | | ) |
403 | 316k | { |
404 | 316k | return opus_multistream_decode_native(st, data, len, |
405 | 316k | pcm, opus_copy_channel_out_short, frame_size, decode_fec, OPTIONAL_CLIP, NULL); |
406 | 316k | } |
407 | | |
408 | | int opus_multistream_decode24( |
409 | | OpusMSDecoder *st, |
410 | | const unsigned char *data, |
411 | | opus_int32 len, |
412 | | opus_int32 *pcm, |
413 | | int frame_size, |
414 | | int decode_fec |
415 | | ) |
416 | 0 | { |
417 | 0 | return opus_multistream_decode_native(st, data, len, |
418 | 0 | pcm, opus_copy_channel_out_int24, frame_size, decode_fec, 0, NULL); |
419 | 0 | } |
420 | | |
421 | | #ifndef DISABLE_FLOAT_API |
422 | | int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data, |
423 | | opus_int32 len, float *pcm, int frame_size, int decode_fec) |
424 | 0 | { |
425 | 0 | return opus_multistream_decode_native(st, data, len, |
426 | 0 | pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0, NULL); |
427 | 0 | } |
428 | | #endif |
429 | | |
430 | | int opus_multistream_decoder_ctl_va_list(OpusMSDecoder *st, int request, |
431 | | va_list ap) |
432 | 470k | { |
433 | 470k | int coupled_size, mono_size; |
434 | 470k | char *ptr; |
435 | 470k | int ret = OPUS_OK; |
436 | | |
437 | 470k | coupled_size = opus_decoder_get_size(2); |
438 | 470k | mono_size = opus_decoder_get_size(1); |
439 | 470k | ptr = (char*)st + align(sizeof(OpusMSDecoder)); |
440 | 470k | switch (request) |
441 | 470k | { |
442 | 0 | case OPUS_GET_BANDWIDTH_REQUEST: |
443 | 316k | case OPUS_GET_SAMPLE_RATE_REQUEST: |
444 | 316k | case OPUS_GET_GAIN_REQUEST: |
445 | 316k | case OPUS_GET_LAST_PACKET_DURATION_REQUEST: |
446 | 316k | case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: |
447 | 316k | case OPUS_GET_COMPLEXITY_REQUEST: |
448 | 316k | { |
449 | 316k | OpusDecoder *dec; |
450 | | /* For int32* GET params, just query the first stream */ |
451 | 316k | opus_int32 *value = va_arg(ap, opus_int32*); |
452 | 316k | dec = (OpusDecoder*)ptr; |
453 | 316k | ret = opus_decoder_ctl(dec, request, value); |
454 | 316k | } |
455 | 316k | break; |
456 | 0 | case OPUS_GET_FINAL_RANGE_REQUEST: |
457 | 0 | { |
458 | 0 | int s; |
459 | 0 | opus_uint32 *value = va_arg(ap, opus_uint32*); |
460 | 0 | opus_uint32 tmp; |
461 | 0 | if (!value) |
462 | 0 | { |
463 | 0 | goto bad_arg; |
464 | 0 | } |
465 | 0 | *value = 0; |
466 | 0 | for (s=0;s<st->layout.nb_streams;s++) |
467 | 0 | { |
468 | 0 | OpusDecoder *dec; |
469 | 0 | dec = (OpusDecoder*)ptr; |
470 | 0 | if (s < st->layout.nb_coupled_streams) |
471 | 0 | ptr += align(coupled_size); |
472 | 0 | else |
473 | 0 | ptr += align(mono_size); |
474 | 0 | ret = opus_decoder_ctl(dec, request, &tmp); |
475 | 0 | if (ret != OPUS_OK) break; |
476 | 0 | *value ^= tmp; |
477 | 0 | } |
478 | 0 | } |
479 | 0 | break; |
480 | 140k | case OPUS_RESET_STATE: |
481 | 140k | { |
482 | 140k | int s; |
483 | 2.54M | for (s=0;s<st->layout.nb_streams;s++) |
484 | 2.40M | { |
485 | 2.40M | OpusDecoder *dec; |
486 | | |
487 | 2.40M | dec = (OpusDecoder*)ptr; |
488 | 2.40M | if (s < st->layout.nb_coupled_streams) |
489 | 928k | ptr += align(coupled_size); |
490 | 1.47M | else |
491 | 1.47M | ptr += align(mono_size); |
492 | 2.40M | ret = opus_decoder_ctl(dec, OPUS_RESET_STATE); |
493 | 2.40M | if (ret != OPUS_OK) |
494 | 0 | break; |
495 | 2.40M | } |
496 | 140k | } |
497 | 140k | break; |
498 | 0 | case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST: |
499 | 0 | { |
500 | 0 | int s; |
501 | 0 | opus_int32 stream_id; |
502 | 0 | OpusDecoder **value; |
503 | 0 | stream_id = va_arg(ap, opus_int32); |
504 | 0 | if (stream_id<0 || stream_id >= st->layout.nb_streams) |
505 | 0 | goto bad_arg; |
506 | 0 | value = va_arg(ap, OpusDecoder**); |
507 | 0 | if (!value) |
508 | 0 | { |
509 | 0 | goto bad_arg; |
510 | 0 | } |
511 | 0 | for (s=0;s<stream_id;s++) |
512 | 0 | { |
513 | 0 | if (s < st->layout.nb_coupled_streams) |
514 | 0 | ptr += align(coupled_size); |
515 | 0 | else |
516 | 0 | ptr += align(mono_size); |
517 | 0 | } |
518 | 0 | *value = (OpusDecoder*)ptr; |
519 | 0 | } |
520 | 0 | break; |
521 | 6.67k | case OPUS_SET_GAIN_REQUEST: |
522 | 6.67k | case OPUS_SET_COMPLEXITY_REQUEST: |
523 | 13.3k | case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: |
524 | 13.3k | { |
525 | 13.3k | int s; |
526 | | /* This works for int32 params */ |
527 | 13.3k | opus_int32 value = va_arg(ap, opus_int32); |
528 | 135k | for (s=0;s<st->layout.nb_streams;s++) |
529 | 121k | { |
530 | 121k | OpusDecoder *dec; |
531 | | |
532 | 121k | dec = (OpusDecoder*)ptr; |
533 | 121k | if (s < st->layout.nb_coupled_streams) |
534 | 28.0k | ptr += align(coupled_size); |
535 | 93.5k | else |
536 | 93.5k | ptr += align(mono_size); |
537 | 121k | ret = opus_decoder_ctl(dec, request, value); |
538 | 121k | if (ret != OPUS_OK) |
539 | 0 | break; |
540 | 121k | } |
541 | 13.3k | } |
542 | 13.3k | break; |
543 | 0 | default: |
544 | 0 | ret = OPUS_UNIMPLEMENTED; |
545 | 0 | break; |
546 | 470k | } |
547 | 470k | return ret; |
548 | 0 | bad_arg: |
549 | 0 | return OPUS_BAD_ARG; |
550 | 470k | } |
551 | | |
552 | | int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) |
553 | 470k | { |
554 | 470k | int ret; |
555 | 470k | va_list ap; |
556 | 470k | va_start(ap, request); |
557 | 470k | ret = opus_multistream_decoder_ctl_va_list(st, request, ap); |
558 | 470k | va_end(ap); |
559 | 470k | return ret; |
560 | 470k | } |
561 | | |
562 | | void opus_multistream_decoder_destroy(OpusMSDecoder *st) |
563 | 6.67k | { |
564 | 6.67k | opus_free(st); |
565 | 6.67k | } |