blob: 08dff3631eceb6eb77aca99830b1b1c7404a40ec [file] [log] [blame]
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -05001/* 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"
Jean-Marc Valin51f4a322013-02-20 04:08:04 -050039#include "analysis.h"
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050040
41struct OpusMSEncoder {
Jean-Marc Valin51f4a322013-02-20 04:08:04 -050042 TonalityAnalysisState analysis;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050043 ChannelLayout layout;
Jean-Marc Valin74483662012-12-17 16:23:42 -050044 int variable_duration;
45 opus_int32 bitrate_bps;
46 opus_val32 subframe_mem[3];
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050047 /* Encoder states go here */
48};
49
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050050
51static int validate_encoder_layout(const ChannelLayout *layout)
52{
53 int s;
54 for (s=0;s<layout->nb_streams;s++)
55 {
56 if (s < layout->nb_coupled_streams)
57 {
58 if (get_left_channel(layout, s, -1)==-1)
59 return 0;
60 if (get_right_channel(layout, s, -1)==-1)
61 return 0;
62 } else {
63 if (get_mono_channel(layout, s, -1)==-1)
64 return 0;
65 }
66 }
67 return 1;
68}
69
70
71opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams)
72{
73 int coupled_size;
74 int mono_size;
75
76 if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
77 coupled_size = opus_encoder_get_size(2);
78 mono_size = opus_encoder_get_size(1);
79 return align(sizeof(OpusMSEncoder))
80 + nb_coupled_streams * align(coupled_size)
81 + (nb_streams-nb_coupled_streams) * align(mono_size);
82}
83
84
85
86int opus_multistream_encoder_init(
87 OpusMSEncoder *st,
88 opus_int32 Fs,
89 int channels,
90 int streams,
91 int coupled_streams,
92 const unsigned char *mapping,
93 int application
94)
95{
96 int coupled_size;
97 int mono_size;
98 int i, ret;
99 char *ptr;
100
101 if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
102 (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
103 return OPUS_BAD_ARG;
104
105 st->layout.nb_channels = channels;
106 st->layout.nb_streams = streams;
107 st->layout.nb_coupled_streams = coupled_streams;
Jean-Marc Valinb0429352013-05-05 02:22:06 -0400108 st->subframe_mem[0]=st->subframe_mem[1]=st->subframe_mem[2]=0;
109 OPUS_CLEAR(&st->analysis,1);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500110
Jean-Marc Valin95561be2012-12-17 17:54:01 -0500111 st->bitrate_bps = OPUS_AUTO;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500112 st->variable_duration = OPUS_FRAMESIZE_ARG;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500113 for (i=0;i<st->layout.nb_channels;i++)
114 st->layout.mapping[i] = mapping[i];
115 if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout))
116 return OPUS_BAD_ARG;
117 ptr = (char*)st + align(sizeof(OpusMSEncoder));
118 coupled_size = opus_encoder_get_size(2);
119 mono_size = opus_encoder_get_size(1);
120
121 for (i=0;i<st->layout.nb_coupled_streams;i++)
122 {
123 ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application);
124 if(ret!=OPUS_OK)return ret;
125 ptr += align(coupled_size);
126 }
127 for (;i<st->layout.nb_streams;i++)
128 {
129 ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application);
130 if(ret!=OPUS_OK)return ret;
131 ptr += align(mono_size);
132 }
133 return OPUS_OK;
134}
135
136OpusMSEncoder *opus_multistream_encoder_create(
137 opus_int32 Fs,
138 int channels,
139 int streams,
140 int coupled_streams,
141 const unsigned char *mapping,
142 int application,
143 int *error
144)
145{
146 int ret;
147 OpusMSEncoder *st;
148 if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
149 (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
150 {
151 if (error)
152 *error = OPUS_BAD_ARG;
153 return NULL;
154 }
155 st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams));
156 if (st==NULL)
157 {
158 if (error)
159 *error = OPUS_ALLOC_FAIL;
160 return NULL;
161 }
162 ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application);
163 if (ret != OPUS_OK)
164 {
165 opus_free(st);
166 st = NULL;
167 }
168 if (error)
169 *error = ret;
170 return st;
171}
172
173typedef void (*opus_copy_channel_in_func)(
174 opus_val16 *dst,
175 int dst_stride,
176 const void *src,
177 int src_stride,
178 int src_channel,
179 int frame_size
180);
181
182/* Max size in case the encoder decides to return three frames */
183#define MS_FRAME_TMP (3*1275+7)
184static int opus_multistream_encode_native
185(
186 OpusMSEncoder *st,
187 opus_copy_channel_in_func copy_channel_in,
188 const void *pcm,
189 int frame_size,
190 unsigned char *data,
Jean-Marc Valinb3eba242012-12-20 23:11:53 -0500191 opus_int32 max_data_bytes,
192 int lsb_depth
Jean-Marc Valin10a34a52012-12-20 00:23:01 -0500193#ifndef FIXED_POINT
194 , downmix_func downmix
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500195 , const void *pcm_analysis
Jean-Marc Valin10a34a52012-12-20 00:23:01 -0500196#endif
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500197)
198{
199 opus_int32 Fs;
200 int coupled_size;
201 int mono_size;
202 int s;
203 char *ptr;
204 int tot_size;
205 VARDECL(opus_val16, buf);
206 unsigned char tmp_data[MS_FRAME_TMP];
207 OpusRepacketizer rp;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500208 int orig_frame_size;
209 int coded_channels;
210 opus_int32 channel_rate;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500211 opus_int32 complexity;
212 AnalysisInfo analysis_info;
213 const CELTMode *celt_mode;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500214 ALLOC_STACK;
215
216 ptr = (char*)st + align(sizeof(OpusMSEncoder));
217 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500218 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_COMPLEXITY(&complexity));
219 opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode));
Jean-Marc Valin74483662012-12-17 16:23:42 -0500220
221 if (400*frame_size < Fs)
222 {
223 RESTORE_STACK;
224 return OPUS_BAD_ARG;
225 }
226 orig_frame_size = IMIN(frame_size,Fs/50);
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500227#ifndef FIXED_POINT
228 analysis_info.valid = 0;
229 if (complexity >= 7 && Fs==48000)
Jean-Marc Valin74483662012-12-17 16:23:42 -0500230 {
Jean-Marc Valin74483662012-12-17 16:23:42 -0500231 opus_int32 delay_compensation;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500232 int channels;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500233
234 channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
235 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_LOOKAHEAD(&delay_compensation));
236 delay_compensation -= Fs/400;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500237
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500238 frame_size = run_analysis(&st->analysis, celt_mode, pcm, pcm_analysis,
239 frame_size, st->variable_duration, channels, Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix, &analysis_info);
240 } else
241#endif
242 {
243 frame_size = frame_size_select(frame_size, st->variable_duration, Fs);
244 }
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500245 /* Validate frame_size before using it to allocate stack space.
246 This mirrors the checks in opus_encode[_float](). */
247 if (400*frame_size != Fs && 200*frame_size != Fs &&
248 100*frame_size != Fs && 50*frame_size != Fs &&
249 25*frame_size != Fs && 50*frame_size != 3*Fs)
250 {
251 RESTORE_STACK;
252 return OPUS_BAD_ARG;
253 }
254 ALLOC(buf, 2*frame_size, opus_val16);
255 coupled_size = opus_encoder_get_size(2);
256 mono_size = opus_encoder_get_size(1);
257
258 if (max_data_bytes < 4*st->layout.nb_streams-1)
259 {
260 RESTORE_STACK;
261 return OPUS_BUFFER_TOO_SMALL;
262 }
Jean-Marc Valin74483662012-12-17 16:23:42 -0500263
264 /* Compute bitrate allocation between streams (this could be a lot better) */
265 coded_channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
Jean-Marc Valin95561be2012-12-17 17:54:01 -0500266 if (st->bitrate_bps==OPUS_AUTO)
267 {
268 channel_rate = Fs+60*Fs/orig_frame_size;
269 } else if (st->bitrate_bps==OPUS_BITRATE_MAX)
270 {
271 channel_rate = 300000;
272 } else {
273 channel_rate = st->bitrate_bps/coded_channels;
274 }
Jean-Marc Valin74483662012-12-17 16:23:42 -0500275#ifndef FIXED_POINT
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500276 if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50)
Jean-Marc Valin74483662012-12-17 16:23:42 -0500277 {
278 opus_int32 bonus;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500279 bonus = 60*(Fs/frame_size-50);
Jean-Marc Valin74483662012-12-17 16:23:42 -0500280 channel_rate += bonus;
281 }
282#endif
283 ptr = (char*)st + align(sizeof(OpusMSEncoder));
284 for (s=0;s<st->layout.nb_streams;s++)
285 {
286 OpusEncoder *enc;
287 enc = (OpusEncoder*)ptr;
288 if (s < st->layout.nb_coupled_streams)
289 ptr += align(coupled_size);
290 else
291 ptr += align(mono_size);
292 opus_encoder_ctl(enc, OPUS_SET_BITRATE(channel_rate * (s < st->layout.nb_coupled_streams ? 2 : 1)));
293 }
294
295 ptr = (char*)st + align(sizeof(OpusMSEncoder));
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500296 /* Counting ToC */
297 tot_size = 0;
298 for (s=0;s<st->layout.nb_streams;s++)
299 {
300 OpusEncoder *enc;
301 int len;
302 int curr_max;
303
304 opus_repacketizer_init(&rp);
305 enc = (OpusEncoder*)ptr;
306 if (s < st->layout.nb_coupled_streams)
307 {
308 int left, right;
309 left = get_left_channel(&st->layout, s, -1);
310 right = get_right_channel(&st->layout, s, -1);
311 (*copy_channel_in)(buf, 2,
312 pcm, st->layout.nb_channels, left, frame_size);
313 (*copy_channel_in)(buf+1, 2,
314 pcm, st->layout.nb_channels, right, frame_size);
315 ptr += align(coupled_size);
316 } else {
317 int chan = get_mono_channel(&st->layout, s, -1);
318 (*copy_channel_in)(buf, 1,
319 pcm, st->layout.nb_channels, chan, frame_size);
320 ptr += align(mono_size);
321 }
322 /* number of bytes left (+Toc) */
323 curr_max = max_data_bytes - tot_size;
324 /* Reserve three bytes for the last stream and four for the others */
325 curr_max -= IMAX(0,4*(st->layout.nb_streams-s-1)-1);
326 curr_max = IMIN(curr_max,MS_FRAME_TMP);
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500327 len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth
328#ifndef FIXED_POINT
329 , &analysis_info
330#endif
331 );
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500332 if (len<0)
333 {
334 RESTORE_STACK;
335 return len;
336 }
337 /* We need to use the repacketizer to add the self-delimiting lengths
338 while taking into account the fact that the encoder can now return
339 more than one frame at a time (e.g. 60 ms CELT-only) */
340 opus_repacketizer_cat(&rp, tmp_data, len);
341 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);
342 data += len;
343 tot_size += len;
344 }
345 RESTORE_STACK;
346 return tot_size;
347
348}
349
350#if !defined(DISABLE_FLOAT_API)
351static void opus_copy_channel_in_float(
352 opus_val16 *dst,
353 int dst_stride,
354 const void *src,
355 int src_stride,
356 int src_channel,
357 int frame_size
358)
359{
360 const float *float_src;
Timothy B. Terriberrya8f04b22013-03-18 14:42:44 -0700361 opus_int32 i;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500362 float_src = (const float *)src;
363 for (i=0;i<frame_size;i++)
364#if defined(FIXED_POINT)
365 dst[i*dst_stride] = FLOAT2INT16(float_src[i*src_stride+src_channel]);
366#else
367 dst[i*dst_stride] = float_src[i*src_stride+src_channel];
368#endif
369}
370#endif
371
372static void opus_copy_channel_in_short(
373 opus_val16 *dst,
374 int dst_stride,
375 const void *src,
376 int src_stride,
377 int src_channel,
378 int frame_size
379)
380{
381 const opus_int16 *short_src;
Timothy B. Terriberrya8f04b22013-03-18 14:42:44 -0700382 opus_int32 i;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500383 short_src = (const opus_int16 *)src;
384 for (i=0;i<frame_size;i++)
385#if defined(FIXED_POINT)
386 dst[i*dst_stride] = short_src[i*src_stride+src_channel];
387#else
388 dst[i*dst_stride] = (1/32768.f)*short_src[i*src_stride+src_channel];
389#endif
390}
391
392#ifdef FIXED_POINT
393int opus_multistream_encode(
394 OpusMSEncoder *st,
395 const opus_val16 *pcm,
396 int frame_size,
397 unsigned char *data,
398 opus_int32 max_data_bytes
399)
400{
401 return opus_multistream_encode_native(st, opus_copy_channel_in_short,
Jean-Marc Valinb3eba242012-12-20 23:11:53 -0500402 pcm, frame_size, data, max_data_bytes, 16);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500403}
404
405#ifndef DISABLE_FLOAT_API
406int opus_multistream_encode_float(
407 OpusMSEncoder *st,
408 const float *pcm,
409 int frame_size,
410 unsigned char *data,
411 opus_int32 max_data_bytes
412)
413{
414 return opus_multistream_encode_native(st, opus_copy_channel_in_float,
Jean-Marc Valinb3eba242012-12-20 23:11:53 -0500415 pcm, frame_size, data, max_data_bytes, 16);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500416}
417#endif
418
419#else
420
421int opus_multistream_encode_float
422(
423 OpusMSEncoder *st,
424 const opus_val16 *pcm,
425 int frame_size,
426 unsigned char *data,
427 opus_int32 max_data_bytes
428)
429{
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500430 int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500431 return opus_multistream_encode_native(st, opus_copy_channel_in_float,
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500432 pcm, frame_size, data, max_data_bytes, 24, downmix_float, pcm+channels*st->analysis.analysis_offset);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500433}
434
435int opus_multistream_encode(
436 OpusMSEncoder *st,
437 const opus_int16 *pcm,
438 int frame_size,
439 unsigned char *data,
440 opus_int32 max_data_bytes
441)
442{
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500443 int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500444 return opus_multistream_encode_native(st, opus_copy_channel_in_short,
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500445 pcm, frame_size, data, max_data_bytes, 16, downmix_int, pcm+channels*st->analysis.analysis_offset);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500446}
447#endif
448
449int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
450{
451 va_list ap;
452 int coupled_size, mono_size;
453 char *ptr;
454 int ret = OPUS_OK;
455
456 va_start(ap, request);
457
458 coupled_size = opus_encoder_get_size(2);
459 mono_size = opus_encoder_get_size(1);
460 ptr = (char*)st + align(sizeof(OpusMSEncoder));
461 switch (request)
462 {
463 case OPUS_SET_BITRATE_REQUEST:
464 {
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500465 opus_int32 value = va_arg(ap, opus_int32);
Jean-Marc Valin95561be2012-12-17 17:54:01 -0500466 if (value<0 && value!=OPUS_AUTO && value!=OPUS_BITRATE_MAX)
467 goto bad_arg;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500468 st->bitrate_bps = value;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500469 }
470 break;
471 case OPUS_GET_BITRATE_REQUEST:
472 {
473 int s;
474 opus_int32 *value = va_arg(ap, opus_int32*);
475 *value = 0;
476 for (s=0;s<st->layout.nb_streams;s++)
477 {
478 opus_int32 rate;
479 OpusEncoder *enc;
480 enc = (OpusEncoder*)ptr;
481 if (s < st->layout.nb_coupled_streams)
482 ptr += align(coupled_size);
483 else
484 ptr += align(mono_size);
485 opus_encoder_ctl(enc, request, &rate);
486 *value += rate;
487 }
488 }
489 break;
490 case OPUS_GET_LSB_DEPTH_REQUEST:
491 case OPUS_GET_VBR_REQUEST:
492 case OPUS_GET_APPLICATION_REQUEST:
493 case OPUS_GET_BANDWIDTH_REQUEST:
494 case OPUS_GET_COMPLEXITY_REQUEST:
495 case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
496 case OPUS_GET_DTX_REQUEST:
497 case OPUS_GET_VOICE_RATIO_REQUEST:
498 case OPUS_GET_VBR_CONSTRAINT_REQUEST:
499 case OPUS_GET_SIGNAL_REQUEST:
500 case OPUS_GET_LOOKAHEAD_REQUEST:
501 case OPUS_GET_SAMPLE_RATE_REQUEST:
502 case OPUS_GET_INBAND_FEC_REQUEST:
503 case OPUS_GET_FORCE_CHANNELS_REQUEST:
504 {
505 OpusEncoder *enc;
506 /* For int32* GET params, just query the first stream */
507 opus_int32 *value = va_arg(ap, opus_int32*);
508 enc = (OpusEncoder*)ptr;
509 ret = opus_encoder_ctl(enc, request, value);
510 }
511 break;
512 case OPUS_GET_FINAL_RANGE_REQUEST:
513 {
514 int s;
515 opus_uint32 *value = va_arg(ap, opus_uint32*);
516 opus_uint32 tmp;
517 *value=0;
518 for (s=0;s<st->layout.nb_streams;s++)
519 {
520 OpusEncoder *enc;
521 enc = (OpusEncoder*)ptr;
522 if (s < st->layout.nb_coupled_streams)
523 ptr += align(coupled_size);
524 else
525 ptr += align(mono_size);
526 ret = opus_encoder_ctl(enc, request, &tmp);
527 if (ret != OPUS_OK) break;
528 *value ^= tmp;
529 }
530 }
531 break;
532 case OPUS_SET_LSB_DEPTH_REQUEST:
533 case OPUS_SET_COMPLEXITY_REQUEST:
534 case OPUS_SET_VBR_REQUEST:
535 case OPUS_SET_VBR_CONSTRAINT_REQUEST:
536 case OPUS_SET_BANDWIDTH_REQUEST:
537 case OPUS_SET_SIGNAL_REQUEST:
538 case OPUS_SET_APPLICATION_REQUEST:
539 case OPUS_SET_INBAND_FEC_REQUEST:
540 case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
541 case OPUS_SET_DTX_REQUEST:
542 case OPUS_SET_FORCE_MODE_REQUEST:
543 case OPUS_SET_FORCE_CHANNELS_REQUEST:
544 {
545 int s;
546 /* This works for int32 params */
547 opus_int32 value = va_arg(ap, opus_int32);
548 for (s=0;s<st->layout.nb_streams;s++)
549 {
550 OpusEncoder *enc;
551
552 enc = (OpusEncoder*)ptr;
553 if (s < st->layout.nb_coupled_streams)
554 ptr += align(coupled_size);
555 else
556 ptr += align(mono_size);
557 ret = opus_encoder_ctl(enc, request, value);
558 if (ret != OPUS_OK)
559 break;
560 }
561 }
562 break;
563 case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST:
564 {
565 int s;
566 opus_int32 stream_id;
567 OpusEncoder **value;
568 stream_id = va_arg(ap, opus_int32);
569 if (stream_id<0 || stream_id >= st->layout.nb_streams)
570 ret = OPUS_BAD_ARG;
571 value = va_arg(ap, OpusEncoder**);
572 for (s=0;s<stream_id;s++)
573 {
574 if (s < st->layout.nb_coupled_streams)
575 ptr += align(coupled_size);
576 else
577 ptr += align(mono_size);
578 }
579 *value = (OpusEncoder*)ptr;
580 }
Jean-Marc Valin74483662012-12-17 16:23:42 -0500581 break;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500582 case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
Jean-Marc Valin74483662012-12-17 16:23:42 -0500583 {
584 opus_int32 value = va_arg(ap, opus_int32);
Jean-Marc Valin74483662012-12-17 16:23:42 -0500585 st->variable_duration = value;
586 }
587 break;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500588 case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
Jean-Marc Valin74483662012-12-17 16:23:42 -0500589 {
590 opus_int32 *value = va_arg(ap, opus_int32*);
591 *value = st->variable_duration;
592 }
593 break;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500594 default:
595 ret = OPUS_UNIMPLEMENTED;
596 break;
597 }
598
599 va_end(ap);
600 return ret;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500601bad_arg:
602 va_end(ap);
603 return OPUS_BAD_ARG;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500604}
605
606void opus_multistream_encoder_destroy(OpusMSEncoder *st)
607{
608 opus_free(st);
609}
610
611