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