1 /* GStreamer Opus Encoder
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk>
4  * Copyright (C) <2011> Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 /*
23  * Based on the speexenc element
24  */
25 
26 /**
27  * SECTION:element-opusenc
28  * @title: opusenc
29  * @see_also: opusdec, oggmux
30  *
31  * This element encodes raw audio to OPUS.
32  *
33  * ## Example pipelines
34  * |[
35  * gst-launch-1.0 -v audiotestsrc wave=sine num-buffers=100 ! audioconvert ! opusenc ! oggmux ! filesink location=sine.ogg
36  * ]|
37  * Encode a test sine signal to Ogg/OPUS.
38  *
39  */
40 
41 #ifdef HAVE_CONFIG_H
42 #include "config.h"
43 #endif
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47 #include <math.h>
48 #include <opus.h>
49 
50 #include <gst/gsttagsetter.h>
51 #include <gst/audio/audio.h>
52 #include <gst/pbutils/pbutils.h>
53 #include <gst/tag/tag.h>
54 #include <gst/glib-compat-private.h>
55 #include "gstopusheader.h"
56 #include "gstopuscommon.h"
57 #include "gstopusenc.h"
58 
59 GST_DEBUG_CATEGORY_STATIC (opusenc_debug);
60 #define GST_CAT_DEFAULT opusenc_debug
61 
62 /* Some arbitrary bounds beyond which it really doesn't make sense.
63    The spec mentions 6 kb/s to 510 kb/s, so 4000 and 650000 ought to be
64    safe as property bounds. */
65 #define LOWEST_BITRATE 4000
66 #define HIGHEST_BITRATE 650000
67 
68 #define GST_OPUS_ENC_TYPE_BANDWIDTH (gst_opus_enc_bandwidth_get_type())
69 static GType
gst_opus_enc_bandwidth_get_type(void)70 gst_opus_enc_bandwidth_get_type (void)
71 {
72   static const GEnumValue values[] = {
73     {OPUS_BANDWIDTH_NARROWBAND, "Narrow band", "narrowband"},
74     {OPUS_BANDWIDTH_MEDIUMBAND, "Medium band", "mediumband"},
75     {OPUS_BANDWIDTH_WIDEBAND, "Wide band", "wideband"},
76     {OPUS_BANDWIDTH_SUPERWIDEBAND, "Super wide band", "superwideband"},
77     {OPUS_BANDWIDTH_FULLBAND, "Full band", "fullband"},
78     {OPUS_AUTO, "Auto", "auto"},
79     {0, NULL, NULL}
80   };
81   static volatile GType id = 0;
82 
83   if (g_once_init_enter ((gsize *) & id)) {
84     GType _id;
85 
86     _id = g_enum_register_static ("GstOpusEncBandwidth", values);
87 
88     g_once_init_leave ((gsize *) & id, _id);
89   }
90 
91   return id;
92 }
93 
94 #define GST_OPUS_ENC_TYPE_FRAME_SIZE (gst_opus_enc_frame_size_get_type())
95 static GType
gst_opus_enc_frame_size_get_type(void)96 gst_opus_enc_frame_size_get_type (void)
97 {
98   static const GEnumValue values[] = {
99     {2, "2.5", "2.5"},
100     {5, "5", "5"},
101     {10, "10", "10"},
102     {20, "20", "20"},
103     {40, "40", "40"},
104     {60, "60", "60"},
105     {0, NULL, NULL}
106   };
107   static volatile GType id = 0;
108 
109   if (g_once_init_enter ((gsize *) & id)) {
110     GType _id;
111 
112     _id = g_enum_register_static ("GstOpusEncFrameSize", values);
113 
114     g_once_init_leave ((gsize *) & id, _id);
115   }
116 
117   return id;
118 }
119 
120 #define GST_OPUS_ENC_TYPE_AUDIO_TYPE (gst_opus_enc_audio_type_get_type())
121 static GType
gst_opus_enc_audio_type_get_type(void)122 gst_opus_enc_audio_type_get_type (void)
123 {
124   static const GEnumValue values[] = {
125     {OPUS_APPLICATION_AUDIO, "Generic audio", "generic"},
126     {OPUS_APPLICATION_VOIP, "Voice", "voice"},
127     {0, NULL, NULL}
128   };
129   static volatile GType id = 0;
130 
131   if (g_once_init_enter ((gsize *) & id)) {
132     GType _id;
133 
134     _id = g_enum_register_static ("GstOpusEncAudioType", values);
135 
136     g_once_init_leave ((gsize *) & id, _id);
137   }
138 
139   return id;
140 }
141 
142 #define GST_OPUS_ENC_TYPE_BITRATE_TYPE (gst_opus_enc_bitrate_type_get_type())
143 static GType
gst_opus_enc_bitrate_type_get_type(void)144 gst_opus_enc_bitrate_type_get_type (void)
145 {
146   static const GEnumValue values[] = {
147     {BITRATE_TYPE_CBR, "CBR", "cbr"},
148     {BITRATE_TYPE_VBR, "VBR", "vbr"},
149     {BITRATE_TYPE_CONSTRAINED_VBR, "Constrained VBR", "constrained-vbr"},
150     {0, NULL, NULL}
151   };
152   static volatile GType id = 0;
153 
154   if (g_once_init_enter ((gsize *) & id)) {
155     GType _id;
156 
157     _id = g_enum_register_static ("GstOpusEncBitrateType", values);
158 
159     g_once_init_leave ((gsize *) & id, _id);
160   }
161 
162   return id;
163 }
164 
165 #define FORMAT_STR GST_AUDIO_NE(S16)
166 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
167     GST_PAD_SINK,
168     GST_PAD_ALWAYS,
169     GST_STATIC_CAPS ("audio/x-raw, "
170         "format = (string) " FORMAT_STR ", "
171         "layout = (string) interleaved, "
172         "rate = (int) 48000, "
173         "channels = (int) [ 1, 8 ]; "
174         "audio/x-raw, "
175         "format = (string) " FORMAT_STR ", "
176         "layout = (string) interleaved, "
177         "rate = (int) { 8000, 12000, 16000, 24000 }, "
178         "channels = (int) [ 1, 8 ] ")
179     );
180 
181 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
182     GST_PAD_SRC,
183     GST_PAD_ALWAYS,
184     GST_STATIC_CAPS ("audio/x-opus")
185     );
186 
187 #define DEFAULT_AUDIO           TRUE
188 #define DEFAULT_AUDIO_TYPE      OPUS_APPLICATION_AUDIO
189 #define DEFAULT_BITRATE         64000
190 #define DEFAULT_BANDWIDTH       OPUS_BANDWIDTH_FULLBAND
191 #define DEFAULT_FRAMESIZE       20
192 #define DEFAULT_CBR             TRUE
193 #define DEFAULT_CONSTRAINED_VBR TRUE
194 #define DEFAULT_BITRATE_TYPE    BITRATE_TYPE_CBR
195 #define DEFAULT_COMPLEXITY      10
196 #define DEFAULT_INBAND_FEC      FALSE
197 #define DEFAULT_DTX             FALSE
198 #define DEFAULT_PACKET_LOSS_PERCENT 0
199 #define DEFAULT_MAX_PAYLOAD_SIZE 4000
200 
201 enum
202 {
203   PROP_0,
204   PROP_AUDIO_TYPE,
205   PROP_BITRATE,
206   PROP_BANDWIDTH,
207   PROP_FRAME_SIZE,
208   PROP_BITRATE_TYPE,
209   PROP_COMPLEXITY,
210   PROP_INBAND_FEC,
211   PROP_DTX,
212   PROP_PACKET_LOSS_PERCENT,
213   PROP_MAX_PAYLOAD_SIZE
214 };
215 
216 static void gst_opus_enc_finalize (GObject * object);
217 
218 static gboolean gst_opus_enc_sink_event (GstAudioEncoder * benc,
219     GstEvent * event);
220 static GstCaps *gst_opus_enc_sink_getcaps (GstAudioEncoder * benc,
221     GstCaps * filter);
222 static gboolean gst_opus_enc_setup (GstOpusEnc * enc);
223 
224 static void gst_opus_enc_get_property (GObject * object, guint prop_id,
225     GValue * value, GParamSpec * pspec);
226 static void gst_opus_enc_set_property (GObject * object, guint prop_id,
227     const GValue * value, GParamSpec * pspec);
228 
229 static void gst_opus_enc_set_tags (GstOpusEnc * enc);
230 static gboolean gst_opus_enc_start (GstAudioEncoder * benc);
231 static gboolean gst_opus_enc_stop (GstAudioEncoder * benc);
232 static gboolean gst_opus_enc_set_format (GstAudioEncoder * benc,
233     GstAudioInfo * info);
234 static GstFlowReturn gst_opus_enc_handle_frame (GstAudioEncoder * benc,
235     GstBuffer * buf);
236 static gint64 gst_opus_enc_get_latency (GstOpusEnc * enc);
237 
238 static GstFlowReturn gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buffer);
239 
240 #define gst_opus_enc_parent_class parent_class
241 G_DEFINE_TYPE_WITH_CODE (GstOpusEnc, gst_opus_enc, GST_TYPE_AUDIO_ENCODER,
242     G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
243     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
244 
245 static void
gst_opus_enc_set_tags(GstOpusEnc * enc)246 gst_opus_enc_set_tags (GstOpusEnc * enc)
247 {
248   GstTagList *taglist;
249 
250   /* create a taglist and add a bitrate tag to it */
251   taglist = gst_tag_list_new_empty ();
252   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
253       GST_TAG_BITRATE, enc->bitrate, NULL);
254 
255   gst_audio_encoder_merge_tags (GST_AUDIO_ENCODER (enc), taglist,
256       GST_TAG_MERGE_REPLACE);
257 
258   gst_tag_list_unref (taglist);
259 }
260 
261 static void
gst_opus_enc_class_init(GstOpusEncClass * klass)262 gst_opus_enc_class_init (GstOpusEncClass * klass)
263 {
264   GObjectClass *gobject_class;
265   GstAudioEncoderClass *base_class;
266   GstElementClass *gstelement_class;
267 
268   gobject_class = (GObjectClass *) klass;
269   base_class = (GstAudioEncoderClass *) klass;
270   gstelement_class = (GstElementClass *) klass;
271 
272   gobject_class->set_property = gst_opus_enc_set_property;
273   gobject_class->get_property = gst_opus_enc_get_property;
274 
275   gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
276   gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
277   gst_element_class_set_static_metadata (gstelement_class, "Opus audio encoder",
278       "Codec/Encoder/Audio",
279       "Encodes audio in Opus format",
280       "Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>");
281 
282   base_class->start = GST_DEBUG_FUNCPTR (gst_opus_enc_start);
283   base_class->stop = GST_DEBUG_FUNCPTR (gst_opus_enc_stop);
284   base_class->set_format = GST_DEBUG_FUNCPTR (gst_opus_enc_set_format);
285   base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_opus_enc_handle_frame);
286   base_class->sink_event = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_event);
287   base_class->getcaps = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_getcaps);
288 
289   g_object_class_install_property (gobject_class, PROP_AUDIO_TYPE,
290       g_param_spec_enum ("audio-type", "What type of audio to optimize for",
291           "What type of audio to optimize for", GST_OPUS_ENC_TYPE_AUDIO_TYPE,
292           DEFAULT_AUDIO_TYPE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
293   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
294       g_param_spec_int ("bitrate", "Encoding Bit-rate",
295           "Specify an encoding bit-rate (in bps).", LOWEST_BITRATE,
296           HIGHEST_BITRATE, DEFAULT_BITRATE,
297           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
298           GST_PARAM_MUTABLE_PLAYING));
299   g_object_class_install_property (gobject_class, PROP_BANDWIDTH,
300       g_param_spec_enum ("bandwidth", "Band Width", "Audio Band Width",
301           GST_OPUS_ENC_TYPE_BANDWIDTH, DEFAULT_BANDWIDTH,
302           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
303           GST_PARAM_MUTABLE_PLAYING));
304   g_object_class_install_property (gobject_class, PROP_FRAME_SIZE,
305       g_param_spec_enum ("frame-size", "Frame Size",
306           "The duration of an audio frame, in ms", GST_OPUS_ENC_TYPE_FRAME_SIZE,
307           DEFAULT_FRAMESIZE,
308           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
309           GST_PARAM_MUTABLE_PLAYING));
310   g_object_class_install_property (gobject_class, PROP_BITRATE_TYPE,
311       g_param_spec_enum ("bitrate-type", "Bitrate type", "Bitrate type",
312           GST_OPUS_ENC_TYPE_BITRATE_TYPE, DEFAULT_BITRATE_TYPE,
313           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
314           GST_PARAM_MUTABLE_PLAYING));
315   g_object_class_install_property (gobject_class, PROP_COMPLEXITY,
316       g_param_spec_int ("complexity", "Complexity", "Complexity", 0, 10,
317           DEFAULT_COMPLEXITY,
318           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
319           GST_PARAM_MUTABLE_PLAYING));
320   g_object_class_install_property (gobject_class, PROP_INBAND_FEC,
321       g_param_spec_boolean ("inband-fec", "In-band FEC",
322           "Enable forward error correction", DEFAULT_INBAND_FEC,
323           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
324           GST_PARAM_MUTABLE_PLAYING));
325   g_object_class_install_property (gobject_class, PROP_DTX,
326       g_param_spec_boolean ("dtx", "DTX", "DTX", DEFAULT_DTX,
327           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
328           GST_PARAM_MUTABLE_PLAYING));
329   g_object_class_install_property (G_OBJECT_CLASS (klass),
330       PROP_PACKET_LOSS_PERCENT, g_param_spec_int ("packet-loss-percentage",
331           "Loss percentage", "Packet loss percentage", 0, 100,
332           DEFAULT_PACKET_LOSS_PERCENT,
333           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
334           GST_PARAM_MUTABLE_PLAYING));
335   g_object_class_install_property (G_OBJECT_CLASS (klass),
336       PROP_MAX_PAYLOAD_SIZE, g_param_spec_uint ("max-payload-size",
337           "Max payload size", "Maximum payload size in bytes", 2, 4000,
338           DEFAULT_MAX_PAYLOAD_SIZE,
339           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
340           GST_PARAM_MUTABLE_PLAYING));
341 
342   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_opus_enc_finalize);
343 
344   GST_DEBUG_CATEGORY_INIT (opusenc_debug, "opusenc", 0, "Opus encoder");
345 }
346 
347 static void
gst_opus_enc_finalize(GObject * object)348 gst_opus_enc_finalize (GObject * object)
349 {
350   GstOpusEnc *enc;
351 
352   enc = GST_OPUS_ENC (object);
353 
354   g_mutex_clear (&enc->property_lock);
355 
356   G_OBJECT_CLASS (parent_class)->finalize (object);
357 }
358 
359 static void
gst_opus_enc_init(GstOpusEnc * enc)360 gst_opus_enc_init (GstOpusEnc * enc)
361 {
362   GST_DEBUG_OBJECT (enc, "init");
363 
364   GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (enc));
365 
366   g_mutex_init (&enc->property_lock);
367 
368   enc->n_channels = -1;
369   enc->sample_rate = -1;
370   enc->frame_samples = 0;
371   enc->unpositioned = FALSE;
372 
373   enc->bitrate = DEFAULT_BITRATE;
374   enc->bandwidth = DEFAULT_BANDWIDTH;
375   enc->frame_size = DEFAULT_FRAMESIZE;
376   enc->bitrate_type = DEFAULT_BITRATE_TYPE;
377   enc->complexity = DEFAULT_COMPLEXITY;
378   enc->inband_fec = DEFAULT_INBAND_FEC;
379   enc->dtx = DEFAULT_DTX;
380   enc->packet_loss_percentage = DEFAULT_PACKET_LOSS_PERCENT;
381   enc->max_payload_size = DEFAULT_MAX_PAYLOAD_SIZE;
382   enc->audio_type = DEFAULT_AUDIO_TYPE;
383 }
384 
385 static gboolean
gst_opus_enc_start(GstAudioEncoder * benc)386 gst_opus_enc_start (GstAudioEncoder * benc)
387 {
388   GstOpusEnc *enc = GST_OPUS_ENC (benc);
389 
390   GST_DEBUG_OBJECT (enc, "start");
391   enc->encoded_samples = 0;
392   enc->consumed_samples = 0;
393 
394   return TRUE;
395 }
396 
397 static gboolean
gst_opus_enc_stop(GstAudioEncoder * benc)398 gst_opus_enc_stop (GstAudioEncoder * benc)
399 {
400   GstOpusEnc *enc = GST_OPUS_ENC (benc);
401 
402   GST_DEBUG_OBJECT (enc, "stop");
403   if (enc->state) {
404     opus_multistream_encoder_destroy (enc->state);
405     enc->state = NULL;
406   }
407   gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
408 
409   return TRUE;
410 }
411 
412 static gint64
gst_opus_enc_get_latency(GstOpusEnc * enc)413 gst_opus_enc_get_latency (GstOpusEnc * enc)
414 {
415   gint64 latency = gst_util_uint64_scale (enc->frame_samples, GST_SECOND,
416       enc->sample_rate);
417   GST_DEBUG_OBJECT (enc, "Latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency));
418   return latency;
419 }
420 
421 static void
gst_opus_enc_setup_base_class(GstOpusEnc * enc,GstAudioEncoder * benc)422 gst_opus_enc_setup_base_class (GstOpusEnc * enc, GstAudioEncoder * benc)
423 {
424   gst_audio_encoder_set_latency (benc,
425       gst_opus_enc_get_latency (enc), gst_opus_enc_get_latency (enc));
426   gst_audio_encoder_set_frame_samples_min (benc, enc->frame_samples);
427   gst_audio_encoder_set_frame_samples_max (benc, enc->frame_samples);
428   gst_audio_encoder_set_frame_max (benc, 1);
429 }
430 
431 static gint
gst_opus_enc_get_frame_samples(GstOpusEnc * enc)432 gst_opus_enc_get_frame_samples (GstOpusEnc * enc)
433 {
434   gint frame_samples = 0;
435   switch (enc->frame_size) {
436     case 2:
437       frame_samples = enc->sample_rate / 400;
438       break;
439     case 5:
440       frame_samples = enc->sample_rate / 200;
441       break;
442     case 10:
443       frame_samples = enc->sample_rate / 100;
444       break;
445     case 20:
446       frame_samples = enc->sample_rate / 50;
447       break;
448     case 40:
449       frame_samples = enc->sample_rate / 25;
450       break;
451     case 60:
452       frame_samples = 3 * enc->sample_rate / 50;
453       break;
454     default:
455       GST_WARNING_OBJECT (enc, "Unsupported frame size: %d", enc->frame_size);
456       frame_samples = 0;
457       break;
458   }
459   return frame_samples;
460 }
461 
462 static void
gst_opus_enc_setup_trivial_mapping(GstOpusEnc * enc,guint8 mapping[256])463 gst_opus_enc_setup_trivial_mapping (GstOpusEnc * enc, guint8 mapping[256])
464 {
465   int n;
466 
467   for (n = 0; n < 255; ++n)
468     mapping[n] = n;
469 }
470 
471 static int
gst_opus_enc_find_channel_position(GstOpusEnc * enc,const GstAudioInfo * info,GstAudioChannelPosition position)472 gst_opus_enc_find_channel_position (GstOpusEnc * enc, const GstAudioInfo * info,
473     GstAudioChannelPosition position)
474 {
475   int n;
476   for (n = 0; n < enc->n_channels; ++n) {
477     if (GST_AUDIO_INFO_POSITION (info, n) == position) {
478       return n;
479     }
480   }
481   return -1;
482 }
483 
484 static int
gst_opus_enc_find_channel_position_in_vorbis_order(GstOpusEnc * enc,GstAudioChannelPosition position)485 gst_opus_enc_find_channel_position_in_vorbis_order (GstOpusEnc * enc,
486     GstAudioChannelPosition position)
487 {
488   int c;
489 
490   for (c = 0; c < enc->n_channels; ++c) {
491     if (gst_opus_channel_positions[enc->n_channels - 1][c] == position) {
492       GST_INFO_OBJECT (enc,
493           "Channel position %s maps to index %d in Vorbis order",
494           gst_opus_channel_names[position], c);
495       return c;
496     }
497   }
498   GST_WARNING_OBJECT (enc,
499       "Channel position %s is not representable in Vorbis order",
500       gst_opus_channel_names[position]);
501   return -1;
502 }
503 
504 static void
gst_opus_enc_setup_channel_mappings(GstOpusEnc * enc,const GstAudioInfo * info)505 gst_opus_enc_setup_channel_mappings (GstOpusEnc * enc,
506     const GstAudioInfo * info)
507 {
508 #define MAPS(idx,pos) (GST_AUDIO_INFO_POSITION (info, (idx)) == GST_AUDIO_CHANNEL_POSITION_##pos)
509 
510   int n;
511 
512   GST_DEBUG_OBJECT (enc, "Setting up channel mapping for %d channels",
513       enc->n_channels);
514 
515   /* Start by setting up a default trivial mapping */
516   enc->n_stereo_streams = 0;
517   gst_opus_enc_setup_trivial_mapping (enc, enc->encoding_channel_mapping);
518   gst_opus_enc_setup_trivial_mapping (enc, enc->decoding_channel_mapping);
519 
520   /* For one channel, use the basic RTP mapping */
521   if (enc->n_channels == 1 && !enc->unpositioned) {
522     GST_INFO_OBJECT (enc, "Mono, trivial RTP mapping");
523     enc->channel_mapping_family = 0;
524     /* implicit mapping for family 0 */
525     return;
526   }
527 
528   /* For two channels, use the basic RTP mapping if the channels are
529      mapped as left/right. */
530   if (enc->n_channels == 2 && !enc->unpositioned) {
531     GST_INFO_OBJECT (enc, "Stereo, trivial RTP mapping");
532     enc->channel_mapping_family = 0;
533     enc->n_stereo_streams = 1;
534     /* implicit mapping for family 0 */
535     return;
536   }
537 
538   /* For channels between 3 and 8, we use the Vorbis mapping if we can
539      find a permutation that matches it. Mono and stereo will have been taken
540      care of earlier, but this code also handles it. There are two mappings.
541      One maps the input channels to an ordering which has the natural pairs
542      first so they can benefit from the Opus stereo channel coupling, and the
543      other maps this ordering to the Vorbis ordering. */
544   if (enc->n_channels >= 3 && enc->n_channels <= 8 && !enc->unpositioned) {
545     int c0, c1, c0v, c1v;
546     int mapped;
547     gboolean positions_done[256];
548     static const GstAudioChannelPosition pairs[][2] = {
549       {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
550           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
551       {GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
552           GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
553       {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
554           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER},
555       {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
556           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER},
557       {GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
558           GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
559       {GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
560           GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
561     };
562     size_t pair;
563 
564     GST_DEBUG_OBJECT (enc,
565         "In range for the Vorbis mapping, building channel mapping tables");
566 
567     enc->n_stereo_streams = 0;
568     mapped = 0;
569     for (n = 0; n < 256; ++n)
570       positions_done[n] = FALSE;
571 
572     /* First, find any natural pairs, and move them to the front */
573     for (pair = 0; pair < G_N_ELEMENTS (pairs); ++pair) {
574       GstAudioChannelPosition p0 = pairs[pair][0];
575       GstAudioChannelPosition p1 = pairs[pair][1];
576       c0 = gst_opus_enc_find_channel_position (enc, info, p0);
577       c1 = gst_opus_enc_find_channel_position (enc, info, p1);
578       if (c0 >= 0 && c1 >= 0) {
579         /* We found a natural pair */
580         GST_DEBUG_OBJECT (enc, "Natural pair '%s/%s' found at %d %d",
581             gst_opus_channel_names[p0], gst_opus_channel_names[p1], c0, c1);
582         /* Find where they map in Vorbis order */
583         c0v = gst_opus_enc_find_channel_position_in_vorbis_order (enc, p0);
584         c1v = gst_opus_enc_find_channel_position_in_vorbis_order (enc, p1);
585         if (c0v < 0 || c1v < 0) {
586           GST_WARNING_OBJECT (enc,
587               "Cannot map channel positions to Vorbis order, using unknown mapping");
588           enc->channel_mapping_family = 255;
589           enc->n_stereo_streams = 0;
590           return;
591         }
592 
593         enc->encoding_channel_mapping[mapped] = c0;
594         enc->encoding_channel_mapping[mapped + 1] = c1;
595         enc->decoding_channel_mapping[c0v] = mapped;
596         enc->decoding_channel_mapping[c1v] = mapped + 1;
597         enc->n_stereo_streams++;
598         mapped += 2;
599         positions_done[p0] = positions_done[p1] = TRUE;
600       }
601     }
602 
603     /* Now add all other input channels as mono streams */
604     for (n = 0; n < enc->n_channels; ++n) {
605       GstAudioChannelPosition position = GST_AUDIO_INFO_POSITION (info, n);
606 
607       /* if we already mapped it while searching for pairs, nothing else
608          needs to be done */
609       if (!positions_done[position]) {
610         int cv;
611         GST_DEBUG_OBJECT (enc, "Channel position %s is not mapped yet, adding",
612             gst_opus_channel_names[position]);
613         cv = gst_opus_enc_find_channel_position_in_vorbis_order (enc, position);
614         if (cv < 0)
615           g_assert_not_reached ();
616         enc->encoding_channel_mapping[mapped] = n;
617         enc->decoding_channel_mapping[cv] = mapped;
618         mapped++;
619       }
620     }
621 
622 #ifndef GST_DISABLE_GST_DEBUG
623     GST_INFO_OBJECT (enc,
624         "Mapping tables built: %d channels, %d stereo streams", enc->n_channels,
625         enc->n_stereo_streams);
626     gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
627         "Encoding mapping table", enc->n_channels,
628         enc->encoding_channel_mapping);
629     gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
630         "Decoding mapping table", enc->n_channels,
631         enc->decoding_channel_mapping);
632 #endif
633 
634     enc->channel_mapping_family = 1;
635     return;
636   }
637 
638   /* More than 8 channels, if future mappings are added for those */
639 
640   /* For other cases, we use undefined, with the default trivial mapping
641      and all mono streams */
642   if (!enc->unpositioned)
643     GST_WARNING_OBJECT (enc, "Unknown mapping");
644   else
645     GST_INFO_OBJECT (enc, "Unpositioned mapping, all channels mono");
646 
647   enc->channel_mapping_family = 255;
648   enc->n_stereo_streams = 0;
649 
650 #undef MAPS
651 }
652 
653 static gboolean
gst_opus_enc_set_format(GstAudioEncoder * benc,GstAudioInfo * info)654 gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
655 {
656   GstOpusEnc *enc;
657 
658   enc = GST_OPUS_ENC (benc);
659 
660   g_mutex_lock (&enc->property_lock);
661 
662   enc->n_channels = GST_AUDIO_INFO_CHANNELS (info);
663   enc->unpositioned = GST_AUDIO_INFO_IS_UNPOSITIONED (info);
664   enc->sample_rate = GST_AUDIO_INFO_RATE (info);
665   gst_opus_enc_setup_channel_mappings (enc, info);
666   GST_DEBUG_OBJECT (benc, "Setup with %d channels, %d Hz", enc->n_channels,
667       enc->sample_rate);
668 
669   /* handle reconfigure */
670   if (enc->state) {
671     opus_multistream_encoder_destroy (enc->state);
672     enc->state = NULL;
673   }
674   if (!gst_opus_enc_setup (enc)) {
675     g_mutex_unlock (&enc->property_lock);
676     return FALSE;
677   }
678 
679   /* update the tags */
680   gst_opus_enc_set_tags (enc);
681 
682   enc->frame_samples = gst_opus_enc_get_frame_samples (enc);
683 
684   /* feedback to base class */
685   gst_opus_enc_setup_base_class (enc, benc);
686 
687   g_mutex_unlock (&enc->property_lock);
688 
689   return TRUE;
690 }
691 
692 static gboolean
gst_opus_enc_setup(GstOpusEnc * enc)693 gst_opus_enc_setup (GstOpusEnc * enc)
694 {
695   int error = OPUS_OK;
696   GstCaps *caps;
697   gboolean ret;
698   gint32 lookahead;
699   const GstTagList *tags;
700   GstTagList *empty_tags = NULL;
701   GstBuffer *header, *comments;
702 
703 #ifndef GST_DISABLE_GST_DEBUG
704   GST_DEBUG_OBJECT (enc,
705       "setup: %d Hz, %d channels, %d stereo streams, family %d",
706       enc->sample_rate, enc->n_channels, enc->n_stereo_streams,
707       enc->channel_mapping_family);
708   GST_INFO_OBJECT (enc, "Mapping tables built: %d channels, %d stereo streams",
709       enc->n_channels, enc->n_stereo_streams);
710   gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
711       "Encoding mapping table", enc->n_channels, enc->encoding_channel_mapping);
712   gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
713       "Decoding mapping table", enc->n_channels, enc->decoding_channel_mapping);
714 #endif
715 
716   enc->state = opus_multistream_encoder_create (enc->sample_rate,
717       enc->n_channels, enc->n_channels - enc->n_stereo_streams,
718       enc->n_stereo_streams, enc->encoding_channel_mapping,
719       enc->audio_type, &error);
720   if (!enc->state || error != OPUS_OK)
721     goto encoder_creation_failed;
722 
723   opus_multistream_encoder_ctl (enc->state, OPUS_SET_BITRATE (enc->bitrate), 0);
724   opus_multistream_encoder_ctl (enc->state, OPUS_SET_BANDWIDTH (enc->bandwidth),
725       0);
726   opus_multistream_encoder_ctl (enc->state,
727       OPUS_SET_VBR (enc->bitrate_type != BITRATE_TYPE_CBR), 0);
728   opus_multistream_encoder_ctl (enc->state,
729       OPUS_SET_VBR_CONSTRAINT (enc->bitrate_type ==
730           BITRATE_TYPE_CONSTRAINED_VBR), 0);
731   opus_multistream_encoder_ctl (enc->state,
732       OPUS_SET_COMPLEXITY (enc->complexity), 0);
733   opus_multistream_encoder_ctl (enc->state,
734       OPUS_SET_INBAND_FEC (enc->inband_fec), 0);
735   opus_multistream_encoder_ctl (enc->state, OPUS_SET_DTX (enc->dtx), 0);
736   opus_multistream_encoder_ctl (enc->state,
737       OPUS_SET_PACKET_LOSS_PERC (enc->packet_loss_percentage), 0);
738 
739   opus_multistream_encoder_ctl (enc->state, OPUS_GET_LOOKAHEAD (&lookahead), 0);
740 
741   GST_LOG_OBJECT (enc, "we have frame size %d, lookahead %d", enc->frame_size,
742       lookahead);
743 
744   /* lookahead is samples, the Opus header wants it in 48kHz samples */
745   lookahead = lookahead * 48000 / enc->sample_rate;
746   enc->lookahead = enc->pending_lookahead = lookahead;
747 
748   header = gst_codec_utils_opus_create_header (enc->sample_rate,
749       enc->n_channels, enc->channel_mapping_family,
750       enc->n_channels - enc->n_stereo_streams, enc->n_stereo_streams,
751       enc->decoding_channel_mapping, lookahead, 0);
752   tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
753   if (!tags)
754     tags = empty_tags = gst_tag_list_new_empty ();
755   comments =
756       gst_tag_list_to_vorbiscomment_buffer (tags, (const guint8 *) "OpusTags",
757       8, "Encoded with GStreamer opusenc");
758   caps = gst_codec_utils_opus_create_caps_from_header (header, comments);
759   if (empty_tags)
760     gst_tag_list_unref (empty_tags);
761   gst_buffer_unref (header);
762   gst_buffer_unref (comments);
763 
764   /* negotiate with these caps */
765   GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
766 
767   ret = gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (enc), caps);
768   gst_caps_unref (caps);
769 
770   return ret;
771 
772 encoder_creation_failed:
773   GST_ERROR_OBJECT (enc, "Encoder creation failed");
774   return FALSE;
775 }
776 
777 static gboolean
gst_opus_enc_sink_event(GstAudioEncoder * benc,GstEvent * event)778 gst_opus_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
779 {
780   GstOpusEnc *enc;
781 
782   enc = GST_OPUS_ENC (benc);
783 
784   GST_DEBUG_OBJECT (enc, "sink event: %s", GST_EVENT_TYPE_NAME (event));
785   switch (GST_EVENT_TYPE (event)) {
786     case GST_EVENT_TAG:
787     {
788       GstTagList *list;
789       GstTagSetter *setter = GST_TAG_SETTER (enc);
790       const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
791 
792       gst_event_parse_tag (event, &list);
793       gst_tag_setter_merge_tags (setter, list, mode);
794       break;
795     }
796     case GST_EVENT_SEGMENT:
797       enc->encoded_samples = 0;
798       enc->consumed_samples = 0;
799       break;
800 
801     default:
802       break;
803   }
804 
805   return GST_AUDIO_ENCODER_CLASS (parent_class)->sink_event (benc, event);
806 }
807 
808 static GstCaps *
gst_opus_enc_get_sink_template_caps(void)809 gst_opus_enc_get_sink_template_caps (void)
810 {
811   static volatile gsize init = 0;
812   static GstCaps *caps = NULL;
813 
814   if (g_once_init_enter (&init)) {
815     GValue rate_array = G_VALUE_INIT;
816     GValue v = G_VALUE_INIT;
817     GstStructure *s1, *s2, *s;
818     gint i, c;
819 
820     caps = gst_caps_new_empty ();
821 
822     /* The caps is cached */
823     GST_MINI_OBJECT_FLAG_SET (caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
824 
825     /* Generate our two template structures */
826     g_value_init (&rate_array, GST_TYPE_LIST);
827     g_value_init (&v, G_TYPE_INT);
828     g_value_set_int (&v, 8000);
829     gst_value_list_append_value (&rate_array, &v);
830     g_value_set_int (&v, 12000);
831     gst_value_list_append_value (&rate_array, &v);
832     g_value_set_int (&v, 16000);
833     gst_value_list_append_value (&rate_array, &v);
834     g_value_set_int (&v, 24000);
835     gst_value_list_append_value (&rate_array, &v);
836 
837     s1 = gst_structure_new ("audio/x-raw",
838         "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
839         "layout", G_TYPE_STRING, "interleaved",
840         "rate", G_TYPE_INT, 48000, NULL);
841     s2 = gst_structure_new ("audio/x-raw",
842         "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
843         "layout", G_TYPE_STRING, "interleaved", NULL);
844     gst_structure_set_value (s2, "rate", &rate_array);
845     g_value_unset (&rate_array);
846     g_value_unset (&v);
847 
848     /* Mono */
849     s = gst_structure_copy (s1);
850     gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
851     gst_caps_append_structure (caps, s);
852 
853     s = gst_structure_copy (s2);
854     gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL);
855     gst_caps_append_structure (caps, s);
856 
857     /* Stereo and further */
858     for (i = 2; i <= 8; i++) {
859       guint64 channel_mask = 0;
860       const GstAudioChannelPosition *pos = gst_opus_channel_positions[i - 1];
861 
862       for (c = 0; c < i; c++) {
863         channel_mask |= G_GUINT64_CONSTANT (1) << pos[c];
864       }
865 
866       s = gst_structure_copy (s1);
867       gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
868           GST_TYPE_BITMASK, channel_mask, NULL);
869       gst_caps_append_structure (caps, s);
870 
871       s = gst_structure_copy (s2);
872       gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
873           GST_TYPE_BITMASK, channel_mask, NULL);
874       gst_caps_append_structure (caps, s);
875 
876       /* We also allow unpositioned channels, input will be
877        * treated as a set of individual mono channels */
878       s = gst_structure_copy (s2);
879       gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
880           GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
881       gst_caps_append_structure (caps, s);
882 
883       s = gst_structure_copy (s1);
884       gst_structure_set (s, "channels", G_TYPE_INT, i, "channel-mask",
885           GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
886       gst_caps_append_structure (caps, s);
887     }
888 
889     gst_structure_free (s1);
890     gst_structure_free (s2);
891 
892     g_once_init_leave (&init, 1);
893   }
894 
895   return caps;
896 }
897 
898 static GstCaps *
gst_opus_enc_sink_getcaps(GstAudioEncoder * benc,GstCaps * filter)899 gst_opus_enc_sink_getcaps (GstAudioEncoder * benc, GstCaps * filter)
900 {
901   GstOpusEnc *enc;
902   GstCaps *caps;
903 
904   enc = GST_OPUS_ENC (benc);
905 
906   GST_DEBUG_OBJECT (enc, "sink getcaps");
907 
908   caps = gst_opus_enc_get_sink_template_caps ();
909   caps = gst_audio_encoder_proxy_getcaps (benc, caps, filter);
910 
911   GST_DEBUG_OBJECT (enc, "Returning caps: %" GST_PTR_FORMAT, caps);
912 
913   return caps;
914 }
915 
916 static GstFlowReturn
gst_opus_enc_encode(GstOpusEnc * enc,GstBuffer * buf)917 gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
918 {
919   guint8 *bdata = NULL, *data, *mdata = NULL;
920   gsize bsize, size;
921   gsize bytes;
922   gint ret = GST_FLOW_OK;
923   GstMapInfo map;
924   GstMapInfo omap;
925   gint outsize;
926   GstBuffer *outbuf;
927   guint64 trim_start = 0, trim_end = 0;
928 
929   guint max_payload_size;
930   gint frame_samples, input_samples, output_samples;
931 
932   g_mutex_lock (&enc->property_lock);
933 
934   bytes = enc->frame_samples * enc->n_channels * 2;
935   max_payload_size = enc->max_payload_size;
936   frame_samples = input_samples = enc->frame_samples;
937 
938   g_mutex_unlock (&enc->property_lock);
939 
940   if (G_LIKELY (buf)) {
941     gst_buffer_map (buf, &map, GST_MAP_READ);
942     bdata = map.data;
943     bsize = map.size;
944 
945     if (G_UNLIKELY (bsize % bytes)) {
946       gint64 diff;
947 
948       GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
949       g_assert (bsize < bytes);
950 
951       input_samples = bsize / (enc->n_channels * 2);
952       diff =
953           (enc->encoded_samples + frame_samples) - (enc->consumed_samples +
954           input_samples);
955       if (diff >= 0) {
956         GST_DEBUG_OBJECT (enc,
957             "%" G_GINT64_FORMAT " extra samples of padding in this frame",
958             diff);
959         output_samples = frame_samples - diff;
960         trim_end = diff * 48000 / enc->sample_rate;
961       } else {
962         GST_DEBUG_OBJECT (enc,
963             "Need to add %" G_GINT64_FORMAT " extra samples in the next frame",
964             -diff);
965         output_samples = frame_samples;
966       }
967 
968       size = ((bsize / bytes) + 1) * bytes;
969       mdata = g_malloc0 (size);
970       /* FIXME: Instead of silence, use LPC with the last real samples.
971        * Otherwise we will create a discontinuity here, which will distort the
972        * last few encoded samples
973        */
974       memcpy (mdata, bdata, bsize);
975       data = mdata;
976     } else {
977       data = bdata;
978       size = bsize;
979 
980       /* Adjust for lookahead here */
981       if (enc->pending_lookahead) {
982         guint scaled_lookahead =
983             enc->pending_lookahead * enc->sample_rate / 48000;
984 
985         if (input_samples > scaled_lookahead) {
986           output_samples = input_samples - scaled_lookahead;
987           trim_start = enc->pending_lookahead;
988           enc->pending_lookahead = 0;
989         } else {
990           trim_start = ((guint64) input_samples) * 48000 / enc->sample_rate;
991           enc->pending_lookahead -= trim_start;
992           output_samples = 0;
993         }
994       } else {
995         output_samples = input_samples;
996       }
997     }
998   } else {
999     if (enc->encoded_samples < enc->consumed_samples) {
1000       /* FIXME: Instead of silence, use LPC with the last real samples.
1001        * Otherwise we will create a discontinuity here, which will distort the
1002        * last few encoded samples
1003        */
1004       data = mdata = g_malloc0 (bytes);
1005       size = bytes;
1006       output_samples = enc->consumed_samples - enc->encoded_samples;
1007       input_samples = 0;
1008       GST_DEBUG_OBJECT (enc, "draining %d samples", output_samples);
1009       trim_end =
1010           ((guint64) frame_samples - output_samples) * 48000 / enc->sample_rate;
1011     } else if (enc->encoded_samples == enc->consumed_samples) {
1012       GST_DEBUG_OBJECT (enc, "nothing to drain");
1013       goto done;
1014     } else {
1015       g_assert_not_reached ();
1016       goto done;
1017     }
1018   }
1019 
1020   g_assert (size == bytes);
1021 
1022   outbuf =
1023       gst_audio_encoder_allocate_output_buffer (GST_AUDIO_ENCODER (enc),
1024       max_payload_size * enc->n_channels);
1025   if (!outbuf)
1026     goto done;
1027 
1028   GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)",
1029       frame_samples, (int) bytes);
1030 
1031   if (trim_start || trim_end) {
1032     GST_DEBUG_OBJECT (enc,
1033         "Adding trim-start %" G_GUINT64_FORMAT " trim-end %" G_GUINT64_FORMAT,
1034         trim_start, trim_end);
1035     gst_buffer_add_audio_clipping_meta (outbuf, GST_FORMAT_DEFAULT, trim_start,
1036         trim_end);
1037   }
1038 
1039   gst_buffer_map (outbuf, &omap, GST_MAP_WRITE);
1040 
1041   outsize =
1042       opus_multistream_encode (enc->state, (const gint16 *) data,
1043       frame_samples, omap.data, max_payload_size * enc->n_channels);
1044 
1045   gst_buffer_unmap (outbuf, &omap);
1046 
1047   if (outsize < 0) {
1048     GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1049         ("Encoding failed (%d): %s", outsize, opus_strerror (outsize)));
1050     ret = GST_FLOW_ERROR;
1051     goto done;
1052   } else if (outsize > max_payload_size) {
1053     GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
1054         ("Encoded size %d is higher than max payload size (%d bytes)",
1055             outsize, max_payload_size));
1056     ret = GST_FLOW_ERROR;
1057     goto done;
1058   }
1059 
1060   GST_DEBUG_OBJECT (enc, "Output packet is %u bytes", outsize);
1061   gst_buffer_set_size (outbuf, outsize);
1062 
1063 
1064   ret =
1065       gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc), outbuf,
1066       output_samples);
1067   enc->encoded_samples += output_samples;
1068   enc->consumed_samples += input_samples;
1069 
1070 done:
1071 
1072   if (bdata)
1073     gst_buffer_unmap (buf, &map);
1074 
1075   g_free (mdata);
1076 
1077   return ret;
1078 }
1079 
1080 static GstFlowReturn
gst_opus_enc_handle_frame(GstAudioEncoder * benc,GstBuffer * buf)1081 gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
1082 {
1083   GstOpusEnc *enc;
1084   GstFlowReturn ret = GST_FLOW_OK;
1085 
1086   enc = GST_OPUS_ENC (benc);
1087   GST_DEBUG_OBJECT (enc, "handle_frame");
1088   GST_DEBUG_OBJECT (enc, "received buffer %p of %" G_GSIZE_FORMAT " bytes", buf,
1089       buf ? gst_buffer_get_size (buf) : 0);
1090 
1091   ret = gst_opus_enc_encode (enc, buf);
1092 
1093   return ret;
1094 }
1095 
1096 static void
gst_opus_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1097 gst_opus_enc_get_property (GObject * object, guint prop_id, GValue * value,
1098     GParamSpec * pspec)
1099 {
1100   GstOpusEnc *enc;
1101 
1102   enc = GST_OPUS_ENC (object);
1103 
1104   g_mutex_lock (&enc->property_lock);
1105 
1106   switch (prop_id) {
1107     case PROP_AUDIO_TYPE:
1108       g_value_set_enum (value, enc->audio_type);
1109       break;
1110     case PROP_BITRATE:
1111       g_value_set_int (value, enc->bitrate);
1112       break;
1113     case PROP_BANDWIDTH:
1114       g_value_set_enum (value, enc->bandwidth);
1115       break;
1116     case PROP_FRAME_SIZE:
1117       g_value_set_enum (value, enc->frame_size);
1118       break;
1119     case PROP_BITRATE_TYPE:
1120       g_value_set_enum (value, enc->bitrate_type);
1121       break;
1122     case PROP_COMPLEXITY:
1123       g_value_set_int (value, enc->complexity);
1124       break;
1125     case PROP_INBAND_FEC:
1126       g_value_set_boolean (value, enc->inband_fec);
1127       break;
1128     case PROP_DTX:
1129       g_value_set_boolean (value, enc->dtx);
1130       break;
1131     case PROP_PACKET_LOSS_PERCENT:
1132       g_value_set_int (value, enc->packet_loss_percentage);
1133       break;
1134     case PROP_MAX_PAYLOAD_SIZE:
1135       g_value_set_uint (value, enc->max_payload_size);
1136       break;
1137     default:
1138       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1139       break;
1140   }
1141 
1142   g_mutex_unlock (&enc->property_lock);
1143 }
1144 
1145 static void
gst_opus_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1146 gst_opus_enc_set_property (GObject * object, guint prop_id,
1147     const GValue * value, GParamSpec * pspec)
1148 {
1149   GstOpusEnc *enc;
1150 
1151   enc = GST_OPUS_ENC (object);
1152 
1153 #define GST_OPUS_UPDATE_PROPERTY(prop,type,ctl) do { \
1154   g_mutex_lock (&enc->property_lock); \
1155   enc->prop = g_value_get_##type (value); \
1156   if (enc->state) { \
1157     opus_multistream_encoder_ctl (enc->state, OPUS_SET_##ctl (enc->prop)); \
1158   } \
1159   g_mutex_unlock (&enc->property_lock); \
1160 } while(0)
1161 
1162   switch (prop_id) {
1163     case PROP_AUDIO_TYPE:
1164       enc->audio_type = g_value_get_enum (value);
1165       break;
1166     case PROP_BITRATE:
1167       GST_OPUS_UPDATE_PROPERTY (bitrate, int, BITRATE);
1168       break;
1169     case PROP_BANDWIDTH:
1170       GST_OPUS_UPDATE_PROPERTY (bandwidth, enum, BANDWIDTH);
1171       break;
1172     case PROP_FRAME_SIZE:
1173       g_mutex_lock (&enc->property_lock);
1174       enc->frame_size = g_value_get_enum (value);
1175       enc->frame_samples = gst_opus_enc_get_frame_samples (enc);
1176       gst_opus_enc_setup_base_class (enc, GST_AUDIO_ENCODER (enc));
1177       g_mutex_unlock (&enc->property_lock);
1178       break;
1179     case PROP_BITRATE_TYPE:
1180       /* this one has an opposite meaning to the opus ctl... */
1181       g_mutex_lock (&enc->property_lock);
1182       enc->bitrate_type = g_value_get_enum (value);
1183       if (enc->state) {
1184         opus_multistream_encoder_ctl (enc->state,
1185             OPUS_SET_VBR (enc->bitrate_type != BITRATE_TYPE_CBR));
1186         opus_multistream_encoder_ctl (enc->state,
1187             OPUS_SET_VBR_CONSTRAINT (enc->bitrate_type ==
1188                 BITRATE_TYPE_CONSTRAINED_VBR), 0);
1189       }
1190       g_mutex_unlock (&enc->property_lock);
1191       break;
1192     case PROP_COMPLEXITY:
1193       GST_OPUS_UPDATE_PROPERTY (complexity, int, COMPLEXITY);
1194       break;
1195     case PROP_INBAND_FEC:
1196       GST_OPUS_UPDATE_PROPERTY (inband_fec, boolean, INBAND_FEC);
1197       break;
1198     case PROP_DTX:
1199       GST_OPUS_UPDATE_PROPERTY (dtx, boolean, DTX);
1200       break;
1201     case PROP_PACKET_LOSS_PERCENT:
1202       GST_OPUS_UPDATE_PROPERTY (packet_loss_percentage, int, PACKET_LOSS_PERC);
1203       break;
1204     case PROP_MAX_PAYLOAD_SIZE:
1205       g_mutex_lock (&enc->property_lock);
1206       enc->max_payload_size = g_value_get_uint (value);
1207       g_mutex_unlock (&enc->property_lock);
1208       break;
1209     default:
1210       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1211       break;
1212   }
1213 
1214 #undef GST_OPUS_UPDATE_PROPERTY
1215 
1216 }
1217