bluez5: fix rounding error on hardware volume conversion

Ensure the conversions between spa_bt_volume_linear_to_hw and spa_bt_volume_hw_to_linear are reversible when
operating on hardware volume.
This commit is contained in:
Huang-Huang Bao 2021-07-30 05:10:43 +08:00 committed by Wim Taymans
parent 73217818cc
commit 9f2d6d6d28

View file

@ -625,45 +625,28 @@ static inline enum spa_bt_transport_state spa_bt_transport_state_from_string(con
#define DEFAULT_AG_VOLUME 1.0f #define DEFAULT_AG_VOLUME 1.0f
#define DEFAULT_RX_VOLUME 1.0f #define DEFAULT_RX_VOLUME 1.0f
#define DEFAULT_TX_VOLUME 0.064f /* pa_sw_volume_to_linear(0.4 * PA_VOLUME_NORM) */ #define DEFAULT_TX_VOLUME 0.064f /* spa_bt_volume_hw_to_linear(40, 100) */
#define PA_VOLUME_MUTED ((uint32_t) 0u) /* AVRCP/HSP volume is considered as percentage, so map it to pulseaudio (cubic) volume. */
#define PA_VOLUME_NORM ((uint32_t) 0x10000u)
#define PA_VOLUME_MAX ((uint32_t) UINT32_MAX/2)
static inline uint32_t pa_sw_volume_from_linear(double v)
{
if (v <= 0.0)
return PA_VOLUME_MUTED;
return SPA_CLAMP(
(uint64_t) lround(cbrt(v) * PA_VOLUME_NORM),
PA_VOLUME_MUTED, PA_VOLUME_MAX);
}
static inline double pa_sw_volume_to_linear(uint32_t v)
{
double f;
if (v <= PA_VOLUME_MUTED)
return 0.0;
if (v == PA_VOLUME_NORM)
return 1.0;
f = ((double) v / PA_VOLUME_NORM);
return f*f*f;
}
/* AVRCP/HSP volume is considered as percentage, so map it to pulseaudio volume. */
static inline uint32_t spa_bt_volume_linear_to_hw(double v, uint32_t hw_volume_max) static inline uint32_t spa_bt_volume_linear_to_hw(double v, uint32_t hw_volume_max)
{ {
return SPA_CLAMP( if (v <= 0.0)
pa_sw_volume_from_linear(v) * hw_volume_max / PA_VOLUME_NORM, return 0;
if (v >= 1.0)
return hw_volume_max;
return SPA_CLAMP((uint64_t) lround(cbrt(v) * hw_volume_max),
0u, hw_volume_max); 0u, hw_volume_max);
} }
static inline double spa_bt_volume_hw_to_linear(uint32_t v, uint32_t hw_volume_max) static inline double spa_bt_volume_hw_to_linear(uint32_t v, uint32_t hw_volume_max)
{ {
return SPA_CLAMP( double f;
pa_sw_volume_to_linear(v * PA_VOLUME_NORM / hw_volume_max), if (v <= 0)
0.0, 1.0); return 0.0;
if (v >= hw_volume_max)
return 1.0;
f = ((double) v / hw_volume_max);
return f * f * f;
} }
enum spa_bt_feature { enum spa_bt_feature {