Fix a number of multistream decoder bugs; add some very basic multistream decoder...
[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 opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams)
137 {
138    int coupled_size;
139    int mono_size;
140
141    if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
142    coupled_size = opus_encoder_get_size(2);
143    mono_size = opus_encoder_get_size(1);
144    return align(sizeof(OpusMSEncoder))
145         + nb_coupled_streams * align(coupled_size)
146         + (nb_streams-nb_coupled_streams) * align(mono_size);
147 }
148
149
150
151 int opus_multistream_encoder_init(
152       OpusMSEncoder *st,
153       opus_int32 Fs,
154       int channels,
155       int streams,
156       int coupled_streams,
157       unsigned char *mapping,
158       int application
159 )
160 {
161    int coupled_size;
162    int mono_size;
163    int i;
164    char *ptr;
165
166    st->layout.nb_channels = channels;
167    st->layout.nb_streams = streams;
168    st->layout.nb_coupled_streams = coupled_streams;
169
170    for (i=0;i<st->layout.nb_channels;i++)
171       st->layout.mapping[i] = mapping[i];
172    if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout))
173       return OPUS_BAD_ARG;
174    ptr = (char*)st + align(sizeof(OpusMSEncoder));
175    coupled_size = opus_encoder_get_size(2);
176    mono_size = opus_encoder_get_size(1);
177
178    for (i=0;i<st->layout.nb_coupled_streams;i++)
179    {
180       opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application);
181       ptr += align(coupled_size);
182    }
183    for (;i<st->layout.nb_streams;i++)
184    {
185       opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application);
186       ptr += align(mono_size);
187    }
188    return OPUS_OK;
189 }
190
191 OpusMSEncoder *opus_multistream_encoder_create(
192       opus_int32 Fs,
193       int channels,
194       int streams,
195       int coupled_streams,
196       unsigned char *mapping,
197       int application,
198       int *error
199 )
200 {
201    int ret;
202    OpusMSEncoder *st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams));
203    if (st==NULL)
204    {
205       if (error)
206          *error = OPUS_ALLOC_FAIL;
207       return NULL;
208    }
209    ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application);
210    if (ret != OPUS_OK)
211    {
212       opus_free(st);
213       st = NULL;
214    }
215    if (error)
216       *error = ret;
217    return st;
218 }
219
220
221 #ifdef FIXED_POINT
222 int opus_multistream_encode(
223 #else
224 int opus_multistream_encode_float(
225 #endif
226     OpusMSEncoder *st,
227     const opus_val16 *pcm,
228     int frame_size,
229     unsigned char *data,
230     int max_data_bytes
231 )
232 {
233    int coupled_size;
234    int mono_size;
235    int s, i;
236    char *ptr;
237    int tot_size;
238    VARDECL(opus_val16, buf);
239    /* Max size in case the encoder decides to return three frames */
240    unsigned char tmp_data[3*1275+7];
241    OpusRepacketizer rp;
242    ALLOC_STACK;
243
244    ALLOC(buf, 2*frame_size, opus_val16);
245    ptr = (char*)st + align(sizeof(OpusMSEncoder));
246    coupled_size = opus_encoder_get_size(2);
247    mono_size = opus_encoder_get_size(1);
248
249    if (max_data_bytes < 2*st->layout.nb_streams-1)
250    {
251       RESTORE_STACK;
252       return OPUS_BUFFER_TOO_SMALL;
253    }
254    /* Counting ToC */
255    tot_size = 0;
256    for (s=0;s<st->layout.nb_streams;s++)
257    {
258       OpusEncoder *enc;
259       int len;
260       int curr_max;
261
262       opus_repacketizer_init(&rp);
263       enc = (OpusEncoder*)ptr;
264       if (s < st->layout.nb_coupled_streams)
265       {
266          int left, right;
267          left = get_left_channel(&st->layout, s, -1);
268          right = get_right_channel(&st->layout, s, -1);
269          for (i=0;i<frame_size;i++)
270          {
271             buf[2*i] = pcm[st->layout.nb_channels*i+left];
272             buf[2*i+1] = pcm[st->layout.nb_channels*i+right];
273          }
274          ptr += align(coupled_size);
275       } else {
276          int chan = get_mono_channel(&st->layout, s, -1);
277          for (i=0;i<frame_size;i++)
278             buf[i] = pcm[st->layout.nb_channels*i+chan];
279          ptr += align(mono_size);
280       }
281       /* number of bytes left (+Toc) */
282       curr_max = max_data_bytes - tot_size;
283       /* Reserve one byte for the last stream and 2 for the others */
284       curr_max -= 2*(st->layout.nb_streams-s)-1;
285       len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max);
286       if (len<0)
287       {
288          RESTORE_STACK;
289          return len;
290       }
291       /* We need to use the repacketizer to add the self-delimiting lengths
292          while taking into account the fact that the encoder can now return
293          more than one frame at a time (e.g. 60 ms CELT-only) */
294       opus_repacketizer_cat(&rp, tmp_data, len);
295       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);
296       data += len;
297       tot_size += len;
298    }
299    RESTORE_STACK;
300    return tot_size;
301
302 }
303
304 #ifdef FIXED_POINT
305
306 #ifndef DISABLE_FLOAT_API
307 int opus_multistream_encode_float(
308     OpusMSEncoder *st,
309     const float *pcm,
310     int frame_size,
311     unsigned char *data,
312     int max_data_bytes
313 )
314 {
315    int i, ret;
316    VARDECL(opus_int16, in);
317    ALLOC_STACK;
318
319    ALLOC(in, frame_size*st->layout.nb_channels, opus_int16);
320
321    for (i=0;i<frame_size*st->layout.nb_channels;i++)
322       in[i] = FLOAT2INT16(pcm[i]);
323    ret = opus_multistream_encode(st, in, frame_size, data, max_data_bytes);
324    RESTORE_STACK;
325    return ret;
326 }
327 #endif
328
329 #else
330
331 int opus_multistream_encode(
332     OpusMSEncoder *st,
333     const opus_int16 *pcm,
334     int frame_size,
335     unsigned char *data,
336     int max_data_bytes
337 )
338 {
339    int i, ret;
340    VARDECL(float, in);
341    ALLOC_STACK;
342
343    ALLOC(in, frame_size*st->layout.nb_channels, float);
344
345    for (i=0;i<frame_size*st->layout.nb_channels;i++)
346       in[i] = (1./32768)*pcm[i];
347    ret = opus_multistream_encode_float(st, in, frame_size, data, max_data_bytes);
348    RESTORE_STACK;
349    return ret;
350 }
351
352 #endif
353
354 int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
355 {
356    va_list ap;
357    int coupled_size, mono_size;
358    char *ptr;
359    int ret = OPUS_OK;
360
361    va_start(ap, request);
362
363    coupled_size = opus_encoder_get_size(2);
364    mono_size = opus_encoder_get_size(1);
365    ptr = (char*)st + align(sizeof(OpusMSEncoder));
366    switch (request)
367    {
368    case OPUS_SET_BITRATE_REQUEST:
369    {
370       int chan, s;
371       opus_int32 value = va_arg(ap, opus_int32);
372       chan = st->layout.nb_streams + st->layout.nb_coupled_streams;
373       value /= chan;
374       for (s=0;s<st->layout.nb_streams;s++)
375       {
376          OpusEncoder *enc;
377          enc = (OpusEncoder*)ptr;
378          opus_encoder_ctl(enc, request, value * (s < st->layout.nb_coupled_streams ? 2 : 1));
379       }
380    }
381    break;
382    case OPUS_GET_BITRATE_REQUEST:
383    {
384       int s;
385       opus_int32 *value = va_arg(ap, opus_int32*);
386       *value = 0;
387       for (s=0;s<st->layout.nb_streams;s++)
388       {
389          opus_int32 rate;
390          OpusEncoder *enc;
391          enc = (OpusEncoder*)ptr;
392          opus_encoder_ctl(enc, request, &rate);
393          *value += rate;
394       }
395    }
396    break;
397    case OPUS_GET_VBR_REQUEST:
398    case OPUS_GET_APPLICATION_REQUEST:
399    case OPUS_GET_BANDWIDTH_REQUEST:
400    case OPUS_GET_COMPLEXITY_REQUEST:
401    case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
402    case OPUS_GET_DTX_REQUEST:
403    case OPUS_GET_VOICE_RATIO_REQUEST:
404    case OPUS_GET_VBR_CONSTRAINT_REQUEST:
405    case OPUS_GET_SIGNAL_REQUEST:
406    case OPUS_GET_LOOKAHEAD_REQUEST:
407    case OPUS_GET_INBAND_FEC_REQUEST:
408    {
409       OpusEncoder *enc;
410       /* For int32* GET params, just query the first stream */
411       opus_int32 *value = va_arg(ap, opus_int32*);
412       enc = (OpusEncoder*)ptr;
413       ret = opus_encoder_ctl(enc, request, value);
414    }
415    break;
416    case OPUS_SET_COMPLEXITY_REQUEST:
417    case OPUS_SET_VBR_REQUEST:
418    case OPUS_SET_VBR_CONSTRAINT_REQUEST:
419    case OPUS_SET_BANDWIDTH_REQUEST:
420    case OPUS_SET_SIGNAL_REQUEST:
421    case OPUS_SET_APPLICATION_REQUEST:
422    case OPUS_SET_INBAND_FEC_REQUEST:
423    case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
424    case OPUS_SET_DTX_REQUEST:
425    {
426       int s;
427       /* This works for int32 params */
428       opus_int32 value = va_arg(ap, opus_int32);
429       for (s=0;s<st->layout.nb_streams;s++)
430       {
431          OpusEncoder *enc;
432
433          enc = (OpusEncoder*)ptr;
434          if (s < st->layout.nb_coupled_streams)
435             ptr += align(coupled_size);
436          else
437             ptr += align(mono_size);
438          ret = opus_encoder_ctl(enc, request, value);
439          if (ret != OPUS_OK)
440             break;
441       }
442    }
443    break;
444    case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST:
445    {
446       int s;
447       opus_int32 stream_id;
448       OpusEncoder **value;
449       stream_id = va_arg(ap, opus_int32);
450       if (stream_id<0 || stream_id >= st->layout.nb_streams)
451          ret = OPUS_BAD_ARG;
452       value = va_arg(ap, OpusEncoder**);
453       for (s=0;s<stream_id;s++)
454       {
455          if (s < st->layout.nb_coupled_streams)
456             ptr += align(coupled_size);
457          else
458             ptr += align(mono_size);
459       }
460       *value = (OpusEncoder*)ptr;
461    }
462       break;
463    default:
464       ret = OPUS_UNIMPLEMENTED;
465       break;
466    }
467
468    va_end(ap);
469    return ret;
470 }
471
472 void opus_multistream_encoder_destroy(OpusMSEncoder *st)
473 {
474     opus_free(st);
475 }
476
477
478 /* DECODER */
479
480 opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams)
481 {
482    int coupled_size;
483    int mono_size;
484
485    if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
486    coupled_size = opus_decoder_get_size(2);
487    mono_size = opus_decoder_get_size(1);
488    return align(sizeof(OpusMSDecoder))
489          + nb_coupled_streams * align(coupled_size)
490          + (nb_streams-nb_coupled_streams) * align(mono_size);
491 }
492
493 int opus_multistream_decoder_init(
494       OpusMSDecoder *st,
495       opus_int32 Fs,
496       int channels,
497       int streams,
498       int coupled_streams,
499       unsigned char *mapping
500 )
501 {
502    int coupled_size;
503    int mono_size;
504    int i, ret;
505    char *ptr;
506
507    st->layout.nb_channels = channels;
508    st->layout.nb_streams = streams;
509    st->layout.nb_coupled_streams = coupled_streams;
510
511    for (i=0;i<st->layout.nb_channels;i++)
512       st->layout.mapping[i] = mapping[i];
513    if (!validate_layout(&st->layout))
514       return OPUS_BAD_ARG;
515
516    ptr = (char*)st + align(sizeof(OpusMSDecoder));
517    coupled_size = opus_decoder_get_size(2);
518    mono_size = opus_decoder_get_size(1);
519
520    for (i=0;i<st->layout.nb_coupled_streams;i++)
521    {
522       ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2);
523       if(ret!=OPUS_OK)return ret;
524       ptr += align(coupled_size);
525    }
526    for (;i<st->layout.nb_streams;i++)
527    {
528       ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1);
529       if(ret!=OPUS_OK)return ret;
530       ptr += align(mono_size);
531    }
532    return OPUS_OK;
533 }
534
535
536 OpusMSDecoder *opus_multistream_decoder_create(
537       opus_int32 Fs,
538       int channels,
539       int streams,
540       int coupled_streams,
541       unsigned char *mapping,
542       int *error
543 )
544 {
545    int ret;
546    OpusMSDecoder *st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams));
547    if (st==NULL)
548    {
549       if (error)
550          *error = OPUS_ALLOC_FAIL;
551       return NULL;
552    }
553    ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping);
554    if (error)
555       *error = ret;
556    if (ret != OPUS_OK)
557    {
558       opus_free(st);
559       st = NULL;
560    }
561    return st;
562
563
564 }
565
566 static int opus_multistream_decode_native(
567       OpusMSDecoder *st,
568       const unsigned char *data,
569       int len,
570       opus_val16 *pcm,
571       int frame_size,
572       int decode_fec
573 )
574 {
575    int coupled_size;
576    int mono_size;
577    int s, i, c;
578    char *ptr;
579    VARDECL(opus_val16, buf);
580    ALLOC_STACK;
581
582    ALLOC(buf, 2*frame_size, opus_val16);
583    ptr = (char*)st + align(sizeof(OpusMSDecoder));
584    coupled_size = opus_decoder_get_size(2);
585    mono_size = opus_decoder_get_size(1);
586
587    if (len < 0)
588       return OPUS_BAD_ARG;
589    for (s=0;s<st->layout.nb_streams;s++)
590    {
591       OpusDecoder *dec;
592       int packet_offset, ret;
593
594       dec = (OpusDecoder*)ptr;
595       ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size);
596
597       if (len<0)
598       {
599          RESTORE_STACK;
600          return OPUS_INVALID_PACKET;
601       }
602       ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset);
603       data += packet_offset;
604       len -= packet_offset;
605       if (ret > frame_size)
606       {
607          RESTORE_STACK;
608          return OPUS_BUFFER_TOO_SMALL;
609       }
610       if (s>0 && ret != frame_size)
611       {
612          RESTORE_STACK;
613          return OPUS_INVALID_PACKET;
614       }
615       if (ret <= 0)
616       {
617          RESTORE_STACK;
618          return ret;
619       }
620       frame_size = ret;
621       if (s < st->layout.nb_coupled_streams)
622       {
623          int chan, prev;
624          prev = -1;
625          /* Copy "left" audio to the channel(s) where it belongs */
626          while ( (chan = get_left_channel(&st->layout, s, prev)) != -1)
627          {
628             for (i=0;i<frame_size;i++)
629                pcm[st->layout.nb_channels*i+chan] = buf[2*i];
630             prev = chan;
631          }
632          prev = -1;
633          /* Copy "right" audio to the channel(s) where it belongs */
634          while ( (chan = get_right_channel(&st->layout, s, prev)) != -1)
635          {
636             for (i=0;i<frame_size;i++)
637                pcm[st->layout.nb_channels*i+chan] = buf[2*i+1];
638             prev = chan;
639          }
640       } else {
641          int chan, prev;
642          prev = -1;
643          /* Copy audio to the channel(s) where it belongs */
644          while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1)
645          {
646             for (i=0;i<frame_size;i++)
647                pcm[st->layout.nb_channels*i+chan] = buf[i];
648             prev = chan;
649          }
650       }
651    }
652    /* Handle muted channels */
653    for (c=0;c<st->layout.nb_channels;c++)
654    {
655       if (st->layout.mapping[c] == 255)
656       {
657          for (i=0;i<frame_size;i++)
658             pcm[st->layout.nb_channels*i+c] = 0;
659       }
660    }
661    RESTORE_STACK;
662    return frame_size;
663 }
664
665 #ifdef FIXED_POINT
666 int opus_multistream_decode(
667       OpusMSDecoder *st,
668       const unsigned char *data,
669       int len,
670       opus_int16 *pcm,
671       int frame_size,
672       int decode_fec
673 )
674 {
675    return opus_multistream_decode_native(st, data, len, pcm, frame_size, decode_fec);
676 }
677
678 #ifndef DISABLE_FLOAT_API
679 int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data,
680       int len, float *pcm, int frame_size, int decode_fec)
681 {
682    VARDECL(opus_int16, out);
683    int ret, i;
684    ALLOC_STACK;
685
686    ALLOC(out, frame_size*st->layout.nb_channels, opus_int16);
687
688    ret = opus_multistream_decode_native(st, data, len, out, frame_size, decode_fec);
689    if (ret > 0)
690    {
691       for (i=0;i<ret*st->layout.nb_channels;i++)
692          pcm[i] = (1./32768.)*(out[i]);
693    }
694    RESTORE_STACK;
695    return ret;
696 }
697 #endif
698
699 #else
700
701 int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data,
702       int len, opus_int16 *pcm, int frame_size, int decode_fec)
703 {
704    VARDECL(float, out);
705    int ret, i;
706    ALLOC_STACK;
707
708    ALLOC(out, frame_size*st->layout.nb_channels, float);
709
710    ret = opus_multistream_decode_native(st, data, len, out, frame_size, decode_fec);
711    if (ret > 0)
712    {
713       for (i=0;i<ret*st->layout.nb_channels;i++)
714          pcm[i] = FLOAT2INT16(out[i]);
715    }
716    RESTORE_STACK;
717    return ret;
718 }
719
720 int opus_multistream_decode_float(
721       OpusMSDecoder *st,
722       const unsigned char *data,
723       int len,
724       float *pcm,
725       int frame_size,
726       int decode_fec
727 )
728 {
729    return opus_multistream_decode_native(st, data, len, pcm, frame_size, decode_fec);
730 }
731 #endif
732
733 int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
734 {
735    va_list ap;
736    int coupled_size, mono_size;
737    char *ptr;
738    int ret = OPUS_OK;
739
740    va_start(ap, request);
741
742    coupled_size = opus_decoder_get_size(2);
743    mono_size = opus_decoder_get_size(1);
744    ptr = (char*)st + align(sizeof(OpusMSDecoder));
745    switch (request)
746    {
747        case OPUS_GET_BANDWIDTH_REQUEST:
748        case OPUS_GET_FINAL_RANGE_REQUEST:
749        {
750           int s;
751           opus_uint32 *value = va_arg(ap, opus_uint32*);
752           for (s=0;s<st->layout.nb_streams;s++)
753           {
754              OpusDecoder *dec;
755
756              dec = (OpusDecoder*)ptr;
757              if (s < st->layout.nb_coupled_streams)
758                 ptr += align(coupled_size);
759              else
760                 ptr += align(mono_size);
761              ret = opus_decoder_ctl(dec, request, value);
762              if (ret != OPUS_OK)
763                 break;
764           }
765        }
766        break;
767        case OPUS_RESET_STATE:
768        {
769           int s;
770           for (s=0;s<st->layout.nb_streams;s++)
771           {
772              OpusDecoder *dec;
773
774              dec = (OpusDecoder*)ptr;
775              if (s < st->layout.nb_coupled_streams)
776                 ptr += align(coupled_size);
777              else
778                 ptr += align(mono_size);
779              ret = opus_decoder_ctl(dec, OPUS_RESET_STATE);
780              if (ret != OPUS_OK)
781                 break;
782           }
783        }
784        break;
785        case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST:
786        {
787           int s;
788           opus_int32 stream_id;
789           OpusDecoder **value;
790           stream_id = va_arg(ap, opus_int32);
791           if (stream_id<0 || stream_id >= st->layout.nb_streams)
792              ret = OPUS_BAD_ARG;
793           value = va_arg(ap, OpusDecoder**);
794           for (s=0;s<stream_id;s++)
795           {
796              if (s < st->layout.nb_coupled_streams)
797                 ptr += align(coupled_size);
798              else
799                 ptr += align(mono_size);
800           }
801           *value = (OpusDecoder*)ptr;
802        }
803           break;
804        default:
805           ret = OPUS_UNIMPLEMENTED;
806        break;
807    }
808
809    va_end(ap);
810    return ret;
811 }
812
813
814 void opus_multistream_decoder_destroy(OpusMSDecoder *st)
815 {
816     opus_free(st);
817 }