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