153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright (C) 2020 Asymptotic <sanchayan@asymptotic.io> 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 853a5a1b3Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of the 953a5a1b3Sopenharmony_ci License, or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public 1753a5a1b3Sopenharmony_ci License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 2553a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 2653a5a1b3Sopenharmony_ci#include <pulsecore/once.h> 2753a5a1b3Sopenharmony_ci#include <pulse/sample.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <arpa/inet.h> 3053a5a1b3Sopenharmony_ci 3153a5a1b3Sopenharmony_ci#include "a2dp-codecs.h" 3253a5a1b3Sopenharmony_ci#include "a2dp-codec-api.h" 3353a5a1b3Sopenharmony_ci#include "a2dp-codec-gst.h" 3453a5a1b3Sopenharmony_ci#include "rtp.h" 3553a5a1b3Sopenharmony_ci 3653a5a1b3Sopenharmony_cistatic bool can_be_supported(bool for_encoding) { 3753a5a1b3Sopenharmony_ci GstElementFactory *element_factory; 3853a5a1b3Sopenharmony_ci 3953a5a1b3Sopenharmony_ci if (!for_encoding) 4053a5a1b3Sopenharmony_ci return false; 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci element_factory = gst_element_factory_find("ldacenc"); 4353a5a1b3Sopenharmony_ci if (element_factory == NULL) { 4453a5a1b3Sopenharmony_ci pa_log_info("LDAC encoder element `ldacenc` not found"); 4553a5a1b3Sopenharmony_ci return false; 4653a5a1b3Sopenharmony_ci } 4753a5a1b3Sopenharmony_ci gst_object_unref(element_factory); 4853a5a1b3Sopenharmony_ci 4953a5a1b3Sopenharmony_ci return true; 5053a5a1b3Sopenharmony_ci} 5153a5a1b3Sopenharmony_ci 5253a5a1b3Sopenharmony_cistatic bool can_accept_capabilities_common(const a2dp_ldac_t *capabilities, uint32_t vendor_id, uint16_t codec_id) { 5353a5a1b3Sopenharmony_ci if (A2DP_GET_VENDOR_ID(capabilities->info) != vendor_id || A2DP_GET_CODEC_ID(capabilities->info) != codec_id) 5453a5a1b3Sopenharmony_ci return false; 5553a5a1b3Sopenharmony_ci 5653a5a1b3Sopenharmony_ci if (!(capabilities->frequency & (LDAC_SAMPLING_FREQ_44100 | LDAC_SAMPLING_FREQ_48000 | 5753a5a1b3Sopenharmony_ci LDAC_SAMPLING_FREQ_88200 | LDAC_SAMPLING_FREQ_96000))) 5853a5a1b3Sopenharmony_ci return false; 5953a5a1b3Sopenharmony_ci 6053a5a1b3Sopenharmony_ci if (!(capabilities->channel_mode & LDAC_CHANNEL_MODE_STEREO)) 6153a5a1b3Sopenharmony_ci return false; 6253a5a1b3Sopenharmony_ci 6353a5a1b3Sopenharmony_ci return true; 6453a5a1b3Sopenharmony_ci} 6553a5a1b3Sopenharmony_ci 6653a5a1b3Sopenharmony_cistatic bool can_accept_capabilities(const uint8_t *capabilities_buffer, uint8_t capabilities_size, bool for_encoding) { 6753a5a1b3Sopenharmony_ci const a2dp_ldac_t *capabilities = (const a2dp_ldac_t *) capabilities_buffer; 6853a5a1b3Sopenharmony_ci 6953a5a1b3Sopenharmony_ci if (capabilities_size != sizeof(*capabilities)) 7053a5a1b3Sopenharmony_ci return false; 7153a5a1b3Sopenharmony_ci 7253a5a1b3Sopenharmony_ci return can_accept_capabilities_common(capabilities, LDAC_VENDOR_ID, LDAC_CODEC_ID); 7353a5a1b3Sopenharmony_ci} 7453a5a1b3Sopenharmony_ci 7553a5a1b3Sopenharmony_cistatic const char *choose_remote_endpoint(const pa_hashmap *capabilities_hashmap, const pa_sample_spec *default_sample_spec, bool for_encoding) { 7653a5a1b3Sopenharmony_ci const pa_a2dp_codec_capabilities *a2dp_capabilities; 7753a5a1b3Sopenharmony_ci const char *key; 7853a5a1b3Sopenharmony_ci void *state; 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_ci /* There is no preference, just choose random valid entry */ 8153a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, capabilities_hashmap, state) { 8253a5a1b3Sopenharmony_ci if (can_accept_capabilities(a2dp_capabilities->buffer, a2dp_capabilities->size, for_encoding)) 8353a5a1b3Sopenharmony_ci return key; 8453a5a1b3Sopenharmony_ci } 8553a5a1b3Sopenharmony_ci 8653a5a1b3Sopenharmony_ci return NULL; 8753a5a1b3Sopenharmony_ci} 8853a5a1b3Sopenharmony_ci 8953a5a1b3Sopenharmony_cistatic void fill_capabilities_common(a2dp_ldac_t *capabilities, uint32_t vendor_id, uint16_t codec_id) { 9053a5a1b3Sopenharmony_ci capabilities->info = A2DP_SET_VENDOR_ID_CODEC_ID(vendor_id, codec_id); 9153a5a1b3Sopenharmony_ci capabilities->channel_mode = LDAC_CHANNEL_MODE_STEREO; 9253a5a1b3Sopenharmony_ci capabilities->frequency = LDAC_SAMPLING_FREQ_44100 | LDAC_SAMPLING_FREQ_48000 | 9353a5a1b3Sopenharmony_ci LDAC_SAMPLING_FREQ_88200 | LDAC_SAMPLING_FREQ_96000; 9453a5a1b3Sopenharmony_ci} 9553a5a1b3Sopenharmony_ci 9653a5a1b3Sopenharmony_cistatic uint8_t fill_capabilities(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) { 9753a5a1b3Sopenharmony_ci a2dp_ldac_t *capabilities = (a2dp_ldac_t *) capabilities_buffer; 9853a5a1b3Sopenharmony_ci 9953a5a1b3Sopenharmony_ci pa_zero(*capabilities); 10053a5a1b3Sopenharmony_ci fill_capabilities_common(capabilities, LDAC_VENDOR_ID, LDAC_CODEC_ID); 10153a5a1b3Sopenharmony_ci return sizeof(*capabilities); 10253a5a1b3Sopenharmony_ci} 10353a5a1b3Sopenharmony_ci 10453a5a1b3Sopenharmony_cistatic bool is_configuration_valid(const uint8_t *config_buffer, uint8_t config_size) { 10553a5a1b3Sopenharmony_ci const a2dp_ldac_t *config = (const a2dp_ldac_t *) config_buffer; 10653a5a1b3Sopenharmony_ci 10753a5a1b3Sopenharmony_ci if (config_size != sizeof(*config)) { 10853a5a1b3Sopenharmony_ci pa_log_error("Invalid size of config buffer"); 10953a5a1b3Sopenharmony_ci return false; 11053a5a1b3Sopenharmony_ci } 11153a5a1b3Sopenharmony_ci 11253a5a1b3Sopenharmony_ci if (A2DP_GET_VENDOR_ID(config->info) != LDAC_VENDOR_ID || A2DP_GET_CODEC_ID(config->info) != LDAC_CODEC_ID) { 11353a5a1b3Sopenharmony_ci pa_log_error("Invalid vendor codec information in configuration"); 11453a5a1b3Sopenharmony_ci return false; 11553a5a1b3Sopenharmony_ci } 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_ci if (config->frequency != LDAC_SAMPLING_FREQ_44100 && config->frequency != LDAC_SAMPLING_FREQ_48000 && 11853a5a1b3Sopenharmony_ci config->frequency != LDAC_SAMPLING_FREQ_88200 && config->frequency != LDAC_SAMPLING_FREQ_96000) { 11953a5a1b3Sopenharmony_ci pa_log_error("Invalid sampling frequency in configuration"); 12053a5a1b3Sopenharmony_ci return false; 12153a5a1b3Sopenharmony_ci } 12253a5a1b3Sopenharmony_ci 12353a5a1b3Sopenharmony_ci if (config->channel_mode != LDAC_CHANNEL_MODE_STEREO) { 12453a5a1b3Sopenharmony_ci pa_log_error("Invalid channel mode in configuration"); 12553a5a1b3Sopenharmony_ci return false; 12653a5a1b3Sopenharmony_ci } 12753a5a1b3Sopenharmony_ci 12853a5a1b3Sopenharmony_ci return true; 12953a5a1b3Sopenharmony_ci} 13053a5a1b3Sopenharmony_ci 13153a5a1b3Sopenharmony_cistatic int fill_preferred_configuration_common(const pa_sample_spec *default_sample_spec, const a2dp_ldac_t *capabilities, a2dp_ldac_t *config, uint32_t vendor_id, uint16_t codec_id) { 13253a5a1b3Sopenharmony_ci int i; 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci static const struct { 13553a5a1b3Sopenharmony_ci uint32_t rate; 13653a5a1b3Sopenharmony_ci uint8_t cap; 13753a5a1b3Sopenharmony_ci } freq_table[] = { 13853a5a1b3Sopenharmony_ci { 44100U, LDAC_SAMPLING_FREQ_44100 }, 13953a5a1b3Sopenharmony_ci { 48000U, LDAC_SAMPLING_FREQ_48000 }, 14053a5a1b3Sopenharmony_ci { 88200U, LDAC_SAMPLING_FREQ_88200 }, 14153a5a1b3Sopenharmony_ci { 96000U, LDAC_SAMPLING_FREQ_96000 } 14253a5a1b3Sopenharmony_ci }; 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_ci if (A2DP_GET_VENDOR_ID(capabilities->info) != LDAC_VENDOR_ID || A2DP_GET_CODEC_ID(capabilities->info) != LDAC_CODEC_ID) { 14553a5a1b3Sopenharmony_ci pa_log_error("No supported vendor codec information"); 14653a5a1b3Sopenharmony_ci return -1; 14753a5a1b3Sopenharmony_ci } 14853a5a1b3Sopenharmony_ci 14953a5a1b3Sopenharmony_ci config->info = A2DP_SET_VENDOR_ID_CODEC_ID(vendor_id, codec_id); 15053a5a1b3Sopenharmony_ci 15153a5a1b3Sopenharmony_ci if (!(capabilities->channel_mode & LDAC_CHANNEL_MODE_STEREO)) { 15253a5a1b3Sopenharmony_ci pa_log_error("No supported channel modes"); 15353a5a1b3Sopenharmony_ci return -1; 15453a5a1b3Sopenharmony_ci } 15553a5a1b3Sopenharmony_ci 15653a5a1b3Sopenharmony_ci config->channel_mode = LDAC_CHANNEL_MODE_STEREO; 15753a5a1b3Sopenharmony_ci 15853a5a1b3Sopenharmony_ci /* Find the lowest freq that is at least as high as the requested sampling rate */ 15953a5a1b3Sopenharmony_ci for (i = 0; (unsigned) i < PA_ELEMENTSOF(freq_table); i++) { 16053a5a1b3Sopenharmony_ci if (freq_table[i].rate >= default_sample_spec->rate && (capabilities->frequency & freq_table[i].cap)) { 16153a5a1b3Sopenharmony_ci config->frequency = freq_table[i].cap; 16253a5a1b3Sopenharmony_ci break; 16353a5a1b3Sopenharmony_ci } 16453a5a1b3Sopenharmony_ci } 16553a5a1b3Sopenharmony_ci 16653a5a1b3Sopenharmony_ci if ((unsigned) i == PA_ELEMENTSOF(freq_table)) { 16753a5a1b3Sopenharmony_ci for (--i; i >= 0; i--) { 16853a5a1b3Sopenharmony_ci if (capabilities->frequency & freq_table[i].cap) { 16953a5a1b3Sopenharmony_ci config->frequency = freq_table[i].cap; 17053a5a1b3Sopenharmony_ci break; 17153a5a1b3Sopenharmony_ci } 17253a5a1b3Sopenharmony_ci } 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_ci if (i < 0) { 17553a5a1b3Sopenharmony_ci pa_log_error("Not suitable sample rate"); 17653a5a1b3Sopenharmony_ci return false; 17753a5a1b3Sopenharmony_ci } 17853a5a1b3Sopenharmony_ci } 17953a5a1b3Sopenharmony_ci 18053a5a1b3Sopenharmony_ci return 0; 18153a5a1b3Sopenharmony_ci} 18253a5a1b3Sopenharmony_ci 18353a5a1b3Sopenharmony_cistatic uint8_t fill_preferred_configuration(const pa_sample_spec *default_sample_spec, const uint8_t *capabilities_buffer, uint8_t capabilities_size, uint8_t config_buffer[MAX_A2DP_CAPS_SIZE]) { 18453a5a1b3Sopenharmony_ci a2dp_ldac_t *config = (a2dp_ldac_t *) config_buffer; 18553a5a1b3Sopenharmony_ci const a2dp_ldac_t *capabilities = (const a2dp_ldac_t *) capabilities_buffer; 18653a5a1b3Sopenharmony_ci 18753a5a1b3Sopenharmony_ci if (capabilities_size != sizeof(*capabilities)) { 18853a5a1b3Sopenharmony_ci pa_log_error("Invalid size of capabilities buffer"); 18953a5a1b3Sopenharmony_ci return 0; 19053a5a1b3Sopenharmony_ci } 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_ci pa_zero(*config); 19353a5a1b3Sopenharmony_ci 19453a5a1b3Sopenharmony_ci if (fill_preferred_configuration_common(default_sample_spec, capabilities, config, LDAC_VENDOR_ID, LDAC_CODEC_ID) < 0) 19553a5a1b3Sopenharmony_ci return 0; 19653a5a1b3Sopenharmony_ci 19753a5a1b3Sopenharmony_ci return sizeof(*config); 19853a5a1b3Sopenharmony_ci} 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ciGstElement *gst_init_ldac(struct gst_info *info, pa_sample_spec *ss, bool for_encoding) { 20153a5a1b3Sopenharmony_ci GstElement *bin; 20253a5a1b3Sopenharmony_ci GstElement *enc; 20353a5a1b3Sopenharmony_ci GstPad *pad; 20453a5a1b3Sopenharmony_ci 20553a5a1b3Sopenharmony_ci if (!for_encoding) { 20653a5a1b3Sopenharmony_ci pa_log_error("LDAC does not support decoding"); 20753a5a1b3Sopenharmony_ci return NULL; 20853a5a1b3Sopenharmony_ci } 20953a5a1b3Sopenharmony_ci 21053a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_FLOAT32LE; 21153a5a1b3Sopenharmony_ci 21253a5a1b3Sopenharmony_ci switch (info->a2dp_codec_t.ldac_config->frequency) { 21353a5a1b3Sopenharmony_ci case LDAC_SAMPLING_FREQ_44100: 21453a5a1b3Sopenharmony_ci ss->rate = 44100u; 21553a5a1b3Sopenharmony_ci break; 21653a5a1b3Sopenharmony_ci case LDAC_SAMPLING_FREQ_48000: 21753a5a1b3Sopenharmony_ci ss->rate = 48000u; 21853a5a1b3Sopenharmony_ci break; 21953a5a1b3Sopenharmony_ci case LDAC_SAMPLING_FREQ_88200: 22053a5a1b3Sopenharmony_ci ss->rate = 88200; 22153a5a1b3Sopenharmony_ci break; 22253a5a1b3Sopenharmony_ci case LDAC_SAMPLING_FREQ_96000: 22353a5a1b3Sopenharmony_ci ss->rate = 96000; 22453a5a1b3Sopenharmony_ci break; 22553a5a1b3Sopenharmony_ci default: 22653a5a1b3Sopenharmony_ci pa_log_error("LDAC invalid frequency %d", info->a2dp_codec_t.ldac_config->frequency); 22753a5a1b3Sopenharmony_ci goto fail; 22853a5a1b3Sopenharmony_ci } 22953a5a1b3Sopenharmony_ci 23053a5a1b3Sopenharmony_ci switch (info->a2dp_codec_t.ldac_config->channel_mode) { 23153a5a1b3Sopenharmony_ci case LDAC_CHANNEL_MODE_STEREO: 23253a5a1b3Sopenharmony_ci ss->channels = 2; 23353a5a1b3Sopenharmony_ci break; 23453a5a1b3Sopenharmony_ci case LDAC_CHANNEL_MODE_MONO: 23553a5a1b3Sopenharmony_ci ss->channels = 1; 23653a5a1b3Sopenharmony_ci break; 23753a5a1b3Sopenharmony_ci case LDAC_CHANNEL_MODE_DUAL: 23853a5a1b3Sopenharmony_ci ss->channels = 1; 23953a5a1b3Sopenharmony_ci break; 24053a5a1b3Sopenharmony_ci default: 24153a5a1b3Sopenharmony_ci pa_log_error("LDAC invalid channel mode %d", info->a2dp_codec_t.ldac_config->channel_mode); 24253a5a1b3Sopenharmony_ci goto fail; 24353a5a1b3Sopenharmony_ci } 24453a5a1b3Sopenharmony_ci 24553a5a1b3Sopenharmony_ci enc = gst_element_factory_make("ldacenc", "ldac_enc"); 24653a5a1b3Sopenharmony_ci if (!enc) { 24753a5a1b3Sopenharmony_ci pa_log_error("Could not create LDAC encoder element"); 24853a5a1b3Sopenharmony_ci goto fail; 24953a5a1b3Sopenharmony_ci } 25053a5a1b3Sopenharmony_ci 25153a5a1b3Sopenharmony_ci switch (info->codec_type) { 25253a5a1b3Sopenharmony_ci case LDAC_EQMID_HQ: 25353a5a1b3Sopenharmony_ci g_object_set(enc, "eqmid", 0, NULL); 25453a5a1b3Sopenharmony_ci break; 25553a5a1b3Sopenharmony_ci case LDAC_EQMID_SQ: 25653a5a1b3Sopenharmony_ci g_object_set(enc, "eqmid", 1, NULL); 25753a5a1b3Sopenharmony_ci break; 25853a5a1b3Sopenharmony_ci case LDAC_EQMID_MQ: 25953a5a1b3Sopenharmony_ci g_object_set(enc, "eqmid", 2, NULL); 26053a5a1b3Sopenharmony_ci break; 26153a5a1b3Sopenharmony_ci default: 26253a5a1b3Sopenharmony_ci goto fail; 26353a5a1b3Sopenharmony_ci } 26453a5a1b3Sopenharmony_ci 26553a5a1b3Sopenharmony_ci bin = gst_bin_new("ldac_enc_bin"); 26653a5a1b3Sopenharmony_ci pa_assert(bin); 26753a5a1b3Sopenharmony_ci 26853a5a1b3Sopenharmony_ci gst_bin_add_many(GST_BIN(bin), enc, NULL); 26953a5a1b3Sopenharmony_ci 27053a5a1b3Sopenharmony_ci pad = gst_element_get_static_pad(enc, "sink"); 27153a5a1b3Sopenharmony_ci pa_assert_se(gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad))); 27253a5a1b3Sopenharmony_ci gst_object_unref(GST_OBJECT(pad)); 27353a5a1b3Sopenharmony_ci 27453a5a1b3Sopenharmony_ci pad = gst_element_get_static_pad(enc, "src"); 27553a5a1b3Sopenharmony_ci pa_assert_se(gst_element_add_pad(bin, gst_ghost_pad_new("src", pad))); 27653a5a1b3Sopenharmony_ci gst_object_unref(GST_OBJECT(pad)); 27753a5a1b3Sopenharmony_ci 27853a5a1b3Sopenharmony_ci return bin; 27953a5a1b3Sopenharmony_ci 28053a5a1b3Sopenharmony_cifail: 28153a5a1b3Sopenharmony_ci pa_log_error("LDAC encoder initialisation failed"); 28253a5a1b3Sopenharmony_ci return NULL; 28353a5a1b3Sopenharmony_ci} 28453a5a1b3Sopenharmony_ci 28553a5a1b3Sopenharmony_cistatic void *init_common(enum a2dp_codec_type codec_type, bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) { 28653a5a1b3Sopenharmony_ci GstElement *bin; 28753a5a1b3Sopenharmony_ci struct gst_info *info = NULL; 28853a5a1b3Sopenharmony_ci 28953a5a1b3Sopenharmony_ci if (!for_encoding) { 29053a5a1b3Sopenharmony_ci pa_log_error("LDAC decoder not supported"); 29153a5a1b3Sopenharmony_ci return NULL; 29253a5a1b3Sopenharmony_ci } 29353a5a1b3Sopenharmony_ci 29453a5a1b3Sopenharmony_ci info = pa_xnew0(struct gst_info, 1); 29553a5a1b3Sopenharmony_ci pa_assert(info); 29653a5a1b3Sopenharmony_ci 29753a5a1b3Sopenharmony_ci info->core = core; 29853a5a1b3Sopenharmony_ci info->ss = sample_spec; 29953a5a1b3Sopenharmony_ci 30053a5a1b3Sopenharmony_ci info->codec_type = codec_type; 30153a5a1b3Sopenharmony_ci info->a2dp_codec_t.ldac_config = (const a2dp_ldac_t *) config_buffer; 30253a5a1b3Sopenharmony_ci pa_assert(config_size == sizeof(*(info->a2dp_codec_t.ldac_config))); 30353a5a1b3Sopenharmony_ci 30453a5a1b3Sopenharmony_ci if (!(bin = gst_init_ldac(info, sample_spec, for_encoding))) 30553a5a1b3Sopenharmony_ci goto fail; 30653a5a1b3Sopenharmony_ci 30753a5a1b3Sopenharmony_ci if (!gst_codec_init(info, for_encoding, bin)) 30853a5a1b3Sopenharmony_ci goto fail; 30953a5a1b3Sopenharmony_ci 31053a5a1b3Sopenharmony_ci return info; 31153a5a1b3Sopenharmony_ci 31253a5a1b3Sopenharmony_cifail: 31353a5a1b3Sopenharmony_ci if (info) 31453a5a1b3Sopenharmony_ci pa_xfree(info); 31553a5a1b3Sopenharmony_ci 31653a5a1b3Sopenharmony_ci return NULL; 31753a5a1b3Sopenharmony_ci} 31853a5a1b3Sopenharmony_ci 31953a5a1b3Sopenharmony_cistatic void *init_hq(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) { 32053a5a1b3Sopenharmony_ci return init_common(LDAC_EQMID_HQ, for_encoding, for_backchannel, config_buffer, config_size, sample_spec, core); 32153a5a1b3Sopenharmony_ci} 32253a5a1b3Sopenharmony_ci 32353a5a1b3Sopenharmony_cistatic void *init_sq(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) { 32453a5a1b3Sopenharmony_ci return init_common(LDAC_EQMID_SQ, for_encoding, for_backchannel, config_buffer, config_size, sample_spec, core); 32553a5a1b3Sopenharmony_ci} 32653a5a1b3Sopenharmony_ci 32753a5a1b3Sopenharmony_cistatic void *init_mq(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) { 32853a5a1b3Sopenharmony_ci return init_common(LDAC_EQMID_MQ, for_encoding, for_backchannel, config_buffer, config_size, sample_spec, core); 32953a5a1b3Sopenharmony_ci} 33053a5a1b3Sopenharmony_ci 33153a5a1b3Sopenharmony_cistatic void deinit(void *codec_info) { 33253a5a1b3Sopenharmony_ci return gst_codec_deinit(codec_info); 33353a5a1b3Sopenharmony_ci} 33453a5a1b3Sopenharmony_ci 33553a5a1b3Sopenharmony_cistatic int reset(void *codec_info) { 33653a5a1b3Sopenharmony_ci return 0; 33753a5a1b3Sopenharmony_ci} 33853a5a1b3Sopenharmony_ci 33953a5a1b3Sopenharmony_cistatic uint32_t get_ldac_num_samples(void *codec_info) { 34053a5a1b3Sopenharmony_ci struct gst_info *info = (struct gst_info *) codec_info; 34153a5a1b3Sopenharmony_ci 34253a5a1b3Sopenharmony_ci switch (info->a2dp_codec_t.ldac_config->frequency) { 34353a5a1b3Sopenharmony_ci case LDAC_SAMPLING_FREQ_44100: 34453a5a1b3Sopenharmony_ci case LDAC_SAMPLING_FREQ_48000: 34553a5a1b3Sopenharmony_ci return 128; 34653a5a1b3Sopenharmony_ci break; 34753a5a1b3Sopenharmony_ci case LDAC_SAMPLING_FREQ_88200: 34853a5a1b3Sopenharmony_ci case LDAC_SAMPLING_FREQ_96000: 34953a5a1b3Sopenharmony_ci return 256; 35053a5a1b3Sopenharmony_ci break; 35153a5a1b3Sopenharmony_ci default: 35253a5a1b3Sopenharmony_ci break; 35353a5a1b3Sopenharmony_ci } 35453a5a1b3Sopenharmony_ci 35553a5a1b3Sopenharmony_ci return 128; 35653a5a1b3Sopenharmony_ci} 35753a5a1b3Sopenharmony_ci 35853a5a1b3Sopenharmony_cistatic uint8_t get_ldac_num_frames(void *codec_info, enum a2dp_codec_type codec_type) { 35953a5a1b3Sopenharmony_ci struct gst_info *info = (struct gst_info *) codec_info; 36053a5a1b3Sopenharmony_ci uint8_t channels; 36153a5a1b3Sopenharmony_ci 36253a5a1b3Sopenharmony_ci switch (info->a2dp_codec_t.ldac_config->channel_mode) { 36353a5a1b3Sopenharmony_ci case LDAC_CHANNEL_MODE_STEREO: 36453a5a1b3Sopenharmony_ci channels = 2; 36553a5a1b3Sopenharmony_ci break; 36653a5a1b3Sopenharmony_ci case LDAC_CHANNEL_MODE_MONO: 36753a5a1b3Sopenharmony_ci case LDAC_CHANNEL_MODE_DUAL: 36853a5a1b3Sopenharmony_ci channels = 1; 36953a5a1b3Sopenharmony_ci break; 37053a5a1b3Sopenharmony_ci default: 37153a5a1b3Sopenharmony_ci break; 37253a5a1b3Sopenharmony_ci } 37353a5a1b3Sopenharmony_ci 37453a5a1b3Sopenharmony_ci switch (codec_type) { 37553a5a1b3Sopenharmony_ci case LDAC_EQMID_HQ: 37653a5a1b3Sopenharmony_ci return 4 / channels; 37753a5a1b3Sopenharmony_ci case LDAC_EQMID_SQ: 37853a5a1b3Sopenharmony_ci return 6 / channels; 37953a5a1b3Sopenharmony_ci case LDAC_EQMID_MQ: 38053a5a1b3Sopenharmony_ci return 12 / channels; 38153a5a1b3Sopenharmony_ci default: 38253a5a1b3Sopenharmony_ci break; 38353a5a1b3Sopenharmony_ci } 38453a5a1b3Sopenharmony_ci 38553a5a1b3Sopenharmony_ci return 6 / channels; 38653a5a1b3Sopenharmony_ci} 38753a5a1b3Sopenharmony_ci 38853a5a1b3Sopenharmony_cistatic size_t get_block_size(void *codec_info, size_t link_mtu) { 38953a5a1b3Sopenharmony_ci struct gst_info *info = (struct gst_info *) codec_info; 39053a5a1b3Sopenharmony_ci 39153a5a1b3Sopenharmony_ci return get_ldac_num_samples(codec_info) * get_ldac_num_frames(codec_info, info->codec_type) * pa_frame_size(info->ss); 39253a5a1b3Sopenharmony_ci} 39353a5a1b3Sopenharmony_ci 39453a5a1b3Sopenharmony_cistatic size_t get_encoded_block_size(void *codec_info, size_t input_size) { 39553a5a1b3Sopenharmony_ci /* encoded block size is not exactly known, report input_size */ 39653a5a1b3Sopenharmony_ci return input_size; 39753a5a1b3Sopenharmony_ci} 39853a5a1b3Sopenharmony_ci 39953a5a1b3Sopenharmony_cistatic size_t reduce_encoder_bitrate(void *codec_info, size_t write_link_mtu) { 40053a5a1b3Sopenharmony_ci return 0; 40153a5a1b3Sopenharmony_ci} 40253a5a1b3Sopenharmony_ci 40353a5a1b3Sopenharmony_cistatic size_t encode_buffer(void *codec_info, uint32_t timestamp, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) { 40453a5a1b3Sopenharmony_ci struct gst_info *info = (struct gst_info *) codec_info; 40553a5a1b3Sopenharmony_ci struct rtp_header *header; 40653a5a1b3Sopenharmony_ci struct rtp_payload *payload; 40753a5a1b3Sopenharmony_ci size_t written; 40853a5a1b3Sopenharmony_ci 40953a5a1b3Sopenharmony_ci if (PA_UNLIKELY(output_size < sizeof(*header) + sizeof(*payload))) { 41053a5a1b3Sopenharmony_ci *processed = 0; 41153a5a1b3Sopenharmony_ci return 0; 41253a5a1b3Sopenharmony_ci } 41353a5a1b3Sopenharmony_ci 41453a5a1b3Sopenharmony_ci written = gst_transcode_buffer(codec_info, timestamp, input_buffer, input_size, output_buffer + sizeof(*header) + sizeof(*payload), output_size - sizeof(*header) - sizeof(*payload), processed); 41553a5a1b3Sopenharmony_ci if (PA_UNLIKELY(*processed != input_size)) 41653a5a1b3Sopenharmony_ci pa_log_error("LDAC encoding error"); 41753a5a1b3Sopenharmony_ci 41853a5a1b3Sopenharmony_ci if (PA_LIKELY(written > 0)) { 41953a5a1b3Sopenharmony_ci header = (struct rtp_header *) output_buffer; 42053a5a1b3Sopenharmony_ci pa_zero(*header); 42153a5a1b3Sopenharmony_ci header->v = 2; 42253a5a1b3Sopenharmony_ci header->pt = 96; 42353a5a1b3Sopenharmony_ci header->sequence_number = htons(info->seq_num++); 42453a5a1b3Sopenharmony_ci header->timestamp = htonl(timestamp); 42553a5a1b3Sopenharmony_ci header->ssrc = htonl(1); 42653a5a1b3Sopenharmony_ci payload = (struct rtp_payload*) (output_buffer + sizeof(*header)); 42753a5a1b3Sopenharmony_ci payload->frame_count = get_ldac_num_frames(codec_info, info->codec_type); 42853a5a1b3Sopenharmony_ci written += sizeof(*header) + sizeof(*payload); 42953a5a1b3Sopenharmony_ci } 43053a5a1b3Sopenharmony_ci 43153a5a1b3Sopenharmony_ci return written; 43253a5a1b3Sopenharmony_ci} 43353a5a1b3Sopenharmony_ci 43453a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_hq = { 43553a5a1b3Sopenharmony_ci .id = { A2DP_CODEC_VENDOR, LDAC_VENDOR_ID, LDAC_CODEC_ID }, 43653a5a1b3Sopenharmony_ci .support_backchannel = false, 43753a5a1b3Sopenharmony_ci .can_be_supported = can_be_supported, 43853a5a1b3Sopenharmony_ci .can_accept_capabilities = can_accept_capabilities, 43953a5a1b3Sopenharmony_ci .choose_remote_endpoint = choose_remote_endpoint, 44053a5a1b3Sopenharmony_ci .fill_capabilities = fill_capabilities, 44153a5a1b3Sopenharmony_ci .is_configuration_valid = is_configuration_valid, 44253a5a1b3Sopenharmony_ci .fill_preferred_configuration = fill_preferred_configuration, 44353a5a1b3Sopenharmony_ci .bt_codec = { 44453a5a1b3Sopenharmony_ci .name = "ldac_hq", 44553a5a1b3Sopenharmony_ci .description = "LDAC (High Quality)", 44653a5a1b3Sopenharmony_ci .init = init_hq, 44753a5a1b3Sopenharmony_ci .deinit = deinit, 44853a5a1b3Sopenharmony_ci .reset = reset, 44953a5a1b3Sopenharmony_ci .get_read_block_size = get_block_size, 45053a5a1b3Sopenharmony_ci .get_write_block_size = get_block_size, 45153a5a1b3Sopenharmony_ci .get_encoded_block_size = get_encoded_block_size, 45253a5a1b3Sopenharmony_ci .reduce_encoder_bitrate = reduce_encoder_bitrate, 45353a5a1b3Sopenharmony_ci .encode_buffer = encode_buffer, 45453a5a1b3Sopenharmony_ci }, 45553a5a1b3Sopenharmony_ci}; 45653a5a1b3Sopenharmony_ci 45753a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_sq = { 45853a5a1b3Sopenharmony_ci .id = { A2DP_CODEC_VENDOR, LDAC_VENDOR_ID, LDAC_CODEC_ID }, 45953a5a1b3Sopenharmony_ci .support_backchannel = false, 46053a5a1b3Sopenharmony_ci .can_be_supported = can_be_supported, 46153a5a1b3Sopenharmony_ci .can_accept_capabilities = can_accept_capabilities, 46253a5a1b3Sopenharmony_ci .choose_remote_endpoint = choose_remote_endpoint, 46353a5a1b3Sopenharmony_ci .fill_capabilities = fill_capabilities, 46453a5a1b3Sopenharmony_ci .is_configuration_valid = is_configuration_valid, 46553a5a1b3Sopenharmony_ci .fill_preferred_configuration = fill_preferred_configuration, 46653a5a1b3Sopenharmony_ci .bt_codec = { 46753a5a1b3Sopenharmony_ci .name = "ldac_sq", 46853a5a1b3Sopenharmony_ci .description = "LDAC (Standard Quality)", 46953a5a1b3Sopenharmony_ci .init = init_sq, 47053a5a1b3Sopenharmony_ci .deinit = deinit, 47153a5a1b3Sopenharmony_ci .reset = reset, 47253a5a1b3Sopenharmony_ci .get_read_block_size = get_block_size, 47353a5a1b3Sopenharmony_ci .get_write_block_size = get_block_size, 47453a5a1b3Sopenharmony_ci .get_encoded_block_size = get_encoded_block_size, 47553a5a1b3Sopenharmony_ci .reduce_encoder_bitrate = reduce_encoder_bitrate, 47653a5a1b3Sopenharmony_ci .encode_buffer = encode_buffer, 47753a5a1b3Sopenharmony_ci }, 47853a5a1b3Sopenharmony_ci}; 47953a5a1b3Sopenharmony_ci 48053a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_mq = { 48153a5a1b3Sopenharmony_ci .id = { A2DP_CODEC_VENDOR, LDAC_VENDOR_ID, LDAC_CODEC_ID }, 48253a5a1b3Sopenharmony_ci .support_backchannel = false, 48353a5a1b3Sopenharmony_ci .can_be_supported = can_be_supported, 48453a5a1b3Sopenharmony_ci .can_accept_capabilities = can_accept_capabilities, 48553a5a1b3Sopenharmony_ci .choose_remote_endpoint = choose_remote_endpoint, 48653a5a1b3Sopenharmony_ci .fill_capabilities = fill_capabilities, 48753a5a1b3Sopenharmony_ci .is_configuration_valid = is_configuration_valid, 48853a5a1b3Sopenharmony_ci .fill_preferred_configuration = fill_preferred_configuration, 48953a5a1b3Sopenharmony_ci .bt_codec = { 49053a5a1b3Sopenharmony_ci .name = "ldac_mq", 49153a5a1b3Sopenharmony_ci .description = "LDAC (Mobile Quality)", 49253a5a1b3Sopenharmony_ci .init = init_mq, 49353a5a1b3Sopenharmony_ci .deinit = deinit, 49453a5a1b3Sopenharmony_ci .reset = reset, 49553a5a1b3Sopenharmony_ci .get_read_block_size = get_block_size, 49653a5a1b3Sopenharmony_ci .get_write_block_size = get_block_size, 49753a5a1b3Sopenharmony_ci .get_encoded_block_size = get_encoded_block_size, 49853a5a1b3Sopenharmony_ci .reduce_encoder_bitrate = reduce_encoder_bitrate, 49953a5a1b3Sopenharmony_ci .encode_buffer = encode_buffer, 50053a5a1b3Sopenharmony_ci }, 50153a5a1b3Sopenharmony_ci}; 502