[pulseaudio-discuss] SBC XQ for PA 13.0
Hyperion
h1p8r10n at yandex.com
Mon Dec 9 12:57:39 UTC 2019
09.12.2019, 12:33, "Andrey Semashev" <andrey.semashev at gmail.com>:
> I have another piece of feedback to provide. Sometimes I experience
> audio dropouts. Sometimes in both left and right headphones, sometimes
> just one. In particular, I noticed this happen when I have a
> Bluetooth-connected DualShock 4 gamepad connected and playing games, but
> it also happens without it, although less often.
>
> I assume this is caused by Bluetooth bandwidth limitation. Note that EOZ
> Air are "truly wireless" (i.e. the two headphones connect wirelessly),
> and I have multiple WiFi networks available (one access point in the
> same room as the Bluetooth transmitter, a few others behind walls). I
> expect 2.4 GHz radio to be rather crowded. The gamepad and the
> headphones are in the same room as the Bluetooth transmitter, in clear
> direct visibility, so it can't get better than that.
>
> I can see Pali's patches offer reduce_encoder_bitrate API that is
> supposed to mitigate this problem, but both SBC XQ profiles don't allow
> bitrate reduction. I think, SBC XQ desperately needs to support bitrate
> reduction, as the codec with the highest bitrate out of all.
Yes, and my patch was providing 100% adaptative SBC XQ, with native bitpool
reduction, as you suggest. But something more complex and yet more "static"' has
been preferred.
Users might
> actually have reduced experience due to audio dropouts compared to the
> previously supported SBC HQ.
>
> On 2019-12-07 21:09, Andrey Semashev wrote:
>> Â FWIW, I tested the patch[1] from your github repository with PulseAudio
>> Â 13.0 on Ubuntu 19.10 with my EOZ Air. It works, and the sound quality is
>> Â subjectively better compared to the stock PA 13.0. The noise level that
>> Â can be heard on silent audio sections seems to be lower.
>>
>> Â However, I can still hear compression artefacts on quiet or nearly
>> Â silent audio sections, which sound like high-pitch squeaking sounds. It
>> Â can often be heard on various music fade out sections. I don't know if
>> Â this is inherrent from SBC codec itself or is a deficiency of libsbc
>> Â implementation, or the headphones. These artefacts are my main complaint
>> Â about SBC.
>>
>> Â My EOZ Air also supports AAC, and the audio quality is better still with
>> Â it (I tested with pulseaudio-modules-bt[2] and my Android phone). There
>> Â are no squeaky artefacts with AAC.
>>
>> Â Which brings me to my question to PA developers. Would an addition of
>> Â support for AAC be possible?
>>
>> Â pulseaudio-modules-bt uses libfdk-aac to implement AAC, and if possible,
>> Â I would prefer that library as it provides the best quality available on
>> Â Linux. However, if licensing is an issue, there is also a built-in
>> Â implementation in ffmpeg.
>>
>> Â [1]: Patch obtained with `git diff
>> Â 200618b32f0964a479d69c9b6e5073e6931c370a..0853d7465729c1fb6c25745c05dc749a1b9a8d6f`
>>
>> Â [2]: https://github.com/EHfive/pulseaudio-modules-bt
>>
>> Â On 2019-09-20 12:45, Hyperion wrote:
>>> Â HI,
>>>
>>> Â I have reworked my mod so that it can safely achieve bitpool 94 in
>>> Â both dual channel and joint stereo, as long as the device supports it
>>> Â (only my high end Harman Kardon support 94 in joint stereo).
>>> Â Devices supporting only bitpool 53 are kept safe (bitpool is always
>>> Â negociated, never forced : this doesn't use fixed caps).
>>>
>>> Â Anyway most devices support at least bitpool 47 in dual channel mode,
>>> Â and BT (version 3 and up) bandwidth is much higher : so this patch
>>> Â deprecates both APTX and LDAC.
>>>
>>> Â The Git is up to date : https://github.com/JPGuillemin/pulseaudio
>>>
>>> Â This patch is likely safe to be applied on the official master cause
>>> Â it doesn't need Bluez multi-codec API, and doesn't introduce any
>>> Â patent issue (mainly from CSR, openaptx being underground reverse
>>> Â ingeniering).
>>>
>>> Â All the best
>>> Â JP
>>>
>>> Â 19.09.2019, 13:07, "Hyperion" <h1p8r10n at yandex.com>:
>>>> Â The Git branch with my mods :
>>>> Â https://github.com/JPGuillemin/pulseaudio/tree/SBC-XQ
>>>>
>>>> Â I'm sure it needs improvement, but I need testers ;) for now it works
>>>> Â as expected on all my devices...
>>>>
>>>> Â JP
>>>>
>>>> Â 19.09.2019, 11:21, "Hyperion" <h1p8r10n at yandex.com>:
>>>>> Â Â Â Yes, thanks, you're right, I'm going to do it as soon as I get
>>>>> Â enough testing feedback.
>>>>>
>>>>> Â Â Â Talking about tests : I'm going to switch back to Pali's default
>>>>> Â values for announced bitpool capabilities, cause some (rare) devices
>>>>> Â produces a few distorsion with dual channel 47 bitpool.
>>>>>
>>>>> Â Â Â So back to dual 38 / 76 , which should be ok on any device.
>>>>>
>>>>> Â Â Â New patch :
>>>>> Â http://download.zenwalk.org/x86_64/testing/pulseaudio-13.0-SBC-XQ_V3.patch
>>>>>
>>>>> Â Â Â Thanks for testing :)
>>>>>
>>>>> Â Â Â jp
>>>>>
>>>>> Â Â Â 19.09.2019, 10:27, "Andrey Semashev" <andrey.semashev at gmail.com>:
>>>>>> Â Â Â Â I'm not the maintainer, but it might be better to create a merge
>>>>>> Â request
>>>>>> Â Â Â Â in GitLab project:
>>>>>>
>>>>>> Â Â Â Â https://gitlab.freedesktop.org/pulseaudio/pulseaudio
>>>>>>
>>>>>> Â Â Â Â and post any additional information there so it doesn't get lost.
>>>>>>
>>>>>> Â Â Â Â On 2019-09-18 14:02, Hyperion wrote:
>>>>>>> Â Â Â Â Â Patch V2 with added DUAL_CHANNEL as preferred mode.
>>>>>>>
>>>>>>> Â Â Â Â Â Works without any issue on more than 10 stereo and mono
>>>>>>> Â devices that I have here.
>>>>>>>
>>>>>>> Â Â Â Â Â http://download.zenwalk.org/x86_64/testing/pulseaudio-13.0-SBC-XQ_V2.patch
>>>>>>>
>>>>>>> Â Â Â Â Â /***
>>>>>>> Â Â Â Â Â Â Â Â This file is part of PulseAudio.
>>>>>>>
>>>>>>>         Copyright 2018-2019 Pali Rohár <pali.rohar at gmail.com>
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â PulseAudio is free software; you can redistribute it and/or
>>>>>>> Â modify
>>>>>>> Â Â Â Â Â Â Â Â it under the terms of the GNU Lesser General Public License as
>>>>>>> Â Â Â Â Â Â Â Â published by the Free Software Foundation; either version
>>>>>>> Â 2.1 of the
>>>>>>> Â Â Â Â Â Â Â Â License, or (at your option) any later version.
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â PulseAudio is distributed in the hope that it will be
>>>>>>> Â useful, but
>>>>>>> Â Â Â Â Â Â Â Â WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>>> Â Â Â Â Â Â Â Â MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
>>>>>>> Â the GNU
>>>>>>> Â Â Â Â Â Â Â Â General Public License for more details.
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â You should have received a copy of the GNU Lesser General
>>>>>>> Â Public
>>>>>>> Â Â Â Â Â Â Â Â License along with PulseAudio; if not, see
>>>>>>> Â <http://www.gnu.org/licenses/>.
>>>>>>> Â Â Â Â Â ***/
>>>>>>>
>>>>>>> Â Â Â Â Â #ifdef HAVE_CONFIG_H
>>>>>>> Â Â Â Â Â #include <config.h>
>>>>>>> Â Â Â Â Â #endif
>>>>>>>
>>>>>>> Â Â Â Â Â #include <pulsecore/core-util.h>
>>>>>>> Â Â Â Â Â #include <pulsecore/log.h>
>>>>>>> Â Â Â Â Â #include <pulsecore/macro.h>
>>>>>>> Â Â Â Â Â #include <pulsecore/once.h>
>>>>>>> Â Â Â Â Â #include <pulse/sample.h>
>>>>>>> Â Â Â Â Â #include <pulse/xmalloc.h>
>>>>>>>
>>>>>>> Â Â Â Â Â #include <arpa/inet.h>
>>>>>>>
>>>>>>> Â Â Â Â Â #include <sbc/sbc.h>
>>>>>>>
>>>>>>> Â Â Â Â Â #include "a2dp-codecs.h"
>>>>>>> Â Â Â Â Â #include "a2dp-codec-api.h"
>>>>>>> Â Â Â Â Â #include "rtp.h"
>>>>>>>
>>>>>>> Â Â Â Â Â #define SBC_BITPOOL_DEC_LIMIT 32
>>>>>>> Â Â Â Â Â #define SBC_BITPOOL_DEC_STEP 5
>>>>>>>
>>>>>>> Â Â Â Â Â struct sbc_info {
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_t sbc; /* Codec data */
>>>>>>> Â Â Â Â Â Â Â Â Â Â size_t codesize, frame_length; /* SBC Codesize,
>>>>>>> Â frame_length. We simply cache those values here */
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint16_t seq_num; /* Cumulative packet sequence */
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t frequency;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t blocks;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t subbands;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t mode;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t allocation;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t initial_bitpool;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t min_bitpool;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t max_bitpool;
>>>>>>> Â Â Â Â Â };
>>>>>>>
>>>>>>> Â Â Â Â Â static bool can_accept_capabilities(const uint8_t
>>>>>>> Â *capabilities_buffer, uint8_t capabilities_size, bool for_encoding) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â const a2dp_sbc_t *capabilities = (const a2dp_sbc_t *)
>>>>>>> Â capabilities_buffer;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (capabilities_size != sizeof(*capabilities))
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (!(capabilities->frequency & (SBC_SAMPLING_FREQ_16000
>>>>>>> Â | SBC_SAMPLING_FREQ_32000 | SBC_SAMPLING_FREQ_44100 |
>>>>>>> Â SBC_SAMPLING_FREQ_48000)))
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (!(capabilities->channel_mode & (SBC_CHANNEL_MODE_MONO
>>>>>>> Â | SBC_CHANNEL_MODE_DUAL_CHANNEL | SBC_CHANNEL_MODE_STEREO |
>>>>>>> Â SBC_CHANNEL_MODE_JOINT_STEREO)))
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (!(capabilities->allocation_method &
>>>>>>> Â (SBC_ALLOCATION_SNR | SBC_ALLOCATION_LOUDNESS)))
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (!(capabilities->subbands & (SBC_SUBBANDS_4 |
>>>>>>> Â SBC_SUBBANDS_8)))
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (!(capabilities->block_length & (SBC_BLOCK_LENGTH_4 |
>>>>>>> Â SBC_BLOCK_LENGTH_8 | SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16)))
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â return true;
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static const char *choose_remote_endpoint(const pa_hashmap
>>>>>>> Â *capabilities_hashmap, const pa_sample_spec *default_sample_spec,
>>>>>>> Â bool for_encoding) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â const pa_a2dp_codec_capabilities *a2dp_capabilities;
>>>>>>> Â Â Â Â Â Â Â Â Â Â const char *key;
>>>>>>> Â Â Â Â Â Â Â Â Â Â void *state;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â /* There is no preference, just choose random valid entry */
>>>>>>> Â Â Â Â Â Â Â Â Â Â PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities,
>>>>>>> Â capabilities_hashmap, state) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â if
>>>>>>> Â (can_accept_capabilities(a2dp_capabilities->buffer,
>>>>>>> Â a2dp_capabilities->size, for_encoding))
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return key;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â return NULL;
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static uint8_t fill_capabilities(uint8_t
>>>>>>> Â capabilities_buffer[MAX_A2DP_CAPS_SIZE]) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â a2dp_sbc_t *capabilities = (a2dp_sbc_t *)
>>>>>>> Â capabilities_buffer;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â pa_zero(*capabilities);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â capabilities->channel_mode = SBC_CHANNEL_MODE_MONO |
>>>>>>> Â SBC_CHANNEL_MODE_DUAL_CHANNEL | SBC_CHANNEL_MODE_STEREO |
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â SBC_CHANNEL_MODE_JOINT_STEREO;
>>>>>>> Â Â Â Â Â Â Â Â Â Â capabilities->frequency = SBC_SAMPLING_FREQ_16000 |
>>>>>>> Â SBC_SAMPLING_FREQ_32000 | SBC_SAMPLING_FREQ_44100 |
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â SBC_SAMPLING_FREQ_48000;
>>>>>>> Â Â Â Â Â Â Â Â Â Â capabilities->allocation_method = SBC_ALLOCATION_SNR |
>>>>>>> Â SBC_ALLOCATION_LOUDNESS;
>>>>>>> Â Â Â Â Â Â Â Â Â Â capabilities->subbands = SBC_SUBBANDS_4 | SBC_SUBBANDS_8;
>>>>>>> Â Â Â Â Â Â Â Â Â Â capabilities->block_length = SBC_BLOCK_LENGTH_4 |
>>>>>>> Â SBC_BLOCK_LENGTH_8 | SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_16;
>>>>>>> Â Â Â Â Â Â Â Â Â Â capabilities->min_bitpool = SBC_MIN_BITPOOL;
>>>>>>> Â Â Â Â Â Â Â Â Â Â capabilities->max_bitpool =
>>>>>>> Â SBC_BITPOOL_HQ_JOINT_STEREO_44100;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â return sizeof(*capabilities);
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static bool is_configuration_valid(const uint8_t
>>>>>>> Â *config_buffer, uint8_t config_size) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â const a2dp_sbc_t *config = (const a2dp_sbc_t *)
>>>>>>> Â config_buffer;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (config_size != sizeof(*config)) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("Invalid size of config buffer");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (config->frequency != SBC_SAMPLING_FREQ_16000 &&
>>>>>>> Â config->frequency != SBC_SAMPLING_FREQ_32000 &&
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->frequency != SBC_SAMPLING_FREQ_44100 &&
>>>>>>> Â config->frequency != SBC_SAMPLING_FREQ_48000) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("Invalid sampling frequency in
>>>>>>> Â configuration");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (config->channel_mode != SBC_CHANNEL_MODE_MONO &&
>>>>>>> Â config->channel_mode != SBC_CHANNEL_MODE_DUAL_CHANNEL &&
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->channel_mode != SBC_CHANNEL_MODE_STEREO &&
>>>>>>> Â config->channel_mode != SBC_CHANNEL_MODE_JOINT_STEREO) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("Invalid channel mode in configuration");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (config->allocation_method != SBC_ALLOCATION_SNR &&
>>>>>>> Â config->allocation_method != SBC_ALLOCATION_LOUDNESS) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("Invalid allocation method in
>>>>>>> Â configuration");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (config->subbands != SBC_SUBBANDS_4 &&
>>>>>>> Â config->subbands != SBC_SUBBANDS_8) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("Invalid SBC subbands in configuration");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (config->block_length != SBC_BLOCK_LENGTH_4 &&
>>>>>>> Â config->block_length != SBC_BLOCK_LENGTH_8 &&
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->block_length != SBC_BLOCK_LENGTH_12 &&
>>>>>>> Â config->block_length != SBC_BLOCK_LENGTH_16) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("Invalid block length in configuration");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (config->min_bitpool > config->max_bitpool) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("Invalid bitpool in configuration");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return false;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â return true;
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static uint8_t default_bitpool(uint8_t freq, uint8_t mode) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â /* These bitpool values were chosen based on the A2DP
>>>>>>> Â spec recommendation */
>>>>>>> Â Â Â Â Â Â Â Â Â Â switch (freq) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_SAMPLING_FREQ_48000:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â switch (mode) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_MONO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_DUAL_CHANNEL:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return SBC_BITPOOL_HQ_MONO_48000;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_STEREO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_JOINT_STEREO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return SBC_BITPOOL_HQ_JOINT_STEREO_48000;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_SAMPLING_FREQ_44100:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â switch (mode) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_MONO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_DUAL_CHANNEL:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return SBC_BITPOOL_HQ_MONO_44100;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_STEREO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_JOINT_STEREO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return SBC_BITPOOL_HQ_JOINT_STEREO_44100;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_SAMPLING_FREQ_16000:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_SAMPLING_FREQ_32000:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â switch (mode) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_MONO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_DUAL_CHANNEL:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_STEREO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_JOINT_STEREO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return SBC_BITPOOL_HQ_JOINT_STEREO_44100;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â pa_assert_not_reached();
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static 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]) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â a2dp_sbc_t *config = (a2dp_sbc_t *) config_buffer;
>>>>>>> Â Â Â Â Â Â Â Â Â Â const a2dp_sbc_t *capabilities = (const a2dp_sbc_t *)
>>>>>>> Â capabilities_buffer;
>>>>>>> Â Â Â Â Â Â Â Â Â Â int i;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â static const struct {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â uint32_t rate;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â uint8_t cap;
>>>>>>> Â Â Â Â Â Â Â Â Â Â } freq_table[] = {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â { 16000U, SBC_SAMPLING_FREQ_16000 },
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â { 32000U, SBC_SAMPLING_FREQ_32000 },
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â { 44100U, SBC_SAMPLING_FREQ_44100 },
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â { 48000U, SBC_SAMPLING_FREQ_48000 }
>>>>>>> Â Â Â Â Â Â Â Â Â Â };
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (capabilities_size != sizeof(*capabilities)) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("Invalid size of capabilities buffer");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â pa_zero(*config);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â /* Find the lowest freq that is at least as high as the
>>>>>>> Â requested sampling rate */
>>>>>>> Â Â Â Â Â Â Â Â Â Â for (i = 0; (unsigned) i < PA_ELEMENTSOF(freq_table); i++)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (freq_table[i].rate >= default_sample_spec->rate
>>>>>>> Â && (capabilities->frequency & freq_table[i].cap)) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->frequency = freq_table[i].cap;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if ((unsigned) i == PA_ELEMENTSOF(freq_table)) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â for (--i; i >= 0; i--) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (capabilities->frequency & freq_table[i].cap) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->frequency = freq_table[i].cap;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (i < 0) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("Not suitable sample rate");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â pa_assert((unsigned) i < PA_ELEMENTSOF(freq_table));
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (default_sample_spec->channels <= 1) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (capabilities->channel_mode & SBC_CHANNEL_MODE_MONO)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->channel_mode = SBC_CHANNEL_MODE_MONO;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â else if (capabilities->channel_mode &
>>>>>>> Â SBC_CHANNEL_MODE_JOINT_STEREO)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->channel_mode =
>>>>>>> Â SBC_CHANNEL_MODE_JOINT_STEREO;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â else if (capabilities->channel_mode &
>>>>>>> Â SBC_CHANNEL_MODE_STEREO)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->channel_mode = SBC_CHANNEL_MODE_STEREO;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â else if (capabilities->channel_mode &
>>>>>>> Â SBC_CHANNEL_MODE_DUAL_CHANNEL)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->channel_mode =
>>>>>>> Â SBC_CHANNEL_MODE_DUAL_CHANNEL;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â else {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("No supported channel modes");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>> Â Â Â Â Â Â Â Â Â Â } else {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (capabilities->channel_mode &
>>>>>>> Â SBC_CHANNEL_MODE_DUAL_CHANNEL)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->channel_mode =
>>>>>>> Â SBC_CHANNEL_MODE_DUAL_CHANNEL;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â else if (capabilities->channel_mode &
>>>>>>> Â SBC_CHANNEL_MODE_STEREO)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->channel_mode = SBC_CHANNEL_MODE_STEREO;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â else if (capabilities->channel_mode &
>>>>>>> Â SBC_CHANNEL_MODE_JOINT_STEREO)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->channel_mode =
>>>>>>> Â SBC_CHANNEL_MODE_JOINT_STEREO;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â else if (capabilities->channel_mode &
>>>>>>> Â SBC_CHANNEL_MODE_MONO)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->channel_mode = SBC_CHANNEL_MODE_MONO;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â else {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("No supported channel modes");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (capabilities->block_length & SBC_BLOCK_LENGTH_16)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->block_length = SBC_BLOCK_LENGTH_16;
>>>>>>> Â Â Â Â Â Â Â Â Â Â else if (capabilities->block_length & SBC_BLOCK_LENGTH_12)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->block_length = SBC_BLOCK_LENGTH_12;
>>>>>>> Â Â Â Â Â Â Â Â Â Â else if (capabilities->block_length & SBC_BLOCK_LENGTH_8)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->block_length = SBC_BLOCK_LENGTH_8;
>>>>>>> Â Â Â Â Â Â Â Â Â Â else if (capabilities->block_length & SBC_BLOCK_LENGTH_4)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->block_length = SBC_BLOCK_LENGTH_4;
>>>>>>> Â Â Â Â Â Â Â Â Â Â else {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("No supported block lengths");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (capabilities->subbands & SBC_SUBBANDS_8)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->subbands = SBC_SUBBANDS_8;
>>>>>>> Â Â Â Â Â Â Â Â Â Â else if (capabilities->subbands & SBC_SUBBANDS_4)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->subbands = SBC_SUBBANDS_4;
>>>>>>> Â Â Â Â Â Â Â Â Â Â else {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("No supported subbands");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (capabilities->allocation_method &
>>>>>>> Â SBC_ALLOCATION_LOUDNESS)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->allocation_method = SBC_ALLOCATION_LOUDNESS;
>>>>>>> Â Â Â Â Â Â Â Â Â Â else if (capabilities->allocation_method &
>>>>>>> Â SBC_ALLOCATION_SNR)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->allocation_method = SBC_ALLOCATION_SNR;
>>>>>>> Â Â Â Â Â Â Â Â Â Â else {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("No supported allocation method");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â config->min_bitpool = (uint8_t) PA_MAX(SBC_MIN_BITPOOL,
>>>>>>> Â capabilities->min_bitpool);
>>>>>>> Â Â Â Â Â Â Â Â Â Â config->max_bitpool = (uint8_t)
>>>>>>> Â PA_MIN(default_bitpool(config->frequency, config->channel_mode),
>>>>>>> Â capabilities->max_bitpool);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (config->min_bitpool > config->max_bitpool) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("No supported bitpool");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â return sizeof(*config);
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static void set_params(struct sbc_info *sbc_info) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.frequency = sbc_info->frequency;
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.blocks = sbc_info->blocks;
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.subbands = sbc_info->subbands;
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.mode = sbc_info->mode;
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.allocation = sbc_info->allocation;
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.bitpool = sbc_info->initial_bitpool;
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.endian = SBC_LE;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc);
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->frame_length =
>>>>>>> Â sbc_get_frame_length(&sbc_info->sbc);
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static void *init(bool for_encoding, bool for_backchannel,
>>>>>>> Â const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec
>>>>>>> Â *sample_spec) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â struct sbc_info *sbc_info;
>>>>>>> Â Â Â Â Â Â Â Â Â Â const a2dp_sbc_t *config = (const a2dp_sbc_t *)
>>>>>>> Â config_buffer;
>>>>>>> Â Â Â Â Â Â Â Â Â Â int ret;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â pa_assert(config_size == sizeof(*config));
>>>>>>> Â Â Â Â Â Â Â Â Â Â pa_assert(!for_backchannel);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info = pa_xnew0(struct sbc_info, 1);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â ret = sbc_init(&sbc_info->sbc, 0);
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (ret != 0) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_xfree(sbc_info);
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("SBC initialization failed: %d", ret);
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return NULL;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â sample_spec->format = PA_SAMPLE_S16LE;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â switch (config->frequency) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_SAMPLING_FREQ_48000:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->frequency = SBC_FREQ_48000;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sample_spec->rate = 48000U;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_SAMPLING_FREQ_44100:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->frequency = SBC_FREQ_44100;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sample_spec->rate = 44100U;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_SAMPLING_FREQ_32000:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->frequency = SBC_FREQ_32000;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sample_spec->rate = 32000U;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_SAMPLING_FREQ_16000:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->frequency = SBC_FREQ_16000;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sample_spec->rate = 16000U;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â default:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_not_reached();
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â switch (config->channel_mode) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_DUAL_CHANNEL:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->mode = SBC_MODE_DUAL_CHANNEL;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sample_spec->channels = 2;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_STEREO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->mode = SBC_MODE_STEREO;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sample_spec->channels = 2;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_JOINT_STEREO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->mode = SBC_MODE_JOINT_STEREO;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sample_spec->channels = 2;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_CHANNEL_MODE_MONO:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->mode = SBC_MODE_MONO;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sample_spec->channels = 1;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â default:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_not_reached();
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â switch (config->allocation_method) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_ALLOCATION_LOUDNESS:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->allocation = SBC_AM_LOUDNESS;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_ALLOCATION_SNR:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->allocation = SBC_AM_SNR;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â default:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_not_reached();
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â switch (config->subbands) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_SUBBANDS_4:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->subbands = SBC_SB_4;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_SUBBANDS_8:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->subbands = SBC_SB_8;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â default:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_not_reached();
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â switch (config->block_length) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_BLOCK_LENGTH_4:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->blocks = SBC_BLK_4;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_BLOCK_LENGTH_8:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->blocks = SBC_BLK_8;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_BLOCK_LENGTH_12:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->blocks = SBC_BLK_12;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â case SBC_BLOCK_LENGTH_16:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->blocks = SBC_BLK_16;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â default:
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_not_reached();
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->min_bitpool = config->min_bitpool;
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->max_bitpool = config->max_bitpool;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â /* Set minimum bitpool for source to get the maximum
>>>>>>> Â possible block_size
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â * in get_block_size() function. This block_size is
>>>>>>> Â length of buffer used
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â * for decoded audio data and so is inversely
>>>>>>> Â proportional to frame length
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â * which depends on bitpool value. Bitpool is controlled
>>>>>>> Â by other side from
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â * range [min_bitpool, max_bitpool]. */
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->initial_bitpool = for_encoding ?
>>>>>>> Â sbc_info->max_bitpool : sbc_info->min_bitpool;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â set_params(sbc_info);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â pa_log_info("SBC parameters: allocation=%s, subbands=%u,
>>>>>>> Â blocks=%u, mode=%s bitpool=%u codesize=%u frame_length=%u",
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.allocation ? "SNR" :
>>>>>>> Â "Loudness", sbc_info->sbc.subbands ? 8 : 4,
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â (sbc_info->sbc.blocks+1)*4,
>>>>>>> Â sbc_info->sbc.mode == SBC_MODE_MONO ? "Mono" :
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.mode == SBC_MODE_DUAL_CHANNEL ?
>>>>>>> Â "DualChannel" :
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.mode == SBC_MODE_STEREO ?
>>>>>>> Â "Stereo" : "JointStereo",
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.bitpool,
>>>>>>> Â (unsigned)sbc_info->codesize, (unsigned)sbc_info->frame_length);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â return sbc_info;
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static void deinit(void *codec_info) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_finish(&sbc_info->sbc);
>>>>>>> Â Â Â Â Â Â Â Â Â Â pa_xfree(sbc_info);
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static void set_bitpool(struct sbc_info *sbc_info, uint8_t
>>>>>>> Â bitpool) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (bitpool > sbc_info->max_bitpool)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â bitpool = sbc_info->max_bitpool;
>>>>>>> Â Â Â Â Â Â Â Â Â Â else if (bitpool < sbc_info->min_bitpool)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â bitpool = sbc_info->min_bitpool;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->sbc.bitpool = bitpool;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc);
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->frame_length =
>>>>>>> Â sbc_get_frame_length(&sbc_info->sbc);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â pa_log_debug("Bitpool has changed to %u",
>>>>>>> Â sbc_info->sbc.bitpool);
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static int reset(void *codec_info) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
>>>>>>> Â Â Â Â Â Â Â Â Â Â int ret;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â ret = sbc_reinit(&sbc_info->sbc, 0);
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (ret != 0) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("SBC reinitialization failed: %d", ret);
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return -1;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â /* sbc_reinit() sets also default parameters, so reset
>>>>>>> Â them back */
>>>>>>> Â Â Â Â Â Â Â Â Â Â set_params(sbc_info);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â sbc_info->seq_num = 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static size_t get_block_size(void *codec_info, size_t link_mtu) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
>>>>>>> Â Â Â Â Â Â Â Â Â Â size_t rtp_size = sizeof(struct rtp_header) +
>>>>>>> Â sizeof(struct rtp_sbc_payload);
>>>>>>> Â Â Â Â Â Â Â Â Â Â size_t frame_count = (link_mtu - rtp_size) /
>>>>>>> Â sbc_info->frame_length;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â /* frame_count is only 4 bit number */
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (frame_count > 15)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â frame_count = 15;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â return frame_count * sbc_info->codesize;
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static size_t reduce_encoder_bitrate(void *codec_info, size_t
>>>>>>> Â write_link_mtu) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t bitpool;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â /* Check if bitpool is already at its limit */
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (sbc_info->sbc.bitpool <= SBC_BITPOOL_DEC_LIMIT)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â bitpool = sbc_info->sbc.bitpool - SBC_BITPOOL_DEC_STEP;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (bitpool < SBC_BITPOOL_DEC_LIMIT)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â bitpool = SBC_BITPOOL_DEC_LIMIT;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (sbc_info->sbc.bitpool == bitpool)
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â set_bitpool(sbc_info, bitpool);
>>>>>>> Â Â Â Â Â Â Â Â Â Â return get_block_size(codec_info, write_link_mtu);
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static 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) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
>>>>>>> Â Â Â Â Â Â Â Â Â Â struct rtp_header *header;
>>>>>>> Â Â Â Â Â Â Â Â Â Â struct rtp_sbc_payload *payload;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t *d;
>>>>>>> Â Â Â Â Â Â Â Â Â Â const uint8_t *p;
>>>>>>> Â Â Â Â Â Â Â Â Â Â size_t to_write, to_encode;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t frame_count;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â header = (struct rtp_header*) output_buffer;
>>>>>>> Â Â Â Â Â Â Â Â Â Â payload = (struct rtp_sbc_payload*) (output_buffer +
>>>>>>> Â sizeof(*header));
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â frame_count = 0;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â p = input_buffer;
>>>>>>> Â Â Â Â Â Â Â Â Â Â to_encode = input_size;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â d = output_buffer + sizeof(*header) + sizeof(*payload);
>>>>>>> Â Â Â Â Â Â Â Â Â Â to_write = output_size - sizeof(*header) - sizeof(*payload);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â /* frame_count is only 4 bit number */
>>>>>>> Â Â Â Â Â Â Â Â Â Â while (PA_LIKELY(to_encode > 0 && to_write > 0 &&
>>>>>>> Â frame_count < 15)) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â ssize_t written;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â ssize_t encoded;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â encoded = sbc_encode(&sbc_info->sbc,
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â p, to_encode,
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â d, to_write,
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â &written);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (PA_UNLIKELY(encoded <= 0)) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("SBC encoding error (%li)", (long)
>>>>>>> Â encoded);
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (PA_UNLIKELY(written < 0)) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("SBC encoding error (%li)", (long)
>>>>>>> Â written);
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_fp((size_t) encoded <= to_encode);
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_fp((size_t) encoded == sbc_info->codesize);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_fp((size_t) written <= to_write);
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_fp((size_t) written ==
>>>>>>> Â sbc_info->frame_length);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â p += encoded;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â to_encode -= encoded;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â d += written;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â to_write -= written;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â frame_count++;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â PA_ONCE_BEGIN {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_debug("Using SBC codec implementation: %s",
>>>>>>> Â pa_strnull(sbc_get_implementation_info(&sbc_info->sbc)));
>>>>>>> Â Â Â Â Â Â Â Â Â Â } PA_ONCE_END;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (PA_UNLIKELY(frame_count == 0)) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â *processed = 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â /* write it to the fifo */
>>>>>>> Â Â Â Â Â Â Â Â Â Â pa_memzero(output_buffer, sizeof(*header) +
>>>>>>> Â sizeof(*payload));
>>>>>>> Â Â Â Â Â Â Â Â Â Â header->v = 2;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â /* A2DP spec: "A payload type in the RTP dynamic range
>>>>>>> Â shall be chosen".
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â * RFC3551 defines the dynamic range to span from 96 to
>>>>>>> Â 127, and 96 appears
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â * to be the most common choice in A2DP implementations. */
>>>>>>> Â Â Â Â Â Â Â Â Â Â header->pt = 96;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â header->sequence_number = htons(sbc_info->seq_num++);
>>>>>>> Â Â Â Â Â Â Â Â Â Â header->timestamp = htonl(timestamp);
>>>>>>> Â Â Â Â Â Â Â Â Â Â header->ssrc = htonl(1);
>>>>>>> Â Â Â Â Â Â Â Â Â Â payload->frame_count = frame_count;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â *processed = p - input_buffer;
>>>>>>> Â Â Â Â Â Â Â Â Â Â return d - output_buffer;
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â static 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) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â struct rtp_header *header;
>>>>>>> Â Â Â Â Â Â Â Â Â Â struct rtp_sbc_payload *payload;
>>>>>>> Â Â Â Â Â Â Â Â Â Â const uint8_t *p;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t *d;
>>>>>>> Â Â Â Â Â Â Â Â Â Â size_t to_write, to_decode;
>>>>>>> Â Â Â Â Â Â Â Â Â Â uint8_t frame_count;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â header = (struct rtp_header *) input_buffer;
>>>>>>> Â Â Â Â Â Â Â Â Â Â payload = (struct rtp_sbc_payload*) (input_buffer +
>>>>>>> Â sizeof(*header));
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â frame_count = payload->frame_count;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â /* TODO: Add support for decoding fragmented SBC frames */
>>>>>>> Â Â Â Â Â Â Â Â Â Â if (payload->is_fragmented) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("Unsupported fragmented SBC frame");
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â *processed = 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â p = input_buffer + sizeof(*header) + sizeof(*payload);
>>>>>>> Â Â Â Â Â Â Â Â Â Â to_decode = input_size - sizeof(*header) - sizeof(*payload);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â d = output_buffer;
>>>>>>> Â Â Â Â Â Â Â Â Â Â to_write = output_size;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â while (PA_LIKELY(to_decode > 0 && to_write > 0 &&
>>>>>>> Â frame_count > 0)) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â size_t written;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â ssize_t decoded;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â decoded = sbc_decode(&sbc_info->sbc,
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â p, to_decode,
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â d, to_write,
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â &written);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (PA_UNLIKELY(decoded <= 0)) {
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("SBC decoding error (%li)", (long)
>>>>>>> Â decoded);
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â /* Reset frame length, it can be changed due to
>>>>>>> Â bitpool change */
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â sbc_info->frame_length =
>>>>>>> Â sbc_get_frame_length(&sbc_info->sbc);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_fp((size_t) decoded <= to_decode);
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_fp((size_t) decoded ==
>>>>>>> Â sbc_info->frame_length);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_fp((size_t) written <= to_write);
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_assert_fp((size_t) written == sbc_info->codesize);
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â p += decoded;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â to_decode -= decoded;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â d += written;
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â to_write -= written;
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â frame_count--;
>>>>>>> Â Â Â Â Â Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â Â Â Â Â Â *processed = p - input_buffer;
>>>>>>> Â Â Â Â Â Â Â Â Â Â return d - output_buffer;
>>>>>>> Â Â Â Â Â }
>>>>>>>
>>>>>>> Â Â Â Â Â const pa_a2dp_codec pa_a2dp_codec_sbc = {
>>>>>>> Â Â Â Â Â Â Â Â Â Â .name = "sbc",
>>>>>>> Â Â Â Â Â Â Â Â Â Â .description = "SBC",
>>>>>>> Â Â Â Â Â Â Â Â Â Â .id = { A2DP_CODEC_SBC, 0, 0 },
>>>>>>> Â Â Â Â Â Â Â Â Â Â .support_backchannel = false,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .can_accept_capabilities = can_accept_capabilities,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .choose_remote_endpoint = choose_remote_endpoint,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .fill_capabilities = fill_capabilities,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .is_configuration_valid = is_configuration_valid,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .fill_preferred_configuration =
>>>>>>> Â fill_preferred_configuration,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .init = init,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .deinit = deinit,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .reset = reset,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .get_read_block_size = get_block_size,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .get_write_block_size = get_block_size,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .reduce_encoder_bitrate = reduce_encoder_bitrate,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .encode_buffer = encode_buffer,
>>>>>>> Â Â Â Â Â Â Â Â Â Â .decode_buffer = decode_buffer,
>>>>>>> Â Â Â Â Â };
>>>>>>>
>>>>>>> Â Â Â Â Â 17.09.2019, 09:34, "Hyperion" <h1p8r10n at yandex.com>:
>>>>>>>> Â Â Â Â Â btw here's the updated V12-12 patch in Pali's latest rel95
>>>>>>>> Â patchset that applies to PA 13.0.
>>>>>>>>
>>>>>>>> Â Â Â Â Â Â Â http://download.zenwalk.org/x86_64/testing/v12-12-13-zen-bluetooth-Implement-A2DP-codec-switching-and-backchannel-support-.patch
>>>>>>>>
>>>>>>>> Â Â Â Â Â JP
>>>>>>>>
>>>>>>>> Â Â Â Â Â 16.09.2019, 09:32, "Hyperion" <h1p8r10n at yandex.com>:
>>>>>>>>> Â Â Â Â Â Â Â Hi,
>>>>>>>>>
>>>>>>>>> Â Â Â Â Â Â Â Following what has already be done in some Android
>>>>>>>>> Â derivatives, here's a simple patch that extend SBP bitpool
>>>>>>>>> Â negociation to XQ quality.
>>>>>>>>>
>>>>>>>>> Â Â Â Â Â Â Â According to :
>>>>>>>>> Â Â Â Â Â Â Â -->
>>>>>>>>> Â http://soundexpert.org/articles/-/blogs/audio-quality-of-sbc-xq-bluetooth-audio-codec
>>>>>>>>>
>>>>>>>>> Â Â Â Â Â Â Â --> https://lineageos.org/engineering/Bluetooth-SBC-XQ/ ,
>>>>>>>>> Â Â Â Â Â Â Â --> and confirmed by my own experimentation on more than
>>>>>>>>> Â 10 different devices,
>>>>>>>>>
>>>>>>>>> Â Â Â Â Â Â Â here are the features of the (very simple and non
>>>>>>>>> Â intrusive) patch :
>>>>>>>>> Â Â Â Â Â Â Â - allow to use bitpool 76 on devices that support it, aka
>>>>>>>>> Â SBC XQ
>>>>>>>>> Â Â Â Â Â Â Â - harmless for devices limited to bitpool 53
>>>>>>>>> Â Â Â Â Â Â Â - deprecates the need for APTX & APTX HD support, which
>>>>>>>>> Â are not better than SBC XQ, are not Open Source, and less
>>>>>>>>> Â supported by devices
>>>>>>>>>
>>>>>>>>> Â Â Â Â Â Â Â This patch will be superseded by multi-profiles Pali Rohar
>>>>>>>>> Â A2DP stack implementation, when it's ready for production.
>>>>>>>>> Â Thanks to Pali for the help testing many codec parameters.
>>>>>>>>>
>>>>>>>>> Â Â Â Â Â Â Â Let me know if I have to clone the git to push my patch,
>>>>>>>>> Â or if a regular PA dev could do it.
>>>>>>>>>
>>>>>>>>> Â Â Â Â Â Â Â All the best
>>>>>>>>> Â Â Â Â Â Â Â JP
>>>>>>>>>
>>>>>>>>> Â Â Â Â Â Â Â diff -rNaud
>>>>>>>>> Â pulseaudio-13.0/src/modules/bluetooth/a2dp-codec-sbc.c
>>>>>>>>> Â pulseaudio-13.0-new/src/modules/bluetooth/a2dp-codec-sbc.c
>>>>>>>>> Â Â Â Â Â Â Â --- pulseaudio-13.0/src/modules/bluetooth/a2dp-codec-sbc.c
>>>>>>>>> Â 2019-09-13 15:20:03.000000000 +0200
>>>>>>>>> Â Â Â Â Â Â Â +++
>>>>>>>>> Â pulseaudio-13.0-new/src/modules/bluetooth/a2dp-codec-sbc.c
>>>>>>>>> Â 2019-09-16 08:57:50.363122019 +0200
>>>>>>>>> Â Â Â Â Â Â Â @@ -290,10 +290,10 @@
>>>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â }
>>>>>>>>>
>>>>>>>>> Â Â Â Â Â Â Â - if (capabilities->allocation_method &
>>>>>>>>> Â SBC_ALLOCATION_LOUDNESS)
>>>>>>>>> Â Â Â Â Â Â Â - config->allocation_method = SBC_ALLOCATION_LOUDNESS;
>>>>>>>>> Â Â Â Â Â Â Â - else if (capabilities->allocation_method &
>>>>>>>>> Â SBC_ALLOCATION_SNR)
>>>>>>>>> Â Â Â Â Â Â Â + if (capabilities->allocation_method & SBC_ALLOCATION_SNR)
>>>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â config->allocation_method = SBC_ALLOCATION_SNR;
>>>>>>>>> Â Â Â Â Â Â Â + else if (capabilities->allocation_method &
>>>>>>>>> Â SBC_ALLOCATION_LOUDNESS)
>>>>>>>>> Â Â Â Â Â Â Â + config->allocation_method = SBC_ALLOCATION_LOUDNESS;
>>>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â else {
>>>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pa_log_error("No supported allocation method");
>>>>>>>>> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â return 0;
>>>>>>>>> Â Â Â Â Â Â Â diff -rNaud
>>>>>>>>> Â pulseaudio-13.0/src/modules/bluetooth/a2dp-codecs.h
>>>>>>>>> Â pulseaudio-13.0-new/src/modules/bluetooth/a2dp-codecs.h
>>>>>>>>> Â Â Â Â Â Â Â --- pulseaudio-13.0/src/modules/bluetooth/a2dp-codecs.h
>>>>>>>>> Â 2019-09-13 15:20:03.000000000 +0200
>>>>>>>>> Â Â Â Â Â Â Â +++
>>>>>>>>> Â pulseaudio-13.0-new/src/modules/bluetooth/a2dp-codecs.h
>>>>>>>>> Â 2019-09-16 08:44:20.382086305 +0200
>>>>>>>>> Â Â Â Â Â Â Â @@ -61,14 +61,11 @@
>>>>>>>>> Â Â Â Â Â Â Â Â Â * Allocation method = Loudness
>>>>>>>>> Â Â Â Â Â Â Â Â Â * Subbands = 8
>>>>>>>>> Â Â Â Â Â Â Â Â Â */
>>>>>>>>> Â Â Â Â Â Â Â -#define SBC_BITPOOL_MQ_MONO_44100 19
>>>>>>>>> Â Â Â Â Â Â Â -#define SBC_BITPOOL_MQ_MONO_48000 18
>>>>>>>>> Â Â Â Â Â Â Â -#define SBC_BITPOOL_MQ_JOINT_STEREO_44100 35
>>>>>>>>> Â Â Â Â Â Â Â -#define SBC_BITPOOL_MQ_JOINT_STEREO_48000 33
>>>>>>>>> Â Â Â Â Â Â Â -#define SBC_BITPOOL_HQ_MONO_44100 31
>>>>>>>>> Â Â Â Â Â Â Â -#define SBC_BITPOOL_HQ_MONO_48000 29
>>>>>>>>> Â Â Â Â Â Â Â -#define SBC_BITPOOL_HQ_JOINT_STEREO_44100 53
>>>>>>>>> Â Â Â Â Â Â Â -#define SBC_BITPOOL_HQ_JOINT_STEREO_48000 51
>>>>>>>>> Â Â Â Â Â Â Â +
>>>>>>>>> Â Â Â Â Â Â Â +#define SBC_BITPOOL_HQ_MONO_44100 38
>>>>>>>>> Â Â Â Â Â Â Â +#define SBC_BITPOOL_HQ_MONO_48000 38
>>>>>>>>> Â Â Â Â Â Â Â +#define SBC_BITPOOL_HQ_JOINT_STEREO_44100 76
>>>>>>>>> Â Â Â Â Â Â Â +#define SBC_BITPOOL_HQ_JOINT_STEREO_48000 76
>>>>>>>>>
>>>>>>>>> Â Â Â Â Â Â Â Â #define MPEG_CHANNEL_MODE_MONO (1 << 3)
>>>>>>>>> Â Â Â Â Â Â Â Â #define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
>>>>>>>>>
>>>>>>>>> Â Â Â Â Â Â Â _______________________________________________
>>>>>>>>> Â Â Â Â Â Â Â pulseaudio-discuss mailing list
>>>>>>>>> Â Â Â Â Â Â Â pulseaudio-discuss at lists.freedesktop.org
>>>>>>>>> Â Â Â Â Â Â Â https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>>>>>>> Â Â Â Â Â _______________________________________________
>>>>>>> Â Â Â Â Â pulseaudio-discuss mailing list
>>>>>>> Â Â Â Â Â pulseaudio-discuss at lists.freedesktop.org
>>>>>>> Â Â Â Â Â https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>>>>>>
>>>>>> Â Â Â Â _______________________________________________
>>>>>> Â Â Â Â pulseaudio-discuss mailing list
>>>>>> Â Â Â Â pulseaudio-discuss at lists.freedesktop.org
>>>>>> Â Â Â Â https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>>>>>
>>>>> Â Â Â _______________________________________________
>>>>> Â Â Â pulseaudio-discuss mailing list
>>>>> Â Â Â pulseaudio-discuss at lists.freedesktop.org
>>>>> Â Â Â https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>>>>
>>>> Â _______________________________________________
>>>> Â pulseaudio-discuss mailing list
>>>> Â pulseaudio-discuss at lists.freedesktop.org
>>>> Â https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>>> Â _______________________________________________
>>> Â pulseaudio-discuss mailing list
>>> Â pulseaudio-discuss at lists.freedesktop.org
>>> Â https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>
> _______________________________________________
> pulseaudio-discuss mailing list
> pulseaudio-discuss at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
More information about the pulseaudio-discuss
mailing list