• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*  GStreamer LDAC audio encoder
2  *  Copyright (C) 2020 Asymptotic <sanchayan@asymptotic.io>
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2.1 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  */
19 
20 /**
21  * SECTION:element-ldacenc
22  * @title: ldacenc
23  *
24  * This element encodes raw integer PCM audio into a Bluetooth LDAC audio.
25  *
26  * ## Example pipeline
27  * |[
28  * gst-launch-1.0 -v audiotestsrc ! ldacenc ! rtpldacpay mtu=679 ! avdtpsink
29  * ]| Encode a sine wave into LDAC, RTP payload it and send over bluetooth
30  *
31  * Since: 1.20
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37 
38 #include <string.h>
39 
40 #include "gstldacenc.h"
41 
42 /*
43  * MTU size required for LDAC A2DP streaming. Required for initializing the
44  * encoder.
45  */
46 #define GST_LDAC_MTU_REQUIRED    679
47 
48 GST_DEBUG_CATEGORY_STATIC (ldac_enc_debug);
49 #define GST_CAT_DEFAULT ldac_enc_debug
50 
51 #define parent_class gst_ldac_enc_parent_class
52 G_DEFINE_TYPE (GstLdacEnc, gst_ldac_enc, GST_TYPE_AUDIO_ENCODER);
53 GST_ELEMENT_REGISTER_DEFINE (ldacenc, "ldacenc", GST_RANK_NONE,
54     GST_TYPE_LDAC_ENC);
55 
56 #define SAMPLE_RATES "44100, 48000, 88200, 96000"
57 
58 static GstStaticPadTemplate ldac_enc_sink_factory =
59 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
60     GST_STATIC_CAPS
61     ("audio/x-raw, format=(string) { S16LE, S24LE, S32LE, F32LE }, "
62         "rate = (int) { " SAMPLE_RATES " }, channels = (int) [ 1, 2 ] "));
63 
64 static GstStaticPadTemplate ldac_enc_src_factory =
65     GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
66     GST_STATIC_CAPS ("audio/x-ldac, "
67         "rate = (int) { " SAMPLE_RATES " }, "
68         "channels = (int) 1, channel-mode = (string)mono; "
69         "audio/x-ldac, "
70         "rate = (int) { " SAMPLE_RATES " }, "
71         "channels = (int) 2, channel-mode = (string) { dual, stereo }"));
72 
73 enum
74 {
75   PROP_0,
76   PROP_EQMID
77 };
78 
79 static void gst_ldac_enc_get_property (GObject * object,
80     guint property_id, GValue * value, GParamSpec * pspec);
81 static void gst_ldac_enc_set_property (GObject * object,
82     guint property_id, const GValue * value, GParamSpec * pspec);
83 
84 static gboolean gst_ldac_enc_start (GstAudioEncoder * enc);
85 static gboolean gst_ldac_enc_stop (GstAudioEncoder * enc);
86 static gboolean gst_ldac_enc_set_format (GstAudioEncoder * enc,
87     GstAudioInfo * info);
88 static gboolean gst_ldac_enc_negotiate (GstAudioEncoder * enc);
89 static GstFlowReturn gst_ldac_enc_handle_frame (GstAudioEncoder * enc,
90     GstBuffer * buffer);
91 static guint gst_ldac_enc_get_num_frames (guint eqmid, guint channels);
92 static guint gst_ldac_enc_get_frame_length (guint eqmid, guint channels);
93 static guint gst_ldac_enc_get_num_samples (guint rate);
94 
95 #define GST_LDAC_EQMID (gst_ldac_eqmid_get_type ())
96 static GType
gst_ldac_eqmid_get_type(void)97 gst_ldac_eqmid_get_type (void)
98 {
99   static GType ldac_eqmid_type = 0;
100   static const GEnumValue eqmid_types[] = {
101     {GST_LDAC_EQMID_HQ, "HQ", "hq"},
102     {GST_LDAC_EQMID_SQ, "SQ", "sq"},
103     {GST_LDAC_EQMID_MQ, "MQ", "mq"},
104     {0, NULL, NULL}
105   };
106 
107   if (!ldac_eqmid_type)
108     ldac_eqmid_type = g_enum_register_static ("GstLdacEqmid", eqmid_types);
109 
110   return ldac_eqmid_type;
111 }
112 
113 static void
gst_ldac_enc_class_init(GstLdacEncClass * klass)114 gst_ldac_enc_class_init (GstLdacEncClass * klass)
115 {
116   GstAudioEncoderClass *encoder_class = GST_AUDIO_ENCODER_CLASS (klass);
117   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
118   GObjectClass *gobject_class = (GObjectClass *) klass;
119 
120   gobject_class->set_property = gst_ldac_enc_set_property;
121   gobject_class->get_property = gst_ldac_enc_get_property;
122 
123   encoder_class->start = GST_DEBUG_FUNCPTR (gst_ldac_enc_start);
124   encoder_class->stop = GST_DEBUG_FUNCPTR (gst_ldac_enc_stop);
125   encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_ldac_enc_set_format);
126   encoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_ldac_enc_handle_frame);
127   encoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_ldac_enc_negotiate);
128 
129   g_object_class_install_property (gobject_class, PROP_EQMID,
130       g_param_spec_enum ("eqmid", "Encode Quality Mode Index",
131           "Encode Quality Mode Index. 0: High Quality 1: Standard Quality "
132           "2: Mobile Use Quality", GST_LDAC_EQMID,
133           GST_LDAC_EQMID_SQ, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
134 
135   gst_element_class_add_static_pad_template (element_class,
136       &ldac_enc_sink_factory);
137   gst_element_class_add_static_pad_template (element_class,
138       &ldac_enc_src_factory);
139 
140   gst_element_class_set_static_metadata (element_class,
141       "Bluetooth LDAC audio encoder", "Codec/Encoder/Audio",
142       "Encode an LDAC audio stream",
143       "Sanchayan Maity <sanchayan@asymptotic.io>");
144 
145   GST_DEBUG_CATEGORY_INIT (ldac_enc_debug, "ldacenc", 0,
146       "LDAC encoding element");
147 }
148 
149 static void
gst_ldac_enc_init(GstLdacEnc * self)150 gst_ldac_enc_init (GstLdacEnc * self)
151 {
152   GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (self));
153   self->eqmid = GST_LDAC_EQMID_SQ;
154   self->channel_mode = 0;
155   self->init_done = FALSE;
156 }
157 
158 static void
gst_ldac_enc_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)159 gst_ldac_enc_set_property (GObject * object, guint property_id,
160     const GValue * value, GParamSpec * pspec)
161 {
162   GstLdacEnc *self = GST_LDAC_ENC (object);
163 
164   switch (property_id) {
165     case PROP_EQMID:
166       self->eqmid = g_value_get_enum (value);
167       break;
168     default:
169       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
170       break;
171   }
172 }
173 
174 static void
gst_ldac_enc_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)175 gst_ldac_enc_get_property (GObject * object, guint property_id,
176     GValue * value, GParamSpec * pspec)
177 {
178   GstLdacEnc *self = GST_LDAC_ENC (object);
179 
180   switch (property_id) {
181     case PROP_EQMID:
182       g_value_set_enum (value, self->eqmid);
183       break;
184     default:
185       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
186       break;
187   }
188 }
189 
190 static GstCaps *
gst_ldac_enc_do_negotiate(GstAudioEncoder * audio_enc)191 gst_ldac_enc_do_negotiate (GstAudioEncoder * audio_enc)
192 {
193   GstLdacEnc *enc = GST_LDAC_ENC (audio_enc);
194   GstCaps *caps, *filter_caps;
195   GstCaps *output_caps = NULL;
196   GstStructure *s;
197 
198   /* Negotiate output format based on downstream caps restrictions */
199   caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (enc));
200 
201   if (caps == NULL)
202     caps = gst_static_pad_template_get_caps (&ldac_enc_src_factory);
203   else if (gst_caps_is_empty (caps))
204     goto failure;
205 
206   /* Fixate output caps */
207   filter_caps = gst_caps_new_simple ("audio/x-ldac", "rate", G_TYPE_INT,
208       enc->rate, "channels", G_TYPE_INT, enc->channels, NULL);
209   output_caps = gst_caps_intersect (caps, filter_caps);
210   gst_caps_unref (filter_caps);
211 
212   if (output_caps == NULL || gst_caps_is_empty (output_caps)) {
213     GST_WARNING_OBJECT (enc, "Couldn't negotiate output caps with input rate "
214         "%d and input channels %d and allowed output caps %" GST_PTR_FORMAT,
215         enc->rate, enc->channels, caps);
216     goto failure;
217   }
218 
219   gst_clear_caps (&caps);
220 
221   GST_DEBUG_OBJECT (enc, "fixating caps %" GST_PTR_FORMAT, output_caps);
222   output_caps = gst_caps_truncate (output_caps);
223   s = gst_caps_get_structure (output_caps, 0);
224   if (enc->channels == 1)
225     gst_structure_fixate_field_string (s, "channel-mode", "mono");
226   else
227     gst_structure_fixate_field_string (s, "channel-mode", "stereo");
228   s = NULL;
229 
230   /* In case there's anything else left to fixate */
231   output_caps = gst_caps_fixate (output_caps);
232   gst_caps_set_simple (output_caps, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
233 
234   /* Set EQMID in caps to be used downstream by rtpldacpay */
235   gst_caps_set_simple (output_caps, "eqmid", G_TYPE_INT, enc->eqmid, NULL);
236 
237   GST_INFO_OBJECT (enc, "output caps %" GST_PTR_FORMAT, output_caps);
238 
239   if (enc->channels == 1)
240     enc->channel_mode = LDACBT_CHANNEL_MODE_MONO;
241   else
242     enc->channel_mode = LDACBT_CHANNEL_MODE_STEREO;
243 
244   return output_caps;
245 
246 failure:
247   if (output_caps)
248     gst_caps_unref (output_caps);
249   if (caps)
250     gst_caps_unref (caps);
251   return NULL;
252 }
253 
254 static gboolean
gst_ldac_enc_negotiate(GstAudioEncoder * audio_enc)255 gst_ldac_enc_negotiate (GstAudioEncoder * audio_enc)
256 {
257   GstLdacEnc *enc = GST_LDAC_ENC (audio_enc);
258   GstCaps *output_caps = NULL;
259 
260   output_caps = gst_ldac_enc_do_negotiate (audio_enc);
261   if (output_caps == NULL) {
262     GST_ERROR_OBJECT (enc, "failed to negotiate");
263     return FALSE;
264   }
265 
266   if (!gst_audio_encoder_set_output_format (audio_enc, output_caps)) {
267     GST_ERROR_OBJECT (enc, "failed to configure output caps on src pad");
268     gst_caps_unref (output_caps);
269     return FALSE;
270   }
271   gst_caps_unref (output_caps);
272 
273   return GST_AUDIO_ENCODER_CLASS (parent_class)->negotiate (audio_enc);
274 }
275 
276 static gboolean
gst_ldac_enc_set_format(GstAudioEncoder * audio_enc,GstAudioInfo * info)277 gst_ldac_enc_set_format (GstAudioEncoder * audio_enc, GstAudioInfo * info)
278 {
279   GstLdacEnc *enc = GST_LDAC_ENC (audio_enc);
280   GstCaps *output_caps = NULL;
281   guint num_ldac_frames, num_samples;
282   gint ret = 0;
283 
284   enc->rate = GST_AUDIO_INFO_RATE (info);
285   enc->channels = GST_AUDIO_INFO_CHANNELS (info);
286 
287   switch (GST_AUDIO_INFO_FORMAT (info)) {
288     case GST_AUDIO_FORMAT_S16:
289       enc->ldac_fmt = LDACBT_SMPL_FMT_S16;
290       break;
291     case GST_AUDIO_FORMAT_S24:
292       enc->ldac_fmt = LDACBT_SMPL_FMT_S24;
293       break;
294     case GST_AUDIO_FORMAT_S32:
295       enc->ldac_fmt = LDACBT_SMPL_FMT_S32;
296       break;
297     case GST_AUDIO_FORMAT_F32:
298       enc->ldac_fmt = LDACBT_SMPL_FMT_F32;
299       break;
300     default:
301       GST_ERROR_OBJECT (enc, "Invalid audio format");
302       return FALSE;
303   }
304 
305   output_caps = gst_ldac_enc_do_negotiate (audio_enc);
306   if (output_caps == NULL) {
307     GST_ERROR_OBJECT (enc, "failed to negotiate");
308     return FALSE;
309   }
310 
311   if (!gst_audio_encoder_set_output_format (audio_enc, output_caps)) {
312     GST_ERROR_OBJECT (enc, "failed to configure output caps on src pad");
313     gst_caps_unref (output_caps);
314     return FALSE;
315   }
316   gst_caps_unref (output_caps);
317 
318   num_samples = gst_ldac_enc_get_num_samples (enc->rate);
319   num_ldac_frames = gst_ldac_enc_get_num_frames (enc->eqmid, enc->channels);
320   gst_audio_encoder_set_frame_samples_min (audio_enc,
321       num_samples * num_ldac_frames);
322 
323   /*
324    * If initialisation was already done means caps have changed, close the
325    * handle. Closed handle can be initialised and used again.
326    */
327   if (enc->init_done) {
328     ldacBT_close_handle (enc->ldac);
329     enc->init_done = FALSE;
330   }
331 
332   /*
333    * libldac exposes a bluetooth centric API and emits multiple LDAC frames
334    * depending on the MTU. The MTU is required for LDAC A2DP streaming, is
335    * inclusive of the RTP header and is required by the encoder. The internal
336    * encoder API is not exposed in the public interface.
337    */
338   ret =
339       ldacBT_init_handle_encode (enc->ldac, GST_LDAC_MTU_REQUIRED, enc->eqmid,
340       enc->channel_mode, enc->ldac_fmt, enc->rate);
341   if (ret != 0) {
342     GST_ERROR_OBJECT (enc, "Failed to initialize LDAC handle, ret: %d", ret);
343     return FALSE;
344   }
345   enc->init_done = TRUE;
346 
347   return TRUE;
348 }
349 
350 static GstFlowReturn
gst_ldac_enc_handle_frame(GstAudioEncoder * audio_enc,GstBuffer * buffer)351 gst_ldac_enc_handle_frame (GstAudioEncoder * audio_enc, GstBuffer * buffer)
352 {
353   GstLdacEnc *enc = GST_LDAC_ENC (audio_enc);
354   GstMapInfo in_map, out_map;
355   GstAudioInfo *info;
356   GstBuffer *outbuf;
357   const guint8 *in_data;
358   guint8 *out_data;
359   gint encoded, to_encode = 0;
360   gint samples_consumed = 0;
361   guint frames, frame_len;
362   guint ldac_enc_read = 0;
363   guint frame_count = 0;
364 
365   if (buffer == NULL)
366     return GST_FLOW_OK;
367 
368   if (!gst_buffer_map (buffer, &in_map, GST_MAP_READ)) {
369     GST_ELEMENT_ERROR (audio_enc, STREAM, FAILED, (NULL),
370         ("Failed to map data from input buffer"));
371     return GST_FLOW_ERROR;
372   }
373 
374   info = gst_audio_encoder_get_audio_info (audio_enc);
375   ldac_enc_read = LDACBT_ENC_LSU * info->bpf;
376   /*
377    * We may produce extra frames at the end of encoding process (See below).
378    * Consider some additional frames while allocating output buffer if this
379    * happens.
380    */
381   frames = (in_map.size / ldac_enc_read) + 4;
382 
383   frame_len = gst_ldac_enc_get_frame_length (enc->eqmid, info->channels);
384   outbuf = gst_audio_encoder_allocate_output_buffer (audio_enc,
385       frames * frame_len);
386   if (outbuf == NULL)
387     goto no_buffer;
388 
389   gst_buffer_map (outbuf, &out_map, GST_MAP_WRITE);
390   in_data = in_map.data;
391   out_data = out_map.data;
392   to_encode = in_map.size;
393 
394   /*
395    * ldacBT_encode does not generate an output frame each time it is called.
396    * For each invocation, it consumes number of sample * bpf bytes of data.
397    * Depending on the eqmid setting and channels, it will emit multiple frames
398    * only after the required number of frames are packed for payloading. Below
399    * for loop exists primarily to handle this.
400    */
401   for (;;) {
402     guint8 pcm[LDACBT_MAX_LSU * 4 /* bytes/sample */  * 2 /* ch */ ] = { 0 };
403     gint ldac_frame_num, written;
404     guint8 *inp_data = NULL;
405     gboolean done = FALSE;
406     gint ret;
407 
408     /*
409      * Even with minimum frame samples specified in set_format with EOS,
410      * we may get a buffer which is not a multiple of LDACBT_ENC_LSU. LDAC
411      * encoder always reads a multiple of this and to handle this scenario
412      * we use local PCM array and in the last iteration when buffer bytes
413      * < LDACBT_ENC_LSU * bpf, we copy only to_encode bytes to prevent
414      * walking off the end of input buffer and the rest of the bytes in
415      * PCM buffer would be zero, so should be safe from encoding point of
416      * view.
417      */
418     if (to_encode < 0) {
419       /*
420        * We got < LDACBT_ENC_LSU * bpf for last iteration. Force the encoder
421        * to encode the remaining bytes in buffer by passing NULL to the input
422        * PCM buffer argument.
423        */
424       inp_data = NULL;
425       done = TRUE;
426     } else if (to_encode >= ldac_enc_read) {
427       memcpy (pcm, in_data, ldac_enc_read);
428       inp_data = &pcm[0];
429     } else if (to_encode > 0 && to_encode < ldac_enc_read) {
430       memcpy (pcm, in_data, to_encode);
431       inp_data = &pcm[0];
432     }
433 
434     /*
435      * Note that while we do not explicitly pass length of data to library
436      * anywhere, based on the initialization considering eqmid and rate, the
437      * library will consume a fix number of samples per call. This combined
438      * with the previous step ensures that the library does not read outside
439      * of in_data and out_data.
440      */
441     ret = ldacBT_encode (enc->ldac, (void *) inp_data, &encoded,
442         (guint8 *) out_data, &written, &ldac_frame_num);
443     if (ret < 0) {
444       GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
445           ("encoding error, ret = %d written = %d", ret, ldac_frame_num));
446       goto encoding_error;
447     } else {
448       to_encode -= encoded;
449       in_data = in_data + encoded;
450       out_data = out_data + written;
451       frame_count += ldac_frame_num;
452 
453       GST_LOG_OBJECT (enc,
454           "To Encode: %d, Encoded: %d, Written: %d, LDAC Frames: %d", to_encode,
455           encoded, written, ldac_frame_num);
456 
457       if (done || (to_encode == 0 && encoded == ldac_enc_read))
458         break;
459     }
460   }
461 
462   gst_buffer_unmap (outbuf, &out_map);
463 
464   if (frame_count > 0) {
465     samples_consumed = in_map.size / info->bpf;
466     gst_buffer_set_size (outbuf, frame_count * frame_len);
467   } else {
468     samples_consumed = 0;
469     gst_buffer_replace (&outbuf, NULL);
470   }
471 
472   gst_buffer_unmap (buffer, &in_map);
473 
474   return gst_audio_encoder_finish_frame (audio_enc, outbuf, samples_consumed);
475 
476 no_buffer:
477   {
478     gst_buffer_unmap (buffer, &in_map);
479 
480     GST_ELEMENT_ERROR (enc, STREAM, FAILED, (NULL),
481         ("could not allocate output buffer"));
482 
483     return GST_FLOW_ERROR;
484   }
485 encoding_error:
486   {
487     gst_buffer_unmap (buffer, &in_map);
488 
489     ldacBT_free_handle (enc->ldac);
490 
491     enc->ldac = NULL;
492 
493     return GST_FLOW_ERROR;
494   }
495 }
496 
497 static gboolean
gst_ldac_enc_start(GstAudioEncoder * audio_enc)498 gst_ldac_enc_start (GstAudioEncoder * audio_enc)
499 {
500   GstLdacEnc *enc = GST_LDAC_ENC (audio_enc);
501 
502   GST_INFO_OBJECT (enc, "Setup LDAC codec");
503   /* Note that this only allocates the LDAC handle */
504   enc->ldac = ldacBT_get_handle ();
505   if (enc->ldac == NULL) {
506     GST_ERROR_OBJECT (enc, "Failed to get LDAC handle");
507     return FALSE;
508   }
509 
510   return TRUE;
511 }
512 
513 static gboolean
gst_ldac_enc_stop(GstAudioEncoder * audio_enc)514 gst_ldac_enc_stop (GstAudioEncoder * audio_enc)
515 {
516   GstLdacEnc *enc = GST_LDAC_ENC (audio_enc);
517 
518   GST_INFO_OBJECT (enc, "Finish LDAC codec");
519 
520   if (enc->ldac) {
521     ldacBT_free_handle (enc->ldac);
522     enc->ldac = NULL;
523   }
524 
525   enc->eqmid = GST_LDAC_EQMID_SQ;
526   enc->channel_mode = 0;
527   enc->init_done = FALSE;
528 
529   return TRUE;
530 }
531 
532 /**
533  * gst_ldac_enc_get_frame_length
534  * @eqmid: Encode Quality Mode Index
535  * @channels: Number of channels
536  *
537  * Returns: Frame length.
538  */
539 static guint
gst_ldac_enc_get_frame_length(guint eqmid,guint channels)540 gst_ldac_enc_get_frame_length (guint eqmid, guint channels)
541 {
542   g_assert (channels == 1 || channels == 2);
543 
544   switch (eqmid) {
545       /* Encode setting for High Quality */
546     case GST_LDAC_EQMID_HQ:
547       return 165 * channels;
548       /* Encode setting for Standard Quality */
549     case GST_LDAC_EQMID_SQ:
550       return 110 * channels;
551       /* Encode setting for Mobile use Quality */
552     case GST_LDAC_EQMID_MQ:
553       return 55 * channels;
554     default:
555       break;
556   }
557 
558   g_assert_not_reached ();
559 
560   /* If assertion gets compiled out */
561   return 110 * channels;
562 }
563 
564 /**
565  * gst_ldac_enc_get_num_frames
566  * @eqmid: Encode Quality Mode Index
567  * @channels: Number of channels
568  *
569  * Returns: Number of LDAC frames per packet.
570  */
571 static guint
gst_ldac_enc_get_num_frames(guint eqmid,guint channels)572 gst_ldac_enc_get_num_frames (guint eqmid, guint channels)
573 {
574   g_assert (channels == 1 || channels == 2);
575 
576   switch (eqmid) {
577       /* Encode setting for High Quality */
578     case GST_LDAC_EQMID_HQ:
579       return 4 / channels;
580       /* Encode setting for Standard Quality */
581     case GST_LDAC_EQMID_SQ:
582       return 6 / channels;
583       /* Encode setting for Mobile use Quality */
584     case GST_LDAC_EQMID_MQ:
585       return 12 / channels;
586     default:
587       break;
588   }
589 
590   g_assert_not_reached ();
591 
592   /* If assertion gets compiled out */
593   return 6 / channels;
594 }
595 
596 /**
597  * gst_ldac_enc_get_num_samples
598  * @rate: Sampling rate
599  *
600  * Number of samples in input PCM signal for encoding is fixed to
601  * LDACBT_ENC_LSU viz. 128 samples/channel and it is not affected
602  * by sampling frequency. However, frame size is 128 samples at 44.1
603  * and 48 KHz and 256 at 88.2 and 96 KHz.
604  *
605  * Returns: Number of samples / channel
606  */
607 static guint
gst_ldac_enc_get_num_samples(guint rate)608 gst_ldac_enc_get_num_samples (guint rate)
609 {
610   switch (rate) {
611     case 44100:
612     case 48000:
613       return 128;
614     case 88200:
615     case 96000:
616       return 256;
617     default:
618       break;
619   }
620 
621   g_assert_not_reached ();
622 
623   /* If assertion gets compiled out */
624   return 128;
625 }
626