Fix multistream packet corruption, implement GET_FINAL_RANGE for multistream, and...
[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_GET_FINAL_RANGE_REQUEST:
417    {
418       int s;
419       opus_uint32 *value = va_arg(ap, opus_uint32*);
420       opus_uint32 tmp;
421       *value=0;
422       for (s=0;s<st->layout.nb_streams;s++)
423       {
424          OpusEncoder *enc;
425          enc = (OpusEncoder*)ptr;
426          if (s < st->layout.nb_coupled_streams)
427             ptr += align(coupled_size);
428          else
429             ptr += align(mono_size);
430          ret = opus_encoder_ctl(enc, request, &tmp);
431          if (ret != OPUS_OK) break;
432          *value ^= tmp;
433       }
434    }
435    break;
436    case OPUS_SET_COMPLEXITY_REQUEST:
437    case OPUS_SET_VBR_REQUEST:
438    case OPUS_SET_VBR_CONSTRAINT_REQUEST:
439    case OPUS_SET_BANDWIDTH_REQUEST:
440    case OPUS_SET_SIGNAL_REQUEST:
441    case OPUS_SET_APPLICATION_REQUEST:
442    case OPUS_SET_INBAND_FEC_REQUEST:
443    case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
444    case OPUS_SET_DTX_REQUEST:
445    case OPUS_SET_FORCE_MODE_REQUEST:
446    {
447       int s;
448       /* This works for int32 params */
449       opus_int32 value = va_arg(ap, opus_int32);
450       for (s=0;s<st->layout.nb_streams;s++)
451       {
452          OpusEncoder *enc;
453
454          enc = (OpusEncoder*)ptr;
455          if (s < st->layout.nb_coupled_streams)
456             ptr += align(coupled_size);
457          else
458             ptr += align(mono_size);
459          ret = opus_encoder_ctl(enc, request, value);
460          if (ret != OPUS_OK)
461             break;
462       }
463    }
464    break;
465    case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST:
466    {
467       int s;
468       opus_int32 stream_id;
469       OpusEncoder **value;
470       stream_id = va_arg(ap, opus_int32);
471       if (stream_id<0 || stream_id >= st->layout.nb_streams)
472          ret = OPUS_BAD_ARG;
473       value = va_arg(ap, OpusEncoder**);
474       for (s=0;s<stream_id;s++)
475       {
476          if (s < st->layout.nb_coupled_streams)
477             ptr += align(coupled_size);
478          else
479             ptr += align(mono_size);
480       }
481       *value = (OpusEncoder*)ptr;
482    }
483       break;
484    default:
485       ret = OPUS_UNIMPLEMENTED;
486       break;
487    }
488
489    va_end(ap);
490    return ret;
491 }
492
493 void opus_multistream_encoder_destroy(OpusMSEncoder *st)
494 {
495     opus_free(st);
496 }
497
498
499 /* DECODER */
500
501 opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams)
502 {
503    int coupled_size;
504    int mono_size;
505
506    if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
507    coupled_size = opus_decoder_get_size(2);
508    mono_size = opus_decoder_get_size(1);
509    return align(sizeof(OpusMSDecoder))
510          + nb_coupled_streams * align(coupled_size)
511          + (nb_streams-nb_coupled_streams) * align(mono_size);
512 }
513
514 int opus_multistream_decoder_init(
515       OpusMSDecoder *st,
516       opus_int32 Fs,
517       int channels,
518       int streams,
519       int coupled_streams,
520       unsigned char *mapping
521 )
522 {
523    int coupled_size;
524    int mono_size;
525    int i, ret;
526    char *ptr;
527
528    st->layout.nb_channels = channels;
529    st->layout.nb_streams = streams;
530    st->layout.nb_coupled_streams = coupled_streams;
531
532    for (i=0;i<st->layout.nb_channels;i++)
533       st->layout.mapping[i] = mapping[i];
534    if (!validate_layout(&st->layout))
535       return OPUS_BAD_ARG;
536
537    ptr = (char*)st + align(sizeof(OpusMSDecoder));
538    coupled_size = opus_decoder_get_size(2);
539    mono_size = opus_decoder_get_size(1);
540
541    for (i=0;i<st->layout.nb_coupled_streams;i++)
542    {
543       ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2);
544       if(ret!=OPUS_OK)return ret;
545       ptr += align(coupled_size);
546    }
547    for (;i<st->layout.nb_streams;i++)
548    {
549       ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1);
550       if(ret!=OPUS_OK)return ret;
551       ptr += align(mono_size);
552    }
553    return OPUS_OK;
554 }
555
556
557 OpusMSDecoder *opus_multistream_decoder_create(
558       opus_int32 Fs,
559       int channels,
560       int streams,
561       int coupled_streams,
562       unsigned char *mapping,
563       int *error
564 )
565 {
566    int ret;
567    OpusMSDecoder *st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams));
568    if (st==NULL)
569    {
570       if (error)
571          *error = OPUS_ALLOC_FAIL;
572       return NULL;
573    }
574    ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping);
575    if (error)
576       *error = ret;
577    if (ret != OPUS_OK)
578    {
579       opus_free(st);
580       st = NULL;
581    }
582    return st;
583
584
585 }
586
587 static int opus_multistream_decode_native(
588       OpusMSDecoder *st,
589       const unsigned char *data,
590       int len,
591       opus_val16 *pcm,
592       int frame_size,
593       int decode_fec
594 )
595 {
596    int coupled_size;
597    int mono_size;
598    int s, i, c;
599    char *ptr;
600    VARDECL(opus_val16, buf);
601    ALLOC_STACK;
602
603    ALLOC(buf, 2*frame_size, opus_val16);
604    ptr = (char*)st + align(sizeof(OpusMSDecoder));
605    coupled_size = opus_decoder_get_size(2);
606    mono_size = opus_decoder_get_size(1);
607
608    if (len < 0)
609       return OPUS_BAD_ARG;
610    for (s=0;s<st->layout.nb_streams;s++)
611    {
612       OpusDecoder *dec;
613       int packet_offset, ret;
614
615       dec = (OpusDecoder*)ptr;
616       ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size);
617
618       if (len<0)
619       {
620          RESTORE_STACK;
621          return OPUS_INVALID_PACKET;
622       }
623       packet_offset = 0;
624       ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset);
625       data += packet_offset;
626       len -= packet_offset;
627       if (ret > frame_size)
628       {
629          RESTORE_STACK;
630          return OPUS_BUFFER_TOO_SMALL;
631       }
632       if (s>0 && ret != frame_size)
633       {
634          RESTORE_STACK;
635          return OPUS_INVALID_PACKET;
636       }
637       if (ret <= 0)
638       {
639          RESTORE_STACK;
640          return ret;
641       }
642       frame_size = ret;
643       if (s < st->layout.nb_coupled_streams)
644       {
645          int chan, prev;
646          prev = -1;
647          /* Copy "left" audio to the channel(s) where it belongs */
648          while ( (chan = get_left_channel(&st->layout, s, prev)) != -1)
649          {
650             for (i=0;i<frame_size;i++)
651                pcm[st->layout.nb_channels*i+chan] = buf[2*i];
652             prev = chan;
653          }
654          prev = -1;
655          /* Copy "right" audio to the channel(s) where it belongs */
656          while ( (chan = get_right_channel(&st->layout, s, prev)) != -1)
657          {
658             for (i=0;i<frame_size;i++)
659                pcm[st->layout.nb_channels*i+chan] = buf[2*i+1];
660             prev = chan;
661          }
662       } else {
663          int chan, prev;
664          prev = -1;
665          /* Copy audio to the channel(s) where it belongs */
666          while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1)
667          {
668             for (i=0;i<frame_size;i++)
669                pcm[st->layout.nb_channels*i+chan] = buf[i];
670             prev = chan;
671          }
672       }
673    }
674    /* Handle muted channels */
675    for (c=0;c<st->layout.nb_channels;c++)
676    {
677       if (st->layout.mapping[c] == 255)
678       {
679          for (i=0;i<frame_size;i++)
680             pcm[st->layout.nb_channels*i+c] = 0;
681       }
682    }
683    RESTORE_STACK;
684    return frame_size;
685 }
686
687 #ifdef FIXED_POINT
688 int opus_multistream_decode(
689       OpusMSDecoder *st,
690       const unsigned char *data,
691       int len,
692       opus_int16 *pcm,
693       int frame_size,
694       int decode_fec
695 )
696 {
697    return opus_multistream_decode_native(st, data, len, pcm, frame_size, decode_fec);
698 }
699
700 #ifndef DISABLE_FLOAT_API
701 int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data,
702       int len, float *pcm, int frame_size, int decode_fec)
703 {
704    VARDECL(opus_int16, out);
705    int ret, i;
706    ALLOC_STACK;
707
708    ALLOC(out, frame_size*st->layout.nb_channels, opus_int16);
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] = (1./32768.)*(out[i]);
715    }
716    RESTORE_STACK;
717    return ret;
718 }
719 #endif
720
721 #else
722
723 int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data,
724       int len, opus_int16 *pcm, int frame_size, int decode_fec)
725 {
726    VARDECL(float, out);
727    int ret, i;
728    ALLOC_STACK;
729
730    ALLOC(out, frame_size*st->layout.nb_channels, float);
731
732    ret = opus_multistream_decode_native(st, data, len, out, frame_size, decode_fec);
733    if (ret > 0)
734    {
735       for (i=0;i<ret*st->layout.nb_channels;i++)
736          pcm[i] = FLOAT2INT16(out[i]);
737    }
738    RESTORE_STACK;
739    return ret;
740 }
741
742 int opus_multistream_decode_float(
743       OpusMSDecoder *st,
744       const unsigned char *data,
745       int len,
746       float *pcm,
747       int frame_size,
748       int decode_fec
749 )
750 {
751    return opus_multistream_decode_native(st, data, len, pcm, frame_size, decode_fec);
752 }
753 #endif
754
755 int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
756 {
757    va_list ap;
758    int coupled_size, mono_size;
759    char *ptr;
760    int ret = OPUS_OK;
761
762    va_start(ap, request);
763
764    coupled_size = opus_decoder_get_size(2);
765    mono_size = opus_decoder_get_size(1);
766    ptr = (char*)st + align(sizeof(OpusMSDecoder));
767    switch (request)
768    {
769        case OPUS_GET_BANDWIDTH_REQUEST:
770        {
771           OpusDecoder *dec;
772           /* For int32* GET params, just query the first stream */
773           opus_int32 *value = va_arg(ap, opus_int32*);
774           dec = (OpusDecoder*)ptr;
775           ret = opus_decoder_ctl(dec, request, value);
776        }
777        break;
778        case OPUS_GET_FINAL_RANGE_REQUEST:
779        {
780           int s;
781           opus_uint32 *value = va_arg(ap, opus_uint32*);
782           opus_uint32 tmp;
783           *value = 0;
784           for (s=0;s<st->layout.nb_streams;s++)
785           {
786              OpusDecoder *dec;
787              dec = (OpusDecoder*)ptr;
788              if (s < st->layout.nb_coupled_streams)
789                 ptr += align(coupled_size);
790              else
791                 ptr += align(mono_size);
792              ret = opus_decoder_ctl(dec, request, &tmp);
793              if (ret != OPUS_OK) break;
794              *value ^= tmp;
795           }
796        }
797        break;
798        case OPUS_RESET_STATE:
799        {
800           int s;
801           for (s=0;s<st->layout.nb_streams;s++)
802           {
803              OpusDecoder *dec;
804
805              dec = (OpusDecoder*)ptr;
806              if (s < st->layout.nb_coupled_streams)
807                 ptr += align(coupled_size);
808              else
809                 ptr += align(mono_size);
810              ret = opus_decoder_ctl(dec, OPUS_RESET_STATE);
811              if (ret != OPUS_OK)
812                 break;
813           }
814        }
815        break;
816        case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST:
817        {
818           int s;
819           opus_int32 stream_id;
820           OpusDecoder **value;
821           stream_id = va_arg(ap, opus_int32);
822           if (stream_id<0 || stream_id >= st->layout.nb_streams)
823              ret = OPUS_BAD_ARG;
824           value = va_arg(ap, OpusDecoder**);
825           for (s=0;s<stream_id;s++)
826           {
827              if (s < st->layout.nb_coupled_streams)
828                 ptr += align(coupled_size);
829              else
830                 ptr += align(mono_size);
831           }
832           *value = (OpusDecoder*)ptr;
833        }
834           break;
835        default:
836           ret = OPUS_UNIMPLEMENTED;
837        break;
838    }
839
840    va_end(ap);
841    return ret;
842 }
843
844
845 void opus_multistream_decoder_destroy(OpusMSDecoder *st)
846 {
847     opus_free(st);
848 }