* A2DP quality (bluetooth-alsa) @ 2011-10-10 10:40 qduaty 2011-10-10 14:11 ` Luiz Augusto von Dentz 2011-10-10 14:54 ` Siarhei Siamashka 0 siblings, 2 replies; 23+ messages in thread From: qduaty @ 2011-10-10 10:40 UTC (permalink / raw) To: linux-bluetooth Hi people, I found that I cannot set A2DP bitpool to anything more than 53 in my ~/.asoundrc file. The bluetooth driver reports an error and keeps reporting it (becomes useless) until it is restarted. Bitpool values as high as 128 are possible on Windows Mobile devices (including mine), which means they are possible in A2DP. Such a high value is necessary for some genres of current music, which are highly compressed (the problem was once discussed in one of Xiph Foundation's articles). SBC is unable to encode such material properly if it doesn't have enough bandwidth. I don't understand Bluetooth. So I'm asking you for an advice: 1. Is it actually possible to set SBC bitpool in linux' A2DP to more than 53? 2. If it is, can I ask for a short success story in order to reproduce it? 2. If not, where should I start (in bluez source code) in order to fix this problem? Regards -- Sebastian ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: A2DP quality (bluetooth-alsa) 2011-10-10 10:40 A2DP quality (bluetooth-alsa) qduaty @ 2011-10-10 14:11 ` Luiz Augusto von Dentz 2011-10-10 14:54 ` Siarhei Siamashka 1 sibling, 0 replies; 23+ messages in thread From: Luiz Augusto von Dentz @ 2011-10-10 14:11 UTC (permalink / raw) To: qduaty@gmail.com; +Cc: linux-bluetooth Hi, On Mon, Oct 10, 2011 at 1:40 PM, qduaty@gmail.com <qduaty@gmail.com> wrote: > Hi people, > > I found that I cannot set A2DP bitpool to anything more than 53 in my > ~/.asoundrc file. The bluetooth driver reports an error and keeps > reporting it (becomes useless) until it is restarted. It can be 2 things, either a bug or the device maximum bitpool is actually 53 so we cannot negotiate it. > Bitpool values as high as 128 are possible on Windows Mobile devices > (including mine), which means they are possible in A2DP. Such a high > value is necessary for some genres of current music, which are highly > compressed (the problem was once discussed in one of Xiph Foundation's > articles). SBC is unable to encode such material properly if it > doesn't have enough bandwidth. PulseAudio uses 64 as bitpool maximum and it seems to work fine, but that depends on available bandwidth, in fact PA reduces the bitpool if it detects the audio is skipping. > I don't understand Bluetooth. So I'm asking you for an advice: > 1. Is it actually possible to set SBC bitpool in linux' A2DP to more than 53? > 2. If it is, can I ask for a short success story in order to reproduce it? > 2. If not, where should I start (in bluez source code) in order to fix > this problem? Take a look a PulseAudio or BlueZ source tree (audio/pcm_bluetooth.c) -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: A2DP quality (bluetooth-alsa) 2011-10-10 10:40 A2DP quality (bluetooth-alsa) qduaty 2011-10-10 14:11 ` Luiz Augusto von Dentz @ 2011-10-10 14:54 ` Siarhei Siamashka 2011-10-10 19:10 ` qduaty 1 sibling, 1 reply; 23+ messages in thread From: Siarhei Siamashka @ 2011-10-10 14:54 UTC (permalink / raw) To: qduaty@gmail.com; +Cc: linux-bluetooth On Mon, Oct 10, 2011 at 1:40 PM, qduaty@gmail.com <qduaty@gmail.com> wrote: > Hi people, > > I found that I cannot set A2DP bitpool to anything more than 53 in my > ~/.asoundrc file. The bluetooth driver reports an error and keeps > reporting it (becomes useless) until it is restarted. > > Bitpool values as high as 128 are possible on Windows Mobile devices > (including mine), which means they are possible in A2DP. The SBC codec itself supports bitpool values higher 53, and sbcenc/sbcdec command line tools can be used to experiment with encoding/decoding audio data. > Such a high value is necessary for some genres of current music, which are highly > compressed (the problem was once discussed in one of Xiph Foundation's > articles). SBC is unable to encode such material properly if it > doesn't have enough bandwidth. Could you please provide a link to the Xiph Foundation's article you have mentioned? Also what does "SBC is unable to encode such material properly" mean? My understanding is that the highly compressed sources are mostly a problem not for SBC encoder, but actually for decoder: http://git.kernel.org/?p=bluetooth/bluez.git;a=commit;h=3df7c3e66042f266dadace88488e532de92d4da9 When the original audio signal is using full range, then going to the frequency domain, doing lossy compression, and going back to the time domain may easily result in some sample values exceeding the valid range. The reference binary SBC decoder seems to be simply clamping the out-of-range values to bring them into valid range (based on the output it produces). And since some time ago, bluez SBC decoder also does the same. This not a perfect solution, because the shape of the decoded signal abruptly changes to "flat" part at the top or bottom. But not doing any clamping is a lot worse and letting the samples overflow results in really bad audible clicks. However it's hard to say how each particular A2DP headset deals with the out-of-range samples. Most of them are apparently also doing clamping and the audio sounds ok. But unfortunately sometimes this is not the case. I happen to be an owner of Logitech FreePulse A2DP headset, and the out-of-range samples can be clearly heard as clicking artifacts (in the worst cases resembling 'frying pan' type of sound). I myself used a hack by patching bluez SBC to also reduce audio volume as the part of the encoding process so that the badly compressed audio sources are less likely to have any out of range samples in the SBC encoded data stream. I guess that increasing bitpool would result in a less lossy encoding with a better approximation of the original audio data. Hence less likely to differ from the original data too much and go out of range. But I don't think that it's a "proper" solution for the problem. Normally, even low bitpool values should be still quite usable. What kind of A2DP headset are you using yourself? -- Best regards, Siarhei Siamashka ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: A2DP quality (bluetooth-alsa) 2011-10-10 14:54 ` Siarhei Siamashka @ 2011-10-10 19:10 ` qduaty 2011-10-18 9:26 ` Siarhei Siamashka 0 siblings, 1 reply; 23+ messages in thread From: qduaty @ 2011-10-10 19:10 UTC (permalink / raw) To: linux-bluetooth Hi, 2011/10/10 Luiz Augusto von Dentz <luiz.dentz@gmail.com>: > It can be 2 things, either a bug or the device maximum bitpool is > actually 53 so we cannot negotiate it. My headset indeed reports bitpool range up to 53. WinMo seems to either override it, or present some features that cause the Nokia BT chip to report a wider range. Unfortunately I don't know how to disable encryption in Windows Mobile to capture its bluetooth session (and how to capture it with Bluez). Can 'hcidump' do this? > PulseAudio uses 64 as bitpool maximum and it seems to work fine Yes, wIth movies, games etc. the quality is excellent. 2011/10/10 Siarhei Siamashka <siarhei.siamashka@gmail.com>: > On Mon, Oct 10, 2011 at 1:40 PM, qduaty@gmail.com <qduaty@gmail.com> wrote: > Could you please provide a link to the Xiph Foundation's article you > have mentioned? Also what does "SBC is unable to encode such material > properly" mean? I remember it was their "About" article, but it seems either they shortened it (removing fragments irrelevant to their mission) or it has never been there and I've seen it somewhere else. Anyway, the whole phenomena is called "Loudness war". CD's are recorded with dynamics compression, so their sound has distortions introduced in production and high energy in all subbands at the same time. Thus, SBC must encode distortions as well as higher energy in all subbands. > The SBC decoder seems to be clamping the out-of-range values [...] > not doing any clamping is a lot worse and letting the samples > overflow results in really bad audible clicks. Maybe sin() would help, who knows? Obviously in the decoder, which usually cannot be reprogrammed, but future /bluez devices/ could benefit from this. > What kind of A2DP headset are you using yourself? Nokia BT-503. Its quality is enough to notice an obvious difference between 'computer' bitpool (<=53) and that coming from Windows Mobile (128 does not cause skipping yet). In presence of dynamics compression, even two guitars with a vocal can be distinguished only with higher bitpool. Another example is a symphony - I can hear individual instruments from WinMo, and a "movie soundtrack" from Bluez. I don't know how the device deals with clicks, but I never heard them. Usual (and also annoying) distortion is a 'chirp' in some bands. Regards -- Sebastian Olter ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: A2DP quality (bluetooth-alsa) 2011-10-10 19:10 ` qduaty @ 2011-10-18 9:26 ` Siarhei Siamashka 2012-03-13 1:48 ` qduaty 0 siblings, 1 reply; 23+ messages in thread From: Siarhei Siamashka @ 2011-10-18 9:26 UTC (permalink / raw) To: qduaty@gmail.com; +Cc: linux-bluetooth [-- Attachment #1: Type: text/plain, Size: 5079 bytes --] On Mon, Oct 10, 2011 at 10:10 PM, qduaty@gmail.com <qduaty@gmail.com> wrote: > 2011/10/10 Siarhei Siamashka <siarhei.siamashka@gmail.com>: >> On Mon, Oct 10, 2011 at 1:40 PM, qduaty@gmail.com <qduaty@gmail.com> wrote: >> Could you please provide a link to the Xiph Foundation's article you >> have mentioned? Also what does "SBC is unable to encode such material >> properly" mean? > > I remember it was their "About" article, but it seems either they > shortened it (removing fragments irrelevant to their mission) or it > has never been there and I've seen it somewhere else. Anyway, the > whole phenomena is called "Loudness war". CD's are recorded with > dynamics compression, so their sound has distortions introduced in > production and high energy in all subbands at the same time. Thus, SBC > must encode distortions as well as higher energy in all subbands. Still I would suggest you to try the attached patch just for a test. It reduces audio volume as part of the sbc encoding process and should eliminate most of the possible clipping cases on the decoding side. Some people on Hydrogenaudio forums have investigated the impact of clipping on the perceived audio quality and found it at least audible: http://www.hydrogenaudio.org/forums/index.php?showtopic=82112 http://en.wikipedia.org/wiki/Clipping_(audio) >> The SBC decoder seems to be clamping the out-of-range values [...] >> not doing any clamping is a lot worse and letting the samples >> overflow results in really bad audible clicks. > > Maybe sin() would help, who knows? Obviously in the decoder, which > usually cannot be reprogrammed, but future /bluez devices/ could > benefit from this. The headset is free to do whatever it likes with the samples falling out of [-0x8000, 0x7FFF] range, like clipping them or adjusting the volume or anything else. It does not have to produce files with 16-bit audio samples but just needs to play some sound in the speakers. >> What kind of A2DP headset are you using yourself? > > Nokia BT-503. Its quality is enough to notice an obvious difference > between 'computer' bitpool (<=53) and that coming from Windows Mobile > (128 does not cause skipping yet). In presence of dynamics > compression, even two guitars with a vocal can be distinguished only > with higher bitpool. Another example is a symphony - I can hear > individual instruments from WinMo, and a "movie soundtrack" from > Bluez. I don't know how the device deals with clicks, but I never > heard them. Usual (and also annoying) distortion is a 'chirp' in some > bands. OK, thanks for the information. It looks like this is not the same issue as I observed with Logitech FreePulse headset. In any case, I'm glad that you are interested in A2DP audio quality and would definitely appreciate any feedback and test results. As I see it, there are two things to take care: 1. make higher sbc bitpool settings usable in bluez with your headset 2. make sure that sbc codec itself is well behaved and providing the best results for any available bitpool But I myself can only comment on the latter. Using bitpool 128 is kind of weird for SBC codec, because the encoded data stream has about the same size as the the original data and this defeats the whole purpose of having any lossy compression at all. It is also worth mentioning that bluez sbc encoder implementation uses a bit lower precision analysis filter by default which allows SIMD optimizations and this should be fine at normal encoding settings. But uncommenting SBC_HIGH_PRECISION define may be important for getting better audio quality at higher bitpool settings. Also trying to enable/disable joint stereo, testing 4 vs. 8 subbands and snr vs. loudness allocation method may probably have some impact on audio quality for your use case. I still recommend you to try sbcenc/sbcdec tools for the experiments with audio quality. They use a somewhat less common big endian http://en.wikipedia.org/wiki/Au_file_format but you can get your audio files converted to it using http://sox.sourceforge.net/ command line tool. Also here I have some ruby script, which can simplify sbc encoding/decoding testing: http://cgit.freedesktop.org/~siamashka/bluez/log/?h=sbc-tests When doing the evaluation of encoding/decoding audio quality with sbcenc/sbcdec, please keep in mind that the current bluez sbc *decoder* implementation has some issues. Partially motivated by your posts, I decided to finally attempt to bring the bluez sbc decoder into a better shape and already sent one patch to the mailing list for review. The rest of the fixes are available here and they improve sbc decoder audio quality: http://cgit.freedesktop.org/~siamashka/bluez/log/?h=sbc-decoder-fixes But the synthesis filter still needs to be converted to fixed point and optimized for performance before really using it in bluez. I'll try to do this work as time permits and will submit the patches later. But quality-wise, it should be already possible to use my 'sbc-decoder-fixes' git branch for testing. -- Best regards, Siarhei Siamashka [-- Attachment #2: 0001-HACK-sbc-reduce-volume-in-sbc-encoder.patch --] [-- Type: text/x-patch, Size: 1864 bytes --] From 123a021376a4fd66c88fc1ed6ca26a6e8ee5e365 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka <siarhei.siamashka@nokia.com> Date: Tue, 18 Oct 2011 04:08:07 +0300 Subject: [PATCH] HACK: sbc: reduce volume in sbc encoder Reducing audio volume when encoding helps to avoid clipping in the decoder for the heavily dynamically compressed audio. Also high precision mode is enabled in sbc encoder to get the best possible audio quality. Some references: http://en.wikipedia.org/wiki/Loudness_war http://www.hydrogenaudio.org/forums/index.php?showtopic=82112 --- sbc/sbc_tables.h | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sbc/sbc_tables.h b/sbc/sbc_tables.h index 28c0d54..8d025e0 100644 --- a/sbc/sbc_tables.h +++ b/sbc/sbc_tables.h @@ -136,7 +136,7 @@ static const int32_t synmatrix8[16][8] = { /* Uncomment the following line to enable high precision build of SBC encoder */ -/* #define SBC_HIGH_PRECISION */ +#define SBC_HIGH_PRECISION #ifdef SBC_HIGH_PRECISION #define FIXED_A int64_t /* data type for fixed point accumulator */ @@ -208,7 +208,7 @@ static const FIXED_T _sbc_proto_fixed4[40] = { */ #define SBC_COS_TABLE_FIXED4_SCALE \ ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) -#define F_COS4(x) (FIXED_A) ((x) * \ +#define F_COS4(x) (FIXED_A) ((x * 0.7) * \ ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) #define F(x) F_COS4(x) static const FIXED_T cos_table_fixed_4[32] = { @@ -305,7 +305,7 @@ static const FIXED_T _sbc_proto_fixed8[80] = { */ #define SBC_COS_TABLE_FIXED8_SCALE \ ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) -#define F_COS8(x) (FIXED_A) ((x) * \ +#define F_COS8(x) (FIXED_A) ((x * 0.7) * \ ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) #define F(x) F_COS8(x) static const FIXED_T cos_table_fixed_8[128] = { -- 1.7.3.4 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: A2DP quality (bluetooth-alsa) 2011-10-18 9:26 ` Siarhei Siamashka @ 2012-03-13 1:48 ` qduaty 2012-03-13 8:25 ` Siarhei Siamashka 0 siblings, 1 reply; 23+ messages in thread From: qduaty @ 2012-03-13 1:48 UTC (permalink / raw) To: linux-bluetooth 2011/10/18 Siarhei Siamashka <siarhei.siamashka@gmail.com>: > Still I would suggest you to try the attached patch just for a test. > It reduces audio volume as part of the sbc encoding process and should > eliminate most of the possible clipping cases on the decoding side. Sorry for responding after a half year :) but I finally tested your encoder patch applied to libbluetooth version 4.96, using AIMP3 and pulseaudio. Unpatched encoder produces a "digital" distortion (which is rather annoying) and sounds much like BlueSoleil on Windows. After patching, music is slightly quieter (which can be expected if you decreased its volume) and has an "analog overdrive" like through a cheap FM radio. Anyway, the annoying "digital" distortion that was present in unpatched encoder, is now gone. Some fluctuations can be heard in higher bands in classical music, and (as expected) instruments are indistinguishable, but it's acceptable given the low bitpool. For the "analog overdrive" I hear, it may also come from the device itself (its proper name is Nokia BH-503). Considering its glue sealed case, it might have been designed as a budget solution and its price was "adjusted" due to no competition. > Using bitpool 128 is kind of weird for SBC codec, because the encoded > data stream has about the same size as the the original data and this > defeats the whole purpose of having any lossy compression at all. Yes, but who needs a lossy compression in an endpoint? SBC and MP3 were introduced to overcome the low throughput problem of the bluetooth link, which is no longer the case since 2.0+EDR has plenty of unused bits. > I still recommend you to try sbcenc/sbcdec tools for the experiments with audio quality. I tried them some time ago, but I believe ALSA backend may serve for the same purpose (and is much easier to use). 8 blocks seems to sound slightly better than 16 for classical music, full stereo eliminates the floating of virtual sound sources, 48 kHz also seems to increase quality a bit when compared to 44.1. Regards -- Sebastian Olter ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: A2DP quality (bluetooth-alsa) 2012-03-13 1:48 ` qduaty @ 2012-03-13 8:25 ` Siarhei Siamashka 2012-03-13 12:45 ` qduaty 0 siblings, 1 reply; 23+ messages in thread From: Siarhei Siamashka @ 2012-03-13 8:25 UTC (permalink / raw) To: qduaty; +Cc: linux-bluetooth On Tue, Mar 13, 2012 at 3:48 AM, qduaty <qduaty@gmail.com> wrote: > 2011/10/18 Siarhei Siamashka <siarhei.siamashka@gmail.com>: >> Still I would suggest you to try the attached patch just for a test. >> It reduces audio volume as part of the sbc encoding process and should >> eliminate most of the possible clipping cases on the decoding side. > > Sorry for responding after a half year :) but I finally tested your > encoder patch applied to libbluetooth version 4.96, using AIMP3 and > pulseaudio. Unpatched encoder produces a "digital" distortion (which > is rather annoying) and sounds much like BlueSoleil on Windows. After > patching, music is slightly quieter (which can be expected if you > decreased its volume) and has an "analog overdrive" like through a > cheap FM radio. Anyway, the annoying "digital" distortion that was > present in unpatched encoder, is now gone. Thanks for testing! One more experiment would be very much welcome. I wonder if just defining SBC_HIGH_PRECISION without doing anything else would have any noticeable effect on audio quality in listening tests. > Some fluctuations can be heard in higher bands in classical music, and > (as expected) instruments are indistinguishable, but it's acceptable > given the low bitpool. > > For the "analog overdrive" I hear, it may also come from the device > itself (its proper name is Nokia BH-503). Considering its glue sealed > case, it might have been designed as a budget solution and its price > was "adjusted" due to no competition. > >> Using bitpool 128 is kind of weird for SBC codec, because the encoded >> data stream has about the same size as the the original data and this >> defeats the whole purpose of having any lossy compression at all. > > Yes, but who needs a lossy compression in an endpoint? SBC and MP3 > were introduced to overcome the low throughput problem of the > bluetooth link, which is no longer the case since 2.0+EDR has plenty > of unused bits. > >> I still recommend you to try sbcenc/sbcdec tools for the experiments with audio quality. > > I tried them some time ago, but I believe ALSA backend may serve for > the same purpose (and is much easier to use). 8 blocks seems to sound > slightly better than 16 for classical music, full stereo eliminates > the floating of virtual sound sources, 48 kHz also seems to increase > quality a bit when compared to 44.1. sbcenc/sbcdec tools can do file-to-file encoding/decoding and eliminate the need to use any bluetooth device (which could potentially be the source of some audio quality issues). However, as I mentioned before, audio quality in the current bluez sbc decoder is far from perfect and the synthesis filter needs to be replaced first. -- Best regards, Siarhei Siamashka ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: A2DP quality (bluetooth-alsa) 2012-03-13 8:25 ` Siarhei Siamashka @ 2012-03-13 12:45 ` qduaty 2012-03-13 13:26 ` Siarhei Siamashka 0 siblings, 1 reply; 23+ messages in thread From: qduaty @ 2012-03-13 12:45 UTC (permalink / raw) To: linux-bluetooth 2012/3/13 Siarhei Siamashka <siarhei.siamashka@gmail.com>: > On Tue, Mar 13, 2012 at 3:48 AM, qduaty <qduaty@gmail.com> wrote: >> 2011/10/18 Siarhei Siamashka <siarhei.siamashka@gmail.com>: > Thanks for testing! One more experiment would be very much welcome. I > wonder if just defining SBC_HIGH_PRECISION without doing anything else > would have any noticeable effect on audio quality in listening tests. Well, before I move on, there is one thing that makes me sad: < ACL data: handle 1 flags 0x02 dlen 7 L2CAP(d): cid 0x006d len 3 [psm 25] AVDTP(s): Capabilities cmd: transaction 10 nsp 0x00 ACP SEID 1 > HCI Event: Number of Completed Packets (0x13) plen 5 handle 1 packets 1 > ACL data: handle 1 flags 0x02 dlen 16 L2CAP(d): cid 0x0040 len 12 [psm 25] AVDTP(s): Capabilities rsp: transaction 10 nsp 0x00 Media Transport Media Codec - SBC 44.1kHz Stereo 16 Blocks 8 Subbands Loudness Bitpool Range 112-128 < ACL data: handle 1 flags 0x02 dlen 18 L2CAP(d): cid 0x006d len 14 [psm 25] AVDTP(s): Set config cmd: transaction 11 nsp 0x00 ACP SEID 1 - INT SEID 2 Media Transport Media Codec - SBC 44.1kHz Stereo 16 Blocks 8 Subbands Loudness Bitpool Range 112-53 > HCI Event: Number of Completed Packets (0x13) plen 5 handle 1 packets 1 > ACL data: handle 1 flags 0x02 dlen 8 L2CAP(d): cid 0x0040 len 4 [psm 25] AVDTP(s): Set config rej: transaction 11 nsp 0x00 Media Codec Error code 204 The other device that tries to communicate at bitpool=112 and gives up, is my phone. Now I'm listening to it with the headset and the sound is perfectly clear, with no sign of that "analog" distortion I mentioned earlier. Bluez has MAX_BITPOOL=53 or 64 stored everywhere and who knows, maybe it's even able to recover these magic numbers from bitrate. Should I look for bitrate constant, like 320 or so? > audio quality in the current bluez sbc decoder is > far from perfect and the synthesis filter needs to be replaced first. I'm not sure what you expect from sbcenc-sbcdec tests. Even if they prove the encoding/decoding within Bluez has a reasonably good quality, what then? Will it propagate among different devices, bluetooth stacks? Regards -- Sebastian Olter ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: A2DP quality (bluetooth-alsa) 2012-03-13 12:45 ` qduaty @ 2012-03-13 13:26 ` Siarhei Siamashka 2012-03-14 12:53 ` qduaty 0 siblings, 1 reply; 23+ messages in thread From: Siarhei Siamashka @ 2012-03-13 13:26 UTC (permalink / raw) To: qduaty; +Cc: linux-bluetooth On Tue, Mar 13, 2012 at 2:45 PM, qduaty <qduaty@gmail.com> wrote: > 2012/3/13 Siarhei Siamashka <siarhei.siamashka@gmail.com>: >> On Tue, Mar 13, 2012 at 3:48 AM, qduaty <qduaty@gmail.com> wrote: >>> 2011/10/18 Siarhei Siamashka <siarhei.siamashka@gmail.com>: >> Thanks for testing! One more experiment would be very much welcome. I >> wonder if just defining SBC_HIGH_PRECISION without doing anything else >> would have any noticeable effect on audio quality in listening tests. > > Well, before I move on, there is one thing that makes me sad: > > < ACL data: handle 1 flags 0x02 dlen 7 > L2CAP(d): cid 0x006d len 3 [psm 25] > AVDTP(s): Capabilities cmd: transaction 10 nsp 0x00 > ACP SEID 1 >> HCI Event: Number of Completed Packets (0x13) plen 5 > handle 1 packets 1 >> ACL data: handle 1 flags 0x02 dlen 16 > L2CAP(d): cid 0x0040 len 12 [psm 25] > AVDTP(s): Capabilities rsp: transaction 10 nsp 0x00 > Media Transport > Media Codec - SBC > 44.1kHz > Stereo > 16 Blocks > 8 Subbands > Loudness > Bitpool Range 112-128 > < ACL data: handle 1 flags 0x02 dlen 18 > L2CAP(d): cid 0x006d len 14 [psm 25] > AVDTP(s): Set config cmd: transaction 11 nsp 0x00 > ACP SEID 1 - INT SEID 2 > Media Transport > Media Codec - SBC > 44.1kHz > Stereo > 16 Blocks > 8 Subbands > Loudness > Bitpool Range 112-53 >> HCI Event: Number of Completed Packets (0x13) plen 5 > handle 1 packets 1 >> ACL data: handle 1 flags 0x02 dlen 8 > L2CAP(d): cid 0x0040 len 4 [psm 25] > AVDTP(s): Set config rej: transaction 11 nsp 0x00 > Media Codec > Error code 204 I'm only familiar with SBC codec in bluez, but not much with A2DP protocol. Maybe somebody else could comment. > The other device that tries to communicate at bitpool=112 and gives > up, is my phone. Now I'm listening to it with the headset and the > sound is perfectly clear, with no sign of that "analog" distortion I > mentioned earlier. Are you now comparing streaming of A2DP audio from your phone to your PC (using bluez A2DP sink) and to your bluetooth headset? > Bluez has MAX_BITPOOL=53 or 64 stored everywhere and who knows, maybe > it's even able to recover these magic numbers from bitrate. Should I > look for bitrate constant, like 320 or so? Maybe. If there is some problem negotiating optimal bitpool setting, then it is better to be fixed. >> audio quality in the current bluez sbc decoder is >> far from perfect and the synthesis filter needs to be replaced first. > > I'm not sure what you expect from sbcenc-sbcdec tests. Even if they > prove the encoding/decoding within Bluez has a reasonably good > quality, what then? Will it propagate among different devices, > bluetooth stacks? sbcenc-sbcdec tests are useful for testing bluez SBC codec. For any given bitpool value, encoding/decoding roundtrip should preserve as much audio quality as possible. And trying different possible combinations of encoder/decoder (bluez / reference sbc codec / bluetooth headset) should help to provide the answers to the questions you are asking. -- Best regards, Siarhei Siamashka ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: A2DP quality (bluetooth-alsa) 2012-03-13 13:26 ` Siarhei Siamashka @ 2012-03-14 12:53 ` qduaty 2012-03-25 2:51 ` [PATCH] " qduaty 2012-03-26 7:43 ` Siarhei Siamashka 0 siblings, 2 replies; 23+ messages in thread From: qduaty @ 2012-03-14 12:53 UTC (permalink / raw) To: linux-bluetooth [-- Attachment #1: Type: text/plain, Size: 883 bytes --] 2012/3/13 Siarhei Siamashka <siarhei.siamashka@gmail.com>: > Are you now comparing streaming of A2DP audio from your phone to your > PC (using bluez A2DP sink) and to your bluetooth headset? I assume that the phone streams data to the headset (whose session is hard to dump on Windows mobile) with bitpool = 112, ie. the same it fails to set in Bluez and I'm saying it gives good results in terms of perceiveable quality, from which Bluez cannot take advantage due to its inherent bitpool=53 limitation. Anyway, I did some additional listening tests (by listening to Bluez SBC on an A2DP headset). SBC_HIGH_PRECISION alone (without your hack) only slightly improves quality. Also I finally managed to force higher bitpool in ALSA (patch attached). This makes further improvement in quality, at least on headsets that do not choke on higher bitpools. Regards -- Sebastian Olter [-- Attachment #2: pcm_bluetooth.c.diff --] [-- Type: application/octet-stream, Size: 862 bytes --] *** pcm_bluetooth.c 2011-12-21 23:53:54.000000000 +0100 --- /usr/src/bluez-4.99/audio/pcm_bluetooth.c 2012-03-14 12:52:34.299173684 +0100 *************** *** 680,690 **** case BT_A2DP_BLOCK_LENGTH_16: a2dp->sbc.blocks = SBC_BLK_16; break; } ! a2dp->sbc.bitpool = active_capabilities.max_bitpool; a2dp->codesize = sbc_get_codesize(&a2dp->sbc); a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); } static int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io, --- 678,689 ---- case BT_A2DP_BLOCK_LENGTH_16: a2dp->sbc.blocks = SBC_BLK_16; break; } ! a2dp->sbc.bitpool = active_capabilities.max_bitpool * 2; ! a2dp->codesize = sbc_get_codesize(&a2dp->sbc); a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); } static int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io, ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-03-14 12:53 ` qduaty @ 2012-03-25 2:51 ` qduaty 2012-03-26 9:44 ` Siarhei Siamashka 2012-03-26 7:43 ` Siarhei Siamashka 1 sibling, 1 reply; 23+ messages in thread From: qduaty @ 2012-03-25 2:51 UTC (permalink / raw) To: linux-bluetooth [-- Attachment #1: Type: text/plain, Size: 704 bytes --] Hello, I found that floating point processing eliminates all the quality issues that were mentioned here. So I added a floating point mode to SBC, which can be enabled with an #ifdef in sbc_tables.h, along with a code for minimizing quantization errors. It reduces noise by several dB and greatly improves the reproduction of higher bands. There is room for further improvements, such as adaptive clipping prevention and high resolution input format, but with current code base, they are somewhat hard to implement. The attached patch may cause some trouble because of one part being rejected. I hope this will not prevent those who are interested, from applying it and testing. -- Sebastian Olter [-- Attachment #2: float.diff --] [-- Type: text/x-diff, Size: 16835 bytes --] diff -bc5 bluez-4.99-orig/sbc//sbc_primitives.c bluez-4.99/sbc//sbc_primitives.c *** bluez-4.99-orig/sbc//sbc_primitives.c 2010-11-20 21:25:14.000000000 +0100 --- bluez-4.99/sbc//sbc_primitives.c 2012-03-25 01:12:29.502123931 +0100 *************** *** 35,44 **** --- 35,47 ---- #include "sbc_primitives_mmx.h" #include "sbc_primitives_iwmmxt.h" #include "sbc_primitives_neon.h" #include "sbc_primitives_armv6.h" + #define ANTICLIP 0.8 + + /* * A reference C code of analysis filter with SIMD-friendly tables * reordering and code layout. This code can be used to develop platform * specific SIMD optimizations. Also it may be used as some kind of test * for compiler autovectorization capabilities (who knows, if the compiler *************** *** 59,73 **** static inline void sbc_analyze_four_simd(const int16_t *in, int32_t *out, const FIXED_T *consts) { FIXED_A t1[4]; FIXED_T t2[4]; ! int hop = 0; ! /* rounding coefficient */ t1[0] = t1[1] = t1[2] = t1[3] = (FIXED_A) 1 << (SBC_PROTO_FIXED4_SCALE - 1); /* low pass polyphase filter */ for (hop = 0; hop < 40; hop += 8) { t1[0] += (FIXED_A) in[hop] * consts[hop]; t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1]; --- 62,82 ---- static inline void sbc_analyze_four_simd(const int16_t *in, int32_t *out, const FIXED_T *consts) { FIXED_A t1[4]; FIXED_T t2[4]; ! int hop = 0, i = 0; ! #ifdef SBC_FLOAT ! #define SBC_PROTO_SCALE_FIXED4(x) x; ! /* rounding coefficient */ ! t1[0] = t1[1] = t1[2] = t1[3] = 1; ! #else ! #define SBC_PROTO_SCALE_FIXED4(x) x >> SBC_PROTO_FIXED4_SCALE /* rounding coefficient */ t1[0] = t1[1] = t1[2] = t1[3] = (FIXED_A) 1 << (SBC_PROTO_FIXED4_SCALE - 1); + #endif /* low pass polyphase filter */ for (hop = 0; hop < 40; hop += 8) { t1[0] += (FIXED_A) in[hop] * consts[hop]; t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1]; *************** *** 78,91 **** t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6]; t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7]; } /* scaling */ ! t2[0] = t1[0] >> SBC_PROTO_FIXED4_SCALE; ! t2[1] = t1[1] >> SBC_PROTO_FIXED4_SCALE; ! t2[2] = t1[2] >> SBC_PROTO_FIXED4_SCALE; ! t2[3] = t1[3] >> SBC_PROTO_FIXED4_SCALE; /* do the cos transform */ t1[0] = (FIXED_A) t2[0] * consts[40 + 0]; t1[0] += (FIXED_A) t2[1] * consts[40 + 1]; t1[1] = (FIXED_A) t2[0] * consts[40 + 2]; --- 87,100 ---- t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6]; t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7]; } /* scaling */ ! t2[0] = SBC_PROTO_SCALE_FIXED4(t1[0]); ! t2[1] = SBC_PROTO_SCALE_FIXED4(t1[1]); ! t2[2] = SBC_PROTO_SCALE_FIXED4(t1[2]); ! t2[3] = SBC_PROTO_SCALE_FIXED4(t1[3]); /* do the cos transform */ t1[0] = (FIXED_A) t2[0] * consts[40 + 0]; t1[0] += (FIXED_A) t2[1] * consts[40 + 1]; t1[1] = (FIXED_A) t2[0] * consts[40 + 2]; *************** *** 102,131 **** t1[2] += (FIXED_A) t2[2] * consts[40 + 12]; t1[2] += (FIXED_A) t2[3] * consts[40 + 13]; t1[3] += (FIXED_A) t2[2] * consts[40 + 14]; t1[3] += (FIXED_A) t2[3] * consts[40 + 15]; ! out[0] = t1[0] >> ! (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); ! out[1] = t1[1] >> ! (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); ! out[2] = t1[2] >> ! (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); ! out[3] = t1[3] >> (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); } static inline void sbc_analyze_eight_simd(const int16_t *in, int32_t *out, const FIXED_T *consts) { FIXED_A t1[8]; FIXED_T t2[8]; int i, hop; ! /* rounding coefficient */ t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = (FIXED_A) 1 << (SBC_PROTO_FIXED8_SCALE-1); /* low pass polyphase filter */ for (hop = 0; hop < 80; hop += 16) { t1[0] += (FIXED_A) in[hop] * consts[hop]; t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1]; --- 111,154 ---- t1[2] += (FIXED_A) t2[2] * consts[40 + 12]; t1[2] += (FIXED_A) t2[3] * consts[40 + 13]; t1[3] += (FIXED_A) t2[2] * consts[40 + 14]; t1[3] += (FIXED_A) t2[3] * consts[40 + 15]; ! #ifdef SBC_FLOAT ! /* Tries to redistribute quantization errors so that exactly half of them ! * is positive. This reduces overall distortion, especially in high bands ! * and increases chances for clipping, hence the ANTICLIP coefficient. */ ! double accumError = 0; ! for (i = 0; i < 4; i++){ ! t1[i] *= (1 << SCALE_OUT_BITS) * ANTICLIP; ! accumError += t1[i] - (int32_t)t1[i]; ! } ! for (i = 0; i < 4; i++) ! out[i] = t1[i] + accumError / 4; ! #else ! for (i = 0; i < 4; i++) ! out[i] = t1[i] >> (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); + #endif } static inline void sbc_analyze_eight_simd(const int16_t *in, int32_t *out, const FIXED_T *consts) { FIXED_A t1[8]; FIXED_T t2[8]; int i, hop; ! #ifdef SBC_FLOAT ! #define SBC_PROTO_SCALE_FIXED8(x) x; ! /* rounding coefficient */ ! t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = 1; ! #else ! #define SBC_PROTO_SCALE_FIXED8(x) x >> SBC_PROTO_FIXED8_SCALE /* rounding coefficient */ t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = (FIXED_A) 1 << (SBC_PROTO_FIXED8_SCALE-1); + #endif /* low pass polyphase filter */ for (hop = 0; hop < 80; hop += 16) { t1[0] += (FIXED_A) in[hop] * consts[hop]; t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1]; *************** *** 144,161 **** t1[7] += (FIXED_A) in[hop + 14] * consts[hop + 14]; t1[7] += (FIXED_A) in[hop + 15] * consts[hop + 15]; } /* scaling */ ! t2[0] = t1[0] >> SBC_PROTO_FIXED8_SCALE; ! t2[1] = t1[1] >> SBC_PROTO_FIXED8_SCALE; ! t2[2] = t1[2] >> SBC_PROTO_FIXED8_SCALE; ! t2[3] = t1[3] >> SBC_PROTO_FIXED8_SCALE; ! t2[4] = t1[4] >> SBC_PROTO_FIXED8_SCALE; ! t2[5] = t1[5] >> SBC_PROTO_FIXED8_SCALE; ! t2[6] = t1[6] >> SBC_PROTO_FIXED8_SCALE; ! t2[7] = t1[7] >> SBC_PROTO_FIXED8_SCALE; /* do the cos transform */ t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = 0; --- 167,184 ---- t1[7] += (FIXED_A) in[hop + 14] * consts[hop + 14]; t1[7] += (FIXED_A) in[hop + 15] * consts[hop + 15]; } /* scaling */ ! t2[0] = SBC_PROTO_SCALE_FIXED8(t1[0]); ! t2[1] = SBC_PROTO_SCALE_FIXED8(t1[1]); ! t2[2] = SBC_PROTO_SCALE_FIXED8(t1[2]); ! t2[3] = SBC_PROTO_SCALE_FIXED8(t1[3]); ! t2[4] = SBC_PROTO_SCALE_FIXED8(t1[4]); ! t2[5] = SBC_PROTO_SCALE_FIXED8(t1[5]); ! t2[6] = SBC_PROTO_SCALE_FIXED8(t1[6]); ! t2[7] = SBC_PROTO_SCALE_FIXED8(t1[7]); /* do the cos transform */ t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = 0; *************** *** 176,188 **** --- 199,227 ---- t1[6] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 13]; t1[7] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 14]; t1[7] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 15]; } + #ifdef SBC_FLOAT + /* Tries to redistribute quantization errors so that exactly half of them + * is positive. This reduces overall distortion, especially in high bands + * and increases chances for clipping, hence the ANTICLIP coefficient. */ + double accumError = 0; + for (i = 0; i < 8; i++){ + t1[i] *= (1 << SCALE_OUT_BITS) * ANTICLIP; + accumError += t1[i] - (int32_t)t1[i]; + } + for (i = 0; i < 8; i++) + out[i] = t1[i] + accumError / 8; + /* + out[i] = t1[i]; + */ + #else for (i = 0; i < 8; i++) out[i] = t1[i] >> (SBC_COS_TABLE_FIXED8_SCALE - SCALE_OUT_BITS); + #endif } static inline void sbc_analyze_4b_4s_simd(int16_t *x, int32_t *out, int out_stride) { diff -bc5 bluez-4.99-orig/sbc//sbc_tables.h bluez-4.99/sbc//sbc_tables.h *** bluez-4.99-orig/sbc//sbc_tables.h 2011-12-21 23:53:54.000000000 +0100 --- bluez-4.99/sbc//sbc_tables.h 2012-03-21 18:08:15.559689237 +0100 *************** *** 136,154 **** SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) } }; /* Uncomment the following line to enable high precision build of SBC encoder */ ! /* #define SBC_HIGH_PRECISION */ #ifdef SBC_HIGH_PRECISION #define FIXED_A int64_t /* data type for fixed point accumulator */ #define FIXED_T int32_t /* data type for fixed point constants */ #define SBC_FIXED_EXTRA_BITS 16 #else #define FIXED_A int32_t /* data type for fixed point accumulator */ #define FIXED_T int16_t /* data type for fixed point constants */ #define SBC_FIXED_EXTRA_BITS 0 #endif /* A2DP specification: Section 12.8 Tables * --- 136,175 ---- SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) } }; /* Uncomment the following line to enable high precision build of SBC encoder */ ! //#define SBC_HIGH_PRECISION ! #define SBC_FLOAT #ifdef SBC_HIGH_PRECISION #define FIXED_A int64_t /* data type for fixed point accumulator */ #define FIXED_T int32_t /* data type for fixed point constants */ + #define FIXED_T_BITS (sizeof(FIXED_T) * CHAR_BIT - 1) + #define F_PROTO4(x) (FIXED_A) ((x * 2) * (1LL << FIXED_T_BITS) + 0.5) + #define F_COS4(x) ((x) * (1LL << FIXED_T_BITS) + 0.5) + #define F_PROTO8(x) ((x * 2) * (1LL << FIXED_T_BITS) + 0.5) + #define F_COS8(x) ((x) * (1LL << FIXED_T_BITS) + 0.5) #define SBC_FIXED_EXTRA_BITS 16 + #elif defined(SBC_FLOAT) + #define SBC_HIGH_PRECISION // disable MMX + #define FIXED_A double /* data type for fixed point accumulator */ + #define FIXED_T float /* data type for fixed point constants */ + #define FIXED_T_BITS (sizeof(FIXED_T) * CHAR_BIT - 1) + #define F_PROTO4(x) (x) + #define F_COS4(x) (x) + #define F_PROTO8(x) (x) + #define F_COS8(x) (x) + #define SBC_FIXED_EXTRA_BITS 0 #else #define FIXED_A int32_t /* data type for fixed point accumulator */ #define FIXED_T int16_t /* data type for fixed point constants */ + #define FIXED_T_BITS (sizeof(FIXED_T) * CHAR_BIT - 1) + #define F_PROTO4(x) (FIXED_A) ((x * 2) * (1 << FIXED_T_BITS) + 0.5) + #define F_COS4(x) ((x) * (1 << FIXED_T_BITS) + 0.5) + #define F_PROTO8(x) ((x * 2) * (1 << FIXED_T_BITS) + 0.5) + #define F_COS8(x) ((x) * (1 << FIXED_T_BITS) + 0.5) #define SBC_FIXED_EXTRA_BITS 0 #endif /* A2DP specification: Section 12.8 Tables * *************** *** 156,191 **** * maximum which is possible without overflows) * * Note: in each block of 8 numbers sign was changed for elements 2 and 7 * in order to compensate the same change applied to cos_table_fixed_4 */ ! #define SBC_PROTO_FIXED4_SCALE \ ! ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1) ! #define F_PROTO4(x) (FIXED_A) ((x * 2) * \ ! ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) #define F(x) F_PROTO4(x) static const FIXED_T _sbc_proto_fixed4[40] = { F(0.00000000E+00), F(5.36548976E-04), -F(1.49188357E-03), F(2.73370904E-03), F(3.83720193E-03), F(3.89205149E-03), F(1.86581691E-03), F(3.06012286E-03), - F(1.09137620E-02), F(2.04385087E-02), -F(2.88757392E-02), F(3.21939290E-02), F(2.58767811E-02), F(6.13245186E-03), -F(2.88217274E-02), F(7.76463494E-02), - F(1.35593274E-01), F(1.94987841E-01), -F(2.46636662E-01), F(2.81828203E-01), F(2.94315332E-01), F(2.81828203E-01), F(2.46636662E-01), -F(1.94987841E-01), - -F(1.35593274E-01), -F(7.76463494E-02), F(2.88217274E-02), F(6.13245186E-03), F(2.58767811E-02), F(3.21939290E-02), F(2.88757392E-02), -F(2.04385087E-02), - -F(1.09137620E-02), -F(3.06012286E-03), -F(1.86581691E-03), F(3.89205149E-03), F(3.83720193E-03), F(2.73370904E-03), F(1.49188357E-03), -F(5.36548976E-04), }; --- 177,205 ---- * maximum which is possible without overflows) * * Note: in each block of 8 numbers sign was changed for elements 2 and 7 * in order to compensate the same change applied to cos_table_fixed_4 */ ! #define SBC_PROTO_FIXED4_SCALE (FIXED_T_BITS - SBC_FIXED_EXTRA_BITS + 1) #define F(x) F_PROTO4(x) static const FIXED_T _sbc_proto_fixed4[40] = { F(0.00000000E+00), F(5.36548976E-04), -F(1.49188357E-03), F(2.73370904E-03), F(3.83720193E-03), F(3.89205149E-03), F(1.86581691E-03), F(3.06012286E-03), F(1.09137620E-02), F(2.04385087E-02), -F(2.88757392E-02), F(3.21939290E-02), F(2.58767811E-02), F(6.13245186E-03), -F(2.88217274E-02), F(7.76463494E-02), F(1.35593274E-01), F(1.94987841E-01), -F(2.46636662E-01), F(2.81828203E-01), F(2.94315332E-01), F(2.81828203E-01), F(2.46636662E-01), -F(1.94987841E-01), -F(1.35593274E-01), -F(7.76463494E-02), F(2.88217274E-02), F(6.13245186E-03), F(2.58767811E-02), F(3.21939290E-02), F(2.88757392E-02), -F(2.04385087E-02), -F(1.09137620E-02), -F(3.06012286E-03), -F(1.86581691E-03), F(3.89205149E-03), F(3.83720193E-03), F(2.73370904E-03), F(1.49188357E-03), -F(5.36548976E-04), }; *************** *** 206,219 **** * Change of sign for element 2 allows to replace constant 1.0 (not * representable in Q15 format) with -1.0 (fine with Q15). * Changed sign for element 7 allows to have more similar constants * and simplify subband filter function code. */ ! #define SBC_COS_TABLE_FIXED4_SCALE \ ! ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) ! #define F_COS4(x) (FIXED_A) ((x) * \ ! ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) #define F(x) F_COS4(x) static const FIXED_T cos_table_fixed_4[32] = { F(0.7071067812), F(0.9238795325), -F(1.0000000000), F(0.9238795325), F(0.7071067812), F(0.3826834324), F(0.0000000000), F(0.3826834324), --- 220,230 ---- * Change of sign for element 2 allows to replace constant 1.0 (not * representable in Q15 format) with -1.0 (fine with Q15). * Changed sign for element 7 allows to have more similar constants * and simplify subband filter function code. */ ! #define SBC_COS_TABLE_FIXED4_SCALE (FIXED_T_BITS + SBC_FIXED_EXTRA_BITS) #define F(x) F_COS4(x) static const FIXED_T cos_table_fixed_4[32] = { F(0.7071067812), F(0.9238795325), -F(1.0000000000), F(0.9238795325), F(0.7071067812), F(0.3826834324), F(0.0000000000), F(0.3826834324), *************** *** 234,247 **** * maximum which is possible without overflows) * * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15 * in order to compensate the same change applied to cos_table_fixed_8 */ ! #define SBC_PROTO_FIXED8_SCALE \ ! ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1) ! #define F_PROTO8(x) (FIXED_A) ((x * 2) * \ ! ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) #define F(x) F_PROTO8(x) static const FIXED_T _sbc_proto_fixed8[80] = { F(0.00000000E+00), F(1.56575398E-04), F(3.43256425E-04), F(5.54620202E-04), -F(8.23919506E-04), F(1.13992507E-03), --- 245,255 ---- * maximum which is possible without overflows) * * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15 * in order to compensate the same change applied to cos_table_fixed_8 */ ! #define SBC_PROTO_FIXED8_SCALE (FIXED_T_BITS - SBC_FIXED_EXTRA_BITS + 1) #define F(x) F_PROTO8(x) static const FIXED_T _sbc_proto_fixed8[80] = { F(0.00000000E+00), F(1.56575398E-04), F(3.43256425E-04), F(5.54620202E-04), -F(8.23919506E-04), F(1.13992507E-03), *************** *** 303,316 **** * Change of sign for element 4 allows to replace constant 1.0 (not * representable in Q15 format) with -1.0 (fine with Q15). * Changed signs for elements 13, 14, 15 allow to have more similar constants * and simplify subband filter function code. */ ! #define SBC_COS_TABLE_FIXED8_SCALE \ ! ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) ! #define F_COS8(x) (FIXED_A) ((x) * \ ! ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) #define F(x) F_COS8(x) static const FIXED_T cos_table_fixed_8[128] = { F(0.7071067812), F(0.8314696123), F(0.9238795325), F(0.9807852804), -F(1.0000000000), F(0.9807852804), F(0.9238795325), F(0.8314696123), F(0.7071067812), F(0.5555702330), F(0.3826834324), F(0.1950903220), --- 311,321 ---- * Change of sign for element 4 allows to replace constant 1.0 (not * representable in Q15 format) with -1.0 (fine with Q15). * Changed signs for elements 13, 14, 15 allow to have more similar constants * and simplify subband filter function code. */ ! #define SBC_COS_TABLE_FIXED8_SCALE (FIXED_T_BITS + SBC_FIXED_EXTRA_BITS) #define F(x) F_COS8(x) static const FIXED_T cos_table_fixed_8[128] = { F(0.7071067812), F(0.8314696123), F(0.9238795325), F(0.9807852804), -F(1.0000000000), F(0.9807852804), F(0.9238795325), F(0.8314696123), F(0.7071067812), F(0.5555702330), F(0.3826834324), F(0.1950903220), ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-03-25 2:51 ` [PATCH] " qduaty @ 2012-03-26 9:44 ` Siarhei Siamashka 2012-03-26 21:11 ` qduaty 0 siblings, 1 reply; 23+ messages in thread From: Siarhei Siamashka @ 2012-03-26 9:44 UTC (permalink / raw) To: qduaty; +Cc: linux-bluetooth On Sun, Mar 25, 2012 at 5:51 AM, qduaty <qduaty@gmail.com> wrote: > Hello, > > I found that floating point processing eliminates all the quality > issues that were mentioned here. So I added a floating point mode to > SBC, which can be enabled with an #ifdef in sbc_tables.h, along with a > code for minimizing quantization errors. It reduces noise by several > dB and greatly improves the reproduction of higher bands. Out of curiosity, how do you measure noise reduction? Regarding your changes: ! #ifdef SBC_FLOAT ! #define SBC_PROTO_SCALE_FIXED4(x) x; ! /* rounding coefficient */ ! t1[0] = t1[1] = t1[2] = t1[3] = 1; This does not look right. For the fixed point code, rounding coefficient is needed because we are shifting results after the first multiplication pass. Simply right shifting the data would discard the lowest bits, effectively doing rounding down. Introducing rounding coefficient allows rounding to nearest: "(x + (1 << (SBC_PROTO_FIXED4_SCALE - 1))) >> SBC_PROTO_FIXED4_SCALE" Floating point code does not need any rounding coefficient. ! #ifdef SBC_FLOAT ! /* Tries to redistribute quantization errors so that exactly half of them ! * is positive. This reduces overall distortion, especially in high bands ! * and increases chances for clipping, hence the ANTICLIP coefficient. */ ! double accumError = 0; ! for (i = 0; i < 4; i++){ ! t1[i] *= (1 << SCALE_OUT_BITS) * ANTICLIP; ! accumError += t1[i] - (int32_t)t1[i]; ! } ! for (i = 0; i < 4; i++) ! out[i] = t1[i] + accumError / 4; I find it hard to believe that this accumError would make any noticeable difference on the output (neither good nor bad). The analysis filter produces fixed point values with SCALE_OUT_BITS fractional bits (selected to be 15 currently). So the output is in 17.15 fixed point format. 15 extra bits have been selected just because we can, and this allows to use full range of 32-bit variables. If we further divide it by 2 as needed on quantization step later, then we actually have 16.16 format. These extra bits are needed to avoid precision loss on normalization. If quantized value is for example in [-127, 127] range, then it needs to be stored as 8 bits or [0, 255] range in the bitstream, which gives a rather nasty 255/256 scale ratio and this is a potential source of rounding errors unless we preserve as many bits as possible. From A2DP spec: "levels[ch][sb] = pow(2.0, bits[ch][sb]) - 1" "scalefactor[ch][ sb] = pow(2.0, (scale_factor[ch][sb] + 1))" "quantized_sb_sample[blk][ch][sb] = ((sb_sample[blk][ch][sb] / scalefactor[ch][sb] + 1.0) * levels[ch][sb]) / 2.0" "quantized_sb_sample" is rounded towards minus infinity, "levels" are powers of two minus one and scalefactor is a power of two. But even less than 15 extra bits for SCALE_OUT_BITS seems to be also fine in practice (you can do some experiments with reducing it), assuming that the values are quantized even a little bit. With your change, you are only messing around the lowest bit in the extra fractional part. Scaling down the input with ANTICLIP should get rid of clipping (on the decoder side) with heavily compressed audio sources as expected, but this is not anything new. > There is room for further improvements, such as adaptive clipping > prevention and high resolution input format, but with current code > base, they are somewhat hard to implement. If you have any questions about the current code, just ask. > The attached patch may cause some trouble because of one part being > rejected. I hope this will not prevent those who are interested, from > applying it and testing. Could you please at least use unified diff (-u option)? And the best would be to use "git commit" and then "git format-patch". In any case, the ability to reduce the audio volume as part of SBC encoding process looks like a useful improvement to me (and maybe it's a good idea to even have it used by default). This should help to workaround the audio quality problems with some A2DP headsets. -- Best regards, Siarhei Siamashka ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-03-26 9:44 ` Siarhei Siamashka @ 2012-03-26 21:11 ` qduaty 2012-03-27 1:29 ` qduaty 0 siblings, 1 reply; 23+ messages in thread From: qduaty @ 2012-03-26 21:11 UTC (permalink / raw) To: linux-bluetooth 2012/3/26 Siarhei Siamashka <siarhei.siamashka@gmail.com>: > On Sun, Mar 25, 2012 at 5:51 AM, qduaty <qduaty@gmail.com> wrote: > Out of curiosity, how do you measure noise reduction? It seems to reduce noise making it less audible. I didn't perform objective measurements because it's not relevant as long as the (decoded) stream is not used for encoding. > Floating point code does not need any rounding coefficient. You have right, I missed the comment. t1 should be initialized to 0. > I find it hard to believe that this accumError would make any > noticeable difference on the output (neither good nor bad). I don't believe it either, but it is a trick. Perhaps my results are biased, but it always seems that adding 0.5 before rounding adds some noise, while adding accumError calculated this way, does the opposite (removes some noise). Objective measurements could give the right answer. Anyway, if you're interested in the patch, I'd be careful with removing the part of code involving accumError - it's computationally cheap and at least one listener claims it improves quality. Three "blind" listeners could give you meaningful statistical data. > With your change, you are only messing around the lowest bit in the extra > fractional part. Now I'm surprised that it actually works. > If you have any questions about the current code, just ask. How to call sbc_encode(), sbc_decode() and again sbc_encode() in a single function? It seems they cannot use the same instance of sbc_t struct. I tried to estimate the amount of attenuation for adaptive clipping prevention (obviously this solution is suboptimal but can be a good starting point). Regards -- Sebastian Olter ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-03-26 21:11 ` qduaty @ 2012-03-27 1:29 ` qduaty 2012-03-27 7:57 ` Siarhei Siamashka 0 siblings, 1 reply; 23+ messages in thread From: qduaty @ 2012-03-27 1:29 UTC (permalink / raw) To: linux-bluetooth > 2012/3/26 Siarhei Siamashka <siarhei.siamashka@gmail.com>: >> Floating point code does not need any rounding coefficient. I'm very likely to agreed that I was wrong with initializing t1 elements to 1, but seemingly it helps with quality, especially in conjunction with accumError. So either I discovered something new, or I repeatedly "hear" my changes in C code instead of actual difference. Maybe I should look at sbcdec output. Regarding the bitpool: >> Do you have a hcidump log before and after patching bluez for the part >> where A2DP settings are negotiated? Actually I just forced bluez to use higher bitpool for SBC than negotiated. This is the hcidump after the change, but it does not differ from what has been before. > ACL data: handle 1 flags 0x02 dlen 20 L2CAP(d): cid 0x0040 len 16 [psm 25] AVDTP(s): Capabilities rsp: transaction 4 nsp 0x00 Media Transport Media Codec - SBC 16kHz 32kHz 44.1kHz 48kHz Mono DualChannel Stereo JointStereo 4 8 12 16 Blocks 4 8 Subbands SNR Loudness Bitpool Range 2-53 Content Protection 02 00 < ACL data: handle 1 flags 0x02 dlen 18 L2CAP(d): cid 0x0060 len 14 [psm 25] AVDTP(s): Set config cmd: transaction 5 nsp 0x00 ACP SEID 1 - INT SEID 1 Media Transport Media Codec - SBC 44.1kHz Stereo 16 Blocks 8 Subbands Loudness Bitpool Range 46-46 The headset reports bltpool range of 2-53 and bluez reports 46-46, but according to Blueman, it streams at 99 KB/s. Also, I removed calls to default_bitpool(), which is now reported as unused function, and increased MAX_BITPOOL everywhere. It does not change anything. When bitpool is not set in ./asoundrc, Bluez responds with the same values it received from the device. There is a difference between Bluez and WinMo, which first sends its own capabilities and then asks the device (see my previous hcidump). I don't know what BH-503 answers, but it's possible that it adapts to higher limits of the phone and reports higher bitpools than 53, or the phone overrides negotiated settings and streams at any bitpool it likes. I tested it with bitpools up to 250 and it always worked. Contrary to that, Bluez copies the (fake or backward-compatible) value of 53 that was received from the device and limits itself instead of reporting its real capabilities. -- Sebastian Olter ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-03-27 1:29 ` qduaty @ 2012-03-27 7:57 ` Siarhei Siamashka 2012-03-27 23:28 ` qduaty 0 siblings, 1 reply; 23+ messages in thread From: Siarhei Siamashka @ 2012-03-27 7:57 UTC (permalink / raw) To: linux-bluetooth [-- Attachment #1: Type: text/plain, Size: 3835 bytes --] On Tue, Mar 27, 2012 at 4:29 AM, qduaty <qduaty@gmail.com> wrote: >> 2012/3/26 Siarhei Siamashka <siarhei.siamashka@gmail.com>: >>> Floating point code does not need any rounding coefficient. > > I'm very likely to agreed that I was wrong with initializing t1 > elements to 1, but seemingly it helps with quality, especially in > conjunction with accumError. So either I discovered something new, or > I repeatedly "hear" my changes in C code instead of actual difference. I think Double Blind listening Test is necessary, otherwise everything is very subjective: http://www.hydrogenaudio.org/forums/index.php?showtopic=16295 > Maybe I should look at sbcdec output. You could also look at fixing sbc decoder, it still does have some real audio quality problems :) > Regarding the bitpool: > >>> Do you have a hcidump log before and after patching bluez for the part >>> where A2DP settings are negotiated? > > Actually I just forced bluez to use higher bitpool for SBC than > negotiated. This is the hcidump after the change, but it does not > differ from what has been before. > >> ACL data: handle 1 flags 0x02 dlen 20 > L2CAP(d): cid 0x0040 len 16 [psm 25] > AVDTP(s): Capabilities rsp: transaction 4 nsp 0x00 > Media Transport > Media Codec - SBC > 16kHz 32kHz 44.1kHz 48kHz > Mono DualChannel Stereo JointStereo > 4 8 12 16 Blocks > 4 8 Subbands > SNR Loudness > Bitpool Range 2-53 > Content Protection > 02 00 > < ACL data: handle 1 flags 0x02 dlen 18 > L2CAP(d): cid 0x0060 len 14 [psm 25] > AVDTP(s): Set config cmd: transaction 5 nsp 0x00 > ACP SEID 1 - INT SEID 1 > Media Transport > Media Codec - SBC > 44.1kHz > Stereo > 16 Blocks > 8 Subbands > Loudness > Bitpool Range 46-46 > > The headset reports bltpool range of 2-53 and bluez reports 46-46, but > according to Blueman, it streams at 99 KB/s This is getting really confusing. If I run blueman, it reports ~40 KB/s for bitpool 53, ~48 KB/s for bitpool 64 and ~36 KB/s for bitpool 46 (if I add 'bitpool "46"' line to my .asoundrc). > Also, I removed calls to > default_bitpool(), which is now reported as unused function, and > increased MAX_BITPOOL everywhere. It does not change anything. I have attached two test patches. The first patch adds debug prints to syslog from sbc encoder, just to clearly confirm the real bitpool used by the encoder. If the encoder is encoding data with some certain bitpool settings and you hear something from your headset, then there is no way for the bitpool to be magically different from that. The second patch removes default_bitpool() limitation, and this boosts bitpool from 53 to 64 for me. Confirmed by sbc encoder debug prints from my first patch, hcidump log and blueman streaming rate statistics. > When bitpool is not set in ./asoundrc, Bluez responds with the same > values it received from the device. There is a difference between > Bluez and WinMo, which first sends its own capabilities and then asks > the device (see my previous hcidump). I don't know what BH-503 > answers, but it's possible that it adapts to higher limits of the > phone and reports higher bitpools than 53, or the phone overrides > negotiated settings and streams at any bitpool it likes. I tested it > with bitpools up to 250 and it always worked. Contrary to that, Bluez > copies the (fake or backward-compatible) value of 53 that was received > from the device and limits itself instead of reporting its real > capabilities. -- Best regards, Siarhei Siamashka [-- Attachment #2: 0001-HACK-report-bitpool-to-syslog-from-sbc-encoder.patch --] [-- Type: text/x-patch, Size: 1116 bytes --] From 94a7494f063b3e22c8e2c3556a021c5315598e86 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka <siarhei.siamashka@gmail.com> Date: Tue, 27 Mar 2012 10:03:00 +0300 Subject: [PATCH 1/2] HACK: report bitpool to syslog from sbc encoder --- sbc/sbc.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/sbc/sbc.c b/sbc/sbc.c index c5015ab..0273035 100644 --- a/sbc/sbc.c +++ b/sbc/sbc.c @@ -42,6 +42,7 @@ #include <stdlib.h> #include <sys/types.h> #include <limits.h> +#include <syslog.h> #include "sbc_math.h" #include "sbc_tables.h" @@ -1060,9 +1061,11 @@ ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len, sbc_encoder_init(&priv->enc_state, &priv->frame); priv->init = 1; + syslog(LOG_USER | LOG_INFO, "sbc_encode: bitpool set to %d\n", sbc->bitpool); } else if (priv->frame.bitpool != sbc->bitpool) { priv->frame.length = sbc_get_frame_length(sbc); priv->frame.bitpool = sbc->bitpool; + syslog(LOG_USER | LOG_INFO, "sbc_encode: bitpool changed to %d\n", sbc->bitpool); } /* input must be large enough to encode a complete frame */ -- 1.7.3.4 [-- Attachment #3: 0002-HACK-remove-default_bitpool-limitation.patch --] [-- Type: text/x-patch, Size: 1424 bytes --] From bbd5102a185d8c80b3668864618f34359c2d2139 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka <siarhei.siamashka@gmail.com> Date: Tue, 27 Mar 2012 10:10:27 +0300 Subject: [PATCH 2/2] HACK: remove default_bitpool limitation --- audio/a2dp.c | 3 +-- audio/pcm_bluetooth.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/audio/a2dp.c b/audio/a2dp.c index 623a0bc..8153819 100644 --- a/audio/a2dp.c +++ b/audio/a2dp.c @@ -1839,8 +1839,7 @@ static gboolean select_sbc_params(struct sbc_codec_cap *cap, cap->allocation_method = SBC_ALLOCATION_SNR; min_bitpool = MAX(MIN_BITPOOL, supported->min_bitpool); - max_bitpool = MIN(default_bitpool(cap->frequency, cap->channel_mode), - supported->max_bitpool); + max_bitpool = MAX(min_bitpool, supported->max_bitpool); cap->min_bitpool = min_bitpool; cap->max_bitpool = max_bitpool; diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c index 85566a3..9130e35 100644 --- a/audio/pcm_bluetooth.c +++ b/audio/pcm_bluetooth.c @@ -609,9 +609,7 @@ static int bluetooth_a2dp_init(struct bluetooth_data *data, min_bitpool = max_bitpool = cfg->bitpool; else { min_bitpool = MAX(MIN_BITPOOL, cap->min_bitpool); - max_bitpool = MIN(default_bitpool(cap->frequency, - cap->channel_mode), - cap->max_bitpool); + max_bitpool = MAX(min_bitpool, cap->max_bitpool); } cap->min_bitpool = min_bitpool; -- 1.7.3.4 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-03-27 7:57 ` Siarhei Siamashka @ 2012-03-27 23:28 ` qduaty 2012-04-02 9:44 ` Siarhei Siamashka 0 siblings, 1 reply; 23+ messages in thread From: qduaty @ 2012-03-27 23:28 UTC (permalink / raw) To: linux-bluetooth [-- Attachment #1: Type: text/plain, Size: 1267 bytes --] ALSA bitpool patch is attached. 2012/3/27 Siarhei Siamashka <siarhei.siamashka@gmail.com>: > The first patch adds debug prints to syslog from sbc encoder, just to > clearly confirm the real bitpool used by the encoder. It obviously worked: Mar 27 17:49:41 machina-turbo pulseaudio[2355]: sbc_encode: bitpool set to 138 > The second patch removes default_bitpool() limitation, and this boosts > bitpool from 53 to 64 for me. I found it was my device that prevented Bluez from using higher bitpools. Bluez assumes that requesting a wider range of bitpools from a device will cause an error, and indeed, my device cannot be configured with a bitpool range wider than 2-53. So the only way to achieve higher bitrates is to force them. There is (was) a rather serious problem in the ALSA module, when it tried to set bitpool exceding device capabilities, it ended with an error and next tries, even with a valid bitpool, resulted in "Invalid seid 0" in syslog and required bluetooth service to be restarted. With my patch, bluez only uses the configured bitpool for sbc, without sending it to the device. So, any bitpool value not exceeding true device and adapter capabilities will work (and these can be much higher than negotiated). Regards -- Sebastian Olter [-- Attachment #2: alsa_use_arbitrary_bitpool.diff --] [-- Type: text/x-diff, Size: 1991 bytes --] --- bluez-4.99-orig/audio/pcm_bluetooth.c 2011-12-21 23:53:54.000000000 +0100 +++ bluez-4.99/audio/pcm_bluetooth.c 2012-03-28 01:20:41.977829080 +0200 @@ -78,7 +78,7 @@ # define MAX(x, y) ((x) > (y) ? (x) : (y)) #endif -#define MAX_BITPOOL 64 +#define MAX_BITPOOL 250 #define MIN_BITPOOL 2 /* adapted from glibc sys/time.h timersub() macro */ @@ -606,13 +606,12 @@ cap->allocation_method = BT_A2DP_ALLOCATION_SNR; if (cfg->has_bitpool) - min_bitpool = max_bitpool = cfg->bitpool; - else { - min_bitpool = MAX(MIN_BITPOOL, cap->min_bitpool); - max_bitpool = MIN(default_bitpool(cap->frequency, - cap->channel_mode), - cap->max_bitpool); - } + data->a2dp.sbc.bitpool = cfg->bitpool; + else /* Initialize to MIN_BITPOOL in order to replace it with negotiated maximum */ + data->a2dp.sbc.bitpool = MIN_BITPOOL; + + min_bitpool = MAX(MIN_BITPOOL, cap->min_bitpool); + max_bitpool = MIN(MAX_BITPOOL, cap->max_bitpool); cap->min_bitpool = min_bitpool; cap->max_bitpool = max_bitpool; @@ -623,11 +622,15 @@ static void bluetooth_a2dp_setup(struct bluetooth_a2dp *a2dp) { sbc_capabilities_t active_capabilities = a2dp->sbc_capabilities; + int stored_bitpool = a2dp->sbc.bitpool; if (a2dp->sbc_initialized) sbc_reinit(&a2dp->sbc, 0); else sbc_init(&a2dp->sbc, 0); + + /* restore configured (or minimum) bitpool */ + a2dp->sbc.bitpool = stored_bitpool; a2dp->sbc_initialized = 1; if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_16000) @@ -682,7 +685,10 @@ break; } - a2dp->sbc.bitpool = active_capabilities.max_bitpool; + /* Increase the bitpool to allowed maximum, if it was not configured */ + if(a2dp->sbc.bitpool <= MIN_BITPOOL) + a2dp->sbc.bitpool = active_capabilities.max_bitpool; + a2dp->codesize = sbc_get_codesize(&a2dp->sbc); a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); } @@ -1714,7 +1720,7 @@ goto failed; bluetooth_parse_capabilities(data, rsp); - + return 0; failed: ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-03-27 23:28 ` qduaty @ 2012-04-02 9:44 ` Siarhei Siamashka 2012-04-03 0:56 ` qduaty 0 siblings, 1 reply; 23+ messages in thread From: Siarhei Siamashka @ 2012-04-02 9:44 UTC (permalink / raw) To: linux-bluetooth On Wed, Mar 28, 2012 at 2:28 AM, qduaty <qduaty@gmail.com> wrote: > ALSA bitpool patch is attached. > > 2012/3/27 Siarhei Siamashka <siarhei.siamashka@gmail.com>: >> The first patch adds debug prints to syslog from sbc encoder, just to >> clearly confirm the real bitpool used by the encoder. > > It obviously worked: > > Mar 27 17:49:41 machina-turbo pulseaudio[2355]: sbc_encode: bitpool set to 138 > >> The second patch removes default_bitpool() limitation, and this boosts >> bitpool from 53 to 64 for me. > > I found it was my device that prevented Bluez from using higher > bitpools. Bluez assumes that requesting a wider range of bitpools from > a device will cause an error, and indeed, my device cannot be > configured with a bitpool range wider than 2-53. So the only way to > achieve higher bitrates is to force them. I guess this depends on the headset. Your patch hacks around and allows you to use higher bitpool with your Nokia BH-503 headset. With my Logitech FreePulse headset, your patch does not seem to break audio playback, but on the other hand such radical changes are not needed (just removing default_bitpool() is enough to be able to set bitpool to 128 via ./asoundrc). For somebody else your patch might possibly even break audio playback if their headset does not like to be forced. > There is (was) a rather serious problem in the ALSA module, when it > tried to set bitpool exceding device capabilities, it ended with an > error and next tries, even with a valid bitpool, resulted in "Invalid > seid 0" in syslog and required bluetooth service to be restarted. With > my patch, bluez only uses the configured bitpool for sbc, without > sending it to the device. So, any bitpool value not exceeding true > device and adapter capabilities will work (and these can be much > higher than negotiated). Apparently this works a bit different in my case and I don't get the same "Invalid seid 0" error. In any case, what we have here is that (some?) A2DP headsets can support a lot higher SBC bitpool settings than they are normally reporting. Now the big question is how to probe for this information without violating negotiation protocol in any way and not causing any regressions. The next question is how to decide which bitpool to use by default, because in my case bitpool 128 occasionally causes some skips in music playback which did not happen with lower bitpool settings. Could you provide a short summary for this whole discussion? The discussion has been changing from bitpool negotiation to SBC codec improvements back and forth. And now it's becoming hard to follow and see which problems are still relevant and need to be solved. Also do you want to work on some code yourself or mostly trying to escalate the problems? A2DP is in the list of ideas for BlueZ GSoC, so maybe that's a good chance to get some improvements implemented: http://www.bluez.org/development/gsoc/gsoc-ideas-list-2012/ -- Best regards, Siarhei Siamashka ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-04-02 9:44 ` Siarhei Siamashka @ 2012-04-03 0:56 ` qduaty 2012-04-04 8:12 ` Siarhei Siamashka 0 siblings, 1 reply; 23+ messages in thread From: qduaty @ 2012-04-03 0:56 UTC (permalink / raw) To: linux-bluetooth 2012/4/2 Siarhei Siamashka <siarhei.siamashka@gmail.com>: > Your patch hacks around and > allows you to use higher bitpool with your Nokia BH-503 headset. With > my Logitech FreePulse headset, your patch does not seem to break audio > playback, but on the other hand such radical changes are not needed > (just removing default_bitpool() is enough to be able to set bitpool > to 128 via ./asoundrc). For somebody else your patch might possibly > even break audio playback if their headset does not like to be forced. This means your headset is capable of decoding at higher bitpool than it claims, as well as mine. So there is 50% probability that all A2DP headsets support higher bitpools than they report. My patch won't break anyone's playback unless they specify extremely high bitpool values; most users won't do it due to the lack of knowledge that it's possible (and has any purpose), and the rest will know exactly what they're doing. The solution works as well in pulseaudio (though, it is hard to specify the bitpool and I have it currently hardcoded in setup_a2dp()). > In any case, what we have here is that (some?) A2DP headsets can > support a lot higher SBC bitpool settings than they are normally > reporting. Now the big question is how to probe for this information > without violating negotiation protocol in any way and not causing any > regressions. The next question is how to decide which bitpool to use > by default Just use default_bitpool(), but let users override it. I didn't post a modified patch because it seemed obvious, but here it is (a modification of bluetooth_a2dp_setup()): /* If the bitpool was not configured, use default */ if(a2dp->sbc.bitpool <= MIN_BITPOOL) a2dp->sbc.bitpool = MIN(default_bitpool(active_capabilities.frequency, active_capabilities.channel_mode), active_capabilities.max_bitpool); With this change, Bluez will use default_bitpool() unless a user specifies a bitpool in the config file. Regarding the detection - I think any way of probing the maximum is likely to be magic and can mysteriously fail with an unsupported device. >, because in my case bitpool 128 occasionally causes some > skips in music playback which did not happen with lower bitpool > settings. L2CAP speed tests that I've seen, show that no 2.0+EDR device is capable of transmitting even 2 Mb/s. In my case, a bitrate of 800kbps (bitpool=138, 44100 Hz, 16 blocks) is achievable in A2DP. > Could you provide a short summary for this whole discussion? The > discussion has been changing from bitpool negotiation to SBC codec > improvements back and forth. And now it's becoming hard to follow and > see which problems are still relevant and need to be solved. Also do > you want to work on some code yourself or mostly trying to escalate > the problems? > > A2DP is in the list of ideas for BlueZ GSoC, so maybe that's a good > chance to get some improvements implemented: > http://www.bluez.org/development/gsoc/gsoc-ideas-list-2012/ Ok. This is the summary. 1. It was found that Bluez can occasionally limit available bitpool because some devices report a narrow bitpool range that does not reflect their real capabilities. A solution was proposed by means of encoding at a higher bitpool than negotiated, and it was confirmed to both work and not break compatibility, unless it is misused. 2. It was found that Bluez audio sink has quality problems even on high bitpools. An SBC encoder fix was proposed, which (re)enables floating point processing. Tests are needed to confirm whether it improves quality in all cases. 3. It was (previously) found and now confirmed that reducing volume in SBC encoder by a factor of 0.7-0.8 improves quality by eliminating audible effects of clipping in the decoder. For myself, I'm likely to be done with it. I've already solved the problems that prevented me from using A2DP on Linux. Further work would require more time and I cannot benefit from it (but students obviously can). My proposals: 1. Introduce a less restrictive input format for the audio sink, such as float32. Currently it supports only S16LE, which is not suitable for audio processing (ALSA softvol is a known example). 2. Find out what quality problems the SBC decoder has and fix them. Possibly introduce floating point output to eliminate clipping. 3. Implement proper (adaptive?) clipping prevention in the SBC encoder. Regards -- Sebastian Olter ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-04-03 0:56 ` qduaty @ 2012-04-04 8:12 ` Siarhei Siamashka 2012-07-31 10:09 ` Luiz Augusto von Dentz 0 siblings, 1 reply; 23+ messages in thread From: Siarhei Siamashka @ 2012-04-04 8:12 UTC (permalink / raw) To: linux-bluetooth On Tue, Apr 3, 2012 at 3:56 AM, qduaty <qduaty@gmail.com> wrote: > 2012/4/2 Siarhei Siamashka <siarhei.siamashka@gmail.com>: >> Could you provide a short summary for this whole discussion? The >> discussion has been changing from bitpool negotiation to SBC codec >> improvements back and forth. And now it's becoming hard to follow and >> see which problems are still relevant and need to be solved. Also do >> you want to work on some code yourself or mostly trying to escalate >> the problems? >> >> A2DP is in the list of ideas for BlueZ GSoC, so maybe that's a good >> chance to get some improvements implemented: >> http://www.bluez.org/development/gsoc/gsoc-ideas-list-2012/ > > Ok. This is the summary. > 1. It was found that Bluez can occasionally limit available bitpool > because some devices report a narrow bitpool range that does not > reflect their real capabilities. A solution was proposed by means of > encoding at a higher bitpool than negotiated, and it was confirmed to > both work and not break compatibility, unless it is misused. > 2. It was found that Bluez audio sink has quality problems even on > high bitpools. An SBC encoder fix was proposed, which (re)enables > floating point processing. Tests are needed to confirm whether it > improves quality in all cases. > 3. It was (previously) found and now confirmed that reducing volume in > SBC encoder by a factor of 0.7-0.8 improves quality by eliminating > audible effects of clipping in the decoder. OK, thanks. > For myself, I'm likely to be done with it. I've already solved the > problems that prevented me from using A2DP on Linux. Further work > would require more time and I cannot benefit from it (but students > obviously can). Fair enough. > My proposals: > 1. Introduce a less restrictive input format for the audio sink, such > as float32. Currently it supports only S16LE, which is not suitable > for audio processing (ALSA softvol is a known example). > 2. Find out what quality problems the SBC decoder has and fix them. > Possibly introduce floating point output to eliminate clipping. > 3. Implement proper (adaptive?) clipping prevention in the SBC encoder. -- Best regards, Siarhei Siamashka ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-04-04 8:12 ` Siarhei Siamashka @ 2012-07-31 10:09 ` Luiz Augusto von Dentz 2012-09-27 22:20 ` Siarhei Siamashka 0 siblings, 1 reply; 23+ messages in thread From: Luiz Augusto von Dentz @ 2012-07-31 10:09 UTC (permalink / raw) To: Siarhei Siamashka; +Cc: linux-bluetooth Hi Siarhei, On Wed, Apr 4, 2012 at 11:12 AM, Siarhei Siamashka <siarhei.siamashka@gmail.com> wrote: > On Tue, Apr 3, 2012 at 3:56 AM, qduaty <qduaty@gmail.com> wrote: >> 2012/4/2 Siarhei Siamashka <siarhei.siamashka@gmail.com>: >>> Could you provide a short summary for this whole discussion? The >>> discussion has been changing from bitpool negotiation to SBC codec >>> improvements back and forth. And now it's becoming hard to follow and >>> see which problems are still relevant and need to be solved. Also do >>> you want to work on some code yourself or mostly trying to escalate >>> the problems? >>> >>> A2DP is in the list of ideas for BlueZ GSoC, so maybe that's a good >>> chance to get some improvements implemented: >>> http://www.bluez.org/development/gsoc/gsoc-ideas-list-2012/ >> >> Ok. This is the summary. >> 1. It was found that Bluez can occasionally limit available bitpool >> because some devices report a narrow bitpool range that does not >> reflect their real capabilities. A solution was proposed by means of >> encoding at a higher bitpool than negotiated, and it was confirmed to >> both work and not break compatibility, unless it is misused. >> 2. It was found that Bluez audio sink has quality problems even on >> high bitpools. An SBC encoder fix was proposed, which (re)enables >> floating point processing. Tests are needed to confirm whether it >> improves quality in all cases. >> 3. It was (previously) found and now confirmed that reducing volume in >> SBC encoder by a factor of 0.7-0.8 improves quality by eliminating >> audible effects of clipping in the decoder. > > OK, thanks. > >> For myself, I'm likely to be done with it. I've already solved the >> problems that prevented me from using A2DP on Linux. Further work >> would require more time and I cannot benefit from it (but students >> obviously can). > > Fair enough. > >> My proposals: >> 1. Introduce a less restrictive input format for the audio sink, such >> as float32. Currently it supports only S16LE, which is not suitable >> for audio processing (ALSA softvol is a known example). >> 2. Find out what quality problems the SBC decoder has and fix them. >> Possibly introduce floating point output to eliminate clipping. >> 3. Implement proper (adaptive?) clipping prevention in the SBC encoder. Is there anyone working on this proposals? Specially the decoder seems to need some optimization as it consumes quite a bit of CPU (6-8% on my i7) and some people seems to notice some quality issues. -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-07-31 10:09 ` Luiz Augusto von Dentz @ 2012-09-27 22:20 ` Siarhei Siamashka 2012-09-27 22:25 ` Siarhei Siamashka 0 siblings, 1 reply; 23+ messages in thread From: Siarhei Siamashka @ 2012-09-27 22:20 UTC (permalink / raw) To: Luiz Augusto von Dentz; +Cc: linux-bluetooth On Tue, 31 Jul 2012 13:09:19 +0300 Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote: > Hi Siarhei, > > On Wed, Apr 4, 2012 at 11:12 AM, Siarhei Siamashka > <siarhei.siamashka@gmail.com> wrote: > > On Tue, Apr 3, 2012 at 3:56 AM, qduaty <qduaty@gmail.com> wrote: > >> 2012/4/2 Siarhei Siamashka <siarhei.siamashka@gmail.com>: > >>> Could you provide a short summary for this whole discussion? The > >>> discussion has been changing from bitpool negotiation to SBC codec > >>> improvements back and forth. And now it's becoming hard to follow > >>> and see which problems are still relevant and need to be solved. > >>> Also do you want to work on some code yourself or mostly trying > >>> to escalate the problems? > >>> > >>> A2DP is in the list of ideas for BlueZ GSoC, so maybe that's a > >>> good chance to get some improvements implemented: > >>> http://www.bluez.org/development/gsoc/gsoc-ideas-list-2012/ > >> > >> Ok. This is the summary. > >> 1. It was found that Bluez can occasionally limit available bitpool > >> because some devices report a narrow bitpool range that does not > >> reflect their real capabilities. A solution was proposed by means > >> of encoding at a higher bitpool than negotiated, and it was > >> confirmed to both work and not break compatibility, unless it is > >> misused. 2. It was found that Bluez audio sink has quality > >> problems even on high bitpools. An SBC encoder fix was proposed, > >> which (re)enables floating point processing. Tests are needed to > >> confirm whether it improves quality in all cases. > >> 3. It was (previously) found and now confirmed that reducing > >> volume in SBC encoder by a factor of 0.7-0.8 improves quality by > >> eliminating audible effects of clipping in the decoder. > > > > OK, thanks. > > > >> For myself, I'm likely to be done with it. I've already solved the > >> problems that prevented me from using A2DP on Linux. Further work > >> would require more time and I cannot benefit from it (but students > >> obviously can). > > > > Fair enough. > > > >> My proposals: > >> 1. Introduce a less restrictive input format for the audio sink, > >> such as float32. Currently it supports only S16LE, which is not > >> suitable for audio processing (ALSA softvol is a known example). > >> 2. Find out what quality problems the SBC decoder has and fix them. > >> Possibly introduce floating point output to eliminate clipping. > >> 3. Implement proper (adaptive?) clipping prevention in the SBC > >> encoder. Sorry for a late reply, I have missed this one. > Is there anyone working on this proposals? These were all qduaty's ideas. If (s)he is not working on this stuff, then I guess nobody does. > Specially the decoder seems to need some optimization as it consumes > quite a bit of CPU (6-8% on my i7) Yes, there are lots of low hanging fruits. For example, getting rid of integer division and better bitstream reading should provide a significant performance boost for the decoder. I might do that eventually. > and some people seems to notice some quality issues. Are there some links to more information? Or to some audio quality tests, which can be confirmed/reproduced? The precision of fixed point calculations in the decoder is not very good, so it definitely can be improved. But it should not be too bad either. The audio quality should be quite good for the encoder. Except for the clamping problem, which may be happening on the decoder side with some heavily compressed audio data and a poor/buggy A2DP headset. This can be workarounded by reducing audio volume in the encoder by 20-30%. The SBC encoder may get these extra volume adjustment settings, but the big unresolved question is who and when is going to enable it? Would it be some configuration file (pulseaudio/alsa/anything else)? Or would it be some automatic heuristics kicking in for known bad headsets? -- Best regards, Siarhei Siamashka ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Re: A2DP quality (bluetooth-alsa) 2012-09-27 22:20 ` Siarhei Siamashka @ 2012-09-27 22:25 ` Siarhei Siamashka 0 siblings, 0 replies; 23+ messages in thread From: Siarhei Siamashka @ 2012-09-27 22:25 UTC (permalink / raw) To: Luiz Augusto von Dentz; +Cc: linux-bluetooth On Fri, Sep 28, 2012 at 1:20 AM, Siarhei Siamashka <siarhei.siamashka@gmail.com> wrote: > On Tue, 31 Jul 2012 13:09:19 +0300 > Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote: > >> Hi Siarhei, By the way, thanks for moving libsbc into its own library. This definitely looks like the right thing. -- Best regards, Siarhei Siamashka ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: A2DP quality (bluetooth-alsa) 2012-03-14 12:53 ` qduaty 2012-03-25 2:51 ` [PATCH] " qduaty @ 2012-03-26 7:43 ` Siarhei Siamashka 1 sibling, 0 replies; 23+ messages in thread From: Siarhei Siamashka @ 2012-03-26 7:43 UTC (permalink / raw) To: qduaty; +Cc: linux-bluetooth On Wed, Mar 14, 2012 at 2:53 PM, qduaty <qduaty@gmail.com> wrote: > 2012/3/13 Siarhei Siamashka <siarhei.siamashka@gmail.com>: >> Are you now comparing streaming of A2DP audio from your phone to your >> PC (using bluez A2DP sink) and to your bluetooth headset? > > I assume that the phone streams data to the headset (whose session is > hard to dump on Windows mobile) with bitpool = 112, ie. the same it > fails to set in Bluez and I'm saying it gives good results in terms of > perceiveable quality, from which Bluez cannot take advantage due to > its inherent bitpool=53 limitation. > > Anyway, I did some additional listening tests (by listening to Bluez > SBC on an A2DP headset). SBC_HIGH_PRECISION alone (without your hack) > only slightly improves quality. Also I finally managed to force higher > bitpool in ALSA (patch attached). This makes further improvement in > quality, at least on headsets that do not choke on higher bitpools. Do you have a hcidump log before and after patching bluez for the part where A2DP settings are negotiated? For normal bluez 4.99, this is what I get with Logitech FreePulse headset: > ACL data: handle 11 flags 0x02 dlen 12 L2CAP(d): cid 0x0040 len 8 [psm 25] AVDTP(s): Discover rsp: transaction 11 nsp 0x00 ACP SEID 1 - Audio Sink ACP SEID 2 - Audio Sink ACP SEID 3 - Audio Sink < ACL data: handle 11 flags 0x00 dlen 7 L2CAP(d): cid 0x0200 len 3 [psm 25] AVDTP(s): Capabilities cmd: transaction 12 nsp 0x00 ACP SEID 1 > HCI Event: Number of Completed Packets (0x13) plen 5 handle 11 packets 1 > ACL data: handle 11 flags 0x02 dlen 20 L2CAP(d): cid 0x0040 len 16 [psm 25] AVDTP(s): Capabilities rsp: transaction 12 nsp 0x00 Media Transport Media Codec - SBC 16kHz 32kHz 44.1kHz 48kHz Mono DualChannel Stereo JointStereo 8 12 16 Blocks 4 8 Subbands SNR Loudness Bitpool Range 2-64 Content Protection 02 00 < ACL data: handle 11 flags 0x00 dlen 7 L2CAP(d): cid 0x0200 len 3 [psm 25] AVDTP(s): Capabilities cmd: transaction 13 nsp 0x00 ACP SEID 2 > ACL data: handle 11 flags 0x02 dlen 20 L2CAP(d): cid 0x0040 len 16 [psm 25] AVDTP(s): Capabilities rsp: transaction 13 nsp 0x00 Media Transport Media Codec - SBC 16kHz 32kHz 44.1kHz 48kHz Mono DualChannel Stereo JointStereo 4 Blocks 4 8 Subbands SNR Loudness Bitpool Range 2-32 Content Protection 02 00 < ACL data: handle 11 flags 0x00 dlen 7 L2CAP(d): cid 0x0200 len 3 [psm 25] AVDTP(s): Capabilities cmd: transaction 14 nsp 0x00 ACP SEID 3 > HCI Event: Number of Completed Packets (0x13) plen 5 handle 11 packets 2 > ACL data: handle 11 flags 0x02 dlen 24 L2CAP(d): cid 0x0040 len 20 [psm 25] AVDTP(s): Capabilities rsp: transaction 14 nsp 0x00 Media Transport Media Codec - non-A2DP 27 00 00 00 01 00 F7 77 02 56 00 FA < ACL data: handle 11 flags 0x00 dlen 18 L2CAP(d): cid 0x0200 len 14 [psm 25] AVDTP(s): Set config cmd: transaction 15 nsp 0x00 ACP SEID 1 - INT SEID 1 Media Transport Media Codec - SBC 44.1kHz JointStereo 16 Blocks 8 Subbands Loudness Bitpool Range 2-53 The headset reports 2-64 bitpool capabilities, but bluez sets bitpool to 53 because it does not use anything higher than suggested by 'default_bitpool' function (actually in two places): "max_bitpool = MIN(default_bitpool(cap->frequency, cap->channel_mode), supported->max_bitpool);" If I change this code, bitpool 64 can be used, however my ears are not trained enough to hear any differences between 53 and 64. By the way, high bitpool settings are causing problems for some users, so not everything is so clear: https://bugs.launchpad.net/ubuntu/+source/bluez/+bug/424215 Would it be a good idea if you come up with a clean patch, making bitpool selection strategy tunable via a configuration file? Or implement some kind of heuristics based on whether EDR is supported or not? -- Best regards, Siarhei Siamashka ^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2012-09-27 22:25 UTC | newest] Thread overview: 23+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2011-10-10 10:40 A2DP quality (bluetooth-alsa) qduaty 2011-10-10 14:11 ` Luiz Augusto von Dentz 2011-10-10 14:54 ` Siarhei Siamashka 2011-10-10 19:10 ` qduaty 2011-10-18 9:26 ` Siarhei Siamashka 2012-03-13 1:48 ` qduaty 2012-03-13 8:25 ` Siarhei Siamashka 2012-03-13 12:45 ` qduaty 2012-03-13 13:26 ` Siarhei Siamashka 2012-03-14 12:53 ` qduaty 2012-03-25 2:51 ` [PATCH] " qduaty 2012-03-26 9:44 ` Siarhei Siamashka 2012-03-26 21:11 ` qduaty 2012-03-27 1:29 ` qduaty 2012-03-27 7:57 ` Siarhei Siamashka 2012-03-27 23:28 ` qduaty 2012-04-02 9:44 ` Siarhei Siamashka 2012-04-03 0:56 ` qduaty 2012-04-04 8:12 ` Siarhei Siamashka 2012-07-31 10:09 ` Luiz Augusto von Dentz 2012-09-27 22:20 ` Siarhei Siamashka 2012-09-27 22:25 ` Siarhei Siamashka 2012-03-26 7:43 ` Siarhei Siamashka
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.