TF decoding details
[opus.git] / src / opus_multistream.c
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 FOUNDATION OR
19    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 typedef struct ChannelLayout {
41    int nb_channels;
42    int nb_streams;
43    int nb_coupled_streams;
44    unsigned char mapping[256];
45 } ChannelLayout;
46
47 struct OpusMSEncoder {
48    ChannelLayout layout;
49    int bitrate;
50    /* Encoder states go here */
51 };
52
53 struct OpusMSDecoder {
54    ChannelLayout layout;
55    /* Decoder states go here */
56 };
57
58
59 #ifdef FIXED_POINT
60 #define opus_encode_native opus_encode
61 #else
62 #define opus_encode_native opus_encode_float
63 #endif
64
65 static int validate_layout(const ChannelLayout *layout)
66 {
67    int i, max_channel;
68
69    max_channel = layout->nb_streams+layout->nb_coupled_streams;
70    if (max_channel>255)
71       return 0;
72    for (i=0;i<layout->nb_channels;i++)
73    {
74       if (layout->mapping[i] >= max_channel && layout->mapping[i] != 255)
75          return 0;
76    }
77    return 1;
78 }
79
80
81 static int get_left_channel(const ChannelLayout *layout, int stream_id, int prev)
82 {
83    int i;
84    i = (prev<0) ? 0 : prev+1;
85    for (;i<layout->nb_channels;i++)
86    {
87       if (layout->mapping[i]==stream_id*2)
88          return i;
89    }
90    return -1;
91 }
92
93 static int get_right_channel(const ChannelLayout *layout, int stream_id, int prev)
94 {
95    int i;
96    i = (prev<0) ? 0 : prev+1;
97    for (;i<layout->nb_channels;i++)
98    {
99       if (layout->mapping[i]==stream_id*2+1)
100          return i;
101    }
102    return -1;
103 }
104
105 static int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev)
106 {
107    int i;
108    i = (prev<0) ? 0 : prev+1;
109    for (;i<layout->nb_channels;i++)
110    {
111       if (layout->mapping[i]==2*layout->nb_coupled_streams+stream_id)
112          return i;
113    }
114    return -1;
115 }
116
117 static int validate_encoder_layout(const ChannelLayout *layout)
118 {
119    int s;
120    for (s=0;s<layout->nb_streams;s++)
121    {
122       if (s < layout->nb_coupled_streams)
123       {
124          if (get_left_channel(layout, s, -1)==-1)
125             return 0;
126          if (get_right_channel(layout, s, -1)==-1)
127             return 0;
128       } else {
129          if (get_mono_channel(layout, s, -1)==-1)
130             return 0;
131       }
132    }
133    return 1;
134 }
135
136 int opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams)
137 {
138         int coupled_size;
139         int mono_size;
140
141         coupled_size = opus_encoder_get_size(2);
142         mono_size = opus_encoder_get_size(1);
143         return align(sizeof(OpusMSEncoder))
144                         + nb_coupled_streams * align(coupled_size)
145                 + (nb_streams-nb_coupled_streams) * align(mono_size);
146 }
147
148
149
150 int opus_multistream_encoder_init(
151       OpusMSEncoder *st,            /* Encoder state */
152       opus_int32 Fs,                     /* Sampling rate of input signal (Hz) */
153       int channels,               /* Number of channels (1/2) in input signal */
154       int streams,
155       int coupled_streams,
156       unsigned char *mapping,
157       int application             /* Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO) */
158 )
159 {
160    int coupled_size;
161    int mono_size;
162    int i;
163    char *ptr;
164
165    st->layout.nb_channels = channels;
166    st->layout.nb_streams = streams;
167    st->layout.nb_coupled_streams = coupled_streams;
168
169    for (i=0;i<st->layout.nb_channels;i++)
170       st->layout.mapping[i] = mapping[i];
171    if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout))
172       return OPUS_BAD_ARG;
173    ptr = (char*)st + align(sizeof(OpusMSEncoder));
174    coupled_size = opus_encoder_get_size(2);
175    mono_size = opus_encoder_get_size(1);
176
177    for (i=0;i<st->layout.nb_coupled_streams;i++)
178    {
179       opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application);
180       ptr += align(coupled_size);
181    }
182    for (;i<st->layout.nb_streams;i++)
183    {
184       opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application);
185       ptr += align(mono_size);
186    }
187    return OPUS_OK;
188 }
189
190 OpusMSEncoder *opus_multistream_encoder_create(
191       opus_int32 Fs,                     /* Sampling rate of input signal (Hz) */
192       int channels,               /* Number of channels (1/2) in input signal */
193       int streams,
194       int coupled_streams,
195       unsigned char *mapping,
196       int application,            /* Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO) */
197       int *error                  /* Error code */
198 )
199 {
200    int ret;
201    OpusMSEncoder *st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams));
202    if (st==NULL)
203    {
204       if (error)
205          *error = OPUS_ALLOC_FAIL;
206       return NULL;
207    }
208    ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application);
209    if (ret != OPUS_OK)
210    {
211       opus_free(st);
212       st = NULL;
213    }
214    if (error)
215       *error = ret;
216    return st;
217 }
218
219
220 #ifdef FIXED_POINT
221 int opus_multistream_encode(
222 #else
223 int opus_multistream_encode_float(
224 #endif
225     OpusMSEncoder *st,            /* Encoder state */
226     const opus_val16 *pcm,      /* Input signal (interleaved if 2 channels). length is frame_size*channels */
227     int frame_size,             /* Number of samples per frame of input signal */
228     unsigned char *data,        /* Output payload (no more than max_data_bytes long) */
229     int max_data_bytes          /* Allocated memory for payload; don't use for controlling bitrate */
230 )
231 {
232    int coupled_size;
233    int mono_size;
234    int s, i;
235    char *ptr;
236    int tot_size;
237    VARDECL(opus_val16, buf);
238    /* Max size in case the encoder decides to return three frames */
239    unsigned char tmp_data[3*1275+7];
240    VARDECL(unsigned char, rp_);
241    OpusRepacketizer *rp;
242    ALLOC_STACK;
243
244    ALLOC(buf, 2*frame_size, opus_val16);
245    ALLOC(rp_, opus_repacketizer_get_size(), unsigned char);
246    rp = (OpusRepacketizer*)rp_;
247    ptr = (char*)st + align(sizeof(OpusMSEncoder));
248    coupled_size = opus_encoder_get_size(2);
249    mono_size = opus_encoder_get_size(1);
250
251    if (max_data_bytes < 2*st->layout.nb_streams-1)
252    {
253       RESTORE_STACK;
254       return OPUS_BUFFER_TOO_SMALL;
255    }
256    /* Counting ToC */
257    tot_size = 0;
258    for (s=0;s<st->layout.nb_streams;s++)
259    {
260       OpusEncoder *enc;
261       int len;
262       int curr_max;
263
264       opus_repacketizer_init(rp);
265       enc = (OpusEncoder*)ptr;
266       if (s < st->layout.nb_coupled_streams)
267       {
268          int left, right;
269          left = get_left_channel(&st->layout, s, -1);
270          right = get_right_channel(&st->layout, s, -1);
271          for (i=0;i<frame_size;i++)
272          {
273             buf[2*i] = pcm[st->layout.nb_channels*i+left];
274             buf[2*i+1] = pcm[st->layout.nb_channels*i+right];
275          }
276          ptr += align(coupled_size);
277       } else {
278          int chan = get_mono_channel(&st->layout, s, -1);
279          for (i=0;i<frame_size;i++)
280             buf[i] = pcm[st->layout.nb_channels*i+chan];
281          ptr += align(mono_size);
282       }
283       /* number of bytes left (+Toc) */
284       curr_max = max_data_bytes - tot_size;
285       /* Reserve one byte for the last stream and 2 for the others */
286       curr_max -= 2*(st->layout.nb_streams-s)-1;
287       len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max);
288       if (len<0)
289       {
290          RESTORE_STACK;
291          return len;
292       }
293       /* We need to use the repacketizer to add the self-delimiting lengths
294          while taking into account the fact that the encoder can now return
295          more than one frame at a time (e.g. 60 ms CELT-only) */
296       opus_repacketizer_cat(rp, tmp_data, len);
297       len = opus_repacketizer_out_range_impl(rp, 0, opus_repacketizer_get_nb_frames(rp), data, max_data_bytes-tot_size, s != st->layout.nb_streams-1);
298       data += len;
299       tot_size += len;
300    }
301    RESTORE_STACK;
302    return tot_size;
303
304 }
305
306 #ifdef FIXED_POINT
307
308 #ifndef DISABLE_FLOAT_API
309 int opus_multistream_encode_float(
310     OpusMSEncoder *st,          /* Encoder state */
311     const float *pcm,           /* Input signal (interleaved if 2 channels). length is frame_size*channels */
312     int frame_size,             /* Number of samples per frame of input signal */
313     unsigned char *data,        /* Output payload (no more than max_data_bytes long) */
314     int max_data_bytes          /* Allocated memory for payload; don't use for controlling bitrate */
315 )
316 {
317    int i, ret;
318    VARDECL(opus_int16, in);
319    ALLOC_STACK;
320
321    ALLOC(in, frame_size*st->layout.nb_channels, opus_int16);
322
323    for (i=0;i<frame_size*st->layout.nb_channels;i++)
324       in[i] = FLOAT2INT16(pcm[i]);
325    ret = opus_multistream_encode(st, in, frame_size, data, max_data_bytes);
326    RESTORE_STACK;
327    return ret;
328 }
329 #endif
330
331 #else
332
333 int opus_multistream_encode(
334     OpusMSEncoder *st,          /* Encoder state */
335     const opus_int16 *pcm,      /* Input signal (interleaved if 2 channels). length is frame_size*channels */
336     int frame_size,             /* Number of samples per frame of input signal */
337     unsigned char *data,        /* Output payload (no more than max_data_bytes long) */
338     int max_data_bytes          /* Allocated memory for payload; don't use for controlling bitrate */
339 )
340 {
341    int i, ret;
342    VARDECL(float, in);
343    ALLOC_STACK;
344
345    ALLOC(in, frame_size*st->layout.nb_channels, float);
346
347    for (i=0;i<frame_size*st->layout.nb_channels;i++)
348       in[i] = (1./32768)*pcm[i];
349    ret = opus_multistream_encode_float(st, in, frame_size, data, max_data_bytes);
350    RESTORE_STACK;
351    return ret;
352 }
353
354 #endif
355
356 int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
357 {
358    va_list ap;
359    int coupled_size, mono_size;
360    char *ptr;
361    int ret = OPUS_OK;
362
363    va_start(ap, request);
364
365    coupled_size = opus_encoder_get_size(2);
366    mono_size = opus_encoder_get_size(1);
367    ptr = (char*)st + align(sizeof(OpusMSEncoder));
368    switch (request)
369    {
370    case OPUS_SET_BITRATE_REQUEST:
371    {
372       int chan, s;
373       opus_uint32 value = va_arg(ap, opus_uint32);
374       chan = st->layout.nb_streams + st->layout.nb_coupled_streams;
375       value /= chan;
376       for (s=0;s<st->layout.nb_streams;s++)
377       {
378          OpusEncoder *enc;
379          enc = (OpusEncoder*)ptr;
380          opus_encoder_ctl(enc, request, value * (s < st->layout.nb_coupled_streams ? 2 : 1));
381       }
382    }
383    break;
384    /* FIXME: Add missing ones */
385    case OPUS_GET_BITRATE_REQUEST:
386    case OPUS_GET_VBR_REQUEST:
387    case OPUS_GET_APPLICATION_REQUEST:
388    case OPUS_GET_BANDWIDTH_REQUEST:
389    case OPUS_GET_COMPLEXITY_REQUEST:
390    case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
391    case OPUS_GET_DTX_REQUEST:
392    case OPUS_GET_VOICE_RATIO_REQUEST:
393    case OPUS_GET_VBR_CONSTRAINT_REQUEST:
394    case OPUS_GET_SIGNAL_REQUEST:
395    case OPUS_GET_LOOKAHEAD_REQUEST:
396    {
397       int s;
398       /* This works for int32* params */
399       opus_uint32 *value = va_arg(ap, opus_uint32*);
400       for (s=0;s<st->layout.nb_streams;s++)
401       {
402          OpusEncoder *enc;
403
404          enc = (OpusEncoder*)ptr;
405          if (s < st->layout.nb_coupled_streams)
406             ptr += align(coupled_size);
407          else
408             ptr += align(mono_size);
409          ret = opus_encoder_ctl(enc, request, value);
410          if (ret < 0)
411             break;
412       }
413    }
414    break;
415    default:
416    {
417       int s;
418       /* This works for int32 params */
419       opus_uint32 value = va_arg(ap, opus_uint32);
420       for (s=0;s<st->layout.nb_streams;s++)
421       {
422          OpusEncoder *enc;
423
424          enc = (OpusEncoder*)ptr;
425          if (s < st->layout.nb_coupled_streams)
426             ptr += align(coupled_size);
427          else
428             ptr += align(mono_size);
429          ret = opus_encoder_ctl(enc, request, value);
430          if (ret < 0)
431             break;
432       }
433    }
434    break;
435    }
436
437    va_end(ap);
438    return ret;
439 }
440
441 void opus_multistream_encoder_destroy(OpusMSEncoder *st)
442 {
443     opus_free(st);
444 }
445
446
447 /* DECODER */
448
449 int opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams)
450 {
451    int coupled_size;
452    int mono_size;
453
454    coupled_size = opus_decoder_get_size(2);
455    mono_size = opus_decoder_get_size(1);
456    return align(sizeof(OpusMSDecoder))
457          + nb_coupled_streams * align(coupled_size)
458          + (nb_streams-nb_coupled_streams) * align(mono_size);
459 }
460
461 int opus_multistream_decoder_init(
462       OpusMSDecoder *st,            /* Encoder state */
463       opus_int32 Fs,                     /* Sampling rate of input signal (Hz) */
464       int channels,               /* Number of channels (1/2) in input signal */
465       int streams,
466       int coupled_streams,
467       unsigned char *mapping
468 )
469 {
470    int coupled_size;
471    int mono_size;
472    int i;
473    char *ptr;
474
475    st->layout.nb_channels = channels;
476    st->layout.nb_streams = streams;
477    st->layout.nb_coupled_streams = coupled_streams;
478
479    for (i=0;i<st->layout.nb_channels;i++)
480       st->layout.mapping[i] = mapping[i];
481    if (!validate_layout(&st->layout))
482       return OPUS_BAD_ARG;
483
484    ptr = (char*)st + align(sizeof(OpusMSEncoder));
485    coupled_size = opus_decoder_get_size(2);
486    mono_size = opus_decoder_get_size(1);
487
488    for (i=0;i<st->layout.nb_coupled_streams;i++)
489    {
490       opus_decoder_init((OpusDecoder*)ptr, Fs, 2);
491       ptr += align(coupled_size);
492    }
493    for (;i<st->layout.nb_streams;i++)
494    {
495       opus_decoder_init((OpusDecoder*)ptr, Fs, 1);
496       ptr += align(mono_size);
497    }
498    return OPUS_OK;
499 }
500
501
502 OpusMSDecoder *opus_multistream_decoder_create(
503       opus_int32 Fs,                     /* Sampling rate of input signal (Hz) */
504       int channels,               /* Number of channels (1/2) in input signal */
505       int streams,
506       int coupled_streams,
507       unsigned char *mapping,
508       int *error                  /* Error code */
509 )
510 {
511    int ret;
512    OpusMSDecoder *st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams));
513    if (st==NULL)
514    {
515       if (error)
516          *error = OPUS_ALLOC_FAIL;
517       return NULL;
518    }
519    ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping);
520    if (error)
521       *error = ret;
522    if (ret != OPUS_OK)
523    {
524       opus_free(st);
525       st = NULL;
526    }
527    return st;
528
529
530 }
531
532 static int opus_multistream_decode_native(
533       OpusMSDecoder *st,            /* Encoder state */
534       const unsigned char *data,
535       int len,
536       opus_val16 *pcm,
537       int frame_size,
538       int decode_fec
539 )
540 {
541    int coupled_size;
542    int mono_size;
543    int s, i, c;
544    char *ptr;
545    VARDECL(opus_val16, buf);
546    ALLOC_STACK;
547
548    ALLOC(buf, 2*frame_size, opus_val16);
549    ptr = (char*)st + align(sizeof(OpusMSEncoder));
550    coupled_size = opus_decoder_get_size(2);
551    mono_size = opus_decoder_get_size(1);
552
553    if (len < 2*st->layout.nb_streams-1)
554       return OPUS_BUFFER_TOO_SMALL;
555    for (s=0;s<st->layout.nb_streams;s++)
556    {
557       OpusDecoder *dec;
558       int packet_offset, ret;
559
560       dec = (OpusDecoder*)ptr;
561       ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size);
562
563       if (len<=0)
564       {
565          RESTORE_STACK;
566          return OPUS_INVALID_PACKET;
567       }
568       ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset);
569       data += packet_offset;
570       len -= packet_offset;
571       if (ret > frame_size)
572       {
573          RESTORE_STACK;
574          return OPUS_BUFFER_TOO_SMALL;
575       }
576       if (s>0 && ret != frame_size)
577       {
578          RESTORE_STACK;
579          return OPUS_INVALID_PACKET;
580       }
581       if (ret <= 0)
582       {
583          RESTORE_STACK;
584          return ret;
585       }
586       frame_size = ret;
587       if (s < st->layout.nb_coupled_streams)
588       {
589          int chan, prev;
590          prev = -1;
591          /* Copy "left" audio to the channel(s) where it belongs */
592          while ( (chan = get_left_channel(&st->layout, s, prev)) != -1)
593          {
594             for (i=0;i<frame_size;i++)
595                pcm[st->layout.nb_channels*i+chan] = buf[2*i];
596             prev = chan;
597          }
598          prev = -1;
599          /* Copy "right" audio to the channel(s) where it belongs */
600          while ( (chan = get_right_channel(&st->layout, s, prev)) != -1)
601          {
602             for (i=0;i<frame_size;i++)
603                pcm[st->layout.nb_channels*i+chan] = buf[2*i+1];
604             prev = chan;
605          }
606       } else {
607          int chan, prev;
608          prev = -1;
609          /* Copy audio to the channel(s) where it belongs */
610          while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1)
611          {
612             for (i=0;i<frame_size;i++)
613                pcm[st->layout.nb_channels*i+chan] = buf[i];
614             prev = chan;
615          }
616       }
617    }
618    /* Handle muted channels */
619    for (c=0;c<st->layout.nb_channels;c++)
620    {
621       if (st->layout.mapping[c] == 255)
622       {
623          for (i=0;i<frame_size;i++)
624             pcm[st->layout.nb_channels*i+c] = 0;
625       }
626    }
627    RESTORE_STACK;
628    return frame_size;
629 }
630
631 #ifdef FIXED_POINT
632 int opus_multistream_decode(
633       OpusMSDecoder *st,            /* Encoder state */
634       const unsigned char *data,
635       int len,
636       opus_int16 *pcm,
637       int frame_size,
638       int decode_fec
639 )
640 {
641    return opus_multistream_decode_native(st, data, len, pcm, frame_size, decode_fec);
642 }
643
644 #ifndef DISABLE_FLOAT_API
645 int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data,
646       int len, float *pcm, int frame_size, int decode_fec)
647 {
648    VARDECL(opus_int16, out);
649    int ret, i;
650    ALLOC_STACK;
651
652    ALLOC(out, frame_size*st->layout.nb_channels, opus_int16);
653
654    ret = opus_multistream_decode_native(st, data, len, out, frame_size, decode_fec);
655    if (ret > 0)
656    {
657       for (i=0;i<ret*st->layout.nb_channels;i++)
658          pcm[i] = (1./32768.)*(out[i]);
659    }
660    RESTORE_STACK;
661    return ret;
662 }
663 #endif
664
665 #else
666
667 int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data,
668       int len, opus_int16 *pcm, int frame_size, int decode_fec)
669 {
670    VARDECL(float, out);
671    int ret, i;
672    ALLOC_STACK;
673
674    ALLOC(out, frame_size*st->layout.nb_channels, float);
675
676    ret = opus_multistream_decode_native(st, data, len, out, frame_size, decode_fec);
677    if (ret > 0)
678    {
679       for (i=0;i<ret*st->layout.nb_channels;i++)
680          pcm[i] = FLOAT2INT16(out[i]);
681    }
682    RESTORE_STACK;
683    return ret;
684 }
685
686 int opus_multistream_decode_float(
687       OpusMSDecoder *st,            /* Encoder state */
688       const unsigned char *data,
689       int len,
690       float *pcm,
691       int frame_size,
692       int decode_fec
693 )
694 {
695    return opus_multistream_decode_native(st, data, len, pcm, frame_size, decode_fec);
696 }
697 #endif
698
699 int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
700 {
701    va_list ap;
702    int coupled_size, mono_size;
703    char *ptr;
704    int ret = OPUS_OK;
705
706    va_start(ap, request);
707
708    coupled_size = opus_decoder_get_size(2);
709    mono_size = opus_decoder_get_size(1);
710    ptr = (char*)st + align(sizeof(OpusMSDecoder));
711    switch (request)
712    {
713        default:
714        {
715           int s;
716           /* This only works for int32* params, but that's all we have right now */
717           opus_uint32 *value = va_arg(ap, opus_uint32*);
718           for (s=0;s<st->layout.nb_streams;s++)
719           {
720              OpusDecoder *enc;
721
722              enc = (OpusDecoder*)ptr;
723              if (s < st->layout.nb_coupled_streams)
724                 ptr += align(coupled_size);
725              else
726                 ptr += align(mono_size);
727              ret = opus_decoder_ctl(enc, request, value);
728              if (ret < 0)
729                 break;
730           }
731        }
732        break;
733    }
734
735    va_end(ap);
736    return ret;
737 }
738
739
740 void opus_multistream_decoder_destroy(OpusMSDecoder *st)
741 {
742     opus_free(st);
743 }