1e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/* Copyright (c) 2011 Xiph.Org Foundation
2e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   Written by Jean-Marc Valin */
3e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/*
4e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   Redistribution and use in source and binary forms, with or without
5e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   modification, are permitted provided that the following conditions
6e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   are met:
7e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
8e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   - Redistributions of source code must retain the above copyright
9e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   notice, this list of conditions and the following disclaimer.
10e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
11e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   - Redistributions in binary form must reproduce the above copyright
12e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   notice, this list of conditions and the following disclaimer in the
13e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   documentation and/or other materials provided with the distribution.
14e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
15e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org*/
27e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
28e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#ifdef HAVE_CONFIG_H
29e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "config.h"
30e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#endif
31e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
32e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "opus_multistream.h"
33e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "opus.h"
34e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "opus_private.h"
35e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "stack_alloc.h"
36e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include <stdarg.h>
37e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "float_cast.h"
38e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "os_support.h"
39e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
40e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgstruct OpusMSDecoder {
41e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ChannelLayout layout;
42e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   /* Decoder states go here */
43e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org};
44e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
45e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
46e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
47e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
48e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/* DECODER */
49e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
50e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgopus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams)
51e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
52e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int coupled_size;
53e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int mono_size;
54e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
55e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
56e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   coupled_size = opus_decoder_get_size(2);
57e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   mono_size = opus_decoder_get_size(1);
58e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return align(sizeof(OpusMSDecoder))
59e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         + nb_coupled_streams * align(coupled_size)
60e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         + (nb_streams-nb_coupled_streams) * align(mono_size);
61e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
62e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
63e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgint opus_multistream_decoder_init(
64e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      OpusMSDecoder *st,
65e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_int32 Fs,
66e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int channels,
67e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int streams,
68e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int coupled_streams,
69e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      const unsigned char *mapping
70e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org)
71e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
72e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int coupled_size;
73e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int mono_size;
74e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int i, ret;
75e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   char *ptr;
76e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
77e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
78e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
79e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      return OPUS_BAD_ARG;
80e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
81e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   st->layout.nb_channels = channels;
82e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   st->layout.nb_streams = streams;
83e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   st->layout.nb_coupled_streams = coupled_streams;
84e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
85e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   for (i=0;i<st->layout.nb_channels;i++)
86e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      st->layout.mapping[i] = mapping[i];
87e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (!validate_layout(&st->layout))
88e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      return OPUS_BAD_ARG;
89e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
90e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ptr = (char*)st + align(sizeof(OpusMSDecoder));
91e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   coupled_size = opus_decoder_get_size(2);
92e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   mono_size = opus_decoder_get_size(1);
93e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
94e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   for (i=0;i<st->layout.nb_coupled_streams;i++)
95e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
96e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2);
97e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if(ret!=OPUS_OK)return ret;
98e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      ptr += align(coupled_size);
99e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
100e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   for (;i<st->layout.nb_streams;i++)
101e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
102e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1);
103e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if(ret!=OPUS_OK)return ret;
104e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      ptr += align(mono_size);
105e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
106e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return OPUS_OK;
107e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
108e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
109e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
110e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgOpusMSDecoder *opus_multistream_decoder_create(
111e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_int32 Fs,
112e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int channels,
113e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int streams,
114e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int coupled_streams,
115e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      const unsigned char *mapping,
116e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int *error
117e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org)
118e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
119e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int ret;
120e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   OpusMSDecoder *st;
121e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
122e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
123e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
124e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (error)
125e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         *error = OPUS_BAD_ARG;
126e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      return NULL;
127e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
128e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams));
129e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (st==NULL)
130e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
131e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (error)
132e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         *error = OPUS_ALLOC_FAIL;
133e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      return NULL;
134e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
135e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping);
136e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (error)
137e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      *error = ret;
138e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (ret != OPUS_OK)
139e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
140e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_free(st);
141e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      st = NULL;
142e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
143e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return st;
144e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
145e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
146e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgtypedef void (*opus_copy_channel_out_func)(
147e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  void *dst,
148e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int dst_stride,
149e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int dst_channel,
150e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  const opus_val16 *src,
151e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int src_stride,
152e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int frame_size
153e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org);
154e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
1553c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic int opus_multistream_packet_validate(const unsigned char *data,
1563c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      opus_int32 len, int nb_streams, opus_int32 Fs)
1573c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com{
1583c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   int s;
1593c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   int count;
1603c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   unsigned char toc;
1613c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   opus_int16 size[48];
1623c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   int samples=0;
1633c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   opus_int32 packet_offset;
1643c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com
1653c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   for (s=0;s<nb_streams;s++)
1663c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   {
1673c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      int tmp_samples;
1683c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      if (len<=0)
1693c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         return OPUS_INVALID_PACKET;
1703c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL,
1713c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com                                     size, NULL, &packet_offset);
1723c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      if (count<0)
1733c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         return count;
1743c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      tmp_samples = opus_packet_get_nb_samples(data, packet_offset, Fs);
1753c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      if (s!=0 && samples != tmp_samples)
1763c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         return OPUS_INVALID_PACKET;
1773c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      samples = tmp_samples;
1783c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      data += packet_offset;
1793c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      len -= packet_offset;
1803c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   }
1813c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   return samples;
1823c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com}
1833c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com
184e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgstatic int opus_multistream_decode_native(
185e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      OpusMSDecoder *st,
186e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      const unsigned char *data,
187e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_int32 len,
188e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      void *pcm,
189e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_copy_channel_out_func copy_channel_out,
190e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int frame_size,
191e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int decode_fec,
192e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int soft_clip
193e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org)
194e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
195e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   opus_int32 Fs;
196e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int coupled_size;
197e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int mono_size;
198e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int s, c;
199e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   char *ptr;
200e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int do_plc=0;
201e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   VARDECL(opus_val16, buf);
202e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ALLOC_STACK;
203e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
204e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   /* Limit frame_size to avoid excessive stack allocations. */
205e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs));
206e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   frame_size = IMIN(frame_size, Fs/25*3);
207e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ALLOC(buf, 2*frame_size, opus_val16);
208e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ptr = (char*)st + align(sizeof(OpusMSDecoder));
209e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   coupled_size = opus_decoder_get_size(2);
210e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   mono_size = opus_decoder_get_size(1);
211e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
212e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (len==0)
213e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      do_plc = 1;
214e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (len < 0)
2153c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   {
2163c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      RESTORE_STACK;
217e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      return OPUS_BAD_ARG;
2183c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   }
219e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (!do_plc && len < 2*st->layout.nb_streams-1)
2203c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   {
2213c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      RESTORE_STACK;
222e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      return OPUS_INVALID_PACKET;
2233c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   }
2243c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   if (!do_plc)
2253c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   {
2263c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs);
2273c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      if (ret < 0)
2283c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      {
2293c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         RESTORE_STACK;
2303c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         return ret;
2313c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      } else if (ret > frame_size)
2323c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      {
2333c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         RESTORE_STACK;
2343c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         return OPUS_BUFFER_TOO_SMALL;
2353c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      }
2363c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   }
237e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   for (s=0;s<st->layout.nb_streams;s++)
238e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
239e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      OpusDecoder *dec;
240e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int packet_offset, ret;
241e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
242e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      dec = (OpusDecoder*)ptr;
243e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size);
244e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
245e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (!do_plc && len<=0)
246e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      {
247e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         RESTORE_STACK;
2483c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         return OPUS_INTERNAL_ERROR;
249e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      }
250e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      packet_offset = 0;
251e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip);
252e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      data += packet_offset;
253e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      len -= packet_offset;
254e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (ret <= 0)
255e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      {
256e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         RESTORE_STACK;
257e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         return ret;
258e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      }
259e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      frame_size = ret;
260e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (s < st->layout.nb_coupled_streams)
261e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      {
262e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         int chan, prev;
263e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         prev = -1;
264e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         /* Copy "left" audio to the channel(s) where it belongs */
265e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         while ( (chan = get_left_channel(&st->layout, s, prev)) != -1)
266e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         {
267e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
268e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org               buf, 2, frame_size);
269e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            prev = chan;
270e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         }
271e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         prev = -1;
272e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         /* Copy "right" audio to the channel(s) where it belongs */
273e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         while ( (chan = get_right_channel(&st->layout, s, prev)) != -1)
274e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         {
275e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
276e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org               buf+1, 2, frame_size);
277e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            prev = chan;
278e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         }
279e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      } else {
280e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         int chan, prev;
281e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         prev = -1;
282e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         /* Copy audio to the channel(s) where it belongs */
283e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1)
284e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         {
285e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
286e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org               buf, 1, frame_size);
287e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            prev = chan;
288e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         }
289e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      }
290e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
291e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   /* Handle muted channels */
292e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   for (c=0;c<st->layout.nb_channels;c++)
293e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
294e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (st->layout.mapping[c] == 255)
295e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      {
296e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         (*copy_channel_out)(pcm, st->layout.nb_channels, c,
297e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            NULL, 0, frame_size);
298e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      }
299e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
300e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   RESTORE_STACK;
301e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return frame_size;
302e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
303e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
304e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#if !defined(DISABLE_FLOAT_API)
305e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgstatic void opus_copy_channel_out_float(
306e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  void *dst,
307e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int dst_stride,
308e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int dst_channel,
309e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  const opus_val16 *src,
310e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int src_stride,
311e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int frame_size
312e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org)
313e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
314e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   float *float_dst;
315e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   opus_int32 i;
316e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   float_dst = (float*)dst;
317e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (src != NULL)
318e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
319e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      for (i=0;i<frame_size;i++)
320e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#if defined(FIXED_POINT)
321e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         float_dst[i*dst_stride+dst_channel] = (1/32768.f)*src[i*src_stride];
322e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#else
323e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         float_dst[i*dst_stride+dst_channel] = src[i*src_stride];
324e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#endif
325e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
326e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   else
327e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
328e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      for (i=0;i<frame_size;i++)
329e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         float_dst[i*dst_stride+dst_channel] = 0;
330e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
331e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
332e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#endif
333e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
334e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgstatic void opus_copy_channel_out_short(
335e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  void *dst,
336e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int dst_stride,
337e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int dst_channel,
338e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  const opus_val16 *src,
339e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int src_stride,
340e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  int frame_size
341e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org)
342e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
343e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   opus_int16 *short_dst;
344e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   opus_int32 i;
345e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   short_dst = (opus_int16*)dst;
346e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (src != NULL)
347e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
348e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      for (i=0;i<frame_size;i++)
349e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#if defined(FIXED_POINT)
350e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         short_dst[i*dst_stride+dst_channel] = src[i*src_stride];
351e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#else
352e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         short_dst[i*dst_stride+dst_channel] = FLOAT2INT16(src[i*src_stride]);
353e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#endif
354e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
355e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   else
356e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
357e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      for (i=0;i<frame_size;i++)
358e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         short_dst[i*dst_stride+dst_channel] = 0;
359e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
360e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
361e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
362e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
363e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
364e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#ifdef FIXED_POINT
365e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgint opus_multistream_decode(
366e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      OpusMSDecoder *st,
367e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      const unsigned char *data,
368e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_int32 len,
369e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_int16 *pcm,
370e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int frame_size,
371e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int decode_fec
372e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org)
373e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
374e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return opus_multistream_decode_native(st, data, len,
375e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0);
376e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
377e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
378e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#ifndef DISABLE_FLOAT_API
379e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgint opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data,
380e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_int32 len, float *pcm, int frame_size, int decode_fec)
381e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
382e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return opus_multistream_decode_native(st, data, len,
383e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0);
384e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
385e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#endif
386e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
387e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#else
388e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
389e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgint opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data,
390e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec)
391e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
392e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return opus_multistream_decode_native(st, data, len,
393e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1);
394e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
395e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
396e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgint opus_multistream_decode_float(
397e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      OpusMSDecoder *st,
398e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      const unsigned char *data,
399e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_int32 len,
400e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      float *pcm,
401e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int frame_size,
402e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      int decode_fec
403e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org)
404e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
405e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return opus_multistream_decode_native(st, data, len,
406e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0);
407e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
408e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#endif
409e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
410e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgint opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
411e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
412e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   va_list ap;
413e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int coupled_size, mono_size;
414e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   char *ptr;
415e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int ret = OPUS_OK;
416e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
417e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   va_start(ap, request);
418e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
419e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   coupled_size = opus_decoder_get_size(2);
420e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   mono_size = opus_decoder_get_size(1);
421e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ptr = (char*)st + align(sizeof(OpusMSDecoder));
422e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   switch (request)
423e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
424e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       case OPUS_GET_BANDWIDTH_REQUEST:
425e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       case OPUS_GET_SAMPLE_RATE_REQUEST:
426e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       case OPUS_GET_GAIN_REQUEST:
427e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
428e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       {
429e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          OpusDecoder *dec;
430e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          /* For int32* GET params, just query the first stream */
431e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          opus_int32 *value = va_arg(ap, opus_int32*);
432e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          dec = (OpusDecoder*)ptr;
433e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          ret = opus_decoder_ctl(dec, request, value);
434e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       }
435e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       break;
436e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       case OPUS_GET_FINAL_RANGE_REQUEST:
437e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       {
438e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          int s;
439e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          opus_uint32 *value = va_arg(ap, opus_uint32*);
440e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          opus_uint32 tmp;
441e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          if (!value)
442e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          {
443e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             goto bad_arg;
444e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          }
445e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          *value = 0;
446e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          for (s=0;s<st->layout.nb_streams;s++)
447e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          {
448e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             OpusDecoder *dec;
449e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             dec = (OpusDecoder*)ptr;
450e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             if (s < st->layout.nb_coupled_streams)
451e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                ptr += align(coupled_size);
452e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             else
453e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                ptr += align(mono_size);
454e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             ret = opus_decoder_ctl(dec, request, &tmp);
455e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             if (ret != OPUS_OK) break;
456e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             *value ^= tmp;
457e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          }
458e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       }
459e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       break;
460e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       case OPUS_RESET_STATE:
461e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       {
462e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          int s;
463e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          for (s=0;s<st->layout.nb_streams;s++)
464e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          {
465e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             OpusDecoder *dec;
466e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
467e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             dec = (OpusDecoder*)ptr;
468e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             if (s < st->layout.nb_coupled_streams)
469e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                ptr += align(coupled_size);
470e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             else
471e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                ptr += align(mono_size);
472e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             ret = opus_decoder_ctl(dec, OPUS_RESET_STATE);
473e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             if (ret != OPUS_OK)
474e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                break;
475e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          }
476e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       }
477e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       break;
478e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST:
479e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       {
480e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          int s;
481e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          opus_int32 stream_id;
482e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          OpusDecoder **value;
483e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          stream_id = va_arg(ap, opus_int32);
484e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          if (stream_id<0 || stream_id >= st->layout.nb_streams)
485e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             ret = OPUS_BAD_ARG;
486e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          value = va_arg(ap, OpusDecoder**);
487e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          if (!value)
488e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          {
489e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             goto bad_arg;
490e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          }
491e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          for (s=0;s<stream_id;s++)
492e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          {
493e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             if (s < st->layout.nb_coupled_streams)
494e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                ptr += align(coupled_size);
495e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             else
496e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                ptr += align(mono_size);
497e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          }
498e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          *value = (OpusDecoder*)ptr;
499e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       }
500e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       break;
501e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       case OPUS_SET_GAIN_REQUEST:
502e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       {
503e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          int s;
504e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          /* This works for int32 params */
505e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          opus_int32 value = va_arg(ap, opus_int32);
506e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          for (s=0;s<st->layout.nb_streams;s++)
507e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          {
508e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             OpusDecoder *dec;
509e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
510e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             dec = (OpusDecoder*)ptr;
511e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             if (s < st->layout.nb_coupled_streams)
512e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                ptr += align(coupled_size);
513e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             else
514e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                ptr += align(mono_size);
515e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             ret = opus_decoder_ctl(dec, request, value);
516e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org             if (ret != OPUS_OK)
517e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org                break;
518e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          }
519e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       }
520e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       break;
521e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       default:
522e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          ret = OPUS_UNIMPLEMENTED;
523e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org       break;
524e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
525e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
526e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   va_end(ap);
527e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return ret;
528e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgbad_arg:
529e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   va_end(ap);
530e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return OPUS_BAD_ARG;
531e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
532e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
533e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
534e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgvoid opus_multistream_decoder_destroy(OpusMSDecoder *st)
535e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org{
536e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    opus_free(st);
537e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
538