mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-16 08:56:45 -05:00
bluez5: add hardware volume support
Add necessary apis to bluez transport. Add A2DP(AVRCP) absolute volume support. Source volume can only update to adapter node but not from due to AG nodes don't have route. Since A2DP/HSP/HFP volume is already percentage itself, it has been mapped to pulseaudio volume then converting to linear volume.
This commit is contained in:
parent
f27ad659f8
commit
80f6ddf526
4 changed files with 508 additions and 64 deletions
|
|
@ -29,6 +29,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <spa/support/dbus.h>
|
||||
#include <spa/support/log.h>
|
||||
#include <spa/support/loop.h>
|
||||
|
|
@ -461,6 +463,14 @@ void spa_bt_sco_io_set_source_cb(struct spa_bt_sco_io *io, int (*source_cb)(void
|
|||
void spa_bt_sco_io_set_sink_cb(struct spa_bt_sco_io *io, int (*sink_cb)(void *userdata), void *userdata);
|
||||
int spa_bt_sco_io_write(struct spa_bt_sco_io *io, uint8_t *data, int size);
|
||||
|
||||
#define SPA_BT_VOLUME_ID_RX 0
|
||||
#define SPA_BT_VOLUME_ID_TX 1
|
||||
#define SPA_BT_VOLUME_ID_TERM 2
|
||||
|
||||
#define SPA_BT_VOLUME_INVALID -1
|
||||
#define SPA_BT_VOLUME_HS_MAX 15
|
||||
#define SPA_BT_VOLUME_A2DP_MAX 127
|
||||
|
||||
enum spa_bt_transport_state {
|
||||
SPA_BT_TRANSPORT_STATE_IDLE,
|
||||
SPA_BT_TRANSPORT_STATE_PENDING,
|
||||
|
|
@ -474,6 +484,7 @@ struct spa_bt_transport_events {
|
|||
void (*destroy) (void *data);
|
||||
void (*state_changed) (void *data, enum spa_bt_transport_state old,
|
||||
enum spa_bt_transport_state state);
|
||||
void (*volume_changed) (void *data);
|
||||
};
|
||||
|
||||
struct spa_bt_transport_implementation {
|
||||
|
|
@ -482,9 +493,20 @@ struct spa_bt_transport_implementation {
|
|||
|
||||
int (*acquire) (void *data, bool optional);
|
||||
int (*release) (void *data);
|
||||
int (*set_volume) (void *data, int id, float volume);
|
||||
int (*destroy) (void *data);
|
||||
};
|
||||
|
||||
struct spa_bt_transport_volume {
|
||||
bool active;
|
||||
float volume;
|
||||
int hw_volume_max;
|
||||
|
||||
/* XXX: items below should be put to user_data */
|
||||
int hw_volume;
|
||||
int new_hw_volume;
|
||||
};
|
||||
|
||||
struct spa_bt_transport {
|
||||
struct spa_list link;
|
||||
struct spa_bt_monitor *monitor;
|
||||
|
|
@ -502,18 +524,24 @@ struct spa_bt_transport {
|
|||
uint32_t n_channels;
|
||||
uint32_t channels[64];
|
||||
|
||||
struct spa_bt_transport_volume volumes[SPA_BT_VOLUME_ID_TERM];
|
||||
|
||||
int acquire_refcount;
|
||||
int fd;
|
||||
uint16_t read_mtu;
|
||||
uint16_t write_mtu;
|
||||
uint16_t delay;
|
||||
void *user_data;
|
||||
|
||||
struct spa_bt_sco_io *sco_io;
|
||||
|
||||
struct spa_source volume_timer;
|
||||
struct spa_source release_timer;
|
||||
|
||||
struct spa_hook_list listener_list;
|
||||
struct spa_callbacks impl;
|
||||
|
||||
/* user_data must be the last item in the struct */
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct spa_bt_transport *spa_bt_transport_create(struct spa_bt_monitor *monitor, char *path, size_t extra);
|
||||
|
|
@ -534,6 +562,7 @@ int spa_bt_transport_ensure_sco_io(struct spa_bt_transport *t, struct spa_loop *
|
|||
m, v, ##__VA_ARGS__)
|
||||
#define spa_bt_transport_emit_destroy(t) spa_bt_transport_emit(t, destroy, 0)
|
||||
#define spa_bt_transport_emit_state_changed(t,...) spa_bt_transport_emit(t, state_changed, 0, __VA_ARGS__)
|
||||
#define spa_bt_transport_emit_volume_changed(t) spa_bt_transport_emit(t, volume_changed, 0)
|
||||
|
||||
#define spa_bt_transport_add_listener(t,listener,events,data) \
|
||||
spa_hook_list_append(&(t)->listener_list, listener, events, data)
|
||||
|
|
@ -550,7 +579,8 @@ int spa_bt_transport_ensure_sco_io(struct spa_bt_transport *t, struct spa_loop *
|
|||
res; \
|
||||
})
|
||||
|
||||
#define spa_bt_transport_destroy(t) spa_bt_transport_impl(t, destroy, 0)
|
||||
#define spa_bt_transport_destroy(t) spa_bt_transport_impl(t, destroy, 0)
|
||||
#define spa_bt_transport_set_volume(t,...) spa_bt_transport_impl(t, set_volume, 0, __VA_ARGS__)
|
||||
|
||||
static inline enum spa_bt_transport_state spa_bt_transport_state_from_string(const char *value)
|
||||
{
|
||||
|
|
@ -564,6 +594,49 @@ static inline enum spa_bt_transport_state spa_bt_transport_state_from_string(con
|
|||
return SPA_BT_TRANSPORT_STATE_IDLE;
|
||||
}
|
||||
|
||||
#define DEFAULT_AG_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 PA_VOLUME_MUTED ((uint32_t) 0u)
|
||||
#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)
|
||||
{
|
||||
return SPA_CLAMP(
|
||||
pa_sw_volume_from_linear(v) * hw_volume_max / PA_VOLUME_NORM,
|
||||
0u, hw_volume_max);
|
||||
}
|
||||
|
||||
static inline double spa_bt_volume_hw_to_linear(uint32_t v, uint32_t hw_volume_max)
|
||||
{
|
||||
return SPA_CLAMP(
|
||||
pa_sw_volume_to_linear(v * PA_VOLUME_NORM / hw_volume_max),
|
||||
0.0, 1.0);
|
||||
}
|
||||
|
||||
struct spa_bt_backend_implementation {
|
||||
#define SPA_VERSION_BT_BACKEND_IMPLEMENTATION 0
|
||||
uint32_t version;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue