153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2018-2019 Pali Rohár <pali.rohar@gmail.com> 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/core-util.h> 2553a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 2653a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 2753a5a1b3Sopenharmony_ci#include <pulsecore/once.h> 2853a5a1b3Sopenharmony_ci#include <pulse/sample.h> 2953a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3053a5a1b3Sopenharmony_ci 3153a5a1b3Sopenharmony_ci#include <arpa/inet.h> 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#include <sbc/sbc.h> 3453a5a1b3Sopenharmony_ci 3553a5a1b3Sopenharmony_ci#include "a2dp-codecs.h" 3653a5a1b3Sopenharmony_ci#include "a2dp-codec-api.h" 3753a5a1b3Sopenharmony_ci#include "rtp.h" 3853a5a1b3Sopenharmony_ci 3953a5a1b3Sopenharmony_ci#define SBC_BITPOOL_DEC_STEP 5 4053a5a1b3Sopenharmony_ci#define SBC_BITPOOL_INC_STEP 1 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_cistruct sbc_info { 4353a5a1b3Sopenharmony_ci sbc_t sbc; /* Codec data */ 4453a5a1b3Sopenharmony_ci size_t codesize, frame_length; /* SBC Codesize, frame_length. We simply cache those values here */ 4553a5a1b3Sopenharmony_ci uint16_t seq_num; /* Cumulative packet sequence */ 4653a5a1b3Sopenharmony_ci uint8_t frequency; 4753a5a1b3Sopenharmony_ci uint8_t blocks; 4853a5a1b3Sopenharmony_ci uint8_t subbands; 4953a5a1b3Sopenharmony_ci uint8_t mode; 5053a5a1b3Sopenharmony_ci uint8_t allocation; 5153a5a1b3Sopenharmony_ci uint8_t initial_bitpool; 5253a5a1b3Sopenharmony_ci uint8_t min_bitpool; 5353a5a1b3Sopenharmony_ci uint8_t max_bitpool; 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_ci uint8_t nr_blocks; 5653a5a1b3Sopenharmony_ci uint8_t nr_subbands; 5753a5a1b3Sopenharmony_ci}; 5853a5a1b3Sopenharmony_ci 5953a5a1b3Sopenharmony_cistatic bool can_be_supported(bool for_encoding) { 6053a5a1b3Sopenharmony_ci return true; 6153a5a1b3Sopenharmony_ci} 6253a5a1b3Sopenharmony_ci 6353a5a1b3Sopenharmony_cistatic bool can_accept_capabilities(const uint8_t *capabilities_buffer, uint8_t capabilities_size, bool for_encoding) { 6453a5a1b3Sopenharmony_ci const a2dp_sbc_t *capabilities = (const a2dp_sbc_t *) capabilities_buffer; 6553a5a1b3Sopenharmony_ci 6653a5a1b3Sopenharmony_ci if (capabilities_size != sizeof(*capabilities)) 6753a5a1b3Sopenharmony_ci return false; 6853a5a1b3Sopenharmony_ci 6953a5a1b3Sopenharmony_ci if (!(capabilities->frequency & (SBC_SAMPLING_FREQ_16000 | SBC_SAMPLING_FREQ_32000 | SBC_SAMPLING_FREQ_44100 | SBC_SAMPLING_FREQ_48000))) 7053a5a1b3Sopenharmony_ci return false; 7153a5a1b3Sopenharmony_ci 7253a5a1b3Sopenharmony_ci if (!(capabilities->channel_mode & (SBC_CHANNEL_MODE_MONO | SBC_CHANNEL_MODE_DUAL_CHANNEL | SBC_CHANNEL_MODE_STEREO | SBC_CHANNEL_MODE_JOINT_STEREO))) 7353a5a1b3Sopenharmony_ci return false; 7453a5a1b3Sopenharmony_ci 7553a5a1b3Sopenharmony_ci if (!(capabilities->allocation_method & (SBC_ALLOCATION_SNR | SBC_ALLOCATION_LOUDNESS))) 7653a5a1b3Sopenharmony_ci return false; 7753a5a1b3Sopenharmony_ci 7853a5a1b3Sopenharmony_ci if (!(capabilities->subbands & (SBC_SUBBANDS_4 | SBC_SUBBANDS_8))) 7953a5a1b3Sopenharmony_ci return false; 8053a5a1b3Sopenharmony_ci 8153a5a1b3Sopenharmony_ci if (!(capabilities->block_length & (SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 | SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16))) 8253a5a1b3Sopenharmony_ci return false; 8353a5a1b3Sopenharmony_ci 8453a5a1b3Sopenharmony_ci return true; 8553a5a1b3Sopenharmony_ci} 8653a5a1b3Sopenharmony_ci 8753a5a1b3Sopenharmony_cistatic bool can_accept_capabilities_xq(const uint8_t *capabilities_buffer, uint8_t capabilities_size, bool for_encoding) { 8853a5a1b3Sopenharmony_ci const a2dp_sbc_t *capabilities = (const a2dp_sbc_t *) capabilities_buffer; 8953a5a1b3Sopenharmony_ci 9053a5a1b3Sopenharmony_ci if (capabilities_size != sizeof(*capabilities)) 9153a5a1b3Sopenharmony_ci return false; 9253a5a1b3Sopenharmony_ci 9353a5a1b3Sopenharmony_ci if (!(capabilities->frequency & (SBC_SAMPLING_FREQ_44100 | SBC_SAMPLING_FREQ_48000))) 9453a5a1b3Sopenharmony_ci return false; 9553a5a1b3Sopenharmony_ci 9653a5a1b3Sopenharmony_ci if (!(capabilities->channel_mode & (SBC_CHANNEL_MODE_DUAL_CHANNEL))) 9753a5a1b3Sopenharmony_ci return false; 9853a5a1b3Sopenharmony_ci 9953a5a1b3Sopenharmony_ci if (!(capabilities->allocation_method & (SBC_ALLOCATION_LOUDNESS))) 10053a5a1b3Sopenharmony_ci return false; 10153a5a1b3Sopenharmony_ci 10253a5a1b3Sopenharmony_ci if (!(capabilities->subbands & (SBC_SUBBANDS_8))) 10353a5a1b3Sopenharmony_ci return false; 10453a5a1b3Sopenharmony_ci 10553a5a1b3Sopenharmony_ci if (!(capabilities->block_length & (SBC_BLOCK_LENGTH_16))) 10653a5a1b3Sopenharmony_ci return false; 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci return true; 10953a5a1b3Sopenharmony_ci} 11053a5a1b3Sopenharmony_ci 11153a5a1b3Sopenharmony_cistatic const char *choose_remote_endpoint(const pa_hashmap *capabilities_hashmap, const pa_sample_spec *default_sample_spec, bool for_encoding) { 11253a5a1b3Sopenharmony_ci const pa_a2dp_codec_capabilities *a2dp_capabilities; 11353a5a1b3Sopenharmony_ci const char *key; 11453a5a1b3Sopenharmony_ci void *state; 11553a5a1b3Sopenharmony_ci 11653a5a1b3Sopenharmony_ci /* There is no preference, just choose random valid entry */ 11753a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, capabilities_hashmap, state) { 11853a5a1b3Sopenharmony_ci if (can_accept_capabilities(a2dp_capabilities->buffer, a2dp_capabilities->size, for_encoding)) 11953a5a1b3Sopenharmony_ci return key; 12053a5a1b3Sopenharmony_ci } 12153a5a1b3Sopenharmony_ci 12253a5a1b3Sopenharmony_ci return NULL; 12353a5a1b3Sopenharmony_ci} 12453a5a1b3Sopenharmony_ci 12553a5a1b3Sopenharmony_cistatic const char *choose_remote_endpoint_xq(const pa_hashmap *capabilities_hashmap, const pa_sample_spec *default_sample_spec, bool for_encoding) { 12653a5a1b3Sopenharmony_ci const pa_a2dp_codec_capabilities *a2dp_capabilities; 12753a5a1b3Sopenharmony_ci const char *key; 12853a5a1b3Sopenharmony_ci void *state; 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci /* There is no preference, just choose random valid entry */ 13153a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, capabilities_hashmap, state) { 13253a5a1b3Sopenharmony_ci if (can_accept_capabilities_xq(a2dp_capabilities->buffer, a2dp_capabilities->size, for_encoding)) 13353a5a1b3Sopenharmony_ci return key; 13453a5a1b3Sopenharmony_ci } 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci return NULL; 13753a5a1b3Sopenharmony_ci} 13853a5a1b3Sopenharmony_ci 13953a5a1b3Sopenharmony_cistatic uint8_t fill_capabilities(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) { 14053a5a1b3Sopenharmony_ci a2dp_sbc_t *capabilities = (a2dp_sbc_t *) capabilities_buffer; 14153a5a1b3Sopenharmony_ci 14253a5a1b3Sopenharmony_ci pa_zero(*capabilities); 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_ci capabilities->channel_mode = SBC_CHANNEL_MODE_MONO | SBC_CHANNEL_MODE_DUAL_CHANNEL | SBC_CHANNEL_MODE_STEREO | 14553a5a1b3Sopenharmony_ci SBC_CHANNEL_MODE_JOINT_STEREO; 14653a5a1b3Sopenharmony_ci capabilities->frequency = SBC_SAMPLING_FREQ_16000 | SBC_SAMPLING_FREQ_32000 | SBC_SAMPLING_FREQ_44100 | 14753a5a1b3Sopenharmony_ci SBC_SAMPLING_FREQ_48000; 14853a5a1b3Sopenharmony_ci capabilities->allocation_method = SBC_ALLOCATION_SNR | SBC_ALLOCATION_LOUDNESS; 14953a5a1b3Sopenharmony_ci capabilities->subbands = SBC_SUBBANDS_4 | SBC_SUBBANDS_8; 15053a5a1b3Sopenharmony_ci capabilities->block_length = SBC_BLOCK_LENGTH_4 | SBC_BLOCK_LENGTH_8 | SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16; 15153a5a1b3Sopenharmony_ci capabilities->min_bitpool = SBC_MIN_BITPOOL; 15253a5a1b3Sopenharmony_ci capabilities->max_bitpool = SBC_BITPOOL_HQ_JOINT_STEREO_44100; 15353a5a1b3Sopenharmony_ci 15453a5a1b3Sopenharmony_ci return sizeof(*capabilities); 15553a5a1b3Sopenharmony_ci} 15653a5a1b3Sopenharmony_ci 15753a5a1b3Sopenharmony_cistatic void set_info_and_sample_spec_from_sbc_config(struct sbc_info *sbc_info, pa_sample_spec *sample_spec, const a2dp_sbc_t *config) { 15853a5a1b3Sopenharmony_ci switch (config->frequency) { 15953a5a1b3Sopenharmony_ci case SBC_SAMPLING_FREQ_16000: 16053a5a1b3Sopenharmony_ci sbc_info->frequency = SBC_FREQ_16000; 16153a5a1b3Sopenharmony_ci sample_spec->rate = 16000U; 16253a5a1b3Sopenharmony_ci break; 16353a5a1b3Sopenharmony_ci case SBC_SAMPLING_FREQ_32000: 16453a5a1b3Sopenharmony_ci sbc_info->frequency = SBC_FREQ_32000; 16553a5a1b3Sopenharmony_ci sample_spec->rate = 32000U; 16653a5a1b3Sopenharmony_ci break; 16753a5a1b3Sopenharmony_ci case SBC_SAMPLING_FREQ_44100: 16853a5a1b3Sopenharmony_ci sbc_info->frequency = SBC_FREQ_44100; 16953a5a1b3Sopenharmony_ci sample_spec->rate = 44100U; 17053a5a1b3Sopenharmony_ci break; 17153a5a1b3Sopenharmony_ci case SBC_SAMPLING_FREQ_48000: 17253a5a1b3Sopenharmony_ci sbc_info->frequency = SBC_FREQ_48000; 17353a5a1b3Sopenharmony_ci sample_spec->rate = 48000U; 17453a5a1b3Sopenharmony_ci break; 17553a5a1b3Sopenharmony_ci default: 17653a5a1b3Sopenharmony_ci pa_assert_not_reached(); 17753a5a1b3Sopenharmony_ci } 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci switch (config->channel_mode) { 18053a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_MONO: 18153a5a1b3Sopenharmony_ci sbc_info->mode = SBC_MODE_MONO; 18253a5a1b3Sopenharmony_ci sample_spec->channels = 1; 18353a5a1b3Sopenharmony_ci break; 18453a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_DUAL_CHANNEL: 18553a5a1b3Sopenharmony_ci sbc_info->mode = SBC_MODE_DUAL_CHANNEL; 18653a5a1b3Sopenharmony_ci sample_spec->channels = 2; 18753a5a1b3Sopenharmony_ci break; 18853a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_STEREO: 18953a5a1b3Sopenharmony_ci sbc_info->mode = SBC_MODE_STEREO; 19053a5a1b3Sopenharmony_ci sample_spec->channels = 2; 19153a5a1b3Sopenharmony_ci break; 19253a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_JOINT_STEREO: 19353a5a1b3Sopenharmony_ci sbc_info->mode = SBC_MODE_JOINT_STEREO; 19453a5a1b3Sopenharmony_ci sample_spec->channels = 2; 19553a5a1b3Sopenharmony_ci break; 19653a5a1b3Sopenharmony_ci default: 19753a5a1b3Sopenharmony_ci pa_assert_not_reached(); 19853a5a1b3Sopenharmony_ci } 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci switch (config->allocation_method) { 20153a5a1b3Sopenharmony_ci case SBC_ALLOCATION_SNR: 20253a5a1b3Sopenharmony_ci sbc_info->allocation = SBC_AM_SNR; 20353a5a1b3Sopenharmony_ci break; 20453a5a1b3Sopenharmony_ci case SBC_ALLOCATION_LOUDNESS: 20553a5a1b3Sopenharmony_ci sbc_info->allocation = SBC_AM_LOUDNESS; 20653a5a1b3Sopenharmony_ci break; 20753a5a1b3Sopenharmony_ci default: 20853a5a1b3Sopenharmony_ci pa_assert_not_reached(); 20953a5a1b3Sopenharmony_ci } 21053a5a1b3Sopenharmony_ci 21153a5a1b3Sopenharmony_ci switch (config->subbands) { 21253a5a1b3Sopenharmony_ci case SBC_SUBBANDS_4: 21353a5a1b3Sopenharmony_ci sbc_info->subbands = SBC_SB_4; 21453a5a1b3Sopenharmony_ci sbc_info->nr_subbands = 4; 21553a5a1b3Sopenharmony_ci break; 21653a5a1b3Sopenharmony_ci case SBC_SUBBANDS_8: 21753a5a1b3Sopenharmony_ci sbc_info->subbands = SBC_SB_8; 21853a5a1b3Sopenharmony_ci sbc_info->nr_subbands = 8; 21953a5a1b3Sopenharmony_ci break; 22053a5a1b3Sopenharmony_ci default: 22153a5a1b3Sopenharmony_ci pa_assert_not_reached(); 22253a5a1b3Sopenharmony_ci } 22353a5a1b3Sopenharmony_ci 22453a5a1b3Sopenharmony_ci switch (config->block_length) { 22553a5a1b3Sopenharmony_ci case SBC_BLOCK_LENGTH_4: 22653a5a1b3Sopenharmony_ci sbc_info->blocks = SBC_BLK_4; 22753a5a1b3Sopenharmony_ci sbc_info->nr_blocks = 4; 22853a5a1b3Sopenharmony_ci break; 22953a5a1b3Sopenharmony_ci case SBC_BLOCK_LENGTH_8: 23053a5a1b3Sopenharmony_ci sbc_info->blocks = SBC_BLK_8; 23153a5a1b3Sopenharmony_ci sbc_info->nr_blocks = 8; 23253a5a1b3Sopenharmony_ci break; 23353a5a1b3Sopenharmony_ci case SBC_BLOCK_LENGTH_12: 23453a5a1b3Sopenharmony_ci sbc_info->blocks = SBC_BLK_12; 23553a5a1b3Sopenharmony_ci sbc_info->nr_blocks = 12; 23653a5a1b3Sopenharmony_ci break; 23753a5a1b3Sopenharmony_ci case SBC_BLOCK_LENGTH_16: 23853a5a1b3Sopenharmony_ci sbc_info->blocks = SBC_BLK_16; 23953a5a1b3Sopenharmony_ci sbc_info->nr_blocks = 16; 24053a5a1b3Sopenharmony_ci break; 24153a5a1b3Sopenharmony_ci default: 24253a5a1b3Sopenharmony_ci pa_assert_not_reached(); 24353a5a1b3Sopenharmony_ci } 24453a5a1b3Sopenharmony_ci 24553a5a1b3Sopenharmony_ci sbc_info->min_bitpool = config->min_bitpool; 24653a5a1b3Sopenharmony_ci sbc_info->max_bitpool = config->max_bitpool; 24753a5a1b3Sopenharmony_ci} 24853a5a1b3Sopenharmony_ci 24953a5a1b3Sopenharmony_cistatic void set_params(struct sbc_info *sbc_info) { 25053a5a1b3Sopenharmony_ci sbc_info->sbc.frequency = sbc_info->frequency; 25153a5a1b3Sopenharmony_ci sbc_info->sbc.blocks = sbc_info->blocks; 25253a5a1b3Sopenharmony_ci sbc_info->sbc.subbands = sbc_info->subbands; 25353a5a1b3Sopenharmony_ci sbc_info->sbc.mode = sbc_info->mode; 25453a5a1b3Sopenharmony_ci sbc_info->sbc.allocation = sbc_info->allocation; 25553a5a1b3Sopenharmony_ci sbc_info->sbc.bitpool = sbc_info->initial_bitpool; 25653a5a1b3Sopenharmony_ci sbc_info->sbc.endian = SBC_LE; 25753a5a1b3Sopenharmony_ci 25853a5a1b3Sopenharmony_ci sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc); 25953a5a1b3Sopenharmony_ci sbc_info->frame_length = sbc_get_frame_length(&sbc_info->sbc); 26053a5a1b3Sopenharmony_ci} 26153a5a1b3Sopenharmony_ci 26253a5a1b3Sopenharmony_cistatic uint8_t sbc_get_max_bitpool_below_rate(a2dp_sbc_t *config, uint8_t lower_bound, uint8_t upper_bound, uint32_t bitrate_cap) { 26353a5a1b3Sopenharmony_ci pa_sample_spec sample_spec; 26453a5a1b3Sopenharmony_ci struct sbc_info sbc_info; 26553a5a1b3Sopenharmony_ci int ret; 26653a5a1b3Sopenharmony_ci 26753a5a1b3Sopenharmony_ci pa_assert(config); 26853a5a1b3Sopenharmony_ci 26953a5a1b3Sopenharmony_ci ret = sbc_init(&sbc_info.sbc, 0); 27053a5a1b3Sopenharmony_ci if (ret != 0) { 27153a5a1b3Sopenharmony_ci pa_log_error("SBC initialization failed: %d", ret); 27253a5a1b3Sopenharmony_ci return lower_bound; 27353a5a1b3Sopenharmony_ci } 27453a5a1b3Sopenharmony_ci 27553a5a1b3Sopenharmony_ci set_info_and_sample_spec_from_sbc_config(&sbc_info, &sample_spec, config); 27653a5a1b3Sopenharmony_ci 27753a5a1b3Sopenharmony_ci while (upper_bound - lower_bound > 1) { 27853a5a1b3Sopenharmony_ci size_t midpoint = (upper_bound + lower_bound) / 2; 27953a5a1b3Sopenharmony_ci 28053a5a1b3Sopenharmony_ci sbc_info.initial_bitpool = midpoint; 28153a5a1b3Sopenharmony_ci set_params(&sbc_info); 28253a5a1b3Sopenharmony_ci 28353a5a1b3Sopenharmony_ci size_t bitrate = sbc_info.frame_length * 8 * sample_spec.rate / (sbc_info.nr_subbands * sbc_info.nr_blocks); 28453a5a1b3Sopenharmony_ci 28553a5a1b3Sopenharmony_ci if (bitrate > bitrate_cap) 28653a5a1b3Sopenharmony_ci upper_bound = midpoint; 28753a5a1b3Sopenharmony_ci else 28853a5a1b3Sopenharmony_ci lower_bound = midpoint; 28953a5a1b3Sopenharmony_ci } 29053a5a1b3Sopenharmony_ci 29153a5a1b3Sopenharmony_ci sbc_finish(&sbc_info.sbc); 29253a5a1b3Sopenharmony_ci 29353a5a1b3Sopenharmony_ci pa_log_debug("SBC target bitrate %u bitpool %u sample rate %u", bitrate_cap, lower_bound, sample_spec.rate); 29453a5a1b3Sopenharmony_ci 29553a5a1b3Sopenharmony_ci return lower_bound; 29653a5a1b3Sopenharmony_ci} 29753a5a1b3Sopenharmony_ci 29853a5a1b3Sopenharmony_ci/* SBC XQ 29953a5a1b3Sopenharmony_ci * 30053a5a1b3Sopenharmony_ci * References: 30153a5a1b3Sopenharmony_ci * https://habr.com/en/post/456476/ 30253a5a1b3Sopenharmony_ci * http://soundexpert.org/articles/-/blogs/audio-quality-of-sbc-xq-bluetooth-audio-codec 30353a5a1b3Sopenharmony_ci * 30453a5a1b3Sopenharmony_ci */ 30553a5a1b3Sopenharmony_cistatic uint8_t fill_capabilities_xq(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE], uint32_t bitrate_cap) { 30653a5a1b3Sopenharmony_ci a2dp_sbc_t *capabilities = (a2dp_sbc_t *) capabilities_buffer; 30753a5a1b3Sopenharmony_ci 30853a5a1b3Sopenharmony_ci pa_zero(*capabilities); 30953a5a1b3Sopenharmony_ci 31053a5a1b3Sopenharmony_ci /* Bitpool value increases with sample rate. Prepare to calculate maximum viable 31153a5a1b3Sopenharmony_ci * bitpool value at specified bitrate_cap, with rest of SBC parameters fixed. */ 31253a5a1b3Sopenharmony_ci capabilities->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL; 31353a5a1b3Sopenharmony_ci capabilities->frequency = SBC_SAMPLING_FREQ_48000; 31453a5a1b3Sopenharmony_ci capabilities->allocation_method = SBC_ALLOCATION_LOUDNESS; 31553a5a1b3Sopenharmony_ci capabilities->subbands = SBC_SUBBANDS_8; 31653a5a1b3Sopenharmony_ci capabilities->block_length = SBC_BLOCK_LENGTH_16; 31753a5a1b3Sopenharmony_ci capabilities->min_bitpool = SBC_MIN_BITPOOL; 31853a5a1b3Sopenharmony_ci capabilities->max_bitpool = SBC_MAX_BITPOOL; /* Upper boundary in calculation below. */ 31953a5a1b3Sopenharmony_ci 32053a5a1b3Sopenharmony_ci /* Now calculate and write it back to be exposed through endpoint capabilities. */ 32153a5a1b3Sopenharmony_ci capabilities->max_bitpool = sbc_get_max_bitpool_below_rate(capabilities, capabilities->min_bitpool, capabilities->max_bitpool, bitrate_cap); 32253a5a1b3Sopenharmony_ci 32353a5a1b3Sopenharmony_ci /* Add back all supported frequencies exposed through endpoint capabilities, rest of SBC parameters are still fixed. */ 32453a5a1b3Sopenharmony_ci capabilities->frequency = SBC_SAMPLING_FREQ_44100 | SBC_SAMPLING_FREQ_48000; 32553a5a1b3Sopenharmony_ci 32653a5a1b3Sopenharmony_ci return sizeof(*capabilities); 32753a5a1b3Sopenharmony_ci} 32853a5a1b3Sopenharmony_ci 32953a5a1b3Sopenharmony_cistatic bool is_configuration_valid(const uint8_t *config_buffer, uint8_t config_size) { 33053a5a1b3Sopenharmony_ci const a2dp_sbc_t *config = (const a2dp_sbc_t *) config_buffer; 33153a5a1b3Sopenharmony_ci 33253a5a1b3Sopenharmony_ci if (config_size != sizeof(*config)) { 33353a5a1b3Sopenharmony_ci pa_log_error("Invalid size of config buffer"); 33453a5a1b3Sopenharmony_ci return false; 33553a5a1b3Sopenharmony_ci } 33653a5a1b3Sopenharmony_ci 33753a5a1b3Sopenharmony_ci if (config->frequency != SBC_SAMPLING_FREQ_16000 && config->frequency != SBC_SAMPLING_FREQ_32000 && 33853a5a1b3Sopenharmony_ci config->frequency != SBC_SAMPLING_FREQ_44100 && config->frequency != SBC_SAMPLING_FREQ_48000) { 33953a5a1b3Sopenharmony_ci pa_log_error("Invalid sampling frequency in configuration"); 34053a5a1b3Sopenharmony_ci return false; 34153a5a1b3Sopenharmony_ci } 34253a5a1b3Sopenharmony_ci 34353a5a1b3Sopenharmony_ci if (config->channel_mode != SBC_CHANNEL_MODE_MONO && config->channel_mode != SBC_CHANNEL_MODE_DUAL_CHANNEL && 34453a5a1b3Sopenharmony_ci config->channel_mode != SBC_CHANNEL_MODE_STEREO && config->channel_mode != SBC_CHANNEL_MODE_JOINT_STEREO) { 34553a5a1b3Sopenharmony_ci pa_log_error("Invalid channel mode in configuration"); 34653a5a1b3Sopenharmony_ci return false; 34753a5a1b3Sopenharmony_ci } 34853a5a1b3Sopenharmony_ci 34953a5a1b3Sopenharmony_ci if (config->allocation_method != SBC_ALLOCATION_SNR && config->allocation_method != SBC_ALLOCATION_LOUDNESS) { 35053a5a1b3Sopenharmony_ci pa_log_error("Invalid allocation method in configuration"); 35153a5a1b3Sopenharmony_ci return false; 35253a5a1b3Sopenharmony_ci } 35353a5a1b3Sopenharmony_ci 35453a5a1b3Sopenharmony_ci if (config->subbands != SBC_SUBBANDS_4 && config->subbands != SBC_SUBBANDS_8) { 35553a5a1b3Sopenharmony_ci pa_log_error("Invalid SBC subbands in configuration"); 35653a5a1b3Sopenharmony_ci return false; 35753a5a1b3Sopenharmony_ci } 35853a5a1b3Sopenharmony_ci 35953a5a1b3Sopenharmony_ci if (config->block_length != SBC_BLOCK_LENGTH_4 && config->block_length != SBC_BLOCK_LENGTH_8 && 36053a5a1b3Sopenharmony_ci config->block_length != SBC_BLOCK_LENGTH_12 && config->block_length != SBC_BLOCK_LENGTH_16) { 36153a5a1b3Sopenharmony_ci pa_log_error("Invalid block length in configuration"); 36253a5a1b3Sopenharmony_ci return false; 36353a5a1b3Sopenharmony_ci } 36453a5a1b3Sopenharmony_ci 36553a5a1b3Sopenharmony_ci if (config->min_bitpool > config->max_bitpool) { 36653a5a1b3Sopenharmony_ci pa_log_error("Invalid bitpool in configuration"); 36753a5a1b3Sopenharmony_ci return false; 36853a5a1b3Sopenharmony_ci } 36953a5a1b3Sopenharmony_ci 37053a5a1b3Sopenharmony_ci return true; 37153a5a1b3Sopenharmony_ci} 37253a5a1b3Sopenharmony_ci 37353a5a1b3Sopenharmony_cistatic uint8_t default_bitpool(uint8_t freq, uint8_t mode) { 37453a5a1b3Sopenharmony_ci /* These bitpool values were chosen based on the A2DP spec recommendation */ 37553a5a1b3Sopenharmony_ci switch (freq) { 37653a5a1b3Sopenharmony_ci case SBC_SAMPLING_FREQ_16000: 37753a5a1b3Sopenharmony_ci case SBC_SAMPLING_FREQ_32000: 37853a5a1b3Sopenharmony_ci switch (mode) { 37953a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_MONO: 38053a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_DUAL_CHANNEL: 38153a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_STEREO: 38253a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_JOINT_STEREO: 38353a5a1b3Sopenharmony_ci return SBC_BITPOOL_HQ_JOINT_STEREO_44100; 38453a5a1b3Sopenharmony_ci } 38553a5a1b3Sopenharmony_ci break; 38653a5a1b3Sopenharmony_ci 38753a5a1b3Sopenharmony_ci case SBC_SAMPLING_FREQ_44100: 38853a5a1b3Sopenharmony_ci switch (mode) { 38953a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_MONO: 39053a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_DUAL_CHANNEL: 39153a5a1b3Sopenharmony_ci return SBC_BITPOOL_HQ_MONO_44100; 39253a5a1b3Sopenharmony_ci 39353a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_STEREO: 39453a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_JOINT_STEREO: 39553a5a1b3Sopenharmony_ci return SBC_BITPOOL_HQ_JOINT_STEREO_44100; 39653a5a1b3Sopenharmony_ci } 39753a5a1b3Sopenharmony_ci break; 39853a5a1b3Sopenharmony_ci 39953a5a1b3Sopenharmony_ci case SBC_SAMPLING_FREQ_48000: 40053a5a1b3Sopenharmony_ci switch (mode) { 40153a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_MONO: 40253a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_DUAL_CHANNEL: 40353a5a1b3Sopenharmony_ci return SBC_BITPOOL_HQ_MONO_48000; 40453a5a1b3Sopenharmony_ci 40553a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_STEREO: 40653a5a1b3Sopenharmony_ci case SBC_CHANNEL_MODE_JOINT_STEREO: 40753a5a1b3Sopenharmony_ci return SBC_BITPOOL_HQ_JOINT_STEREO_48000; 40853a5a1b3Sopenharmony_ci } 40953a5a1b3Sopenharmony_ci break; 41053a5a1b3Sopenharmony_ci } 41153a5a1b3Sopenharmony_ci 41253a5a1b3Sopenharmony_ci pa_assert_not_reached(); 41353a5a1b3Sopenharmony_ci} 41453a5a1b3Sopenharmony_ci 41553a5a1b3Sopenharmony_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]) { 41653a5a1b3Sopenharmony_ci a2dp_sbc_t *config = (a2dp_sbc_t *) config_buffer; 41753a5a1b3Sopenharmony_ci const a2dp_sbc_t *capabilities = (const a2dp_sbc_t *) capabilities_buffer; 41853a5a1b3Sopenharmony_ci int i; 41953a5a1b3Sopenharmony_ci 42053a5a1b3Sopenharmony_ci static const struct { 42153a5a1b3Sopenharmony_ci uint32_t rate; 42253a5a1b3Sopenharmony_ci uint8_t cap; 42353a5a1b3Sopenharmony_ci } freq_table[] = { 42453a5a1b3Sopenharmony_ci { 16000U, SBC_SAMPLING_FREQ_16000 }, 42553a5a1b3Sopenharmony_ci { 32000U, SBC_SAMPLING_FREQ_32000 }, 42653a5a1b3Sopenharmony_ci { 44100U, SBC_SAMPLING_FREQ_44100 }, 42753a5a1b3Sopenharmony_ci { 48000U, SBC_SAMPLING_FREQ_48000 } 42853a5a1b3Sopenharmony_ci }; 42953a5a1b3Sopenharmony_ci 43053a5a1b3Sopenharmony_ci if (capabilities_size != sizeof(*capabilities)) { 43153a5a1b3Sopenharmony_ci pa_log_error("Invalid size of capabilities buffer"); 43253a5a1b3Sopenharmony_ci return 0; 43353a5a1b3Sopenharmony_ci } 43453a5a1b3Sopenharmony_ci 43553a5a1b3Sopenharmony_ci pa_zero(*config); 43653a5a1b3Sopenharmony_ci 43753a5a1b3Sopenharmony_ci /* Find the lowest freq that is at least as high as the requested sampling rate */ 43853a5a1b3Sopenharmony_ci for (i = 0; (unsigned) i < PA_ELEMENTSOF(freq_table); i++) 43953a5a1b3Sopenharmony_ci if (freq_table[i].rate >= default_sample_spec->rate && (capabilities->frequency & freq_table[i].cap)) { 44053a5a1b3Sopenharmony_ci config->frequency = freq_table[i].cap; 44153a5a1b3Sopenharmony_ci break; 44253a5a1b3Sopenharmony_ci } 44353a5a1b3Sopenharmony_ci 44453a5a1b3Sopenharmony_ci if ((unsigned) i == PA_ELEMENTSOF(freq_table)) { 44553a5a1b3Sopenharmony_ci for (--i; i >= 0; i--) { 44653a5a1b3Sopenharmony_ci if (capabilities->frequency & freq_table[i].cap) { 44753a5a1b3Sopenharmony_ci config->frequency = freq_table[i].cap; 44853a5a1b3Sopenharmony_ci break; 44953a5a1b3Sopenharmony_ci } 45053a5a1b3Sopenharmony_ci } 45153a5a1b3Sopenharmony_ci 45253a5a1b3Sopenharmony_ci if (i < 0) { 45353a5a1b3Sopenharmony_ci pa_log_error("Not suitable sample rate"); 45453a5a1b3Sopenharmony_ci return 0; 45553a5a1b3Sopenharmony_ci } 45653a5a1b3Sopenharmony_ci } 45753a5a1b3Sopenharmony_ci 45853a5a1b3Sopenharmony_ci pa_assert((unsigned) i < PA_ELEMENTSOF(freq_table)); 45953a5a1b3Sopenharmony_ci 46053a5a1b3Sopenharmony_ci if (default_sample_spec->channels <= 1) { 46153a5a1b3Sopenharmony_ci if (capabilities->channel_mode & SBC_CHANNEL_MODE_MONO) 46253a5a1b3Sopenharmony_ci config->channel_mode = SBC_CHANNEL_MODE_MONO; 46353a5a1b3Sopenharmony_ci else if (capabilities->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO) 46453a5a1b3Sopenharmony_ci config->channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO; 46553a5a1b3Sopenharmony_ci else if (capabilities->channel_mode & SBC_CHANNEL_MODE_STEREO) 46653a5a1b3Sopenharmony_ci config->channel_mode = SBC_CHANNEL_MODE_STEREO; 46753a5a1b3Sopenharmony_ci else if (capabilities->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL) 46853a5a1b3Sopenharmony_ci config->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL; 46953a5a1b3Sopenharmony_ci else { 47053a5a1b3Sopenharmony_ci pa_log_error("No supported channel modes"); 47153a5a1b3Sopenharmony_ci return 0; 47253a5a1b3Sopenharmony_ci } 47353a5a1b3Sopenharmony_ci } else { 47453a5a1b3Sopenharmony_ci if (capabilities->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO) 47553a5a1b3Sopenharmony_ci config->channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO; 47653a5a1b3Sopenharmony_ci else if (capabilities->channel_mode & SBC_CHANNEL_MODE_STEREO) 47753a5a1b3Sopenharmony_ci config->channel_mode = SBC_CHANNEL_MODE_STEREO; 47853a5a1b3Sopenharmony_ci else if (capabilities->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL) 47953a5a1b3Sopenharmony_ci config->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL; 48053a5a1b3Sopenharmony_ci else if (capabilities->channel_mode & SBC_CHANNEL_MODE_MONO) 48153a5a1b3Sopenharmony_ci config->channel_mode = SBC_CHANNEL_MODE_MONO; 48253a5a1b3Sopenharmony_ci else { 48353a5a1b3Sopenharmony_ci pa_log_error("No supported channel modes"); 48453a5a1b3Sopenharmony_ci return 0; 48553a5a1b3Sopenharmony_ci } 48653a5a1b3Sopenharmony_ci } 48753a5a1b3Sopenharmony_ci 48853a5a1b3Sopenharmony_ci if (capabilities->block_length & SBC_BLOCK_LENGTH_16) 48953a5a1b3Sopenharmony_ci config->block_length = SBC_BLOCK_LENGTH_16; 49053a5a1b3Sopenharmony_ci else if (capabilities->block_length & SBC_BLOCK_LENGTH_12) 49153a5a1b3Sopenharmony_ci config->block_length = SBC_BLOCK_LENGTH_12; 49253a5a1b3Sopenharmony_ci else if (capabilities->block_length & SBC_BLOCK_LENGTH_8) 49353a5a1b3Sopenharmony_ci config->block_length = SBC_BLOCK_LENGTH_8; 49453a5a1b3Sopenharmony_ci else if (capabilities->block_length & SBC_BLOCK_LENGTH_4) 49553a5a1b3Sopenharmony_ci config->block_length = SBC_BLOCK_LENGTH_4; 49653a5a1b3Sopenharmony_ci else { 49753a5a1b3Sopenharmony_ci pa_log_error("No supported block lengths"); 49853a5a1b3Sopenharmony_ci return 0; 49953a5a1b3Sopenharmony_ci } 50053a5a1b3Sopenharmony_ci 50153a5a1b3Sopenharmony_ci if (capabilities->subbands & SBC_SUBBANDS_8) 50253a5a1b3Sopenharmony_ci config->subbands = SBC_SUBBANDS_8; 50353a5a1b3Sopenharmony_ci else if (capabilities->subbands & SBC_SUBBANDS_4) 50453a5a1b3Sopenharmony_ci config->subbands = SBC_SUBBANDS_4; 50553a5a1b3Sopenharmony_ci else { 50653a5a1b3Sopenharmony_ci pa_log_error("No supported subbands"); 50753a5a1b3Sopenharmony_ci return 0; 50853a5a1b3Sopenharmony_ci } 50953a5a1b3Sopenharmony_ci 51053a5a1b3Sopenharmony_ci if (capabilities->allocation_method & SBC_ALLOCATION_LOUDNESS) 51153a5a1b3Sopenharmony_ci config->allocation_method = SBC_ALLOCATION_LOUDNESS; 51253a5a1b3Sopenharmony_ci else if (capabilities->allocation_method & SBC_ALLOCATION_SNR) 51353a5a1b3Sopenharmony_ci config->allocation_method = SBC_ALLOCATION_SNR; 51453a5a1b3Sopenharmony_ci else { 51553a5a1b3Sopenharmony_ci pa_log_error("No supported allocation method"); 51653a5a1b3Sopenharmony_ci return 0; 51753a5a1b3Sopenharmony_ci } 51853a5a1b3Sopenharmony_ci 51953a5a1b3Sopenharmony_ci config->min_bitpool = (uint8_t) PA_MAX(SBC_MIN_BITPOOL, capabilities->min_bitpool); 52053a5a1b3Sopenharmony_ci config->max_bitpool = (uint8_t) PA_MIN(default_bitpool(config->frequency, config->channel_mode), capabilities->max_bitpool); 52153a5a1b3Sopenharmony_ci 52253a5a1b3Sopenharmony_ci if (config->min_bitpool > config->max_bitpool) { 52353a5a1b3Sopenharmony_ci pa_log_error("No supported bitpool"); 52453a5a1b3Sopenharmony_ci return 0; 52553a5a1b3Sopenharmony_ci } 52653a5a1b3Sopenharmony_ci 52753a5a1b3Sopenharmony_ci return sizeof(*config); 52853a5a1b3Sopenharmony_ci} 52953a5a1b3Sopenharmony_ci 53053a5a1b3Sopenharmony_cistatic uint8_t fill_preferred_configuration_xq(const pa_sample_spec *default_sample_spec, const uint8_t *capabilities_buffer, uint8_t capabilities_size, uint8_t config_buffer[MAX_A2DP_CAPS_SIZE], uint32_t bitrate_cap) { 53153a5a1b3Sopenharmony_ci a2dp_sbc_t *config = (a2dp_sbc_t *) config_buffer; 53253a5a1b3Sopenharmony_ci const a2dp_sbc_t *capabilities = (const a2dp_sbc_t *) capabilities_buffer; 53353a5a1b3Sopenharmony_ci int i; 53453a5a1b3Sopenharmony_ci 53553a5a1b3Sopenharmony_ci static const struct { 53653a5a1b3Sopenharmony_ci uint32_t rate; 53753a5a1b3Sopenharmony_ci uint8_t cap; 53853a5a1b3Sopenharmony_ci } freq_table[] = { 53953a5a1b3Sopenharmony_ci { 16000U, SBC_SAMPLING_FREQ_16000 }, 54053a5a1b3Sopenharmony_ci { 32000U, SBC_SAMPLING_FREQ_32000 }, 54153a5a1b3Sopenharmony_ci { 44100U, SBC_SAMPLING_FREQ_44100 }, 54253a5a1b3Sopenharmony_ci { 48000U, SBC_SAMPLING_FREQ_48000 } 54353a5a1b3Sopenharmony_ci }; 54453a5a1b3Sopenharmony_ci 54553a5a1b3Sopenharmony_ci if (capabilities_size != sizeof(*capabilities)) { 54653a5a1b3Sopenharmony_ci pa_log_error("Invalid size of capabilities buffer"); 54753a5a1b3Sopenharmony_ci return 0; 54853a5a1b3Sopenharmony_ci } 54953a5a1b3Sopenharmony_ci 55053a5a1b3Sopenharmony_ci pa_zero(*config); 55153a5a1b3Sopenharmony_ci 55253a5a1b3Sopenharmony_ci /* Find the lowest freq that is at least as high as the requested sampling rate */ 55353a5a1b3Sopenharmony_ci for (i = 0; (unsigned) i < PA_ELEMENTSOF(freq_table); i++) 55453a5a1b3Sopenharmony_ci if (freq_table[i].rate >= default_sample_spec->rate && (capabilities->frequency & freq_table[i].cap)) { 55553a5a1b3Sopenharmony_ci config->frequency = freq_table[i].cap; 55653a5a1b3Sopenharmony_ci break; 55753a5a1b3Sopenharmony_ci } 55853a5a1b3Sopenharmony_ci 55953a5a1b3Sopenharmony_ci if ((unsigned) i == PA_ELEMENTSOF(freq_table)) { 56053a5a1b3Sopenharmony_ci for (--i; i >= 0; i--) { 56153a5a1b3Sopenharmony_ci if (capabilities->frequency & freq_table[i].cap) { 56253a5a1b3Sopenharmony_ci config->frequency = freq_table[i].cap; 56353a5a1b3Sopenharmony_ci break; 56453a5a1b3Sopenharmony_ci } 56553a5a1b3Sopenharmony_ci } 56653a5a1b3Sopenharmony_ci 56753a5a1b3Sopenharmony_ci if (i < 0) { 56853a5a1b3Sopenharmony_ci pa_log_error("Not suitable sample rate"); 56953a5a1b3Sopenharmony_ci return 0; 57053a5a1b3Sopenharmony_ci } 57153a5a1b3Sopenharmony_ci } 57253a5a1b3Sopenharmony_ci 57353a5a1b3Sopenharmony_ci pa_assert((unsigned) i < PA_ELEMENTSOF(freq_table)); 57453a5a1b3Sopenharmony_ci 57553a5a1b3Sopenharmony_ci if (default_sample_spec->channels <= 1) { 57653a5a1b3Sopenharmony_ci if (capabilities->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL) 57753a5a1b3Sopenharmony_ci config->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL; 57853a5a1b3Sopenharmony_ci else { 57953a5a1b3Sopenharmony_ci pa_log_error("No supported channel modes"); 58053a5a1b3Sopenharmony_ci return 0; 58153a5a1b3Sopenharmony_ci } 58253a5a1b3Sopenharmony_ci } else { 58353a5a1b3Sopenharmony_ci if (capabilities->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL) 58453a5a1b3Sopenharmony_ci config->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL; 58553a5a1b3Sopenharmony_ci else { 58653a5a1b3Sopenharmony_ci pa_log_error("No supported channel modes"); 58753a5a1b3Sopenharmony_ci return 0; 58853a5a1b3Sopenharmony_ci } 58953a5a1b3Sopenharmony_ci } 59053a5a1b3Sopenharmony_ci 59153a5a1b3Sopenharmony_ci if (capabilities->block_length & SBC_BLOCK_LENGTH_16) 59253a5a1b3Sopenharmony_ci config->block_length = SBC_BLOCK_LENGTH_16; 59353a5a1b3Sopenharmony_ci else { 59453a5a1b3Sopenharmony_ci pa_log_error("No supported block lengths"); 59553a5a1b3Sopenharmony_ci return 0; 59653a5a1b3Sopenharmony_ci } 59753a5a1b3Sopenharmony_ci 59853a5a1b3Sopenharmony_ci if (capabilities->subbands & SBC_SUBBANDS_8) 59953a5a1b3Sopenharmony_ci config->subbands = SBC_SUBBANDS_8; 60053a5a1b3Sopenharmony_ci else { 60153a5a1b3Sopenharmony_ci pa_log_error("No supported subbands"); 60253a5a1b3Sopenharmony_ci return 0; 60353a5a1b3Sopenharmony_ci } 60453a5a1b3Sopenharmony_ci 60553a5a1b3Sopenharmony_ci if (capabilities->allocation_method & SBC_ALLOCATION_LOUDNESS) 60653a5a1b3Sopenharmony_ci config->allocation_method = SBC_ALLOCATION_LOUDNESS; 60753a5a1b3Sopenharmony_ci else { 60853a5a1b3Sopenharmony_ci pa_log_error("No supported allocation method"); 60953a5a1b3Sopenharmony_ci return 0; 61053a5a1b3Sopenharmony_ci } 61153a5a1b3Sopenharmony_ci 61253a5a1b3Sopenharmony_ci config->min_bitpool = (uint8_t) PA_MAX(SBC_MIN_BITPOOL, capabilities->min_bitpool); 61353a5a1b3Sopenharmony_ci config->max_bitpool = sbc_get_max_bitpool_below_rate(config, config->min_bitpool, capabilities->max_bitpool, bitrate_cap); 61453a5a1b3Sopenharmony_ci 61553a5a1b3Sopenharmony_ci if (config->min_bitpool > config->max_bitpool) { 61653a5a1b3Sopenharmony_ci pa_log_error("No supported bitpool"); 61753a5a1b3Sopenharmony_ci return 0; 61853a5a1b3Sopenharmony_ci } 61953a5a1b3Sopenharmony_ci 62053a5a1b3Sopenharmony_ci return sizeof(*config); 62153a5a1b3Sopenharmony_ci} 62253a5a1b3Sopenharmony_ci 62353a5a1b3Sopenharmony_cistatic uint8_t fill_capabilities_xq_453kbps(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) { 62453a5a1b3Sopenharmony_ci return fill_capabilities_xq(capabilities_buffer, 453000); 62553a5a1b3Sopenharmony_ci} 62653a5a1b3Sopenharmony_ci 62753a5a1b3Sopenharmony_cistatic uint8_t fill_preferred_configuration_xq_453kbps(const pa_sample_spec *default_sample_spec, const uint8_t *capabilities_buffer, uint8_t capabilities_size, uint8_t config_buffer[MAX_A2DP_CAPS_SIZE]) { 62853a5a1b3Sopenharmony_ci return fill_preferred_configuration_xq(default_sample_spec, capabilities_buffer, capabilities_size, config_buffer, 453000); 62953a5a1b3Sopenharmony_ci} 63053a5a1b3Sopenharmony_ci 63153a5a1b3Sopenharmony_cistatic uint8_t fill_capabilities_xq_512kbps(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) { 63253a5a1b3Sopenharmony_ci return fill_capabilities_xq(capabilities_buffer, 512000); 63353a5a1b3Sopenharmony_ci} 63453a5a1b3Sopenharmony_ci 63553a5a1b3Sopenharmony_cistatic uint8_t fill_preferred_configuration_xq_512kbps(const pa_sample_spec *default_sample_spec, const uint8_t *capabilities_buffer, uint8_t capabilities_size, uint8_t config_buffer[MAX_A2DP_CAPS_SIZE]) { 63653a5a1b3Sopenharmony_ci return fill_preferred_configuration_xq(default_sample_spec, capabilities_buffer, capabilities_size, config_buffer, 512000); 63753a5a1b3Sopenharmony_ci} 63853a5a1b3Sopenharmony_ci 63953a5a1b3Sopenharmony_cistatic uint8_t fill_capabilities_xq_552kbps(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) { 64053a5a1b3Sopenharmony_ci return fill_capabilities_xq(capabilities_buffer, 552000); 64153a5a1b3Sopenharmony_ci} 64253a5a1b3Sopenharmony_ci 64353a5a1b3Sopenharmony_cistatic uint8_t fill_preferred_configuration_xq_552kbps(const pa_sample_spec *default_sample_spec, const uint8_t *capabilities_buffer, uint8_t capabilities_size, uint8_t config_buffer[MAX_A2DP_CAPS_SIZE]) { 64453a5a1b3Sopenharmony_ci return fill_preferred_configuration_xq(default_sample_spec, capabilities_buffer, capabilities_size, config_buffer, 552000); 64553a5a1b3Sopenharmony_ci} 64653a5a1b3Sopenharmony_ci 64753a5a1b3Sopenharmony_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) { 64853a5a1b3Sopenharmony_ci struct sbc_info *sbc_info; 64953a5a1b3Sopenharmony_ci const a2dp_sbc_t *config = (const a2dp_sbc_t *) config_buffer; 65053a5a1b3Sopenharmony_ci int ret; 65153a5a1b3Sopenharmony_ci 65253a5a1b3Sopenharmony_ci pa_assert(config_size == sizeof(*config)); 65353a5a1b3Sopenharmony_ci pa_assert(!for_backchannel); 65453a5a1b3Sopenharmony_ci 65553a5a1b3Sopenharmony_ci sbc_info = pa_xnew0(struct sbc_info, 1); 65653a5a1b3Sopenharmony_ci 65753a5a1b3Sopenharmony_ci ret = sbc_init(&sbc_info->sbc, 0); 65853a5a1b3Sopenharmony_ci if (ret != 0) { 65953a5a1b3Sopenharmony_ci pa_xfree(sbc_info); 66053a5a1b3Sopenharmony_ci pa_log_error("SBC initialization failed: %d", ret); 66153a5a1b3Sopenharmony_ci return NULL; 66253a5a1b3Sopenharmony_ci } 66353a5a1b3Sopenharmony_ci 66453a5a1b3Sopenharmony_ci sample_spec->format = PA_SAMPLE_S16LE; 66553a5a1b3Sopenharmony_ci 66653a5a1b3Sopenharmony_ci set_info_and_sample_spec_from_sbc_config(sbc_info, sample_spec, config); 66753a5a1b3Sopenharmony_ci 66853a5a1b3Sopenharmony_ci /* Set minimum bitpool for source to get the maximum possible block_size 66953a5a1b3Sopenharmony_ci * in get_block_size() function. This block_size is length of buffer used 67053a5a1b3Sopenharmony_ci * for decoded audio data and so is inversely proportional to frame length 67153a5a1b3Sopenharmony_ci * which depends on bitpool value. Bitpool is controlled by other side from 67253a5a1b3Sopenharmony_ci * range [min_bitpool, max_bitpool]. */ 67353a5a1b3Sopenharmony_ci sbc_info->initial_bitpool = for_encoding ? sbc_info->max_bitpool : sbc_info->min_bitpool; 67453a5a1b3Sopenharmony_ci 67553a5a1b3Sopenharmony_ci set_params(sbc_info); 67653a5a1b3Sopenharmony_ci 67753a5a1b3Sopenharmony_ci pa_log_info("SBC parameters: allocation=%s, subbands=%u, blocks=%u, mode=%s bitpool=%u codesize=%u frame_length=%u", 67853a5a1b3Sopenharmony_ci sbc_info->sbc.allocation ? "SNR" : "Loudness", sbc_info->sbc.subbands ? 8 : 4, 67953a5a1b3Sopenharmony_ci (sbc_info->sbc.blocks+1)*4, sbc_info->sbc.mode == SBC_MODE_MONO ? "Mono" : 68053a5a1b3Sopenharmony_ci sbc_info->sbc.mode == SBC_MODE_DUAL_CHANNEL ? "DualChannel" : 68153a5a1b3Sopenharmony_ci sbc_info->sbc.mode == SBC_MODE_STEREO ? "Stereo" : "JointStereo", 68253a5a1b3Sopenharmony_ci sbc_info->sbc.bitpool, (unsigned)sbc_info->codesize, (unsigned)sbc_info->frame_length); 68353a5a1b3Sopenharmony_ci 68453a5a1b3Sopenharmony_ci return sbc_info; 68553a5a1b3Sopenharmony_ci} 68653a5a1b3Sopenharmony_ci 68753a5a1b3Sopenharmony_cistatic void deinit(void *codec_info) { 68853a5a1b3Sopenharmony_ci struct sbc_info *sbc_info = (struct sbc_info *) codec_info; 68953a5a1b3Sopenharmony_ci 69053a5a1b3Sopenharmony_ci sbc_finish(&sbc_info->sbc); 69153a5a1b3Sopenharmony_ci pa_xfree(sbc_info); 69253a5a1b3Sopenharmony_ci} 69353a5a1b3Sopenharmony_ci 69453a5a1b3Sopenharmony_cistatic void set_bitpool(struct sbc_info *sbc_info, uint8_t bitpool) { 69553a5a1b3Sopenharmony_ci if (bitpool > sbc_info->max_bitpool) 69653a5a1b3Sopenharmony_ci bitpool = sbc_info->max_bitpool; 69753a5a1b3Sopenharmony_ci else if (bitpool < sbc_info->min_bitpool) 69853a5a1b3Sopenharmony_ci bitpool = sbc_info->min_bitpool; 69953a5a1b3Sopenharmony_ci 70053a5a1b3Sopenharmony_ci sbc_info->sbc.bitpool = bitpool; 70153a5a1b3Sopenharmony_ci 70253a5a1b3Sopenharmony_ci sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc); 70353a5a1b3Sopenharmony_ci sbc_info->frame_length = sbc_get_frame_length(&sbc_info->sbc); 70453a5a1b3Sopenharmony_ci 70553a5a1b3Sopenharmony_ci pa_log_debug("Bitpool has changed to %u", sbc_info->sbc.bitpool); 70653a5a1b3Sopenharmony_ci} 70753a5a1b3Sopenharmony_ci 70853a5a1b3Sopenharmony_cistatic int reset(void *codec_info) { 70953a5a1b3Sopenharmony_ci struct sbc_info *sbc_info = (struct sbc_info *) codec_info; 71053a5a1b3Sopenharmony_ci int ret; 71153a5a1b3Sopenharmony_ci 71253a5a1b3Sopenharmony_ci ret = sbc_reinit(&sbc_info->sbc, 0); 71353a5a1b3Sopenharmony_ci if (ret != 0) { 71453a5a1b3Sopenharmony_ci pa_log_error("SBC reinitialization failed: %d", ret); 71553a5a1b3Sopenharmony_ci return -1; 71653a5a1b3Sopenharmony_ci } 71753a5a1b3Sopenharmony_ci 71853a5a1b3Sopenharmony_ci /* sbc_reinit() sets also default parameters, so reset them back */ 71953a5a1b3Sopenharmony_ci set_params(sbc_info); 72053a5a1b3Sopenharmony_ci 72153a5a1b3Sopenharmony_ci sbc_info->seq_num = 0; 72253a5a1b3Sopenharmony_ci return 0; 72353a5a1b3Sopenharmony_ci} 72453a5a1b3Sopenharmony_ci 72553a5a1b3Sopenharmony_cistatic size_t get_block_size(void *codec_info, size_t link_mtu) { 72653a5a1b3Sopenharmony_ci struct sbc_info *sbc_info = (struct sbc_info *) codec_info; 72753a5a1b3Sopenharmony_ci size_t rtp_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload); 72853a5a1b3Sopenharmony_ci size_t frame_count = (link_mtu - rtp_size) / sbc_info->frame_length; 72953a5a1b3Sopenharmony_ci 73053a5a1b3Sopenharmony_ci /* frame_count is only 4 bit number */ 73153a5a1b3Sopenharmony_ci if (frame_count > 15) 73253a5a1b3Sopenharmony_ci frame_count = 15; 73353a5a1b3Sopenharmony_ci 73453a5a1b3Sopenharmony_ci /* Code dealing with read/write block size expects it to be 73553a5a1b3Sopenharmony_ci * non-zero to make progress, make it at least one frame. 73653a5a1b3Sopenharmony_ci */ 73753a5a1b3Sopenharmony_ci if (frame_count < 1) { 73853a5a1b3Sopenharmony_ci pa_log_warn("SBC packet size %lu is larger than link MTU %lu", sbc_info->frame_length + rtp_size, link_mtu); 73953a5a1b3Sopenharmony_ci frame_count = 1; 74053a5a1b3Sopenharmony_ci } 74153a5a1b3Sopenharmony_ci 74253a5a1b3Sopenharmony_ci return frame_count * sbc_info->codesize; 74353a5a1b3Sopenharmony_ci} 74453a5a1b3Sopenharmony_ci 74553a5a1b3Sopenharmony_cistatic size_t get_encoded_block_size(void *codec_info, size_t input_size) { 74653a5a1b3Sopenharmony_ci struct sbc_info *sbc_info = (struct sbc_info *) codec_info; 74753a5a1b3Sopenharmony_ci size_t rtp_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload); 74853a5a1b3Sopenharmony_ci 74953a5a1b3Sopenharmony_ci /* input size should be aligned to codec input block size */ 75053a5a1b3Sopenharmony_ci pa_assert_fp(input_size % sbc_info->codesize == 0); 75153a5a1b3Sopenharmony_ci 75253a5a1b3Sopenharmony_ci return (input_size / sbc_info->codesize) * sbc_info->frame_length + rtp_size; 75353a5a1b3Sopenharmony_ci} 75453a5a1b3Sopenharmony_ci 75553a5a1b3Sopenharmony_cistatic size_t reduce_encoder_bitrate(void *codec_info, size_t write_link_mtu) { 75653a5a1b3Sopenharmony_ci struct sbc_info *sbc_info = (struct sbc_info *) codec_info; 75753a5a1b3Sopenharmony_ci uint8_t bitpool; 75853a5a1b3Sopenharmony_ci 75953a5a1b3Sopenharmony_ci bitpool = PA_MAX(sbc_info->sbc.bitpool - SBC_BITPOOL_DEC_STEP, sbc_info->min_bitpool); 76053a5a1b3Sopenharmony_ci 76153a5a1b3Sopenharmony_ci if (sbc_info->sbc.bitpool == bitpool) 76253a5a1b3Sopenharmony_ci return 0; 76353a5a1b3Sopenharmony_ci 76453a5a1b3Sopenharmony_ci set_bitpool(sbc_info, bitpool); 76553a5a1b3Sopenharmony_ci return get_block_size(codec_info, write_link_mtu); 76653a5a1b3Sopenharmony_ci} 76753a5a1b3Sopenharmony_ci 76853a5a1b3Sopenharmony_cistatic size_t increase_encoder_bitrate(void *codec_info, size_t write_link_mtu) { 76953a5a1b3Sopenharmony_ci struct sbc_info *sbc_info = (struct sbc_info *) codec_info; 77053a5a1b3Sopenharmony_ci uint8_t bitpool; 77153a5a1b3Sopenharmony_ci 77253a5a1b3Sopenharmony_ci bitpool = PA_MIN(sbc_info->sbc.bitpool + SBC_BITPOOL_INC_STEP, sbc_info->max_bitpool); 77353a5a1b3Sopenharmony_ci 77453a5a1b3Sopenharmony_ci if (sbc_info->sbc.bitpool == bitpool) 77553a5a1b3Sopenharmony_ci return 0; 77653a5a1b3Sopenharmony_ci 77753a5a1b3Sopenharmony_ci set_bitpool(sbc_info, bitpool); 77853a5a1b3Sopenharmony_ci return get_block_size(codec_info, write_link_mtu); 77953a5a1b3Sopenharmony_ci} 78053a5a1b3Sopenharmony_ci 78153a5a1b3Sopenharmony_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) { 78253a5a1b3Sopenharmony_ci struct sbc_info *sbc_info = (struct sbc_info *) codec_info; 78353a5a1b3Sopenharmony_ci struct rtp_header *header; 78453a5a1b3Sopenharmony_ci struct rtp_payload *payload; 78553a5a1b3Sopenharmony_ci uint8_t *d; 78653a5a1b3Sopenharmony_ci const uint8_t *p; 78753a5a1b3Sopenharmony_ci size_t to_write, to_encode; 78853a5a1b3Sopenharmony_ci uint8_t frame_count; 78953a5a1b3Sopenharmony_ci 79053a5a1b3Sopenharmony_ci header = (struct rtp_header*) output_buffer; 79153a5a1b3Sopenharmony_ci payload = (struct rtp_payload*) (output_buffer + sizeof(*header)); 79253a5a1b3Sopenharmony_ci 79353a5a1b3Sopenharmony_ci frame_count = 0; 79453a5a1b3Sopenharmony_ci 79553a5a1b3Sopenharmony_ci p = input_buffer; 79653a5a1b3Sopenharmony_ci to_encode = input_size; 79753a5a1b3Sopenharmony_ci 79853a5a1b3Sopenharmony_ci d = output_buffer + sizeof(*header) + sizeof(*payload); 79953a5a1b3Sopenharmony_ci to_write = output_size - sizeof(*header) - sizeof(*payload); 80053a5a1b3Sopenharmony_ci 80153a5a1b3Sopenharmony_ci /* frame_count is only 4 bit number */ 80253a5a1b3Sopenharmony_ci while (PA_LIKELY(to_encode > 0 && to_write > 0 && frame_count < 15)) { 80353a5a1b3Sopenharmony_ci ssize_t written; 80453a5a1b3Sopenharmony_ci ssize_t encoded; 80553a5a1b3Sopenharmony_ci 80653a5a1b3Sopenharmony_ci encoded = sbc_encode(&sbc_info->sbc, 80753a5a1b3Sopenharmony_ci p, to_encode, 80853a5a1b3Sopenharmony_ci d, to_write, 80953a5a1b3Sopenharmony_ci &written); 81053a5a1b3Sopenharmony_ci 81153a5a1b3Sopenharmony_ci if (PA_UNLIKELY(encoded <= 0)) { 81253a5a1b3Sopenharmony_ci pa_log_error("SBC encoding error (%li)", (long) encoded); 81353a5a1b3Sopenharmony_ci break; 81453a5a1b3Sopenharmony_ci } 81553a5a1b3Sopenharmony_ci 81653a5a1b3Sopenharmony_ci if (PA_UNLIKELY(written < 0)) { 81753a5a1b3Sopenharmony_ci pa_log_error("SBC encoding error (%li)", (long) written); 81853a5a1b3Sopenharmony_ci break; 81953a5a1b3Sopenharmony_ci } 82053a5a1b3Sopenharmony_ci 82153a5a1b3Sopenharmony_ci pa_assert_fp((size_t) encoded <= to_encode); 82253a5a1b3Sopenharmony_ci pa_assert_fp((size_t) encoded == sbc_info->codesize); 82353a5a1b3Sopenharmony_ci 82453a5a1b3Sopenharmony_ci pa_assert_fp((size_t) written <= to_write); 82553a5a1b3Sopenharmony_ci pa_assert_fp((size_t) written == sbc_info->frame_length); 82653a5a1b3Sopenharmony_ci 82753a5a1b3Sopenharmony_ci p += encoded; 82853a5a1b3Sopenharmony_ci to_encode -= encoded; 82953a5a1b3Sopenharmony_ci 83053a5a1b3Sopenharmony_ci d += written; 83153a5a1b3Sopenharmony_ci to_write -= written; 83253a5a1b3Sopenharmony_ci 83353a5a1b3Sopenharmony_ci frame_count++; 83453a5a1b3Sopenharmony_ci } 83553a5a1b3Sopenharmony_ci 83653a5a1b3Sopenharmony_ci PA_ONCE_BEGIN { 83753a5a1b3Sopenharmony_ci pa_log_debug("Using SBC codec implementation: %s", pa_strnull(sbc_get_implementation_info(&sbc_info->sbc))); 83853a5a1b3Sopenharmony_ci } PA_ONCE_END; 83953a5a1b3Sopenharmony_ci 84053a5a1b3Sopenharmony_ci if (PA_UNLIKELY(frame_count == 0)) { 84153a5a1b3Sopenharmony_ci *processed = 0; 84253a5a1b3Sopenharmony_ci return 0; 84353a5a1b3Sopenharmony_ci } 84453a5a1b3Sopenharmony_ci 84553a5a1b3Sopenharmony_ci /* write it to the fifo */ 84653a5a1b3Sopenharmony_ci pa_memzero(output_buffer, sizeof(*header) + sizeof(*payload)); 84753a5a1b3Sopenharmony_ci header->v = 2; 84853a5a1b3Sopenharmony_ci 84953a5a1b3Sopenharmony_ci /* A2DP spec: "A payload type in the RTP dynamic range shall be chosen". 85053a5a1b3Sopenharmony_ci * RFC3551 defines the dynamic range to span from 96 to 127, and 96 appears 85153a5a1b3Sopenharmony_ci * to be the most common choice in A2DP implementations. */ 85253a5a1b3Sopenharmony_ci header->pt = 96; 85353a5a1b3Sopenharmony_ci 85453a5a1b3Sopenharmony_ci header->sequence_number = htons(sbc_info->seq_num++); 85553a5a1b3Sopenharmony_ci header->timestamp = htonl(timestamp); 85653a5a1b3Sopenharmony_ci header->ssrc = htonl(1); 85753a5a1b3Sopenharmony_ci payload->frame_count = frame_count; 85853a5a1b3Sopenharmony_ci 85953a5a1b3Sopenharmony_ci *processed = p - input_buffer; 86053a5a1b3Sopenharmony_ci return d - output_buffer; 86153a5a1b3Sopenharmony_ci} 86253a5a1b3Sopenharmony_ci 86353a5a1b3Sopenharmony_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) { 86453a5a1b3Sopenharmony_ci struct sbc_info *sbc_info = (struct sbc_info *) codec_info; 86553a5a1b3Sopenharmony_ci 86653a5a1b3Sopenharmony_ci struct rtp_header *header; 86753a5a1b3Sopenharmony_ci struct rtp_payload *payload; 86853a5a1b3Sopenharmony_ci const uint8_t *p; 86953a5a1b3Sopenharmony_ci uint8_t *d; 87053a5a1b3Sopenharmony_ci size_t to_write, to_decode; 87153a5a1b3Sopenharmony_ci uint8_t frame_count; 87253a5a1b3Sopenharmony_ci 87353a5a1b3Sopenharmony_ci header = (struct rtp_header *) input_buffer; 87453a5a1b3Sopenharmony_ci payload = (struct rtp_payload*) (input_buffer + sizeof(*header)); 87553a5a1b3Sopenharmony_ci 87653a5a1b3Sopenharmony_ci frame_count = payload->frame_count; 87753a5a1b3Sopenharmony_ci 87853a5a1b3Sopenharmony_ci /* TODO: Add support for decoding fragmented SBC frames */ 87953a5a1b3Sopenharmony_ci if (payload->is_fragmented) { 88053a5a1b3Sopenharmony_ci pa_log_error("Unsupported fragmented SBC frame"); 88153a5a1b3Sopenharmony_ci *processed = 0; 88253a5a1b3Sopenharmony_ci return 0; 88353a5a1b3Sopenharmony_ci } 88453a5a1b3Sopenharmony_ci 88553a5a1b3Sopenharmony_ci p = input_buffer + sizeof(*header) + sizeof(*payload); 88653a5a1b3Sopenharmony_ci to_decode = input_size - sizeof(*header) - sizeof(*payload); 88753a5a1b3Sopenharmony_ci 88853a5a1b3Sopenharmony_ci d = output_buffer; 88953a5a1b3Sopenharmony_ci to_write = output_size; 89053a5a1b3Sopenharmony_ci 89153a5a1b3Sopenharmony_ci while (PA_LIKELY(to_decode > 0 && to_write > 0 && frame_count > 0)) { 89253a5a1b3Sopenharmony_ci size_t written; 89353a5a1b3Sopenharmony_ci ssize_t decoded; 89453a5a1b3Sopenharmony_ci 89553a5a1b3Sopenharmony_ci decoded = sbc_decode(&sbc_info->sbc, 89653a5a1b3Sopenharmony_ci p, to_decode, 89753a5a1b3Sopenharmony_ci d, to_write, 89853a5a1b3Sopenharmony_ci &written); 89953a5a1b3Sopenharmony_ci 90053a5a1b3Sopenharmony_ci if (PA_UNLIKELY(decoded <= 0)) { 90153a5a1b3Sopenharmony_ci pa_log_error("SBC decoding error (%li)", (long) decoded); 90253a5a1b3Sopenharmony_ci break; 90353a5a1b3Sopenharmony_ci } 90453a5a1b3Sopenharmony_ci 90553a5a1b3Sopenharmony_ci /* Reset frame length, it can be changed due to bitpool change */ 90653a5a1b3Sopenharmony_ci sbc_info->frame_length = sbc_get_frame_length(&sbc_info->sbc); 90753a5a1b3Sopenharmony_ci 90853a5a1b3Sopenharmony_ci pa_assert_fp((size_t) decoded <= to_decode); 90953a5a1b3Sopenharmony_ci pa_assert_fp((size_t) decoded == sbc_info->frame_length); 91053a5a1b3Sopenharmony_ci 91153a5a1b3Sopenharmony_ci pa_assert_fp((size_t) written <= to_write); 91253a5a1b3Sopenharmony_ci pa_assert_fp((size_t) written == sbc_info->codesize); 91353a5a1b3Sopenharmony_ci 91453a5a1b3Sopenharmony_ci p += decoded; 91553a5a1b3Sopenharmony_ci to_decode -= decoded; 91653a5a1b3Sopenharmony_ci 91753a5a1b3Sopenharmony_ci d += written; 91853a5a1b3Sopenharmony_ci to_write -= written; 91953a5a1b3Sopenharmony_ci 92053a5a1b3Sopenharmony_ci frame_count--; 92153a5a1b3Sopenharmony_ci } 92253a5a1b3Sopenharmony_ci 92353a5a1b3Sopenharmony_ci *processed = p - input_buffer; 92453a5a1b3Sopenharmony_ci return d - output_buffer; 92553a5a1b3Sopenharmony_ci} 92653a5a1b3Sopenharmony_ci 92753a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc = { 92853a5a1b3Sopenharmony_ci .id = { A2DP_CODEC_SBC, 0, 0 }, 92953a5a1b3Sopenharmony_ci .support_backchannel = false, 93053a5a1b3Sopenharmony_ci .can_be_supported = can_be_supported, 93153a5a1b3Sopenharmony_ci .can_accept_capabilities = can_accept_capabilities, 93253a5a1b3Sopenharmony_ci .choose_remote_endpoint = choose_remote_endpoint, 93353a5a1b3Sopenharmony_ci .fill_capabilities = fill_capabilities, 93453a5a1b3Sopenharmony_ci .is_configuration_valid = is_configuration_valid, 93553a5a1b3Sopenharmony_ci .fill_preferred_configuration = fill_preferred_configuration, 93653a5a1b3Sopenharmony_ci .bt_codec = { 93753a5a1b3Sopenharmony_ci .name = "sbc", 93853a5a1b3Sopenharmony_ci .description = "SBC", 93953a5a1b3Sopenharmony_ci .init = init, 94053a5a1b3Sopenharmony_ci .deinit = deinit, 94153a5a1b3Sopenharmony_ci .reset = reset, 94253a5a1b3Sopenharmony_ci .get_read_block_size = get_block_size, 94353a5a1b3Sopenharmony_ci .get_write_block_size = get_block_size, 94453a5a1b3Sopenharmony_ci .get_encoded_block_size = get_encoded_block_size, 94553a5a1b3Sopenharmony_ci .reduce_encoder_bitrate = reduce_encoder_bitrate, 94653a5a1b3Sopenharmony_ci .increase_encoder_bitrate = increase_encoder_bitrate, 94753a5a1b3Sopenharmony_ci .encode_buffer = encode_buffer, 94853a5a1b3Sopenharmony_ci .decode_buffer = decode_buffer, 94953a5a1b3Sopenharmony_ci }, 95053a5a1b3Sopenharmony_ci}; 95153a5a1b3Sopenharmony_ci 95253a5a1b3Sopenharmony_ci/* There are multiple definitions of SBC XQ, but in all cases this is 95353a5a1b3Sopenharmony_ci * SBC codec in Dual Channel mode, 8 bands, block length 16, allocation method Loudness, 95453a5a1b3Sopenharmony_ci * with bitpool adjusted to match target bitrates. 95553a5a1b3Sopenharmony_ci * 95653a5a1b3Sopenharmony_ci * Most commonly choosen bitrates and reasons are: 95753a5a1b3Sopenharmony_ci * 453000 - this yields most efficient packing of frames on Android for bluetooth EDR 2mbps 95853a5a1b3Sopenharmony_ci * 512000 - this looks to be old limit stated in bluetooth documents 95953a5a1b3Sopenharmony_ci * 552000 - this yields most efficient packing of frames on Android for bluetooth EDR 3mbps 96053a5a1b3Sopenharmony_ci * 96153a5a1b3Sopenharmony_ci * Efficient packing considerations do not apply on Linux (yet?) but still 96253a5a1b3Sopenharmony_ci * we can gain from increased bitrate. 96353a5a1b3Sopenharmony_ci */ 96453a5a1b3Sopenharmony_ci 96553a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc_xq_453 = { 96653a5a1b3Sopenharmony_ci .id = { A2DP_CODEC_SBC, 0, 0 }, 96753a5a1b3Sopenharmony_ci .support_backchannel = false, 96853a5a1b3Sopenharmony_ci .can_be_supported = can_be_supported, 96953a5a1b3Sopenharmony_ci .can_accept_capabilities = can_accept_capabilities_xq, 97053a5a1b3Sopenharmony_ci .choose_remote_endpoint = choose_remote_endpoint_xq, 97153a5a1b3Sopenharmony_ci .fill_capabilities = fill_capabilities_xq_453kbps, 97253a5a1b3Sopenharmony_ci .is_configuration_valid = is_configuration_valid, 97353a5a1b3Sopenharmony_ci .fill_preferred_configuration = fill_preferred_configuration_xq_453kbps, 97453a5a1b3Sopenharmony_ci .bt_codec = { 97553a5a1b3Sopenharmony_ci .name = "sbc_xq_453", 97653a5a1b3Sopenharmony_ci .description = "SBC XQ 453kbps", 97753a5a1b3Sopenharmony_ci .init = init, 97853a5a1b3Sopenharmony_ci .deinit = deinit, 97953a5a1b3Sopenharmony_ci .reset = reset, 98053a5a1b3Sopenharmony_ci .get_read_block_size = get_block_size, 98153a5a1b3Sopenharmony_ci .get_write_block_size = get_block_size, 98253a5a1b3Sopenharmony_ci .get_encoded_block_size = get_encoded_block_size, 98353a5a1b3Sopenharmony_ci .reduce_encoder_bitrate = reduce_encoder_bitrate, 98453a5a1b3Sopenharmony_ci .increase_encoder_bitrate = increase_encoder_bitrate, 98553a5a1b3Sopenharmony_ci .encode_buffer = encode_buffer, 98653a5a1b3Sopenharmony_ci .decode_buffer = decode_buffer, 98753a5a1b3Sopenharmony_ci }, 98853a5a1b3Sopenharmony_ci}; 98953a5a1b3Sopenharmony_ci 99053a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc_xq_512 = { 99153a5a1b3Sopenharmony_ci .id = { A2DP_CODEC_SBC, 0, 0 }, 99253a5a1b3Sopenharmony_ci .support_backchannel = false, 99353a5a1b3Sopenharmony_ci .can_be_supported = can_be_supported, 99453a5a1b3Sopenharmony_ci .can_accept_capabilities = can_accept_capabilities_xq, 99553a5a1b3Sopenharmony_ci .choose_remote_endpoint = choose_remote_endpoint_xq, 99653a5a1b3Sopenharmony_ci .fill_capabilities = fill_capabilities_xq_512kbps, 99753a5a1b3Sopenharmony_ci .is_configuration_valid = is_configuration_valid, 99853a5a1b3Sopenharmony_ci .fill_preferred_configuration = fill_preferred_configuration_xq_512kbps, 99953a5a1b3Sopenharmony_ci .bt_codec = { 100053a5a1b3Sopenharmony_ci .name = "sbc_xq_512", 100153a5a1b3Sopenharmony_ci .description = "SBC XQ 512kbps", 100253a5a1b3Sopenharmony_ci .init = init, 100353a5a1b3Sopenharmony_ci .deinit = deinit, 100453a5a1b3Sopenharmony_ci .reset = reset, 100553a5a1b3Sopenharmony_ci .get_read_block_size = get_block_size, 100653a5a1b3Sopenharmony_ci .get_write_block_size = get_block_size, 100753a5a1b3Sopenharmony_ci .get_encoded_block_size = get_encoded_block_size, 100853a5a1b3Sopenharmony_ci .reduce_encoder_bitrate = reduce_encoder_bitrate, 100953a5a1b3Sopenharmony_ci .increase_encoder_bitrate = increase_encoder_bitrate, 101053a5a1b3Sopenharmony_ci .encode_buffer = encode_buffer, 101153a5a1b3Sopenharmony_ci .decode_buffer = decode_buffer, 101253a5a1b3Sopenharmony_ci }, 101353a5a1b3Sopenharmony_ci}; 101453a5a1b3Sopenharmony_ci 101553a5a1b3Sopenharmony_ciconst pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc_xq_552 = { 101653a5a1b3Sopenharmony_ci .id = { A2DP_CODEC_SBC, 0, 0 }, 101753a5a1b3Sopenharmony_ci .support_backchannel = false, 101853a5a1b3Sopenharmony_ci .can_be_supported = can_be_supported, 101953a5a1b3Sopenharmony_ci .can_accept_capabilities = can_accept_capabilities_xq, 102053a5a1b3Sopenharmony_ci .choose_remote_endpoint = choose_remote_endpoint_xq, 102153a5a1b3Sopenharmony_ci .fill_capabilities = fill_capabilities_xq_552kbps, 102253a5a1b3Sopenharmony_ci .is_configuration_valid = is_configuration_valid, 102353a5a1b3Sopenharmony_ci .fill_preferred_configuration = fill_preferred_configuration_xq_552kbps, 102453a5a1b3Sopenharmony_ci .bt_codec = { 102553a5a1b3Sopenharmony_ci .name = "sbc_xq_552", 102653a5a1b3Sopenharmony_ci .description = "SBC XQ 552kbps", 102753a5a1b3Sopenharmony_ci .init = init, 102853a5a1b3Sopenharmony_ci .deinit = deinit, 102953a5a1b3Sopenharmony_ci .reset = reset, 103053a5a1b3Sopenharmony_ci .get_read_block_size = get_block_size, 103153a5a1b3Sopenharmony_ci .get_write_block_size = get_block_size, 103253a5a1b3Sopenharmony_ci .get_encoded_block_size = get_encoded_block_size, 103353a5a1b3Sopenharmony_ci .reduce_encoder_bitrate = reduce_encoder_bitrate, 103453a5a1b3Sopenharmony_ci .increase_encoder_bitrate = increase_encoder_bitrate, 103553a5a1b3Sopenharmony_ci .encode_buffer = encode_buffer, 103653a5a1b3Sopenharmony_ci .decode_buffer = decode_buffer, 103753a5a1b3Sopenharmony_ci }, 103853a5a1b3Sopenharmony_ci}; 1039