mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-04 13:29:59 -05:00
Update ipc to match new message headers introduced on BlueZ 4.34.
This commit is contained in:
parent
b03c545850
commit
071b3e7fc5
3 changed files with 84 additions and 36 deletions
|
|
@ -35,6 +35,7 @@ static const char *strtypes[] = {
|
||||||
/* This table contains the string representation for messages names */
|
/* This table contains the string representation for messages names */
|
||||||
static const char *strnames[] = {
|
static const char *strnames[] = {
|
||||||
"BT_GET_CAPABILITIES",
|
"BT_GET_CAPABILITIES",
|
||||||
|
"BT_OPEN",
|
||||||
"BT_SET_CONFIGURATION",
|
"BT_SET_CONFIGURATION",
|
||||||
"BT_NEW_STREAM",
|
"BT_NEW_STREAM",
|
||||||
"BT_START_STREAM",
|
"BT_START_STREAM",
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ extern "C" {
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#define BT_SUGGESTED_BUFFER_SIZE 128
|
#define BT_SUGGESTED_BUFFER_SIZE 512
|
||||||
#define BT_IPC_SOCKET_NAME "\0/org/bluez/audio"
|
#define BT_IPC_SOCKET_NAME "\0/org/bluez/audio"
|
||||||
|
|
||||||
/* Generic message header definition, except for RESPONSE messages */
|
/* Generic message header definition, except for RESPONSE messages */
|
||||||
|
|
@ -94,10 +94,12 @@ typedef struct {
|
||||||
|
|
||||||
/* Messages names */
|
/* Messages names */
|
||||||
#define BT_GET_CAPABILITIES 0
|
#define BT_GET_CAPABILITIES 0
|
||||||
#define BT_SET_CONFIGURATION 1
|
#define BT_OPEN 1
|
||||||
#define BT_NEW_STREAM 2
|
#define BT_SET_CONFIGURATION 2
|
||||||
#define BT_START_STREAM 3
|
#define BT_NEW_STREAM 3
|
||||||
#define BT_STOP_STREAM 4
|
#define BT_START_STREAM 4
|
||||||
|
#define BT_STOP_STREAM 5
|
||||||
|
#define BT_CLOSE 6
|
||||||
#define BT_CONTROL 7
|
#define BT_CONTROL 7
|
||||||
|
|
||||||
#define BT_CAPABILITIES_TRANSPORT_A2DP 0
|
#define BT_CAPABILITIES_TRANSPORT_A2DP 0
|
||||||
|
|
@ -112,19 +114,31 @@ typedef struct {
|
||||||
|
|
||||||
struct bt_get_capabilities_req {
|
struct bt_get_capabilities_req {
|
||||||
bt_audio_msg_header_t h;
|
bt_audio_msg_header_t h;
|
||||||
char device[18]; /* Address of the remote Device */
|
char source[18]; /* Address of the local Device */
|
||||||
|
char destination[18];/* Address of the remote Device */
|
||||||
|
char object[128]; /* DBus object path */
|
||||||
uint8_t transport; /* Requested transport */
|
uint8_t transport; /* Requested transport */
|
||||||
uint8_t flags; /* Requested flags */
|
uint8_t flags; /* Requested flags */
|
||||||
|
uint8_t seid; /* Requested capability configuration */
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SBC Codec parameters as per A2DP profile 1.0 § 4.3
|
* SBC Codec parameters as per A2DP profile 1.0 § 4.3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define BT_A2DP_CODEC_SBC 0x00
|
/* A2DP seid are 6 bytes long so HSP/HFP are assigned to 7-8 bits */
|
||||||
#define BT_A2DP_CODEC_MPEG12 0x01
|
#define BT_A2DP_SEID_RANGE (1 << 6) - 1
|
||||||
#define BT_A2DP_CODEC_MPEG24 0x02
|
|
||||||
#define BT_A2DP_CODEC_ATRAC 0x03
|
#define BT_A2DP_SBC_SOURCE 0x00
|
||||||
|
#define BT_A2DP_SBC_SINK 0x01
|
||||||
|
#define BT_A2DP_MPEG12_SOURCE 0x02
|
||||||
|
#define BT_A2DP_MPEG12_SINK 0x03
|
||||||
|
#define BT_A2DP_MPEG24_SOURCE 0x04
|
||||||
|
#define BT_A2DP_MPEG24_SINK 0x05
|
||||||
|
#define BT_A2DP_ATRAC_SOURCE 0x06
|
||||||
|
#define BT_A2DP_ATRAC_SINK 0x07
|
||||||
|
#define BT_A2DP_UNKNOWN_SOURCE 0x08
|
||||||
|
#define BT_A2DP_UNKNOWN_SINK 0x09
|
||||||
|
|
||||||
#define BT_SBC_SAMPLING_FREQ_16000 (1 << 3)
|
#define BT_SBC_SAMPLING_FREQ_16000 (1 << 3)
|
||||||
#define BT_SBC_SAMPLING_FREQ_32000 (1 << 2)
|
#define BT_SBC_SAMPLING_FREQ_32000 (1 << 2)
|
||||||
|
|
@ -163,10 +177,16 @@ struct bt_get_capabilities_req {
|
||||||
#define BT_PCM_FLAG_NREC 0x01
|
#define BT_PCM_FLAG_NREC 0x01
|
||||||
#define BT_PCM_FLAG_PCM_ROUTING 0x02
|
#define BT_PCM_FLAG_PCM_ROUTING 0x02
|
||||||
|
|
||||||
|
#define BT_WRITE_LOCK (1 << 1)
|
||||||
|
#define BT_READ_LOCK 1
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
uint8_t seid;
|
||||||
uint8_t transport;
|
uint8_t transport;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t length;
|
uint8_t length;
|
||||||
|
uint8_t configured;
|
||||||
|
uint8_t lock;
|
||||||
uint8_t data[0];
|
uint8_t data[0];
|
||||||
} __attribute__ ((packed)) codec_capabilities_t;
|
} __attribute__ ((packed)) codec_capabilities_t;
|
||||||
|
|
||||||
|
|
@ -199,20 +219,35 @@ typedef struct {
|
||||||
|
|
||||||
struct bt_get_capabilities_rsp {
|
struct bt_get_capabilities_rsp {
|
||||||
bt_audio_msg_header_t h;
|
bt_audio_msg_header_t h;
|
||||||
|
char source[18]; /* Address of the local Device */
|
||||||
|
char destination[18];/* Address of the remote Device */
|
||||||
|
char object[128]; /* DBus object path */
|
||||||
uint8_t data[0]; /* First codec_capabilities_t */
|
uint8_t data[0]; /* First codec_capabilities_t */
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct bt_open_req {
|
||||||
|
bt_audio_msg_header_t h;
|
||||||
|
char source[18]; /* Address of the local Device */
|
||||||
|
char destination[18];/* Address of the remote Device */
|
||||||
|
char object[128]; /* DBus object path */
|
||||||
|
uint8_t seid; /* Requested capability configuration to lock */
|
||||||
|
uint8_t lock; /* Requested lock */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct bt_open_rsp {
|
||||||
|
bt_audio_msg_header_t h;
|
||||||
|
char source[18]; /* Address of the local Device */
|
||||||
|
char destination[18];/* Address of the remote Device */
|
||||||
|
char object[128]; /* DBus object path */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct bt_set_configuration_req {
|
struct bt_set_configuration_req {
|
||||||
bt_audio_msg_header_t h;
|
bt_audio_msg_header_t h;
|
||||||
char device[18]; /* Address of the remote Device */
|
|
||||||
uint8_t access_mode; /* Requested access mode */
|
|
||||||
codec_capabilities_t codec; /* Requested codec */
|
codec_capabilities_t codec; /* Requested codec */
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct bt_set_configuration_rsp {
|
struct bt_set_configuration_rsp {
|
||||||
bt_audio_msg_header_t h;
|
bt_audio_msg_header_t h;
|
||||||
uint8_t transport; /* Granted transport */
|
|
||||||
uint8_t access_mode; /* Granted access mode */
|
|
||||||
uint16_t link_mtu; /* Max length that transport supports */
|
uint16_t link_mtu; /* Max length that transport supports */
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
@ -241,6 +276,14 @@ struct bt_stop_stream_rsp {
|
||||||
bt_audio_msg_header_t h;
|
bt_audio_msg_header_t h;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct bt_close_req {
|
||||||
|
bt_audio_msg_header_t h;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct bt_close_rsp {
|
||||||
|
bt_audio_msg_header_t h;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct bt_suspend_stream_ind {
|
struct bt_suspend_stream_ind {
|
||||||
bt_audio_msg_header_t h;
|
bt_audio_msg_header_t h;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
|
||||||
|
|
@ -311,7 +311,7 @@ static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp *
|
||||||
} else if (u->profile == PROFILE_A2DP) {
|
} else if (u->profile == PROFILE_A2DP) {
|
||||||
|
|
||||||
while (bytes_left > 0) {
|
while (bytes_left > 0) {
|
||||||
if (codec->type == BT_A2DP_CODEC_SBC)
|
if ((codec->type == BT_A2DP_SBC_SINK) && !codec->lock)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
bytes_left -= codec->length;
|
bytes_left -= codec->length;
|
||||||
|
|
@ -321,7 +321,7 @@ static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp *
|
||||||
if (bytes_left <= 0 || codec->length != sizeof(u->a2dp.sbc_capabilities))
|
if (bytes_left <= 0 || codec->length != sizeof(u->a2dp.sbc_capabilities))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
pa_assert(codec->type == BT_A2DP_CODEC_SBC);
|
pa_assert(codec->type == BT_A2DP_SBC_SINK);
|
||||||
|
|
||||||
memcpy(&u->a2dp.sbc_capabilities, codec, sizeof(u->a2dp.sbc_capabilities));
|
memcpy(&u->a2dp.sbc_capabilities, codec, sizeof(u->a2dp.sbc_capabilities));
|
||||||
}
|
}
|
||||||
|
|
@ -344,7 +344,7 @@ static int get_caps(struct userdata *u) {
|
||||||
msg.getcaps_req.h.name = BT_GET_CAPABILITIES;
|
msg.getcaps_req.h.name = BT_GET_CAPABILITIES;
|
||||||
msg.getcaps_req.h.length = sizeof(msg.getcaps_req);
|
msg.getcaps_req.h.length = sizeof(msg.getcaps_req);
|
||||||
|
|
||||||
pa_strlcpy(msg.getcaps_req.device, u->address, sizeof(msg.getcaps_req.device));
|
pa_strlcpy(msg.getcaps_req.object, u->path, sizeof(msg.getcaps_req.object));
|
||||||
if (u->profile == PROFILE_A2DP)
|
if (u->profile == PROFILE_A2DP)
|
||||||
msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP;
|
msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP;
|
||||||
else {
|
else {
|
||||||
|
|
@ -602,12 +602,29 @@ static void setup_sbc(struct a2dp_info *a2dp) {
|
||||||
|
|
||||||
static int set_conf(struct userdata *u) {
|
static int set_conf(struct userdata *u) {
|
||||||
union {
|
union {
|
||||||
|
struct bt_open_req open_req;
|
||||||
|
struct bt_open_rsp open_rsp;
|
||||||
struct bt_set_configuration_req setconf_req;
|
struct bt_set_configuration_req setconf_req;
|
||||||
struct bt_set_configuration_rsp setconf_rsp;
|
struct bt_set_configuration_rsp setconf_rsp;
|
||||||
bt_audio_error_t error;
|
bt_audio_error_t error;
|
||||||
uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
|
uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
|
||||||
} msg;
|
} msg;
|
||||||
|
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.open_req.h.type = BT_REQUEST;
|
||||||
|
msg.open_req.h.name = BT_OPEN;
|
||||||
|
msg.open_req.h.length = sizeof(msg.open_req);
|
||||||
|
|
||||||
|
pa_strlcpy(msg.open_req.object, u->path, sizeof(msg.open_req.object));
|
||||||
|
msg.open_req.seid = u->profile == PROFILE_A2DP ? u->a2dp.sbc_capabilities.capability.seid : BT_A2DP_SEID_RANGE + 1;
|
||||||
|
msg.open_req.lock = u->profile == PROFILE_A2DP ? BT_WRITE_LOCK : BT_READ_LOCK | BT_WRITE_LOCK;
|
||||||
|
|
||||||
|
if (service_send(u, &msg.open_req.h) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (service_expect(u, &msg.open_rsp.h, sizeof(msg), BT_OPEN, sizeof(msg.open_rsp)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (u->profile == PROFILE_A2DP ) {
|
if (u->profile == PROFILE_A2DP ) {
|
||||||
u->sample_spec.format = PA_SAMPLE_S16LE;
|
u->sample_spec.format = PA_SAMPLE_S16LE;
|
||||||
|
|
||||||
|
|
@ -626,15 +643,14 @@ static int set_conf(struct userdata *u) {
|
||||||
msg.setconf_req.h.name = BT_SET_CONFIGURATION;
|
msg.setconf_req.h.name = BT_SET_CONFIGURATION;
|
||||||
msg.setconf_req.h.length = sizeof(msg.setconf_req);
|
msg.setconf_req.h.length = sizeof(msg.setconf_req);
|
||||||
|
|
||||||
pa_strlcpy(msg.setconf_req.device, u->address, sizeof(msg.setconf_req.device));
|
|
||||||
msg.setconf_req.access_mode = u->profile == PROFILE_A2DP ? BT_CAPABILITIES_ACCESS_MODE_WRITE : BT_CAPABILITIES_ACCESS_MODE_READWRITE;
|
|
||||||
|
|
||||||
msg.setconf_req.codec.transport = u->profile == PROFILE_A2DP ? BT_CAPABILITIES_TRANSPORT_A2DP : BT_CAPABILITIES_TRANSPORT_SCO;
|
|
||||||
|
|
||||||
if (u->profile == PROFILE_A2DP) {
|
if (u->profile == PROFILE_A2DP) {
|
||||||
memcpy(&msg.setconf_req.codec, &u->a2dp.sbc_capabilities, sizeof(u->a2dp.sbc_capabilities));
|
memcpy(&msg.setconf_req.codec, &u->a2dp.sbc_capabilities, sizeof(u->a2dp.sbc_capabilities));
|
||||||
msg.setconf_req.h.length += msg.setconf_req.codec.length - sizeof(msg.setconf_req.codec);
|
} else {
|
||||||
|
msg.setconf_req.codec.transport = BT_CAPABILITIES_TRANSPORT_SCO;
|
||||||
|
msg.setconf_req.codec.seid = BT_A2DP_SEID_RANGE + 1;
|
||||||
|
msg.setconf_req.codec.length = sizeof(pcm_capabilities_t);
|
||||||
}
|
}
|
||||||
|
msg.setconf_req.h.length += msg.setconf_req.codec.length - sizeof(msg.setconf_req.codec);
|
||||||
|
|
||||||
if (service_send(u, &msg.setconf_req.h) < 0)
|
if (service_send(u, &msg.setconf_req.h) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -642,18 +658,6 @@ static int set_conf(struct userdata *u) {
|
||||||
if (service_expect(u, &msg.setconf_rsp.h, sizeof(msg), BT_SET_CONFIGURATION, sizeof(msg.setconf_rsp)) < 0)
|
if (service_expect(u, &msg.setconf_rsp.h, sizeof(msg), BT_SET_CONFIGURATION, sizeof(msg.setconf_rsp)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((u->profile == PROFILE_A2DP && msg.setconf_rsp.transport != BT_CAPABILITIES_TRANSPORT_A2DP) ||
|
|
||||||
(u->profile == PROFILE_HSP && msg.setconf_rsp.transport != BT_CAPABILITIES_TRANSPORT_SCO)) {
|
|
||||||
pa_log("Transport doesn't match what we requested.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((u->profile == PROFILE_A2DP && msg.setconf_rsp.access_mode != BT_CAPABILITIES_ACCESS_MODE_WRITE) ||
|
|
||||||
(u->profile == PROFILE_HSP && msg.setconf_rsp.access_mode != BT_CAPABILITIES_ACCESS_MODE_READWRITE)) {
|
|
||||||
pa_log("Access mode doesn't match what we requested.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
u->link_mtu = msg.setconf_rsp.link_mtu;
|
u->link_mtu = msg.setconf_rsp.link_mtu;
|
||||||
|
|
||||||
/* setup SBC encoder now we agree on parameters */
|
/* setup SBC encoder now we agree on parameters */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue