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