summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2008-12-16 17:09:26 -0300
committerLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2008-12-16 17:19:56 -0300
commit9937db5c590cf69191e94378ebbbffc62a214e15 (patch)
tree38f6ac16eb50b20d8357c731db27a214704d2468 /audio
parent0dbebcc5f0f201a53133bed184c70566166633db (diff)
Fix audio ipc to deal better with codec capabilities.
This should cover custom codec support for a2dp devices and add support for codecs while using SCO transports.
Diffstat (limited to 'audio')
-rw-r--r--audio/ipc.c49
-rw-r--r--audio/ipc.h190
-rw-r--r--audio/unix.c361
3 files changed, 345 insertions, 255 deletions
diff --git a/audio/ipc.c b/audio/ipc.c
index a4561f47..67785309 100644
--- a/audio/ipc.c
+++ b/audio/ipc.c
@@ -22,22 +22,26 @@
#include "ipc.h"
-/* This table contains the string representation for messages */
-static const char *strmsg[] = {
- "BT_GETCAPABILITIES_REQ",
- "BT_GETCAPABILITIES_RSP",
- "BT_SETCONFIGURATION_REQ",
- "BT_SETCONFIGURATION_RSP",
- "BT_STREAMSTART_REQ",
- "BT_STREAMSTART_RSP",
- "BT_STREAMSTOP_REQ",
- "BT_STREAMSTOP_RSP",
- "BT_STREAMSUSPEND_IND",
- "BT_STREAMRESUME_IND",
- "BT_CONTROL_REQ",
- "BT_CONTROL_RSP",
- "BT_CONTROL_IND",
- "BT_STREAMFD_IND",
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+/* This table contains the string representation for messages types */
+static const char *strtypes[] = {
+ "BT_REQUEST",
+ "BT_RESPONSE",
+ "BT_INDICATION",
+ "BT_ERROR",
+};
+
+/* This table contains the string representation for messages names */
+static const char *strnames[] = {
+ "BT_GET_CAPABILITIES",
+ "BT_SET_CONFIGURATION",
+ "BT_NEW_STREAM",
+ "BT_START_STREAM",
+ "BT_STOP_STREAM",
+ "BT_SUSPEND_STREAM",
+ "BT_RESUME_STREAM",
+ "BT_CONTROL",
};
int bt_audio_service_open(void)
@@ -109,11 +113,18 @@ int bt_audio_service_get_data_fd(int sk)
return -1;
}
-const char *bt_audio_strmsg(int type)
+const char *bt_audio_strtype(uint8_t type)
{
- if (type < 0 || type > (sizeof(strmsg) / sizeof(strmsg[0])))
+ if (type >= ARRAY_SIZE(strtypes))
return NULL;
- return strmsg[type];
+ return strtypes[type];
}
+const char *bt_audio_strname(uint8_t name)
+{
+ if (name >= ARRAY_SIZE(strnames))
+ return NULL;
+
+ return strnames[name];
+}
diff --git a/audio/ipc.h b/audio/ipc.h
index ae85e727..0e985c3a 100644
--- a/audio/ipc.h
+++ b/audio/ipc.h
@@ -23,36 +23,36 @@
/*
Message sequence chart of streaming sequence for A2DP transport
- Audio daemon User
- on snd_pcm_open
- <--BT_GETCAPABILITIES_REQ
+ Audio daemon User
+ on snd_pcm_open
+ <--BT_GET_CAPABILITIES_REQ
- BT_GETCAPABILITIES_RSP-->
+ BT_GET_CAPABILITIES_RSP-->
- on snd_pcm_hw_params
- <--BT_SETCONFIGURATION_REQ
+ on snd_pcm_hw_params
+ <--BT_SETCONFIGURATION_REQ
- BT_SETCONFIGURATION_RSP-->
+ BT_SET_CONFIGURATION_RSP-->
- on snd_pcm_prepare
- <--BT_STREAMSTART_REQ
+ on snd_pcm_prepare
+ <--BT_START_STREAM_REQ
<Moves to streaming state>
- BT_STREAMSTART_RSP-->
+ BT_START_STREAM_RSP-->
- BT_STREAMFD_IND -->
+ BT_NEW_STREAM_IND -->
- < streams data >
- ..........
+ < streams data >
+ ..........
- on snd_pcm_drop/snd_pcm_drain
+ on snd_pcm_drop/snd_pcm_drain
- <--BT_STREAMSTOP_REQ
+ <--BT_STOP_STREAM_REQ
<Moves to open state>
- BT_STREAMSTOP_RSP-->
+ BT_STOP_STREAM_RSP-->
- on IPC close or appl crash
+ on IPC close or appl crash
<Moves to idle>
*/
@@ -71,43 +71,36 @@ extern "C" {
#include <sys/un.h>
#include <errno.h>
-#define BT_AUDIO_IPC_PACKET_SIZE 128
+#define BT_SUGGESTED_BUFFER_SIZE 128
#define BT_IPC_SOCKET_NAME "\0/org/bluez/audio"
-/* Generic message header definition, except for RSP messages */
+/* Generic message header definition, except for RESPONSE messages */
typedef struct {
- uint8_t msg_type;
+ uint8_t type;
+ uint8_t name;
+ uint16_t length;
} __attribute__ ((packed)) bt_audio_msg_header_t;
-/* Generic message header definition, for all RSP messages */
typedef struct {
- bt_audio_msg_header_t msg_h;
- uint8_t posix_errno;
-} __attribute__ ((packed)) bt_audio_rsp_msg_header_t;
-
-/* Messages list */
-#define BT_GETCAPABILITIES_REQ 0
-#define BT_GETCAPABILITIES_RSP 1
-
-#define BT_SETCONFIGURATION_REQ 2
-#define BT_SETCONFIGURATION_RSP 3
-
-#define BT_STREAMSTART_REQ 4
-#define BT_STREAMSTART_RSP 5
-
-#define BT_STREAMSTOP_REQ 6
-#define BT_STREAMSTOP_RSP 7
-
-#define BT_STREAMSUSPEND_IND 8
-#define BT_STREAMRESUME_IND 9
-
-#define BT_CONTROL_REQ 10
-#define BT_CONTROL_RSP 11
-#define BT_CONTROL_IND 12
-
-#define BT_STREAMFD_IND 13
-
-/* BT_GETCAPABILITIES_REQ */
+ bt_audio_msg_header_t h;
+ uint8_t posix_errno;
+} __attribute__ ((packed)) bt_audio_error_t;
+
+/* Message types */
+#define BT_REQUEST 0
+#define BT_RESPONSE 1
+#define BT_INDICATION 2
+#define BT_ERROR 3
+
+/* Messages names */
+#define BT_GET_CAPABILITIES 0
+#define BT_SET_CONFIGURATION 1
+#define BT_NEW_STREAM 2
+#define BT_START_STREAM 3
+#define BT_STOP_STREAM 4
+#define BT_SUSPEND_STREAM 5
+#define BT_RESUME_STREAM 6
+#define BT_CONTROL 7
#define BT_CAPABILITIES_TRANSPORT_A2DP 0
#define BT_CAPABILITIES_TRANSPORT_SCO 1
@@ -119,19 +112,22 @@ typedef struct {
#define BT_FLAG_AUTOCONNECT 1
-struct bt_getcapabilities_req {
+struct bt_get_capabilities_req {
bt_audio_msg_header_t h;
char device[18]; /* Address of the remote Device */
uint8_t transport; /* Requested transport */
uint8_t flags; /* Requested flags */
} __attribute__ ((packed));
-/* BT_GETCAPABILITIES_RSP */
-
/**
* SBC Codec parameters as per A2DP profile 1.0 ยง 4.3
*/
+#define BT_A2DP_CODEC_SBC 0x00
+#define BT_A2DP_CODEC_MPEG12 0x01
+#define BT_A2DP_CODEC_MPEG24 0x02
+#define BT_A2DP_CODEC_ATRAC 0x03
+
#define BT_SBC_SAMPLING_FREQ_16000 (1 << 3)
#define BT_SBC_SAMPLING_FREQ_32000 (1 << 2)
#define BT_SBC_SAMPLING_FREQ_44100 (1 << 1)
@@ -164,7 +160,19 @@ struct bt_getcapabilities_req {
#define BT_MPEG_LAYER_2 (1 << 1)
#define BT_MPEG_LAYER_3 1
+#define BT_HFP_CODEC_PCM 0x00
+
+#define BT_PCM_FLAG_NREC 1
+
+typedef struct {
+ uint8_t transport;
+ uint8_t type;
+ uint8_t length;
+ uint8_t data[0];
+} __attribute__ ((packed)) codec_capabilities_t;
+
typedef struct {
+ codec_capabilities_t capability;
uint8_t channel_mode;
uint8_t frequency;
uint8_t allocation_method;
@@ -175,6 +183,7 @@ typedef struct {
} __attribute__ ((packed)) sbc_capabilities_t;
typedef struct {
+ codec_capabilities_t capability;
uint8_t channel_mode;
uint8_t crc;
uint8_t layer;
@@ -183,75 +192,65 @@ typedef struct {
uint16_t bitrate;
} __attribute__ ((packed)) mpeg_capabilities_t;
-struct bt_getcapabilities_rsp {
- bt_audio_rsp_msg_header_t rsp_h;
- uint8_t transport; /* Granted transport */
- sbc_capabilities_t sbc_capabilities; /* A2DP only */
- mpeg_capabilities_t mpeg_capabilities; /* A2DP only */
- uint16_t sampling_rate; /* SCO only */
+typedef struct {
+ codec_capabilities_t capability;
+ uint8_t flags;
+ uint16_t sampling_rate;
+} __attribute__ ((packed)) pcm_capabilities_t;
+
+
+struct bt_get_capabilities_rsp {
+ bt_audio_msg_header_t h;
+ uint8_t data[0]; /* First codec_capabilities_t */
} __attribute__ ((packed));
-/* BT_SETCONFIGURATION_REQ */
-struct bt_setconfiguration_req {
+struct bt_set_configuration_req {
bt_audio_msg_header_t h;
- char device[18]; /* Address of the remote Device */
- uint8_t transport; /* Requested transport */
- uint8_t access_mode; /* Requested access mode */
- sbc_capabilities_t sbc_capabilities; /* A2DP only - only one of this field
- and next one must be filled */
- mpeg_capabilities_t mpeg_capabilities; /* A2DP only */
+ char device[18]; /* Address of the remote Device */
+ uint8_t access_mode; /* Requested access mode */
+ codec_capabilities_t codec; /* Requested codec */
} __attribute__ ((packed));
-/* BT_SETCONFIGURATION_RSP */
-struct bt_setconfiguration_rsp {
- bt_audio_rsp_msg_header_t rsp_h;
- uint8_t transport; /* Granted transport */
- uint8_t access_mode; /* Granted access mode */
- uint16_t link_mtu; /* Max length that transport supports */
+struct bt_set_configuration_rsp {
+ 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 */
} __attribute__ ((packed));
-/* BT_STREAMSTART_REQ */
#define BT_STREAM_ACCESS_READ 0
#define BT_STREAM_ACCESS_WRITE 1
#define BT_STREAM_ACCESS_READWRITE 2
-struct bt_streamstart_req {
+struct bt_start_stream_req {
bt_audio_msg_header_t h;
} __attribute__ ((packed));
-/* BT_STREAMSTART_RSP */
-struct bt_streamstart_rsp {
- bt_audio_rsp_msg_header_t rsp_h;
+struct bt_start_stream_rsp {
+ bt_audio_msg_header_t h;
} __attribute__ ((packed));
-/* BT_STREAMFD_IND */
/* This message is followed by one byte of data containing the stream data fd
as ancilliary data */
-struct bt_streamfd_ind {
+struct bt_new_stream_ind {
bt_audio_msg_header_t h;
} __attribute__ ((packed));
-/* BT_STREAMSTOP_REQ */
-struct bt_streamstop_req {
+struct bt_stop_stream_req {
bt_audio_msg_header_t h;
} __attribute__ ((packed));
-/* BT_STREAMSTOP_RSP */
-struct bt_streamstop_rsp {
- bt_audio_rsp_msg_header_t rsp_h;
+struct bt_stop_stream_rsp {
+ bt_audio_msg_header_t h;
} __attribute__ ((packed));
-/* BT_STREAMSUSPEND_IND */
-struct bt_streamsuspend_ind {
+struct bt_suspend_stream_ind {
bt_audio_msg_header_t h;
} __attribute__ ((packed));
-/* BT_STREAMRESUME_IND */
-struct bt_streamresume_ind {
+struct bt_resume_stream_ind {
bt_audio_msg_header_t h;
} __attribute__ ((packed));
-/* BT_CONTROL_REQ */
-
#define BT_CONTROL_KEY_POWER 0x40
#define BT_CONTROL_KEY_VOL_UP 0x41
#define BT_CONTROL_KEY_VOL_DOWN 0x42
@@ -272,14 +271,12 @@ struct bt_control_req {
uint8_t key; /* Control Key */
} __attribute__ ((packed));
-/* BT_CONTROL_RSP */
struct bt_control_rsp {
- bt_audio_rsp_msg_header_t rsp_h;
- uint8_t mode; /* Control Mode */
- uint8_t key; /* Control Key */
+ bt_audio_msg_header_t h;
+ uint8_t mode; /* Control Mode */
+ uint8_t key; /* Control Key */
} __attribute__ ((packed));
-/* BT_CONTROL_IND */
struct bt_control_ind {
bt_audio_msg_header_t h;
uint8_t mode; /* Control Mode */
@@ -299,7 +296,10 @@ BT_STREAMFD_IND message is returned */
int bt_audio_service_get_data_fd(int sk);
/* Human readable message type string */
-const char *bt_audio_strmsg(int type);
+const char *bt_audio_strtype(uint8_t type);
+
+/* Human readable message name string */
+const char *bt_audio_strname(uint8_t name);
#ifdef __cplusplus
}
diff --git a/audio/unix.c b/audio/unix.c
index 921e15ef..bf0dad47 100644
--- a/audio/unix.c
+++ b/audio/unix.c
@@ -152,25 +152,31 @@ static int unix_sendmsg_fd(int sock, int fd)
static void unix_ipc_sendmsg(struct unix_client *client,
const bt_audio_msg_header_t *msg)
{
- debug("Audio API: sending %s", bt_audio_strmsg(msg->msg_type));
+ const char *type = bt_audio_strtype(msg->type);
+ const char *name = bt_audio_strname(msg->name);
- if (send(client->sock, msg, BT_AUDIO_IPC_PACKET_SIZE, 0) < 0)
+ debug("Audio API: %s -> %s", type, name);
+
+ if (send(client->sock, msg, msg->length, 0) < 0)
error("Error %s(%d)", strerror(errno), errno);
}
-static void unix_ipc_error(struct unix_client *client, int type, int err)
+static void unix_ipc_error(struct unix_client *client, uint8_t name, int err)
{
- char buf[BT_AUDIO_IPC_PACKET_SIZE];
- bt_audio_rsp_msg_header_t *rsp_hdr = (void *) buf;
+ char buf[BT_SUGGESTED_BUFFER_SIZE];
+ bt_audio_error_t *rsp = (void *) buf;
if (!g_slist_find(clients, client))
return;
memset(buf, 0, sizeof(buf));
- rsp_hdr->msg_h.msg_type = type;
- rsp_hdr->posix_errno = err;
+ rsp->h.type = BT_ERROR;
+ rsp->h.name = name;
+ rsp->h.length = sizeof(*rsp);
+
+ rsp->posix_errno = err;
- unix_ipc_sendmsg(client, &rsp_hdr->msg_h);
+ unix_ipc_sendmsg(client, &rsp->h);
}
static service_type_t select_service(struct audio_device *dev, const char *interface)
@@ -223,8 +229,10 @@ static void stream_state_changed(struct avdtp_stream *stream,
static void headset_discovery_complete(struct audio_device *dev, void *user_data)
{
struct unix_client *client = user_data;
- char buf[BT_AUDIO_IPC_PACKET_SIZE];
- struct bt_getcapabilities_rsp *rsp = (void *) buf;
+ char buf[BT_SUGGESTED_BUFFER_SIZE];
+ struct bt_get_capabilities_rsp *rsp = (void *) buf;
+ codec_capabilities_t *codec;
+ pcm_capabilities_t *pcm;
client->req_id = 0;
@@ -233,24 +241,34 @@ static void headset_discovery_complete(struct audio_device *dev, void *user_data
memset(buf, 0, sizeof(buf));
- rsp->rsp_h.msg_h.msg_type = BT_GETCAPABILITIES_RSP;
- rsp->transport = BT_CAPABILITIES_TRANSPORT_SCO;
- rsp->sampling_rate = 8000;
+ codec = (void *) rsp->data;
+ codec->transport = BT_CAPABILITIES_TRANSPORT_SCO;
+ codec->type = BT_HFP_CODEC_PCM;
+ codec->length = sizeof(*pcm);
+
+ pcm = (void *) codec;
+ pcm->sampling_rate = 8000;
+ if (headset_get_nrec(dev))
+ pcm->flags |= BT_PCM_FLAG_NREC;
+
+ rsp->h.type = BT_RESPONSE;
+ rsp->h.name = BT_GET_CAPABILITIES;
+ rsp->h.length = sizeof(*rsp) + codec->length;
- unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+ unix_ipc_sendmsg(client, &rsp->h);
return;
failed:
error("discovery failed");
- unix_ipc_error(client, BT_SETCONFIGURATION_RSP, EIO);
+ unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
}
static void headset_setup_complete(struct audio_device *dev, void *user_data)
{
struct unix_client *client = user_data;
- char buf[BT_AUDIO_IPC_PACKET_SIZE];
- struct bt_setconfiguration_rsp *rsp = (void *) buf;
+ char buf[BT_SUGGESTED_BUFFER_SIZE];
+ struct bt_set_configuration_rsp *rsp = (void *) buf;
client->req_id = 0;
@@ -259,28 +277,31 @@ static void headset_setup_complete(struct audio_device *dev, void *user_data)
memset(buf, 0, sizeof(buf));
- rsp->rsp_h.msg_h.msg_type = BT_SETCONFIGURATION_RSP;
+ rsp->h.type = BT_RESPONSE;
+ rsp->h.name = BT_SET_CONFIGURATION;
+ rsp->h.length = sizeof(*rsp);
+
rsp->transport = BT_CAPABILITIES_TRANSPORT_SCO;
rsp->access_mode = client->access_mode;
rsp->link_mtu = 48;
client->data_fd = headset_get_sco_fd(dev);
- unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+ unix_ipc_sendmsg(client, &rsp->h);
return;
failed:
error("config failed");
- unix_ipc_error(client, BT_SETCONFIGURATION_RSP, EIO);
+ unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
}
static void headset_resume_complete(struct audio_device *dev, void *user_data)
{
struct unix_client *client = user_data;
- char buf[BT_AUDIO_IPC_PACKET_SIZE];
- struct bt_streamstart_rsp *rsp = (void *) buf;
- struct bt_streamfd_ind *ind = (void *) buf;
+ char buf[BT_SUGGESTED_BUFFER_SIZE];
+ struct bt_start_stream_rsp *rsp = (void *) buf;
+ struct bt_new_stream_ind *ind = (void *) buf;
struct headset_data *hs = &client->d.hs;
client->req_id = 0;
@@ -294,13 +315,17 @@ static void headset_resume_complete(struct audio_device *dev, void *user_data)
}
memset(buf, 0, sizeof(buf));
+ rsp->h.type = BT_RESPONSE;
+ rsp->h.name = BT_START_STREAM;
+ rsp->h.length = sizeof(*rsp);
- rsp->rsp_h.msg_h.msg_type = BT_STREAMSTART_RSP;
-
- unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+ unix_ipc_sendmsg(client, &rsp->h);
memset(buf, 0, sizeof(buf));
- ind->h.msg_type = BT_STREAMFD_IND;
+ ind->h.type = BT_INDICATION;
+ ind->h.name = BT_NEW_STREAM;
+ ind->h.length = sizeof(*ind);
+
unix_ipc_sendmsg(client, &ind->h);
client->data_fd = headset_get_sco_fd(dev);
@@ -315,41 +340,105 @@ static void headset_resume_complete(struct audio_device *dev, void *user_data)
failed:
error("headset_resume_complete: resume failed");
- unix_ipc_error(client, BT_STREAMSTART_RSP, EIO);
+ unix_ipc_error(client, BT_START_STREAM, EIO);
}
static void headset_suspend_complete(struct audio_device *dev, void *user_data)
{
struct unix_client *client = user_data;
- char buf[BT_AUDIO_IPC_PACKET_SIZE];
- struct bt_streamstart_rsp *rsp = (void *) buf;
+ char buf[BT_SUGGESTED_BUFFER_SIZE];
+ struct bt_start_stream_rsp *rsp = (void *) buf;
if (!dev)
goto failed;
memset(buf, 0, sizeof(buf));
- rsp->rsp_h.msg_h.msg_type = BT_STREAMSTOP_RSP;
- rsp->rsp_h.posix_errno = 0;
- unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+ rsp->h.type = BT_RESPONSE;
+ rsp->h.name = BT_STOP_STREAM;
+ rsp->h.length = sizeof(*rsp);
+
+ unix_ipc_sendmsg(client, &rsp->h);
return;
failed:
error("suspend failed");
- unix_ipc_error(client, BT_STREAMSTOP_RSP, EIO);
+ unix_ipc_error(client, BT_STOP_STREAM, EIO);
client->dev = NULL;
}
+static int a2dp_append_codec(struct bt_get_capabilities_rsp *rsp,
+ struct avdtp_service_capability *cap)
+{
+ struct avdtp_media_codec_capability *codec_cap = (void *) cap->data;
+ codec_capabilities_t *codec = (void *) rsp + rsp->h.length;
+ int space_left = BT_SUGGESTED_BUFFER_SIZE - rsp->h.length;
+
+ if (space_left <= 0)
+ return -ENOMEM;
+
+ /* endianess prevent direct cast */
+ if (codec_cap->media_codec_type == A2DP_CODEC_SBC) {
+ struct sbc_codec_cap *sbc_cap = (void *) codec_cap;
+ sbc_capabilities_t *sbc = (void *) codec;
+
+ if (space_left - sizeof(sbc_capabilities_t) < 0)
+ return -ENOMEM;
+
+ codec->length = sizeof(sbc_capabilities_t);
+
+ sbc->channel_mode = sbc_cap->channel_mode;
+ sbc->frequency = sbc_cap->frequency;
+ sbc->allocation_method = sbc_cap->allocation_method;
+ sbc->subbands = sbc_cap->subbands;
+ sbc->block_length = sbc_cap->block_length;
+ sbc->min_bitpool = sbc_cap->min_bitpool;
+ sbc->max_bitpool = sbc_cap->max_bitpool;
+ } else if (codec_cap->media_codec_type == A2DP_CODEC_MPEG12) {
+ struct mpeg_codec_cap *mpeg_cap = (void *) codec_cap;
+ mpeg_capabilities_t *mpeg = (void *) codec;
+
+ if (space_left - sizeof(mpeg_capabilities_t) < 0)
+ return -ENOMEM;
+
+ codec->length = sizeof(mpeg_capabilities_t);
+
+ mpeg->channel_mode = mpeg_cap->channel_mode;
+ mpeg->crc = mpeg_cap->crc;
+ mpeg->layer = mpeg_cap->layer;
+ mpeg->frequency = mpeg_cap->frequency;
+ mpeg->mpf = mpeg_cap->mpf;
+ mpeg->bitrate = mpeg_cap->bitrate;
+ } else {
+ int codec_length;
+
+ codec_length = cap->length - (sizeof(struct avdtp_service_capability)
+ + sizeof(struct avdtp_media_codec_capability));
+
+ if (space_left - (codec_length + sizeof(codec_capabilities_t)) < 0)
+ return -ENOMEM;
+
+ codec->length = codec_length + sizeof(codec_capabilities_t);
+ memcpy(codec->data, codec_cap->data, codec_length);
+ }
+
+ codec->type = codec_cap->media_codec_type;
+ rsp->h.length += codec->length;
+
+ debug("Append codec %d - length %d - total %d", codec->type,
+ codec->length, rsp->h.length);
+
+ return 0;
+}
+
static void a2dp_discovery_complete(struct avdtp *session, GSList *seps,
struct avdtp_error *err,
void *user_data)
{
struct unix_client *client = user_data;
- char buf[BT_AUDIO_IPC_PACKET_SIZE];
- struct bt_getcapabilities_rsp *rsp = (void *) buf;
+ char buf[BT_SUGGESTED_BUFFER_SIZE];
+ struct bt_get_capabilities_rsp *rsp = (void *) buf;
struct a2dp_data *a2dp = &client->d.a2dp;
- struct sbc_codec_cap *sbc_cap = NULL;
- struct mpeg_codec_cap *mpeg_cap = NULL;
GSList *l;
if (!g_slist_find(clients, client)) {
@@ -363,55 +452,29 @@ static void a2dp_discovery_complete(struct avdtp *session, GSList *seps,
memset(buf, 0, sizeof(buf));
client->req_id = 0;
- rsp->rsp_h.msg_h.msg_type = BT_GETCAPABILITIES_RSP;
- rsp->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
+ rsp->h.type = BT_RESPONSE;
+ rsp->h.name = BT_GET_CAPABILITIES;
+ rsp->h.length = sizeof(*rsp);
for (l = seps; l; l = g_slist_next(l)) {
struct avdtp_remote_sep *rsep = l->data;
struct avdtp_service_capability *cap;
- struct avdtp_media_codec_capability *codec_cap;
cap = avdtp_get_codec(rsep);
if (cap->category != AVDTP_MEDIA_CODEC)
continue;
- codec_cap = (void *) cap->data;
-
- if (codec_cap->media_codec_type == A2DP_CODEC_SBC && !sbc_cap)
- sbc_cap = (void *) codec_cap;
-
- if (codec_cap->media_codec_type == A2DP_CODEC_MPEG12 && !mpeg_cap)
- mpeg_cap = (void *) codec_cap;
+ a2dp_append_codec(rsp, cap);
}
- /* endianess prevent direct cast */
- if (sbc_cap) {
- rsp->sbc_capabilities.channel_mode = sbc_cap->channel_mode;
- rsp->sbc_capabilities.frequency = sbc_cap->frequency;
- rsp->sbc_capabilities.allocation_method = sbc_cap->allocation_method;
- rsp->sbc_capabilities.subbands = sbc_cap->subbands;
- rsp->sbc_capabilities.block_length = sbc_cap->block_length;
- rsp->sbc_capabilities.min_bitpool = sbc_cap->min_bitpool;
- rsp->sbc_capabilities.max_bitpool = sbc_cap->max_bitpool;
- }
-
- if (mpeg_cap) {
- rsp->mpeg_capabilities.channel_mode = mpeg_cap->channel_mode;
- rsp->mpeg_capabilities.crc = mpeg_cap->crc;
- rsp->mpeg_capabilities.layer = mpeg_cap->layer;
- rsp->mpeg_capabilities.frequency = mpeg_cap->frequency;
- rsp->mpeg_capabilities.mpf = mpeg_cap->mpf;
- rsp->mpeg_capabilities.bitrate = mpeg_cap->bitrate;
- }
-
- unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+ unix_ipc_sendmsg(client, &rsp->h);
return;
failed:
error("discovery failed");
- unix_ipc_error(client, BT_GETCAPABILITIES_RSP, EIO);
+ unix_ipc_error(client, BT_GET_CAPABILITIES, EIO);
avdtp_unref(a2dp->session);
@@ -425,8 +488,8 @@ static void a2dp_config_complete(struct avdtp *session, struct a2dp_sep *sep,
void *user_data)
{
struct unix_client *client = user_data;
- char buf[BT_AUDIO_IPC_PACKET_SIZE];
- struct bt_setconfiguration_rsp *rsp = (void *) buf;
+ char buf[BT_SUGGESTED_BUFFER_SIZE];
+ struct bt_set_configuration_rsp *rsp = (void *) buf;
struct a2dp_data *a2dp = &client->d.a2dp;
uint16_t imtu, omtu;
GSList *caps;
@@ -454,14 +517,17 @@ static void a2dp_config_complete(struct avdtp *session, struct a2dp_sep *sep,
goto failed;
}
- rsp->rsp_h.msg_h.msg_type = BT_SETCONFIGURATION_RSP;
+ rsp->h.type = BT_RESPONSE;
+ rsp->h.name = BT_SET_CONFIGURATION;
+ rsp->h.length = sizeof(*rsp);
+
rsp->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
client->access_mode = BT_CAPABILITIES_ACCESS_MODE_WRITE;
rsp->access_mode = client->access_mode;
/* FIXME: Use imtu when fd_opt is CFG_FD_OPT_READ */
rsp->link_mtu = omtu;
- unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+ unix_ipc_sendmsg(client, &rsp->h);
client->cb_id = avdtp_stream_add_cb(session, stream,
stream_state_changed, client);
@@ -475,7 +541,7 @@ failed:
a2dp_sep_unlock(a2dp->sep, a2dp->session);
a2dp->sep = NULL;
}
- unix_ipc_error(client, BT_SETCONFIGURATION_RSP, EIO);
+ unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
avdtp_unref(a2dp->session);
@@ -487,21 +553,26 @@ static void a2dp_resume_complete(struct avdtp *session,
struct avdtp_error *err, void *user_data)
{
struct unix_client *client = user_data;
- char buf[BT_AUDIO_IPC_PACKET_SIZE];
- struct bt_streamstart_rsp *rsp = (void *) buf;
- struct bt_streamfd_ind *ind = (void *) buf;
+ char buf[BT_SUGGESTED_BUFFER_SIZE];
+ struct bt_start_stream_rsp *rsp = (void *) buf;
+ struct bt_new_stream_ind *ind = (void *) buf;
struct a2dp_data *a2dp = &client->d.a2dp;
if (err)
goto failed;
memset(buf, 0, sizeof(buf));
- rsp->rsp_h.msg_h.msg_type = BT_STREAMSTART_RSP;
- rsp->rsp_h.posix_errno = 0;
- unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+ rsp->h.type = BT_RESPONSE;
+ rsp->h.name = BT_START_STREAM;
+ rsp->h.length = sizeof(*rsp);
+
+ unix_ipc_sendmsg(client, &rsp->h);
memset(buf, 0, sizeof(buf));
- ind->h.msg_type = BT_STREAMFD_IND;
+ ind->h.type = BT_RESPONSE;
+ ind->h.name = BT_NEW_STREAM;
+ rsp->h.length = sizeof(*ind);
+
unix_ipc_sendmsg(client, &ind->h);
if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) {
@@ -518,7 +589,7 @@ failed:
a2dp_sep_unlock(a2dp->sep, a2dp->session);
a2dp->sep = NULL;
}
- unix_ipc_error(client, BT_STREAMSTART_RSP, EIO);
+ unix_ipc_error(client, BT_START_STREAM, EIO);
if (client->cb_id > 0) {
avdtp_stream_remove_cb(a2dp->session, a2dp->stream,
@@ -536,17 +607,19 @@ static void a2dp_suspend_complete(struct avdtp *session,
struct avdtp_error *err, void *user_data)
{
struct unix_client *client = user_data;
- char buf[BT_AUDIO_IPC_PACKET_SIZE];
- struct bt_streamstart_rsp *rsp = (void *) buf;
+ char buf[BT_SUGGESTED_BUFFER_SIZE];
+ struct bt_start_stream_rsp *rsp = (void *) buf;
struct a2dp_data *a2dp = &client->d.a2dp;
if (err)
goto failed;
memset(buf, 0, sizeof(buf));
- rsp->rsp_h.msg_h.msg_type = BT_STREAMSTOP_RSP;
- rsp->rsp_h.posix_errno = 0;
- unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+ rsp->h.type = BT_RESPONSE;
+ rsp->h.name = BT_STOP_STREAM;
+ rsp->h.length = sizeof(*rsp);
+
+ unix_ipc_sendmsg(client, &rsp->h);
return;
@@ -557,7 +630,7 @@ failed:
a2dp_sep_unlock(a2dp->sep, a2dp->session);
a2dp->sep = NULL;
}
- unix_ipc_error(client, BT_STREAMSTOP_RSP, EIO);
+ unix_ipc_error(client, BT_STOP_STREAM, EIO);
avdtp_unref(a2dp->session);
@@ -604,7 +677,7 @@ static void start_discovery(struct audio_device *dev, struct unix_client *client
return;
failed:
- unix_ipc_error(client, BT_GETCAPABILITIES_RSP, err ? : EIO);
+ unix_ipc_error(client, BT_GET_CAPABILITIES, err ? : EIO);
}
static void start_config(struct audio_device *dev, struct unix_client *client)
@@ -671,7 +744,7 @@ static void start_config(struct audio_device *dev, struct unix_client *client)
return;
failed:
- unix_ipc_error(client, BT_SETCONFIGURATION_RSP, EIO);
+ unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
}
static void start_resume(struct audio_device *dev, struct unix_client *client)
@@ -726,7 +799,7 @@ static void start_resume(struct audio_device *dev, struct unix_client *client)
return;
failed:
- unix_ipc_error(client, BT_STREAMSTART_RSP, EIO);
+ unix_ipc_error(client, BT_START_STREAM, EIO);
}
static void start_suspend(struct audio_device *dev, struct unix_client *client)
@@ -780,11 +853,11 @@ static void start_suspend(struct audio_device *dev, struct unix_client *client)
return;
failed:
- unix_ipc_error(client, BT_STREAMSTOP_RSP, EIO);
+ unix_ipc_error(client, BT_STOP_STREAM, EIO);
}
static void handle_getcapabilities_req(struct unix_client *client,
- struct bt_getcapabilities_req *req)
+ struct bt_get_capabilities_req *req)
{
struct audio_device *dev;
bdaddr_t bdaddr;
@@ -820,11 +893,11 @@ static void handle_getcapabilities_req(struct unix_client *client,
return;
failed:
- unix_ipc_error(client, BT_GETCAPABILITIES_RSP, EIO);
+ unix_ipc_error(client, BT_GET_CAPABILITIES, EIO);
}
static int handle_sco_transport(struct unix_client *client,
- struct bt_setconfiguration_req *req)
+ struct bt_set_configuration_req *req)
{
client->interface = g_strdup(AUDIO_HEADSET_INTERFACE);
@@ -835,7 +908,7 @@ static int handle_sco_transport(struct unix_client *client,
}
static int handle_a2dp_transport(struct unix_client *client,
- struct bt_setconfiguration_req *req)
+ struct bt_set_configuration_req *req)
{
struct avdtp_service_capability *media_transport, *media_codec;
struct sbc_codec_cap sbc_cap;
@@ -856,18 +929,19 @@ static int handle_a2dp_transport(struct unix_client *client,
debug("config a2dp - device = %s access_mode = %u", req->device,
req->access_mode);
- if (req->mpeg_capabilities.frequency) {
+ if (req->codec.type == BT_A2DP_CODEC_MPEG12) {
+ mpeg_capabilities_t *mpeg = (void *) &req->codec;
memset(&mpeg_cap, 0, sizeof(mpeg_cap));
mpeg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
mpeg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12;
- mpeg_cap.channel_mode = req->mpeg_capabilities.channel_mode;
- mpeg_cap.crc = req->mpeg_capabilities.crc;
- mpeg_cap.layer = req->mpeg_capabilities.layer;
- mpeg_cap.frequency = req->mpeg_capabilities.frequency;
- mpeg_cap.mpf = req->mpeg_capabilities.mpf;
- mpeg_cap.bitrate = req->mpeg_capabilities.bitrate;
+ mpeg_cap.channel_mode = mpeg->channel_mode;
+ mpeg_cap.crc = mpeg->crc;
+ mpeg_cap.layer = mpeg->layer;
+ mpeg_cap.frequency = mpeg->frequency;
+ mpeg_cap.mpf = mpeg->mpf;
+ mpeg_cap.bitrate = mpeg->bitrate;
media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpeg_cap,
sizeof(mpeg_cap));
@@ -877,18 +951,20 @@ static int handle_a2dp_transport(struct unix_client *client,
mpeg_cap.frequency, mpeg_cap.channel_mode,
mpeg_cap.layer, mpeg_cap.crc, mpeg_cap.mpf,
mpeg_cap.bitrate);
- } else if (req->sbc_capabilities.frequency) {
+ } else if (req->codec.type == BT_A2DP_CODEC_SBC) {
+ sbc_capabilities_t *sbc = (void *) &req->codec;
+
memset(&sbc_cap, 0, sizeof(sbc_cap));
sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC;
- sbc_cap.channel_mode = req->sbc_capabilities.channel_mode;
- sbc_cap.frequency = req->sbc_capabilities.frequency;
- sbc_cap.allocation_method = req->sbc_capabilities.allocation_method;
- sbc_cap.subbands = req->sbc_capabilities.subbands;
- sbc_cap.block_length = req->sbc_capabilities.block_length;
- sbc_cap.min_bitpool = req->sbc_capabilities.min_bitpool;
- sbc_cap.max_bitpool = req->sbc_capabilities.max_bitpool;
+ sbc_cap.channel_mode = sbc->channel_mode;
+ sbc_cap.frequency = sbc->frequency;
+ sbc_cap.allocation_method = sbc->allocation_method;
+ sbc_cap.subbands = sbc->subbands;
+ sbc_cap.block_length = sbc->block_length;
+ sbc_cap.min_bitpool = sbc->min_bitpool;
+ sbc_cap.max_bitpool = sbc->max_bitpool;
media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
sizeof(sbc_cap));
@@ -908,7 +984,7 @@ static int handle_a2dp_transport(struct unix_client *client,
}
static void handle_setconfiguration_req(struct unix_client *client,
- struct bt_setconfiguration_req *req)
+ struct bt_set_configuration_req *req)
{
struct audio_device *dev;
bdaddr_t bdaddr;
@@ -926,13 +1002,13 @@ static void handle_setconfiguration_req(struct unix_client *client,
client->interface = NULL;
}
- if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO) {
+ if (req->codec.transport == BT_CAPABILITIES_TRANSPORT_SCO) {
err = handle_sco_transport(client, req);
if (err < 0) {
err = -err;
goto failed;
}
- } else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
+ } else if (req->codec.transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
err = handle_a2dp_transport(client, req);
if (err < 0) {
err = -err;
@@ -957,11 +1033,11 @@ static void handle_setconfiguration_req(struct unix_client *client,
return;
failed:
- unix_ipc_error(client, BT_SETCONFIGURATION_RSP, err ? : EIO);
+ unix_ipc_error(client, BT_SET_CONFIGURATION, err ? : EIO);
}
static void handle_streamstart_req(struct unix_client *client,
- struct bt_streamstart_req *req)
+ struct bt_start_stream_req *req)
{
if (!client->dev)
goto failed;
@@ -971,11 +1047,11 @@ static void handle_streamstart_req(struct unix_client *client,
return;
failed:
- unix_ipc_error(client, BT_STREAMSTART_REQ, EIO);
+ unix_ipc_error(client, BT_START_STREAM, EIO);
}
static void handle_streamstop_req(struct unix_client *client,
- struct bt_streamstop_req *req)
+ struct bt_stop_stream_req *req)
{
if (!client->dev)
goto failed;
@@ -985,32 +1061,33 @@ static void handle_streamstop_req(struct unix_client *client,
return;
failed:
- unix_ipc_error(client, BT_STREAMSTOP_REQ, EIO);
+ unix_ipc_error(client, BT_STOP_STREAM, EIO);
}
static void handle_control_req(struct unix_client *client,
struct bt_control_req *req)
{
/* FIXME: really implement that */
- char buf[BT_AUDIO_IPC_PACKET_SIZE];
- struct bt_setconfiguration_rsp *rsp = (void *) buf;
+ char buf[BT_SUGGESTED_BUFFER_SIZE];
+ struct bt_set_configuration_rsp *rsp = (void *) buf;
memset(buf, 0, sizeof(buf));
- rsp->rsp_h.msg_h.msg_type = BT_CONTROL_RSP;
- rsp->rsp_h.posix_errno = 0;
+ rsp->h.type = BT_RESPONSE;
+ rsp->h.name = BT_CONTROL;
+ rsp->h.length = sizeof(*rsp);
- unix_ipc_sendmsg(client, &rsp->rsp_h.msg_h);
+ unix_ipc_sendmsg(client, &rsp->h);
}
static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
{
- char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ char buf[BT_SUGGESTED_BUFFER_SIZE];
bt_audio_msg_header_t *msghdr = (void *) buf;
struct unix_client *client = data;
int len;
struct a2dp_data *a2dp = &client->d.a2dp;
struct headset_data *hs = &client->d.hs;
- const char *type;
+ const char *type, *name;
if (cond & G_IO_NVAL)
return FALSE;
@@ -1046,33 +1123,35 @@ static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
goto failed;
}
- if ((type = bt_audio_strmsg(msghdr->msg_type)))
- debug("Audio API: received %s", type);
+ type = bt_audio_strtype(msghdr->type);
+ name = bt_audio_strname(msghdr->name);
+
+ debug("Audio API: %s <- %s", type, name);
- switch (msghdr->msg_type) {
- case BT_GETCAPABILITIES_REQ:
+ switch (msghdr->name) {
+ case BT_GET_CAPABILITIES:
handle_getcapabilities_req(client,
- (struct bt_getcapabilities_req *) msghdr);
+ (struct bt_get_capabilities_req *) msghdr);
break;
- case BT_SETCONFIGURATION_REQ:
+ case BT_SET_CONFIGURATION:
handle_setconfiguration_req(client,
- (struct bt_setconfiguration_req *) msghdr);
+ (struct bt_set_configuration_req *) msghdr);
break;
- case BT_STREAMSTART_REQ:
+ case BT_START_STREAM:
handle_streamstart_req(client,
- (struct bt_streamstart_req *) msghdr);
+ (struct bt_start_stream_req *) msghdr);
break;
- case BT_STREAMSTOP_REQ:
+ case BT_STOP_STREAM:
handle_streamstop_req(client,
- (struct bt_streamstop_req *) msghdr);
+ (struct bt_stop_stream_req *) msghdr);
break;
- case BT_CONTROL_REQ:
+ case BT_CONTROL:
handle_control_req(client,
(struct bt_control_req *) msghdr);
break;
default:
- error("Audio API: received unexpected packet type %d",
- msghdr->msg_type);
+ error("Audio API: received unexpected message name %d",
+ msghdr->name);
}
return TRUE;