153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2020 Sanchayan Maity <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 element_factory = gst_element_factory_find("openaptxenc"); 4153a5a1b3Sopenharmony_ci if (element_factory == NULL) { 4253a5a1b3Sopenharmony_ci pa_log_info("aptX encoder element `openaptxenc` not found"); 4353a5a1b3Sopenharmony_ci return false; 4453a5a1b3Sopenharmony_ci } 4553a5a1b3Sopenharmony_ci 4653a5a1b3Sopenharmony_ci gst_object_unref(element_factory); 4753a5a1b3Sopenharmony_ci } else { 4853a5a1b3Sopenharmony_ci element_factory = gst_element_factory_find("openaptxdec"); 4953a5a1b3Sopenharmony_ci if (element_factory == NULL) { 5053a5a1b3Sopenharmony_ci pa_log_info("aptX decoder element `openaptxdec` not found"); 5153a5a1b3Sopenharmony_ci return false; 5253a5a1b3Sopenharmony_ci } 5353a5a1b3Sopenharmony_ci 5453a5a1b3Sopenharmony_ci gst_object_unref(element_factory); 5553a5a1b3Sopenharmony_ci } 5653a5a1b3Sopenharmony_ci 5753a5a1b3Sopenharmony_ci return true; 5853a5a1b3Sopenharmony_ci} 5953a5a1b3Sopenharmony_ci 6053a5a1b3Sopenharmony_cistatic bool can_accept_capabilities_common(const a2dp_aptx_t *capabilities, uint32_t vendor_id, uint16_t codec_id) { 6153a5a1b3Sopenharmony_ci if (A2DP_GET_VENDOR_ID(capabilities->info) != vendor_id || A2DP_GET_CODEC_ID(capabilities->info) != codec_id) 6253a5a1b3Sopenharmony_ci return false; 6353a5a1b3Sopenharmony_ci 6453a5a1b3Sopenharmony_ci if (!(capabilities->frequency & (APTX_SAMPLING_FREQ_16000 | APTX_SAMPLING_FREQ_32000 | 6553a5a1b3Sopenharmony_ci APTX_SAMPLING_FREQ_44100 | APTX_SAMPLING_FREQ_48000))) 6653a5a1b3Sopenharmony_ci return false; 6753a5a1b3Sopenharmony_ci 6853a5a1b3Sopenharmony_ci if (!(capabilities->channel_mode & APTX_CHANNEL_MODE_STEREO)) 6953a5a1b3Sopenharmony_ci return false; 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_ci return true; 7253a5a1b3Sopenharmony_ci} 7353a5a1b3Sopenharmony_ci 7453a5a1b3Sopenharmony_cistatic bool can_accept_capabilities(const uint8_t *capabilities_buffer, uint8_t capabilities_size, bool for_encoding) { 7553a5a1b3Sopenharmony_ci const a2dp_aptx_t *capabilities = (const a2dp_aptx_t *) capabilities_buffer; 7653a5a1b3Sopenharmony_ci 7753a5a1b3Sopenharmony_ci if (capabilities_size != sizeof(*capabilities)) 7853a5a1b3Sopenharmony_ci return false; 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_ci return can_accept_capabilities_common(capabilities, APTX_VENDOR_ID, APTX_CODEC_ID); 8153a5a1b3Sopenharmony_ci} 8253a5a1b3Sopenharmony_ci 8353a5a1b3Sopenharmony_cistatic bool can_accept_capabilities_hd(const uint8_t *capabilities_buffer, uint8_t capabilities_size, bool for_encoding) { 8453a5a1b3Sopenharmony_ci const a2dp_aptx_hd_t *capabilities = (const a2dp_aptx_hd_t *) capabilities_buffer; 8553a5a1b3Sopenharmony_ci 8653a5a1b3Sopenharmony_ci if (capabilities_size != sizeof(*capabilities)) 8753a5a1b3Sopenharmony_ci return false; 8853a5a1b3Sopenharmony_ci 8953a5a1b3Sopenharmony_ci return can_accept_capabilities_common(&capabilities->aptx, APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID); 9053a5a1b3Sopenharmony_ci} 9153a5a1b3Sopenharmony_ci 9253a5a1b3Sopenharmony_cistatic const char *choose_remote_endpoint(const pa_hashmap *capabilities_hashmap, const pa_sample_spec *default_sample_spec, bool for_encoding) { 9353a5a1b3Sopenharmony_ci const pa_a2dp_codec_capabilities *a2dp_capabilities; 9453a5a1b3Sopenharmony_ci const char *key; 9553a5a1b3Sopenharmony_ci void *state; 9653a5a1b3Sopenharmony_ci 9753a5a1b3Sopenharmony_ci /* There is no preference, just choose random valid entry */ 9853a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, capabilities_hashmap, state) { 9953a5a1b3Sopenharmony_ci if (can_accept_capabilities(a2dp_capabilities->buffer, a2dp_capabilities->size, for_encoding)) 10053a5a1b3Sopenharmony_ci return key; 10153a5a1b3Sopenharmony_ci } 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_ci return NULL; 10453a5a1b3Sopenharmony_ci} 10553a5a1b3Sopenharmony_ci 10653a5a1b3Sopenharmony_cistatic const char *choose_remote_endpoint_hd(const pa_hashmap *capabilities_hashmap, const pa_sample_spec *default_sample_spec, bool for_encoding) { 10753a5a1b3Sopenharmony_ci const pa_a2dp_codec_capabilities *a2dp_capabilities; 10853a5a1b3Sopenharmony_ci const char *key; 10953a5a1b3Sopenharmony_ci void *state; 11053a5a1b3Sopenharmony_ci 11153a5a1b3Sopenharmony_ci /* There is no preference, just choose random valid entry */ 11253a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, capabilities_hashmap, state) { 11353a5a1b3Sopenharmony_ci if (can_accept_capabilities_hd(a2dp_capabilities->buffer, a2dp_capabilities->size, for_encoding)) 11453a5a1b3Sopenharmony_ci return key; 11553a5a1b3Sopenharmony_ci } 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_ci return NULL; 11853a5a1b3Sopenharmony_ci} 11953a5a1b3Sopenharmony_ci 12053a5a1b3Sopenharmony_cistatic void fill_capabilities_common(a2dp_aptx_t *capabilities, uint32_t vendor_id, uint16_t codec_id) { 12153a5a1b3Sopenharmony_ci capabilities->info = A2DP_SET_VENDOR_ID_CODEC_ID(vendor_id, codec_id); 12253a5a1b3Sopenharmony_ci capabilities->channel_mode = APTX_CHANNEL_MODE_STEREO; 12353a5a1b3Sopenharmony_ci capabilities->frequency = APTX_SAMPLING_FREQ_16000 | APTX_SAMPLING_FREQ_32000 | 12453a5a1b3Sopenharmony_ci APTX_SAMPLING_FREQ_44100 | APTX_SAMPLING_FREQ_48000; 12553a5a1b3Sopenharmony_ci} 12653a5a1b3Sopenharmony_ci 12753a5a1b3Sopenharmony_cistatic uint8_t fill_capabilities(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) { 12853a5a1b3Sopenharmony_ci a2dp_aptx_t *capabilities = (a2dp_aptx_t *) capabilities_buffer; 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci pa_zero(*capabilities); 13153a5a1b3Sopenharmony_ci fill_capabilities_common(capabilities, APTX_VENDOR_ID, APTX_CODEC_ID); 13253a5a1b3Sopenharmony_ci return sizeof(*capabilities); 13353a5a1b3Sopenharmony_ci} 13453a5a1b3Sopenharmony_ci 13553a5a1b3Sopenharmony_cistatic uint8_t fill_capabilities_hd(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) { 13653a5a1b3Sopenharmony_ci a2dp_aptx_hd_t *capabilities = (a2dp_aptx_hd_t *) capabilities_buffer; 13753a5a1b3Sopenharmony_ci 13853a5a1b3Sopenharmony_ci pa_zero(*capabilities); 13953a5a1b3Sopenharmony_ci fill_capabilities_common(&capabilities->aptx, APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID); 14053a5a1b3Sopenharmony_ci return sizeof(*capabilities); 14153a5a1b3Sopenharmony_ci} 14253a5a1b3Sopenharmony_ci 14353a5a1b3Sopenharmony_cistatic bool is_configuration_valid_common(const a2dp_aptx_t *config, uint32_t vendor_id, uint16_t codec_id) { 14453a5a1b3Sopenharmony_ci if (A2DP_GET_VENDOR_ID(config->info) != vendor_id || A2DP_GET_CODEC_ID(config->info) != codec_id) { 14553a5a1b3Sopenharmony_ci pa_log_error("Invalid vendor codec information in configuration"); 14653a5a1b3Sopenharmony_ci return false; 14753a5a1b3Sopenharmony_ci } 14853a5a1b3Sopenharmony_ci 14953a5a1b3Sopenharmony_ci if (config->frequency != APTX_SAMPLING_FREQ_16000 && config->frequency != APTX_SAMPLING_FREQ_32000 && 15053a5a1b3Sopenharmony_ci config->frequency != APTX_SAMPLING_FREQ_44100 && config->frequency != APTX_SAMPLING_FREQ_48000) { 15153a5a1b3Sopenharmony_ci pa_log_error("Invalid sampling frequency in configuration"); 15253a5a1b3Sopenharmony_ci return false; 15353a5a1b3Sopenharmony_ci } 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_ci if (config->channel_mode != APTX_CHANNEL_MODE_STEREO) { 15653a5a1b3Sopenharmony_ci pa_log_error("Invalid channel mode in configuration"); 15753a5a1b3Sopenharmony_ci return false; 15853a5a1b3Sopenharmony_ci } 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci return true; 16153a5a1b3Sopenharmony_ci} 16253a5a1b3Sopenharmony_ci 16353a5a1b3Sopenharmony_cistatic bool is_configuration_valid(const uint8_t *config_buffer, uint8_t config_size) { 16453a5a1b3Sopenharmony_ci const a2dp_aptx_t *config = (const a2dp_aptx_t *) config_buffer; 16553a5a1b3Sopenharmony_ci 16653a5a1b3Sopenharmony_ci if (config_size != sizeof(*config)) { 16753a5a1b3Sopenharmony_ci pa_log_error("Invalid size of config buffer"); 16853a5a1b3Sopenharmony_ci return false; 16953a5a1b3Sopenharmony_ci } 17053a5a1b3Sopenharmony_ci 17153a5a1b3Sopenharmony_ci return is_configuration_valid_common(config, APTX_VENDOR_ID, APTX_CODEC_ID); 17253a5a1b3Sopenharmony_ci} 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_cistatic bool is_configuration_valid_hd(const uint8_t *config_buffer, uint8_t config_size) { 17553a5a1b3Sopenharmony_ci const a2dp_aptx_hd_t *config = (const a2dp_aptx_hd_t *) config_buffer; 17653a5a1b3Sopenharmony_ci 17753a5a1b3Sopenharmony_ci if (config_size != sizeof(*config)) { 17853a5a1b3Sopenharmony_ci pa_log_error("Invalid size of config buffer"); 17953a5a1b3Sopenharmony_ci return false; 18053a5a1b3Sopenharmony_ci } 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_ci return is_configuration_valid_common(&config->aptx, APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID); 18353a5a1b3Sopenharmony_ci} 18453a5a1b3Sopenharmony_ci 18553a5a1b3Sopenharmony_cistatic int fill_preferred_configuration_common(const pa_sample_spec *default_sample_spec, const a2dp_aptx_t *capabilities, a2dp_aptx_t *config, uint32_t vendor_id, uint16_t codec_id) { 18653a5a1b3Sopenharmony_ci int i; 18753a5a1b3Sopenharmony_ci 18853a5a1b3Sopenharmony_ci static const struct { 18953a5a1b3Sopenharmony_ci uint32_t rate; 19053a5a1b3Sopenharmony_ci uint8_t cap; 19153a5a1b3Sopenharmony_ci } freq_table[] = { 19253a5a1b3Sopenharmony_ci { 16000U, APTX_SAMPLING_FREQ_16000 }, 19353a5a1b3Sopenharmony_ci { 32000U, APTX_SAMPLING_FREQ_32000 }, 19453a5a1b3Sopenharmony_ci { 44100U, APTX_SAMPLING_FREQ_44100 }, 19553a5a1b3Sopenharmony_ci { 48000U, APTX_SAMPLING_FREQ_48000 } 19653a5a1b3Sopenharmony_ci }; 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_ci if (A2DP_GET_VENDOR_ID(capabilities->info) != vendor_id || A2DP_GET_CODEC_ID(capabilities->info) != codec_id) { 19953a5a1b3Sopenharmony_ci pa_log_error("No supported vendor codec information"); 20053a5a1b3Sopenharmony_ci return -1; 20153a5a1b3Sopenharmony_ci } 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci config->info = A2DP_SET_VENDOR_ID_CODEC_ID(vendor_id, codec_id); 20453a5a1b3Sopenharmony_ci 20553a5a1b3Sopenharmony_ci if (!(capabilities->channel_mode & APTX_CHANNEL_MODE_STEREO)) { 20653a5a1b3Sopenharmony_ci pa_log_error("No supported channel modes"); 20753a5a1b3Sopenharmony_ci return -1; 20853a5a1b3Sopenharmony_ci } 20953a5a1b3Sopenharmony_ci 21053a5a1b3Sopenharmony_ci config->channel_mode = APTX_CHANNEL_MODE_STEREO; 21153a5a1b3Sopenharmony_ci 21253a5a1b3Sopenharmony_ci /* Find the lowest freq that is at least as high as the requested sampling rate */ 21353a5a1b3Sopenharmony_ci for (i = 0; (unsigned) i < PA_ELEMENTSOF(freq_table); i++) { 21453a5a1b3Sopenharmony_ci if (freq_table[i].rate >= default_sample_spec->rate && (capabilities->frequency & freq_table[i].cap)) { 21553a5a1b3Sopenharmony_ci config->frequency = freq_table[i].cap; 21653a5a1b3Sopenharmony_ci break; 21753a5a1b3Sopenharmony_ci } 21853a5a1b3Sopenharmony_ci } 21953a5a1b3Sopenharmony_ci 22053a5a1b3Sopenharmony_ci if ((unsigned) i == PA_ELEMENTSOF(freq_table)) { 22153a5a1b3Sopenharmony_ci for (--i; i >= 0; i--) { 22253a5a1b3Sopenharmony_ci if (capabilities->frequency & freq_table[i].cap) { 22353a5a1b3Sopenharmony_ci config->frequency = freq_table[i].cap; 22453a5a1b3Sopenharmony_ci break; 22553a5a1b3Sopenharmony_ci } 22653a5a1b3Sopenharmony_ci } 22753a5a1b3Sopenharmony_ci 22853a5a1b3Sopenharmony_ci if (i < 0) { 22953a5a1b3Sopenharmony_ci pa_log_error("Not suitable sample rate"); 23053a5a1b3Sopenharmony_ci return false; 23153a5a1b3Sopenharmony_ci } 23253a5a1b3Sopenharmony_ci } 23353a5a1b3Sopenharmony_ci 23453a5a1b3Sopenharmony_ci return 0; 23553a5a1b3Sopenharmony_ci} 23653a5a1b3Sopenharmony_ci 23753a5a1b3Sopenharmony_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]) { 23853a5a1b3Sopenharmony_ci a2dp_aptx_t *config = (a2dp_aptx_t *) config_buffer; 23953a5a1b3Sopenharmony_ci const a2dp_aptx_t *capabilities = (const a2dp_aptx_t *) capabilities_buffer; 24053a5a1b3Sopenharmony_ci 24153a5a1b3Sopenharmony_ci if (capabilities_size != sizeof(*capabilities)) { 24253a5a1b3Sopenharmony_ci pa_log_error("Invalid size of capabilities buffer"); 24353a5a1b3Sopenharmony_ci return 0; 24453a5a1b3Sopenharmony_ci } 24553a5a1b3Sopenharmony_ci 24653a5a1b3Sopenharmony_ci pa_zero(*config); 24753a5a1b3Sopenharmony_ci 24853a5a1b3Sopenharmony_ci if (fill_preferred_configuration_common(default_sample_spec, capabilities, config, APTX_VENDOR_ID, APTX_CODEC_ID) < 0) 24953a5a1b3Sopenharmony_ci return 0; 25053a5a1b3Sopenharmony_ci 25153a5a1b3Sopenharmony_ci return sizeof(*config); 25253a5a1b3Sopenharmony_ci} 25353a5a1b3Sopenharmony_ci 25453a5a1b3Sopenharmony_cistatic uint8_t fill_preferred_configuration_hd(const pa_sample_spec *default_sample_spec, const uint8_t *capabilities_buffer, uint8_t capabilities_size, uint8_t config_buffer[MAX_A2DP_CAPS_SIZE]) { 25553a5a1b3Sopenharmony_ci a2dp_aptx_hd_t *config = (a2dp_aptx_hd_t *) config_buffer; 25653a5a1b3Sopenharmony_ci const a2dp_aptx_hd_t *capabilities = (const a2dp_aptx_hd_t *) capabilities_buffer; 25753a5a1b3Sopenharmony_ci 25853a5a1b3Sopenharmony_ci if (capabilities_size != sizeof(*capabilities)) { 25953a5a1b3Sopenharmony_ci pa_log_error("Invalid size of capabilities buffer"); 26053a5a1b3Sopenharmony_ci return 0; 26153a5a1b3Sopenharmony_ci } 26253a5a1b3Sopenharmony_ci 26353a5a1b3Sopenharmony_ci pa_zero(*config); 26453a5a1b3Sopenharmony_ci 26553a5a1b3Sopenharmony_ci if (fill_preferred_configuration_common(default_sample_spec, &capabilities->aptx, &config->aptx, APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID) < 0) 26653a5a1b3Sopenharmony_ci return 0; 26753a5a1b3Sopenharmony_ci 26853a5a1b3Sopenharmony_ci return sizeof(*config); 26953a5a1b3Sopenharmony_ci} 27053a5a1b3Sopenharmony_ci 27153a5a1b3Sopenharmony_ciGstElement *gst_init_aptx(struct gst_info *info, pa_sample_spec *ss, bool for_encoding) { 27253a5a1b3Sopenharmony_ci GstElement *bin, *sink, *src, *capsf; 27353a5a1b3Sopenharmony_ci GstCaps *caps; 27453a5a1b3Sopenharmony_ci GstPad *pad; 27553a5a1b3Sopenharmony_ci const char *aptx_codec_media_type; 27653a5a1b3Sopenharmony_ci 27753a5a1b3Sopenharmony_ci ss->format = PA_SAMPLE_S24LE; 27853a5a1b3Sopenharmony_ci 27953a5a1b3Sopenharmony_ci if (info->codec_type == APTX_HD) { 28053a5a1b3Sopenharmony_ci switch (info->a2dp_codec_t.aptx_hd_config->aptx.frequency) { 28153a5a1b3Sopenharmony_ci case APTX_SAMPLING_FREQ_16000: 28253a5a1b3Sopenharmony_ci ss->rate = 16000u; 28353a5a1b3Sopenharmony_ci break; 28453a5a1b3Sopenharmony_ci case APTX_SAMPLING_FREQ_32000: 28553a5a1b3Sopenharmony_ci ss->rate = 32000u; 28653a5a1b3Sopenharmony_ci break; 28753a5a1b3Sopenharmony_ci case APTX_SAMPLING_FREQ_44100: 28853a5a1b3Sopenharmony_ci ss->rate = 44100u; 28953a5a1b3Sopenharmony_ci break; 29053a5a1b3Sopenharmony_ci case APTX_SAMPLING_FREQ_48000: 29153a5a1b3Sopenharmony_ci ss->rate = 48000u; 29253a5a1b3Sopenharmony_ci break; 29353a5a1b3Sopenharmony_ci default: 29453a5a1b3Sopenharmony_ci pa_log_error("aptX HD invalid frequency %d", info->a2dp_codec_t.aptx_hd_config->aptx.frequency); 29553a5a1b3Sopenharmony_ci goto fail; 29653a5a1b3Sopenharmony_ci } 29753a5a1b3Sopenharmony_ci 29853a5a1b3Sopenharmony_ci switch (info->a2dp_codec_t.aptx_hd_config->aptx.channel_mode) { 29953a5a1b3Sopenharmony_ci case APTX_CHANNEL_MODE_STEREO: 30053a5a1b3Sopenharmony_ci ss->channels = 2; 30153a5a1b3Sopenharmony_ci break; 30253a5a1b3Sopenharmony_ci default: 30353a5a1b3Sopenharmony_ci pa_log_error("aptX HD invalid channel mode %d", info->a2dp_codec_t.aptx_hd_config->aptx.frequency); 30453a5a1b3Sopenharmony_ci goto fail; 30553a5a1b3Sopenharmony_ci } 30653a5a1b3Sopenharmony_ci } else { 30753a5a1b3Sopenharmony_ci switch (info->a2dp_codec_t.aptx_config->frequency) { 30853a5a1b3Sopenharmony_ci case APTX_SAMPLING_FREQ_16000: 30953a5a1b3Sopenharmony_ci ss->rate = 16000u; 31053a5a1b3Sopenharmony_ci break; 31153a5a1b3Sopenharmony_ci case APTX_SAMPLING_FREQ_32000: 31253a5a1b3Sopenharmony_ci ss->rate = 32000u; 31353a5a1b3Sopenharmony_ci break; 31453a5a1b3Sopenharmony_ci case APTX_SAMPLING_FREQ_44100: 31553a5a1b3Sopenharmony_ci ss->rate = 44100u; 31653a5a1b3Sopenharmony_ci break; 31753a5a1b3Sopenharmony_ci case APTX_SAMPLING_FREQ_48000: 31853a5a1b3Sopenharmony_ci ss->rate = 48000u; 31953a5a1b3Sopenharmony_ci break; 32053a5a1b3Sopenharmony_ci default: 32153a5a1b3Sopenharmony_ci pa_log_error("aptX invalid frequency %d", info->a2dp_codec_t.aptx_config->frequency); 32253a5a1b3Sopenharmony_ci goto fail; 32353a5a1b3Sopenharmony_ci } 32453a5a1b3Sopenharmony_ci 32553a5a1b3Sopenharmony_ci switch (info->a2dp_codec_t.aptx_config->channel_mode) { 32653a5a1b3Sopenharmony_ci case APTX_CHANNEL_MODE_STEREO: 32753a5a1b3Sopenharmony_ci ss->channels = 2; 32853a5a1b3Sopenharmony_ci break; 32953a5a1b3Sopenharmony_ci default: 33053a5a1b3Sopenharmony_ci pa_log_error("aptX invalid channel mode %d", info->a2dp_codec_t.aptx_config->frequency); 33153a5a1b3Sopenharmony_ci goto fail; 33253a5a1b3Sopenharmony_ci } 33353a5a1b3Sopenharmony_ci } 33453a5a1b3Sopenharmony_ci 33553a5a1b3Sopenharmony_ci aptx_codec_media_type = info->codec_type == APTX_HD ? "audio/aptx-hd" : "audio/aptx"; 33653a5a1b3Sopenharmony_ci 33753a5a1b3Sopenharmony_ci capsf = gst_element_factory_make("capsfilter", "aptx_capsfilter"); 33853a5a1b3Sopenharmony_ci if (!capsf) { 33953a5a1b3Sopenharmony_ci pa_log_error("Could not create aptX capsfilter element"); 34053a5a1b3Sopenharmony_ci goto fail; 34153a5a1b3Sopenharmony_ci } 34253a5a1b3Sopenharmony_ci 34353a5a1b3Sopenharmony_ci caps = gst_caps_new_simple(aptx_codec_media_type, 34453a5a1b3Sopenharmony_ci "rate", G_TYPE_INT, (int) ss->rate, 34553a5a1b3Sopenharmony_ci "channels", G_TYPE_INT, (int) ss->channels, 34653a5a1b3Sopenharmony_ci NULL); 34753a5a1b3Sopenharmony_ci g_object_set(capsf, "caps", caps, NULL); 34853a5a1b3Sopenharmony_ci gst_caps_unref(caps); 34953a5a1b3Sopenharmony_ci 35053a5a1b3Sopenharmony_ci if (for_encoding) { 35153a5a1b3Sopenharmony_ci sink = gst_element_factory_make("openaptxenc", "aptx_encoder"); 35253a5a1b3Sopenharmony_ci src = capsf; 35353a5a1b3Sopenharmony_ci 35453a5a1b3Sopenharmony_ci if (sink == NULL) { 35553a5a1b3Sopenharmony_ci pa_log_error("Could not create aptX encoder element"); 35653a5a1b3Sopenharmony_ci goto fail_enc_dec; 35753a5a1b3Sopenharmony_ci } 35853a5a1b3Sopenharmony_ci 35953a5a1b3Sopenharmony_ci bin = gst_bin_new("aptx_enc_bin"); 36053a5a1b3Sopenharmony_ci } else { 36153a5a1b3Sopenharmony_ci sink = capsf; 36253a5a1b3Sopenharmony_ci src = gst_element_factory_make("openaptxdec", "aptx_decoder"); 36353a5a1b3Sopenharmony_ci 36453a5a1b3Sopenharmony_ci if (src == NULL) { 36553a5a1b3Sopenharmony_ci pa_log_error("Could not create aptX decoder element"); 36653a5a1b3Sopenharmony_ci goto fail_enc_dec; 36753a5a1b3Sopenharmony_ci } 36853a5a1b3Sopenharmony_ci 36953a5a1b3Sopenharmony_ci bin = gst_bin_new("aptx_dec_bin"); 37053a5a1b3Sopenharmony_ci } 37153a5a1b3Sopenharmony_ci 37253a5a1b3Sopenharmony_ci pa_assert(bin); 37353a5a1b3Sopenharmony_ci 37453a5a1b3Sopenharmony_ci gst_bin_add_many(GST_BIN(bin), sink, src, NULL); 37553a5a1b3Sopenharmony_ci pa_assert_se(gst_element_link_many(sink, src, NULL)); 37653a5a1b3Sopenharmony_ci 37753a5a1b3Sopenharmony_ci pad = gst_element_get_static_pad(sink, "sink"); 37853a5a1b3Sopenharmony_ci pa_assert_se(gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad))); 37953a5a1b3Sopenharmony_ci gst_object_unref(GST_OBJECT(pad)); 38053a5a1b3Sopenharmony_ci 38153a5a1b3Sopenharmony_ci pad = gst_element_get_static_pad(src, "src"); 38253a5a1b3Sopenharmony_ci pa_assert_se(gst_element_add_pad(bin, gst_ghost_pad_new("src", pad))); 38353a5a1b3Sopenharmony_ci gst_object_unref(GST_OBJECT(pad)); 38453a5a1b3Sopenharmony_ci 38553a5a1b3Sopenharmony_ci return bin; 38653a5a1b3Sopenharmony_ci 38753a5a1b3Sopenharmony_cifail_enc_dec: 38853a5a1b3Sopenharmony_ci gst_object_unref(GST_OBJECT(capsf)); 38953a5a1b3Sopenharmony_ci 39053a5a1b3Sopenharmony_cifail: 39153a5a1b3Sopenharmony_ci pa_log_error("aptX initialisation failed"); 39253a5a1b3Sopenharmony_ci return NULL; 39353a5a1b3Sopenharmony_ci} 39453a5a1b3Sopenharmony_ci 39553a5a1b3Sopenharmony_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) { 39653a5a1b3Sopenharmony_ci GstElement *bin; 39753a5a1b3Sopenharmony_ci struct gst_info *info = NULL; 39853a5a1b3Sopenharmony_ci 39953a5a1b3Sopenharmony_ci info = pa_xnew0(struct gst_info, 1); 40053a5a1b3Sopenharmony_ci pa_assert(info); 40153a5a1b3Sopenharmony_ci 40253a5a1b3Sopenharmony_ci info->core = core; 40353a5a1b3Sopenharmony_ci info->ss = sample_spec; 40453a5a1b3Sopenharmony_ci 40553a5a1b3Sopenharmony_ci if (codec_type == APTX) { 40653a5a1b3Sopenharmony_ci info->codec_type = APTX; 40753a5a1b3Sopenharmony_ci info->a2dp_codec_t.aptx_config = (const a2dp_aptx_t *) config_buffer; 40853a5a1b3Sopenharmony_ci pa_assert(config_size == sizeof(*(info->a2dp_codec_t.aptx_config))); 40953a5a1b3Sopenharmony_ci } else if (codec_type == APTX_HD) { 41053a5a1b3Sopenharmony_ci info->codec_type = APTX_HD; 41153a5a1b3Sopenharmony_ci info->a2dp_codec_t.aptx_hd_config = (const a2dp_aptx_hd_t *) config_buffer; 41253a5a1b3Sopenharmony_ci pa_assert(config_size == sizeof(*(info->a2dp_codec_t.aptx_hd_config))); 41353a5a1b3Sopenharmony_ci } else 41453a5a1b3Sopenharmony_ci pa_assert_not_reached(); 41553a5a1b3Sopenharmony_ci 41653a5a1b3Sopenharmony_ci if (!(bin = gst_init_aptx(info, sample_spec, for_encoding))) 41753a5a1b3Sopenharmony_ci goto fail; 41853a5a1b3Sopenharmony_ci 41953a5a1b3Sopenharmony_ci if (!gst_codec_init(info, for_encoding, bin)) 42053a5a1b3Sopenharmony_ci goto fail; 42153a5a1b3Sopenharmony_ci 42253a5a1b3Sopenharmony_ci return info; 42353a5a1b3Sopenharmony_ci 42453a5a1b3Sopenharmony_cifail: 42553a5a1b3Sopenharmony_ci if (info) 42653a5a1b3Sopenharmony_ci pa_xfree(info); 42753a5a1b3Sopenharmony_ci 42853a5a1b3Sopenharmony_ci return NULL; 42953a5a1b3Sopenharmony_ci} 43053a5a1b3Sopenharmony_ci 43153a5a1b3Sopenharmony_cistatic void *init(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) { 43253a5a1b3Sopenharmony_ci return init_common(APTX, for_encoding, for_backchannel, config_buffer, config_size, sample_spec, core); 43353a5a1b3Sopenharmony_ci} 43453a5a1b3Sopenharmony_ci 43553a5a1b3Sopenharmony_cistatic void *init_hd(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) { 43653a5a1b3Sopenharmony_ci return init_common(APTX_HD, for_encoding, for_backchannel, config_buffer, config_size, sample_spec, core); 43753a5a1b3Sopenharmony_ci} 43853a5a1b3Sopenharmony_ci 43953a5a1b3Sopenharmony_cistatic void deinit(void *codec_info) { 44053a5a1b3Sopenharmony_ci return gst_codec_deinit(codec_info); 44153a5a1b3Sopenharmony_ci} 44253a5a1b3Sopenharmony_ci 44353a5a1b3Sopenharmony_cistatic int reset(void *codec_info) { 44453a5a1b3Sopenharmony_ci return 0; 44553a5a1b3Sopenharmony_ci} 44653a5a1b3Sopenharmony_ci 44753a5a1b3Sopenharmony_cistatic int reset_hd(void *codec_info) { 44853a5a1b3Sopenharmony_ci struct gst_info *info = (struct gst_info *) codec_info; 44953a5a1b3Sopenharmony_ci 45053a5a1b3Sopenharmony_ci info->seq_num = 0; 45153a5a1b3Sopenharmony_ci 45253a5a1b3Sopenharmony_ci return 0; 45353a5a1b3Sopenharmony_ci} 45453a5a1b3Sopenharmony_ci 45553a5a1b3Sopenharmony_cistatic size_t get_block_size(void *codec_info, size_t link_mtu) { 45653a5a1b3Sopenharmony_ci /* aptX compression ratio is 6:1 and we need to process one aptX frame (4 bytes) at once */ 45753a5a1b3Sopenharmony_ci size_t frame_count = (link_mtu / 4); 45853a5a1b3Sopenharmony_ci 45953a5a1b3Sopenharmony_ci return frame_count * 4 * 6; 46053a5a1b3Sopenharmony_ci} 46153a5a1b3Sopenharmony_ci 46253a5a1b3Sopenharmony_cistatic size_t get_encoded_block_size(void *codec_info, size_t input_size) { 46353a5a1b3Sopenharmony_ci /* input size should be aligned to codec input block size */ 46453a5a1b3Sopenharmony_ci pa_assert_fp(input_size % (4 * 6) == 0); 46553a5a1b3Sopenharmony_ci 46653a5a1b3Sopenharmony_ci return (input_size / (4 * 6)) * 4; 46753a5a1b3Sopenharmony_ci} 46853a5a1b3Sopenharmony_ci 46953a5a1b3Sopenharmony_cistatic size_t get_block_size_hd(void *codec_info, size_t link_mtu) { 47053a5a1b3Sopenharmony_ci /* aptX HD compression ratio is 4:1 and we need to process one aptX HD frame (6 bytes) at once, plus aptX HD frames are encapsulated in RTP */ 47153a5a1b3Sopenharmony_ci size_t rtp_size = sizeof(struct rtp_header); 47253a5a1b3Sopenharmony_ci size_t frame_count = (link_mtu - rtp_size) / 6; 47353a5a1b3Sopenharmony_ci 47453a5a1b3Sopenharmony_ci return frame_count * 6 * 4; 47553a5a1b3Sopenharmony_ci} 47653a5a1b3Sopenharmony_ci 47753a5a1b3Sopenharmony_cistatic size_t get_encoded_block_size_hd(void *codec_info, size_t input_size) { 47853a5a1b3Sopenharmony_ci size_t rtp_size = sizeof(struct rtp_header); 47953a5a1b3Sopenharmony_ci 48053a5a1b3Sopenharmony_ci /* input size should be aligned to codec input block size */ 48153a5a1b3Sopenharmony_ci pa_assert_fp(input_size % (4 * 6) == 0); 48253a5a1b3Sopenharmony_ci 48353a5a1b3Sopenharmony_ci return (input_size / (4 * 6)) * 6 + rtp_size; 48453a5a1b3Sopenharmony_ci} 48553a5a1b3Sopenharmony_ci 48653a5a1b3Sopenharmony_cistatic size_t reduce_encoder_bitrate(void *codec_info, size_t write_link_mtu) { 48753a5a1b3Sopenharmony_ci return 0; 48853a5a1b3Sopenharmony_ci} 48953a5a1b3Sopenharmony_ci 49053a5a1b3Sopenharmony_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) { 49153a5a1b3Sopenharmony_ci size_t written; 49253a5a1b3Sopenharmony_ci 49353a5a1b3Sopenharmony_ci written = gst_transcode_buffer(codec_info, timestamp, input_buffer, input_size, output_buffer, output_size, processed); 49453a5a1b3Sopenharmony_ci if (PA_UNLIKELY(*processed == 0 || *processed != input_size)) 49553a5a1b3Sopenharmony_ci pa_log_error("aptX encoding error"); 49653a5a1b3Sopenharmony_ci 49753a5a1b3Sopenharmony_ci return written; 49853a5a1b3Sopenharmony_ci} 49953a5a1b3Sopenharmony_ci 50053a5a1b3Sopenharmony_cistatic size_t encode_buffer_hd(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) { 50153a5a1b3Sopenharmony_ci struct gst_info *info = (struct gst_info *) codec_info; 50253a5a1b3Sopenharmony_ci struct rtp_header *header; 50353a5a1b3Sopenharmony_ci size_t written; 50453a5a1b3Sopenharmony_ci 50553a5a1b3Sopenharmony_ci if (PA_UNLIKELY(output_size < sizeof(*header))) { 50653a5a1b3Sopenharmony_ci *processed = 0; 50753a5a1b3Sopenharmony_ci return 0; 50853a5a1b3Sopenharmony_ci } 50953a5a1b3Sopenharmony_ci 51053a5a1b3Sopenharmony_ci written = encode_buffer(codec_info, timestamp, input_buffer, input_size, output_buffer + sizeof(*header), output_size - sizeof(*header), processed); 51153a5a1b3Sopenharmony_ci 51253a5a1b3Sopenharmony_ci if (PA_LIKELY(written > 0)) { 51353a5a1b3Sopenharmony_ci header = (struct rtp_header *) output_buffer; 51453a5a1b3Sopenharmony_ci pa_zero(*header); 51553a5a1b3Sopenharmony_ci header->v = 2; 51653a5a1b3Sopenharmony_ci header->pt = 96; 51753a5a1b3Sopenharmony_ci header->sequence_number = htons(info->seq_num++); 51853a5a1b3Sopenharmony_ci header->timestamp = htonl(timestamp); 51953a5a1b3Sopenharmony_ci header->ssrc = htonl(1); 52053a5a1b3Sopenharmony_ci written += sizeof(*header); 52153a5a1b3Sopenharmony_ci } 52253a5a1b3Sopenharmony_ci 52353a5a1b3Sopenharmony_ci return written; 52453a5a1b3Sopenharmony_ci} 52553a5a1b3Sopenharmony_ci 52653a5a1b3Sopenharmony_cistatic size_t decode_buffer(void *codec_info, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) { 52753a5a1b3Sopenharmony_ci size_t written; 52853a5a1b3Sopenharmony_ci 52953a5a1b3Sopenharmony_ci written = gst_transcode_buffer(codec_info, -1, input_buffer, input_size, output_buffer, output_size, processed); 53053a5a1b3Sopenharmony_ci 53153a5a1b3Sopenharmony_ci /* Due to aptX latency, aptx_decode starts filling output buffer after 90 input samples. 53253a5a1b3Sopenharmony_ci * If input buffer contains less than 90 samples, aptx_decode returns zero (=no output) 53353a5a1b3Sopenharmony_ci * but set *processed to non zero as input samples were processed. So do not check for 53453a5a1b3Sopenharmony_ci * return value of aptx_decode, zero is valid. Decoding error is indicating by fact that 53553a5a1b3Sopenharmony_ci * not all input samples were processed. */ 53653a5a1b3Sopenharmony_ci if (PA_UNLIKELY(*processed != input_size)) 53753a5a1b3Sopenharmony_ci pa_log_error("aptX decoding error"); 53853a5a1b3Sopenharmony_ci 53953a5a1b3Sopenharmony_ci return written; 54053a5a1b3Sopenharmony_ci} 54153a5a1b3Sopenharmony_ci 54253a5a1b3Sopenharmony_cistatic size_t decode_buffer_hd(void *codec_info, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) { 54353a5a1b3Sopenharmony_ci struct rtp_header *header; 54453a5a1b3Sopenharmony_ci size_t written; 54553a5a1b3Sopenharmony_ci 54653a5a1b3Sopenharmony_ci if (PA_UNLIKELY(input_size < sizeof(*header))) { 54753a5a1b3Sopenharmony_ci *processed = 0; 54853a5a1b3Sopenharmony_ci return 0; 54953a5a1b3Sopenharmony_ci } 55053a5a1b3Sopenharmony_ci 55153a5a1b3Sopenharmony_ci header = (struct rtp_header *) input_buffer; 55253a5a1b3Sopenharmony_ci written = decode_buffer(codec_info, input_buffer + sizeof(*header), input_size - sizeof(*header), output_buffer, output_size, processed); 55353a5a1b3Sopenharmony_ci *processed += sizeof(*header); 55453a5a1b3Sopenharmony_ci return written; 55553a5a1b3Sopenharmony_ci} 55653a5a1b3Sopenharmony_ci 55753a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_aptx = { 55853a5a1b3Sopenharmony_ci .id = { A2DP_CODEC_VENDOR, APTX_VENDOR_ID, APTX_CODEC_ID }, 55953a5a1b3Sopenharmony_ci .support_backchannel = false, 56053a5a1b3Sopenharmony_ci .can_be_supported = can_be_supported, 56153a5a1b3Sopenharmony_ci .can_accept_capabilities = can_accept_capabilities, 56253a5a1b3Sopenharmony_ci .choose_remote_endpoint = choose_remote_endpoint, 56353a5a1b3Sopenharmony_ci .fill_capabilities = fill_capabilities, 56453a5a1b3Sopenharmony_ci .is_configuration_valid = is_configuration_valid, 56553a5a1b3Sopenharmony_ci .fill_preferred_configuration = fill_preferred_configuration, 56653a5a1b3Sopenharmony_ci .bt_codec = { 56753a5a1b3Sopenharmony_ci .name = "aptx", 56853a5a1b3Sopenharmony_ci .description = "aptX", 56953a5a1b3Sopenharmony_ci .init = init, 57053a5a1b3Sopenharmony_ci .deinit = deinit, 57153a5a1b3Sopenharmony_ci .reset = reset, 57253a5a1b3Sopenharmony_ci .get_read_block_size = get_block_size, 57353a5a1b3Sopenharmony_ci .get_write_block_size = get_block_size, 57453a5a1b3Sopenharmony_ci .get_encoded_block_size = get_encoded_block_size, 57553a5a1b3Sopenharmony_ci .reduce_encoder_bitrate = reduce_encoder_bitrate, 57653a5a1b3Sopenharmony_ci .encode_buffer = encode_buffer, 57753a5a1b3Sopenharmony_ci .decode_buffer = decode_buffer, 57853a5a1b3Sopenharmony_ci }, 57953a5a1b3Sopenharmony_ci}; 58053a5a1b3Sopenharmony_ci 58153a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_aptx_hd = { 58253a5a1b3Sopenharmony_ci .id = { A2DP_CODEC_VENDOR, APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID }, 58353a5a1b3Sopenharmony_ci .support_backchannel = false, 58453a5a1b3Sopenharmony_ci .can_be_supported = can_be_supported, 58553a5a1b3Sopenharmony_ci .can_accept_capabilities = can_accept_capabilities_hd, 58653a5a1b3Sopenharmony_ci .choose_remote_endpoint = choose_remote_endpoint_hd, 58753a5a1b3Sopenharmony_ci .fill_capabilities = fill_capabilities_hd, 58853a5a1b3Sopenharmony_ci .is_configuration_valid = is_configuration_valid_hd, 58953a5a1b3Sopenharmony_ci .fill_preferred_configuration = fill_preferred_configuration_hd, 59053a5a1b3Sopenharmony_ci .bt_codec = { 59153a5a1b3Sopenharmony_ci .name = "aptx_hd", 59253a5a1b3Sopenharmony_ci .description = "aptX HD", 59353a5a1b3Sopenharmony_ci .init = init_hd, 59453a5a1b3Sopenharmony_ci .deinit = deinit, 59553a5a1b3Sopenharmony_ci .reset = reset_hd, 59653a5a1b3Sopenharmony_ci .get_read_block_size = get_block_size_hd, 59753a5a1b3Sopenharmony_ci .get_write_block_size = get_block_size_hd, 59853a5a1b3Sopenharmony_ci .get_encoded_block_size = get_encoded_block_size_hd, 59953a5a1b3Sopenharmony_ci .reduce_encoder_bitrate = reduce_encoder_bitrate, 60053a5a1b3Sopenharmony_ci .encode_buffer = encode_buffer_hd, 60153a5a1b3Sopenharmony_ci .decode_buffer = decode_buffer_hd, 60253a5a1b3Sopenharmony_ci }, 60353a5a1b3Sopenharmony_ci}; 604