Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 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 COPYRIGHT OWNER |
| 19 | OR 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 | struct OpusMSDecoder { |
| 41 | ChannelLayout layout; |
| 42 | /* Decoder states go here */ |
| 43 | }; |
| 44 | |
| 45 | |
| 46 | |
| 47 | |
| 48 | /* DECODER */ |
| 49 | |
| 50 | opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams) |
| 51 | { |
| 52 | int coupled_size; |
| 53 | int mono_size; |
| 54 | |
| 55 | if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; |
| 56 | coupled_size = opus_decoder_get_size(2); |
| 57 | mono_size = opus_decoder_get_size(1); |
| 58 | return align(sizeof(OpusMSDecoder)) |
| 59 | + nb_coupled_streams * align(coupled_size) |
| 60 | + (nb_streams-nb_coupled_streams) * align(mono_size); |
| 61 | } |
| 62 | |
| 63 | int opus_multistream_decoder_init( |
| 64 | OpusMSDecoder *st, |
| 65 | opus_int32 Fs, |
| 66 | int channels, |
| 67 | int streams, |
| 68 | int coupled_streams, |
| 69 | const unsigned char *mapping |
| 70 | ) |
| 71 | { |
| 72 | int coupled_size; |
| 73 | int mono_size; |
| 74 | int i, ret; |
| 75 | char *ptr; |
| 76 | |
| 77 | if ((channels>255) || (channels<1) || (coupled_streams>streams) || |
Mark Harris | 25b27a9 | 2014-11-27 08:48:09 -0800 | [diff] [blame] | 78 | (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 79 | return OPUS_BAD_ARG; |
| 80 | |
| 81 | st->layout.nb_channels = channels; |
| 82 | st->layout.nb_streams = streams; |
| 83 | st->layout.nb_coupled_streams = coupled_streams; |
| 84 | |
| 85 | for (i=0;i<st->layout.nb_channels;i++) |
| 86 | st->layout.mapping[i] = mapping[i]; |
| 87 | if (!validate_layout(&st->layout)) |
| 88 | return OPUS_BAD_ARG; |
| 89 | |
| 90 | ptr = (char*)st + align(sizeof(OpusMSDecoder)); |
| 91 | coupled_size = opus_decoder_get_size(2); |
| 92 | mono_size = opus_decoder_get_size(1); |
| 93 | |
| 94 | for (i=0;i<st->layout.nb_coupled_streams;i++) |
| 95 | { |
| 96 | ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2); |
| 97 | if(ret!=OPUS_OK)return ret; |
| 98 | ptr += align(coupled_size); |
| 99 | } |
| 100 | for (;i<st->layout.nb_streams;i++) |
| 101 | { |
| 102 | ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1); |
| 103 | if(ret!=OPUS_OK)return ret; |
| 104 | ptr += align(mono_size); |
| 105 | } |
| 106 | return OPUS_OK; |
| 107 | } |
| 108 | |
| 109 | |
| 110 | OpusMSDecoder *opus_multistream_decoder_create( |
| 111 | opus_int32 Fs, |
| 112 | int channels, |
| 113 | int streams, |
| 114 | int coupled_streams, |
| 115 | const unsigned char *mapping, |
| 116 | int *error |
| 117 | ) |
| 118 | { |
| 119 | int ret; |
| 120 | OpusMSDecoder *st; |
| 121 | if ((channels>255) || (channels<1) || (coupled_streams>streams) || |
Mark Harris | 25b27a9 | 2014-11-27 08:48:09 -0800 | [diff] [blame] | 122 | (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 123 | { |
| 124 | if (error) |
| 125 | *error = OPUS_BAD_ARG; |
| 126 | return NULL; |
| 127 | } |
| 128 | st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams)); |
| 129 | if (st==NULL) |
| 130 | { |
| 131 | if (error) |
| 132 | *error = OPUS_ALLOC_FAIL; |
| 133 | return NULL; |
| 134 | } |
| 135 | ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping); |
| 136 | if (error) |
| 137 | *error = ret; |
| 138 | if (ret != OPUS_OK) |
| 139 | { |
| 140 | opus_free(st); |
| 141 | st = NULL; |
| 142 | } |
| 143 | return st; |
| 144 | } |
| 145 | |
| 146 | typedef void (*opus_copy_channel_out_func)( |
| 147 | void *dst, |
| 148 | int dst_stride, |
| 149 | int dst_channel, |
| 150 | const opus_val16 *src, |
| 151 | int src_stride, |
| 152 | int frame_size |
| 153 | ); |
| 154 | |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 155 | static int opus_multistream_packet_validate(const unsigned char *data, |
Jean-Marc Valin | dbc83d3 | 2013-10-11 20:41:30 -0400 | [diff] [blame] | 156 | opus_int32 len, int nb_streams, opus_int32 Fs) |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 157 | { |
| 158 | int s; |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 159 | int count; |
| 160 | unsigned char toc; |
| 161 | opus_int16 size[48]; |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 162 | int samples=0; |
Jean-Marc Valin | 58042ad | 2013-10-14 13:45:58 -0400 | [diff] [blame] | 163 | opus_int32 packet_offset; |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 164 | |
| 165 | for (s=0;s<nb_streams;s++) |
| 166 | { |
| 167 | int tmp_samples; |
| 168 | if (len<=0) |
| 169 | return OPUS_INVALID_PACKET; |
Jean-Marc Valin | 58042ad | 2013-10-14 13:45:58 -0400 | [diff] [blame] | 170 | count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL, |
| 171 | size, NULL, &packet_offset); |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 172 | if (count<0) |
| 173 | return count; |
Jean-Marc Valin | 58042ad | 2013-10-14 13:45:58 -0400 | [diff] [blame] | 174 | tmp_samples = opus_packet_get_nb_samples(data, packet_offset, Fs); |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 175 | if (s!=0 && samples != tmp_samples) |
| 176 | return OPUS_INVALID_PACKET; |
| 177 | samples = tmp_samples; |
Jean-Marc Valin | 58042ad | 2013-10-14 13:45:58 -0400 | [diff] [blame] | 178 | data += packet_offset; |
| 179 | len -= packet_offset; |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 180 | } |
Jean-Marc Valin | dbc83d3 | 2013-10-11 20:41:30 -0400 | [diff] [blame] | 181 | return samples; |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 182 | } |
| 183 | |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 184 | static int opus_multistream_decode_native( |
| 185 | OpusMSDecoder *st, |
| 186 | const unsigned char *data, |
| 187 | opus_int32 len, |
| 188 | void *pcm, |
| 189 | opus_copy_channel_out_func copy_channel_out, |
| 190 | int frame_size, |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 191 | int decode_fec, |
| 192 | int soft_clip |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 193 | ) |
| 194 | { |
| 195 | opus_int32 Fs; |
| 196 | int coupled_size; |
| 197 | int mono_size; |
| 198 | int s, c; |
| 199 | char *ptr; |
| 200 | int do_plc=0; |
| 201 | VARDECL(opus_val16, buf); |
| 202 | ALLOC_STACK; |
| 203 | |
| 204 | /* Limit frame_size to avoid excessive stack allocations. */ |
| 205 | opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs)); |
| 206 | frame_size = IMIN(frame_size, Fs/25*3); |
| 207 | ALLOC(buf, 2*frame_size, opus_val16); |
| 208 | ptr = (char*)st + align(sizeof(OpusMSDecoder)); |
| 209 | coupled_size = opus_decoder_get_size(2); |
| 210 | mono_size = opus_decoder_get_size(1); |
| 211 | |
| 212 | if (len==0) |
| 213 | do_plc = 1; |
| 214 | if (len < 0) |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 215 | { |
| 216 | RESTORE_STACK; |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 217 | return OPUS_BAD_ARG; |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 218 | } |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 219 | if (!do_plc && len < 2*st->layout.nb_streams-1) |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 220 | { |
| 221 | RESTORE_STACK; |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 222 | return OPUS_INVALID_PACKET; |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 223 | } |
| 224 | if (!do_plc) |
| 225 | { |
Mark Harris | 3a4659a | 2013-11-13 19:31:59 -0500 | [diff] [blame] | 226 | int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs); |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 227 | if (ret < 0) |
| 228 | { |
| 229 | RESTORE_STACK; |
| 230 | return ret; |
Jean-Marc Valin | dbc83d3 | 2013-10-11 20:41:30 -0400 | [diff] [blame] | 231 | } else if (ret > frame_size) |
| 232 | { |
| 233 | RESTORE_STACK; |
| 234 | return OPUS_BUFFER_TOO_SMALL; |
Jean-Marc Valin | ed46323 | 2013-10-11 18:06:00 -0400 | [diff] [blame] | 235 | } |
| 236 | } |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 237 | for (s=0;s<st->layout.nb_streams;s++) |
| 238 | { |
| 239 | OpusDecoder *dec; |
Jean-Marc Valin | 3868831 | 2016-10-04 22:07:52 -0400 | [diff] [blame] | 240 | opus_int32 packet_offset; |
| 241 | int ret; |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 242 | |
| 243 | dec = (OpusDecoder*)ptr; |
| 244 | ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); |
| 245 | |
| 246 | if (!do_plc && len<=0) |
| 247 | { |
| 248 | RESTORE_STACK; |
Jean-Marc Valin | dbc83d3 | 2013-10-11 20:41:30 -0400 | [diff] [blame] | 249 | return OPUS_INTERNAL_ERROR; |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 250 | } |
| 251 | packet_offset = 0; |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 252 | ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip); |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 253 | data += packet_offset; |
| 254 | len -= packet_offset; |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 255 | if (ret <= 0) |
| 256 | { |
| 257 | RESTORE_STACK; |
| 258 | return ret; |
| 259 | } |
| 260 | frame_size = ret; |
| 261 | if (s < st->layout.nb_coupled_streams) |
| 262 | { |
| 263 | int chan, prev; |
| 264 | prev = -1; |
| 265 | /* Copy "left" audio to the channel(s) where it belongs */ |
| 266 | while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) |
| 267 | { |
| 268 | (*copy_channel_out)(pcm, st->layout.nb_channels, chan, |
| 269 | buf, 2, frame_size); |
| 270 | prev = chan; |
| 271 | } |
| 272 | prev = -1; |
| 273 | /* Copy "right" audio to the channel(s) where it belongs */ |
| 274 | while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) |
| 275 | { |
| 276 | (*copy_channel_out)(pcm, st->layout.nb_channels, chan, |
| 277 | buf+1, 2, frame_size); |
| 278 | prev = chan; |
| 279 | } |
| 280 | } else { |
| 281 | int chan, prev; |
| 282 | prev = -1; |
| 283 | /* Copy audio to the channel(s) where it belongs */ |
| 284 | while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) |
| 285 | { |
| 286 | (*copy_channel_out)(pcm, st->layout.nb_channels, chan, |
| 287 | buf, 1, frame_size); |
| 288 | prev = chan; |
| 289 | } |
| 290 | } |
| 291 | } |
| 292 | /* Handle muted channels */ |
| 293 | for (c=0;c<st->layout.nb_channels;c++) |
| 294 | { |
| 295 | if (st->layout.mapping[c] == 255) |
| 296 | { |
| 297 | (*copy_channel_out)(pcm, st->layout.nb_channels, c, |
| 298 | NULL, 0, frame_size); |
| 299 | } |
| 300 | } |
| 301 | RESTORE_STACK; |
| 302 | return frame_size; |
| 303 | } |
| 304 | |
| 305 | #if !defined(DISABLE_FLOAT_API) |
| 306 | static void opus_copy_channel_out_float( |
| 307 | void *dst, |
| 308 | int dst_stride, |
| 309 | int dst_channel, |
| 310 | const opus_val16 *src, |
| 311 | int src_stride, |
| 312 | int frame_size |
| 313 | ) |
| 314 | { |
| 315 | float *float_dst; |
Timothy B. Terriberry | a8f04b2 | 2013-03-18 14:42:44 -0700 | [diff] [blame] | 316 | opus_int32 i; |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 317 | float_dst = (float*)dst; |
| 318 | if (src != NULL) |
| 319 | { |
| 320 | for (i=0;i<frame_size;i++) |
| 321 | #if defined(FIXED_POINT) |
| 322 | float_dst[i*dst_stride+dst_channel] = (1/32768.f)*src[i*src_stride]; |
| 323 | #else |
| 324 | float_dst[i*dst_stride+dst_channel] = src[i*src_stride]; |
| 325 | #endif |
| 326 | } |
| 327 | else |
| 328 | { |
| 329 | for (i=0;i<frame_size;i++) |
| 330 | float_dst[i*dst_stride+dst_channel] = 0; |
| 331 | } |
| 332 | } |
| 333 | #endif |
| 334 | |
| 335 | static void opus_copy_channel_out_short( |
| 336 | void *dst, |
| 337 | int dst_stride, |
| 338 | int dst_channel, |
| 339 | const opus_val16 *src, |
| 340 | int src_stride, |
| 341 | int frame_size |
| 342 | ) |
| 343 | { |
| 344 | opus_int16 *short_dst; |
Timothy B. Terriberry | a8f04b2 | 2013-03-18 14:42:44 -0700 | [diff] [blame] | 345 | opus_int32 i; |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 346 | short_dst = (opus_int16*)dst; |
| 347 | if (src != NULL) |
| 348 | { |
| 349 | for (i=0;i<frame_size;i++) |
| 350 | #if defined(FIXED_POINT) |
| 351 | short_dst[i*dst_stride+dst_channel] = src[i*src_stride]; |
| 352 | #else |
| 353 | short_dst[i*dst_stride+dst_channel] = FLOAT2INT16(src[i*src_stride]); |
| 354 | #endif |
| 355 | } |
| 356 | else |
| 357 | { |
| 358 | for (i=0;i<frame_size;i++) |
| 359 | short_dst[i*dst_stride+dst_channel] = 0; |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | |
| 364 | |
| 365 | #ifdef FIXED_POINT |
| 366 | int opus_multistream_decode( |
| 367 | OpusMSDecoder *st, |
| 368 | const unsigned char *data, |
| 369 | opus_int32 len, |
| 370 | opus_int16 *pcm, |
| 371 | int frame_size, |
| 372 | int decode_fec |
| 373 | ) |
| 374 | { |
| 375 | return opus_multistream_decode_native(st, data, len, |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 376 | pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0); |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 377 | } |
| 378 | |
| 379 | #ifndef DISABLE_FLOAT_API |
| 380 | int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data, |
| 381 | opus_int32 len, float *pcm, int frame_size, int decode_fec) |
| 382 | { |
| 383 | return opus_multistream_decode_native(st, data, len, |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 384 | pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0); |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 385 | } |
| 386 | #endif |
| 387 | |
| 388 | #else |
| 389 | |
| 390 | int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data, |
| 391 | opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) |
| 392 | { |
| 393 | return opus_multistream_decode_native(st, data, len, |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 394 | pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1); |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 395 | } |
| 396 | |
| 397 | int opus_multistream_decode_float( |
| 398 | OpusMSDecoder *st, |
| 399 | const unsigned char *data, |
| 400 | opus_int32 len, |
| 401 | float *pcm, |
| 402 | int frame_size, |
| 403 | int decode_fec |
| 404 | ) |
| 405 | { |
| 406 | return opus_multistream_decode_native(st, data, len, |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 407 | pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0); |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 408 | } |
| 409 | #endif |
| 410 | |
| 411 | int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) |
| 412 | { |
| 413 | va_list ap; |
| 414 | int coupled_size, mono_size; |
| 415 | char *ptr; |
| 416 | int ret = OPUS_OK; |
| 417 | |
| 418 | va_start(ap, request); |
| 419 | |
| 420 | coupled_size = opus_decoder_get_size(2); |
| 421 | mono_size = opus_decoder_get_size(1); |
| 422 | ptr = (char*)st + align(sizeof(OpusMSDecoder)); |
| 423 | switch (request) |
| 424 | { |
| 425 | case OPUS_GET_BANDWIDTH_REQUEST: |
| 426 | case OPUS_GET_SAMPLE_RATE_REQUEST: |
Jean-Marc Valin | 512d849 | 2012-12-04 14:13:46 -0500 | [diff] [blame] | 427 | case OPUS_GET_GAIN_REQUEST: |
| 428 | case OPUS_GET_LAST_PACKET_DURATION_REQUEST: |
Mark Harris | 691d493 | 2016-09-03 10:42:19 -0700 | [diff] [blame] | 429 | case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 430 | { |
| 431 | OpusDecoder *dec; |
| 432 | /* For int32* GET params, just query the first stream */ |
| 433 | opus_int32 *value = va_arg(ap, opus_int32*); |
| 434 | dec = (OpusDecoder*)ptr; |
| 435 | ret = opus_decoder_ctl(dec, request, value); |
| 436 | } |
| 437 | break; |
| 438 | case OPUS_GET_FINAL_RANGE_REQUEST: |
| 439 | { |
| 440 | int s; |
| 441 | opus_uint32 *value = va_arg(ap, opus_uint32*); |
| 442 | opus_uint32 tmp; |
Gregory Maxwell | a0d096f | 2013-06-29 20:33:32 -0700 | [diff] [blame] | 443 | if (!value) |
| 444 | { |
Gregory Maxwell | b271dae | 2013-06-29 20:25:55 -0700 | [diff] [blame] | 445 | goto bad_arg; |
| 446 | } |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 447 | *value = 0; |
| 448 | for (s=0;s<st->layout.nb_streams;s++) |
| 449 | { |
| 450 | OpusDecoder *dec; |
| 451 | dec = (OpusDecoder*)ptr; |
| 452 | if (s < st->layout.nb_coupled_streams) |
| 453 | ptr += align(coupled_size); |
| 454 | else |
| 455 | ptr += align(mono_size); |
| 456 | ret = opus_decoder_ctl(dec, request, &tmp); |
| 457 | if (ret != OPUS_OK) break; |
| 458 | *value ^= tmp; |
| 459 | } |
| 460 | } |
| 461 | break; |
| 462 | case OPUS_RESET_STATE: |
| 463 | { |
| 464 | int s; |
| 465 | for (s=0;s<st->layout.nb_streams;s++) |
| 466 | { |
| 467 | OpusDecoder *dec; |
| 468 | |
| 469 | dec = (OpusDecoder*)ptr; |
| 470 | if (s < st->layout.nb_coupled_streams) |
| 471 | ptr += align(coupled_size); |
| 472 | else |
| 473 | ptr += align(mono_size); |
| 474 | ret = opus_decoder_ctl(dec, OPUS_RESET_STATE); |
| 475 | if (ret != OPUS_OK) |
| 476 | break; |
| 477 | } |
| 478 | } |
| 479 | break; |
| 480 | case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST: |
| 481 | { |
| 482 | int s; |
| 483 | opus_int32 stream_id; |
| 484 | OpusDecoder **value; |
| 485 | stream_id = va_arg(ap, opus_int32); |
| 486 | if (stream_id<0 || stream_id >= st->layout.nb_streams) |
| 487 | ret = OPUS_BAD_ARG; |
| 488 | value = va_arg(ap, OpusDecoder**); |
Gregory Maxwell | a0d096f | 2013-06-29 20:33:32 -0700 | [diff] [blame] | 489 | if (!value) |
| 490 | { |
Gregory Maxwell | b271dae | 2013-06-29 20:25:55 -0700 | [diff] [blame] | 491 | goto bad_arg; |
| 492 | } |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 493 | for (s=0;s<stream_id;s++) |
| 494 | { |
| 495 | if (s < st->layout.nb_coupled_streams) |
| 496 | ptr += align(coupled_size); |
| 497 | else |
| 498 | ptr += align(mono_size); |
| 499 | } |
| 500 | *value = (OpusDecoder*)ptr; |
| 501 | } |
| 502 | break; |
| 503 | case OPUS_SET_GAIN_REQUEST: |
Mark Harris | 691d493 | 2016-09-03 10:42:19 -0700 | [diff] [blame] | 504 | case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 505 | { |
| 506 | int s; |
| 507 | /* This works for int32 params */ |
| 508 | opus_int32 value = va_arg(ap, opus_int32); |
| 509 | for (s=0;s<st->layout.nb_streams;s++) |
| 510 | { |
| 511 | OpusDecoder *dec; |
| 512 | |
| 513 | dec = (OpusDecoder*)ptr; |
| 514 | if (s < st->layout.nb_coupled_streams) |
| 515 | ptr += align(coupled_size); |
| 516 | else |
| 517 | ptr += align(mono_size); |
| 518 | ret = opus_decoder_ctl(dec, request, value); |
| 519 | if (ret != OPUS_OK) |
| 520 | break; |
| 521 | } |
| 522 | } |
| 523 | break; |
| 524 | default: |
| 525 | ret = OPUS_UNIMPLEMENTED; |
| 526 | break; |
| 527 | } |
| 528 | |
| 529 | va_end(ap); |
| 530 | return ret; |
Gregory Maxwell | dd7b0da | 2013-06-29 20:06:07 -0700 | [diff] [blame] | 531 | bad_arg: |
| 532 | va_end(ap); |
| 533 | return OPUS_BAD_ARG; |
Jean-Marc Valin | ae0e2ca | 2012-11-07 19:57:33 -0500 | [diff] [blame] | 534 | } |
| 535 | |
| 536 | |
| 537 | void opus_multistream_decoder_destroy(OpusMSDecoder *st) |
| 538 | { |
| 539 | opus_free(st); |
| 540 | } |