summaryrefslogtreecommitdiffstats
path: root/audio/unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/unix.c')
-rw-r--r--audio/unix.c433
1 files changed, 152 insertions, 281 deletions
diff --git a/audio/unix.c b/audio/unix.c
index 71eb570a..ea96bd4f 100644
--- a/audio/unix.c
+++ b/audio/unix.c
@@ -79,7 +79,8 @@ struct unix_client {
struct headset_data hs;
} d;
int sock;
- int fd_opt;
+ int access_mode;
+ int data_fd; /* To be deleted once two phase configuration is fully implemented */
unsigned int req_id;
unsigned int cb_id;
gboolean (*cancel_stream) (struct device *dev, unsigned int id);
@@ -89,6 +90,11 @@ static GSList *clients = NULL;
static int unix_sock = -1;
+static void unix_ipc_sendmsg(struct unix_client *client,
+ const bt_audio_msg_header_t *msg);
+
+static void send_getcapabilities_rsp_error(struct unix_client *client, int err);
+
static void client_free(struct unix_client *client)
{
struct a2dp_data *a2dp;
@@ -121,7 +127,7 @@ static void client_free(struct unix_client *client)
/* Pass file descriptor through local domain sockets (AF_LOCAL, formerly AF_UNIX)
and the sendmsg() system call with the cmsg_type field of a "struct cmsghdr" set
-to SCM_RIGHTS and the data being an integer value equal to the handle of the
+to SCM_RIGHTS and the data being an integer value equal to the handle of the
file descriptor to be passed.*/
static int unix_sendmsg_fd(int sock, int fd)
{
@@ -193,77 +199,29 @@ static void stream_state_changed(struct avdtp_stream *stream,
}
}
-static int unix_send_cfg(int sock, struct ipc_data_cfg *cfg, int fd)
-{
- char buf[IPC_MTU];
- struct ipc_packet *pkt = (void *) buf;
- int len, codec_len;
-
- memset(buf, 0, sizeof(buf));
-
- pkt->type = PKT_TYPE_CFG_RSP;
-
- if (!cfg) {
- pkt->error = EINVAL;
- len = send(sock, pkt, sizeof(struct ipc_packet), 0);
- if (len < 0)
- error("send: %s (%d)", strerror(errno), errno);
- return len;
- }
-
- debug("fd=%d, fd_opt=%u, pkt_len=%u, sample_size=%u, rate=%u",
- fd, cfg->fd_opt, cfg->pkt_len,
- cfg->sample_size, cfg->rate);
-
- if (cfg->codec == CFG_CODEC_SBC)
- codec_len = sizeof(struct ipc_codec_sbc);
- else
- codec_len = 0;
-
- pkt->error = PKT_ERROR_NONE;
- pkt->length = sizeof(struct ipc_data_cfg) + codec_len;
- memcpy(pkt->data, cfg, pkt->length);
-
- len = sizeof(struct ipc_packet) + pkt->length;
- len = send(sock, pkt, len, 0);
- if (len < 0)
- error("Error %s(%d)", strerror(errno), errno);
-
- debug("%d bytes sent", len);
-
- if (fd != -1) {
- len = unix_sendmsg_fd(sock, fd);
- if (len < 0)
- error("Error %s(%d)", strerror(errno), errno);
- debug("%d bytes sent", len);
- }
-
- return 0;
-}
-
static void headset_setup_complete(struct device *dev, void *user_data)
{
struct unix_client *client = user_data;
- struct ipc_data_cfg cfg;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_getcapabilities_rsp *rsp = (void *) buf;
struct headset_data *hs = &client->d.hs;
- int fd;
client->req_id = 0;
if (!dev) {
- unix_send_cfg(client->sock, NULL, -1);
+ send_getcapabilities_rsp_error(client, EIO);
client->dev = NULL;
return;
}
- switch (client->fd_opt) {
- case CFG_FD_OPT_READ:
+ switch (client->access_mode) {
+ case BT_CAPABILITIES_ACCESS_MODE_READ:
hs->lock = HEADSET_LOCK_READ;
break;
- case CFG_FD_OPT_WRITE:
+ case BT_CAPABILITIES_ACCESS_MODE_WRITE:
hs->lock = HEADSET_LOCK_WRITE;
break;
- case CFG_FD_OPT_READWRITE:
+ case BT_CAPABILITIES_ACCESS_MODE_READWRITE:
hs->lock = HEADSET_LOCK_READ | HEADSET_LOCK_WRITE;
break;
default:
@@ -273,23 +231,22 @@ static void headset_setup_complete(struct device *dev, void *user_data)
if (!headset_lock(dev, hs->lock)) {
error("Unable to lock headset");
- unix_send_cfg(client->sock, NULL, -1);
+ send_getcapabilities_rsp_error(client, EIO);
client->dev = NULL;
return;
}
- memset(&cfg, 0, sizeof(cfg));
+ memset(buf, 0, sizeof(buf));
- cfg.fd_opt = client->fd_opt;
- cfg.codec = CFG_CODEC_SCO;
- cfg.mode = CFG_MODE_MONO;
- cfg.pkt_len = 48;
- cfg.sample_size = 2;
- cfg.rate = 8000;
+ rsp->h.msg_type = BT_GETCAPABILITIES_RSP;
+ rsp->transport = BT_CAPABILITIES_TRANSPORT_SCO;
+ rsp->access_mode = client->access_mode;
+ rsp->link_mtu = 48;
+ rsp->sampling_rate = 8000;
- fd = headset_get_sco_fd(dev);
+ client->data_fd = headset_get_sco_fd(dev);
- unix_send_cfg(client->sock, &cfg, fd);
+ unix_ipc_sendmsg(client, &rsp->h);
}
static void a2dp_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
@@ -297,17 +254,16 @@ static void a2dp_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
void *user_data, struct avdtp_error *err)
{
struct unix_client *client = user_data;
- char buf[sizeof(struct ipc_data_cfg) + sizeof(struct ipc_codec_sbc)];
- struct ipc_data_cfg *cfg = (void *) buf;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_getcapabilities_rsp *rsp = (void *) buf;
struct avdtp_service_capability *cap;
struct avdtp_media_codec_capability *codec_cap;
struct sbc_codec_cap *sbc_cap;
- struct ipc_codec_sbc *sbc = (void *) cfg->data;
struct a2dp_data *a2dp = &client->d.a2dp;
- int fd;
uint16_t imtu, omtu;
GSList *caps;
+ memset(buf, 0, sizeof(buf));
client->req_id = 0;
if (!stream)
@@ -321,7 +277,7 @@ static void a2dp_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
a2dp->sep = sep;
a2dp->stream = stream;
- if (!avdtp_stream_get_transport(stream, &fd, &imtu, &omtu, &caps)) {
+ if (!avdtp_stream_get_transport(stream, &client->data_fd, &imtu, &omtu, &caps)) {
error("Unable to get stream transport");
goto failed;
}
@@ -340,66 +296,27 @@ static void a2dp_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
goto failed;
}
+ rsp->h.msg_type = BT_GETCAPABILITIES_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 */
- cfg->pkt_len = omtu;
- cfg->fd_opt = CFG_FD_OPT_WRITE;
+ rsp->link_mtu = omtu;
sbc_cap = (void *) codec_cap;
- cfg->sample_size = 2;
- switch (sbc_cap->channel_mode) {
- case A2DP_CHANNEL_MODE_MONO:
- cfg->mode = CFG_MODE_MONO;
- break;
- case A2DP_CHANNEL_MODE_DUAL_CHANNEL:
- cfg->mode = CFG_MODE_DUAL_CHANNEL;
- break;
- case A2DP_CHANNEL_MODE_STEREO:
- cfg->mode = CFG_MODE_STEREO;
- break;
- case A2DP_CHANNEL_MODE_JOINT_STEREO:
- cfg->mode = CFG_MODE_JOINT_STEREO;
- break;
- }
+ /* assignations below are ok as soon as newipc.h and a2dp.h are kept */
+ /* in sync. However it is not possible to cast a struct to another */
+ /* dues to endianess issues */
+ 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;
- switch (sbc_cap->frequency) {
- case A2DP_SAMPLING_FREQ_16000:
- cfg->rate = 16000;
- break;
- case A2DP_SAMPLING_FREQ_32000:
- cfg->rate = 32000;
- break;
- case A2DP_SAMPLING_FREQ_44100:
- cfg->rate = 44100;
- break;
- case A2DP_SAMPLING_FREQ_48000:
- cfg->rate = 48000;
- break;
- }
-
- cfg->codec = CFG_CODEC_SBC;
- sbc->allocation = sbc_cap->allocation_method == A2DP_ALLOCATION_SNR ?
- 0x01 : 0x00;
- sbc->subbands = sbc_cap->subbands == A2DP_SUBBANDS_4 ? 4 : 8;
-
- switch (sbc_cap->block_length) {
- case A2DP_BLOCK_LENGTH_4:
- sbc->blocks = 4;
- break;
- case A2DP_BLOCK_LENGTH_8:
- sbc->blocks = 8;
- break;
- case A2DP_BLOCK_LENGTH_12:
- sbc->blocks = 12;
- break;
- case A2DP_BLOCK_LENGTH_16:
- sbc->blocks = 16;
- break;
- }
-
- sbc->bitpool = sbc_cap->max_bitpool;
-
- unix_send_cfg(client->sock, cfg, fd);
+ unix_ipc_sendmsg(client, &rsp->h);
client->cb_id = avdtp_stream_add_cb(session, stream,
stream_state_changed, client);
@@ -412,7 +329,7 @@ failed:
a2dp_sep_unlock(a2dp->sep, a2dp->session);
a2dp->sep = NULL;
}
- unix_send_cfg(client->sock, NULL, -1);
+ send_getcapabilities_rsp_error(client, EIO);
avdtp_unref(a2dp->session);
@@ -469,7 +386,7 @@ static void create_stream(struct device *dev, struct unix_client *client)
return;
failed:
- unix_send_cfg(client->sock, NULL, -1);
+ send_getcapabilities_rsp_error(client, EIO);
}
static void create_cb(struct device *dev, void *user_data)
@@ -477,135 +394,57 @@ static void create_cb(struct device *dev, void *user_data)
struct unix_client *client = user_data;
if (!dev)
- unix_send_cfg(client->sock, NULL, -1);
+ send_getcapabilities_rsp_error(client, EIO);
else
create_stream(dev, client);
}
-static int cfg_to_caps(struct ipc_data_cfg *cfg, struct sbc_codec_cap *sbc_cap)
+static void unix_ipc_sendmsg(struct unix_client *client,
+ const bt_audio_msg_header_t *msg)
{
- struct ipc_codec_sbc *sbc = (void *) cfg->data;
-
- memset(sbc_cap, 0, sizeof(struct sbc_codec_cap));
-
- sbc_cap->cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
- sbc_cap->cap.media_codec_type = A2DP_CODEC_SBC;
-
- switch (cfg->rate) {
- case 48000:
- sbc_cap->frequency = A2DP_SAMPLING_FREQ_48000;
- break;
- case 44100:
- sbc_cap->frequency = A2DP_SAMPLING_FREQ_44100;
- break;
- case 32000:
- sbc_cap->frequency = A2DP_SAMPLING_FREQ_32000;
- break;
- case 16000:
- sbc_cap->frequency = A2DP_SAMPLING_FREQ_16000;
- break;
- default:
- sbc_cap->frequency = A2DP_SAMPLING_FREQ_44100;
- break;
- }
-
- switch (cfg->mode) {
- case CFG_MODE_MONO:
- sbc_cap->channel_mode = A2DP_CHANNEL_MODE_MONO;
- break;
- case CFG_MODE_DUAL_CHANNEL:
- sbc_cap->channel_mode = A2DP_CHANNEL_MODE_DUAL_CHANNEL;
- break;
- case CFG_MODE_STEREO:
- sbc_cap->channel_mode = A2DP_CHANNEL_MODE_STEREO;
- break;
- case CFG_MODE_JOINT_STEREO:
- sbc_cap->channel_mode = A2DP_CHANNEL_MODE_JOINT_STEREO;
- break;
- default:
- sbc_cap->channel_mode = A2DP_CHANNEL_MODE_JOINT_STEREO;
- break;
- }
-
- switch (sbc->allocation) {
- case CFG_ALLOCATION_LOUDNESS:
- sbc_cap->allocation_method = A2DP_ALLOCATION_LOUDNESS;
- break;
- case CFG_ALLOCATION_SNR:
- sbc_cap->allocation_method = A2DP_ALLOCATION_LOUDNESS;
- break;
- default:
- sbc_cap->allocation_method = A2DP_ALLOCATION_LOUDNESS;
- break;
- }
-
- switch (sbc->subbands) {
- case 8:
- sbc_cap->subbands = A2DP_SUBBANDS_8;
- break;
- case 4:
- sbc_cap->subbands = A2DP_SUBBANDS_4;
- break;
- default:
- sbc_cap->subbands = A2DP_SUBBANDS_8;
- break;
- }
-
- switch (sbc->blocks) {
- case 16:
- sbc_cap->block_length = A2DP_BLOCK_LENGTH_16;
- break;
- case 12:
- sbc_cap->block_length = A2DP_BLOCK_LENGTH_12;
- break;
- case 8:
- sbc_cap->block_length = A2DP_BLOCK_LENGTH_8;
- break;
- case 4:
- sbc_cap->block_length = A2DP_BLOCK_LENGTH_4;
- break;
- default:
- sbc_cap->block_length = A2DP_BLOCK_LENGTH_16;
- break;
- }
+ info("Audio API: sending %s", bt_audio_strmsg(msg->msg_type));
+ if (send(client->sock, msg, BT_AUDIO_IPC_PACKET_SIZE, 0) < 0)
+ error("Error %s(%d)", strerror(errno), errno);
+}
- if (sbc->bitpool != 0) {
- if (sbc->bitpool > 250)
- return -EINVAL;
+static void send_getcapabilities_rsp_error(struct unix_client *client, int err)
+{
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_getcapabilities_rsp *rsp = (void *) buf;
- sbc_cap->min_bitpool = sbc->bitpool;
- sbc_cap->max_bitpool = sbc->bitpool;
- }
+ memset(buf, 0, sizeof(buf));
+ rsp->h.msg_type = BT_GETCAPABILITIES_RSP;
+ rsp->posix_errno = err;
- return 0;
+ unix_ipc_sendmsg(client, &rsp->h);
}
-static void cfg_event(struct unix_client *client, struct ipc_packet *pkt, int len)
+static void handle_getcapabilities_req(struct unix_client *client,
+ struct bt_getcapabilities_req *req)
{
struct device *dev;
bdaddr_t bdaddr;
- struct ipc_data_cfg *cfg = (void *) pkt->data;
- struct sbc_codec_cap sbc_cap;
- str2ba(pkt->device, &bdaddr);
+ str2ba(req->device, &bdaddr);
+
+ if (!req->access_mode) {
+ send_getcapabilities_rsp_error(client, EINVAL);
+ return;
+ }
- client->fd_opt = cfg->fd_opt;
+ client->access_mode = req->access_mode;
if (client->interface) {
g_free(client->interface);
client->interface = NULL;
}
- if (pkt->role == PKT_ROLE_VOICE)
+ if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO)
client->interface = g_strdup(AUDIO_HEADSET_INTERFACE);
- else if (pkt->role == PKT_ROLE_HIFI)
+ else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
client->interface = g_strdup(AUDIO_SINK_INTERFACE);
- if (cfg_to_caps(cfg, &sbc_cap) < 0)
- goto failed;
-
- client->media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC,
- &sbc_cap, sizeof(sbc_cap));
+ client->media_codec = 0;
if (!manager_find_device(&bdaddr, NULL, FALSE)) {
if (!bacmp(&bdaddr, BDADDR_ANY))
@@ -627,59 +466,83 @@ static void cfg_event(struct unix_client *client, struct ipc_packet *pkt, int le
return;
failed:
- unix_send_cfg(client->sock, NULL, -1);
+ send_getcapabilities_rsp_error(client, EIO);
}
-static void ctl_event(struct unix_client *client,
- struct ipc_packet *pkt, int len)
+static void handle_setconfiguration_req(struct unix_client *client,
+ struct bt_setconfiguration_req *req)
{
+ /* FIXME: for now we just blindly assume that we receive is the
+ only valid configuration sent.*/
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_setconfiguration_rsp *rsp = (void *) buf;
+
+ memset(buf, 0, sizeof(buf));
+ rsp->h.msg_type = BT_SETCONFIGURATION_RSP;
+ rsp->posix_errno = 0;
+
+ unix_ipc_sendmsg(client, &rsp->h);
}
-static int reply_state(int sock, struct ipc_packet *pkt)
+static void handle_streamstart_req(struct unix_client *client,
+ struct bt_streamstart_req *req)
{
- struct ipc_data_state *state = (struct ipc_data_state *) pkt->data;
- int len;
+ /* FIXME : to be really implemented */
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_streamstart_rsp *rsp = (void *) buf;
+ struct bt_datafd_ind *ind = (void *) buf;
- info("status=%u", state->state);
+ memset(buf, 0, sizeof(buf));
+ rsp->h.msg_type = BT_STREAMSTART_RSP;
+ rsp->posix_errno = 0;
+ unix_ipc_sendmsg(client, &rsp->h);
- pkt->type = PKT_TYPE_STATE_RSP;
- pkt->length = sizeof(struct ipc_data_state);
- pkt->error = PKT_ERROR_NONE;
+ memset(buf, 0, sizeof(buf));
+ ind->h.msg_type = BT_STREAMFD_IND;
+ unix_ipc_sendmsg(client, &ind->h);
- len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_state);
- len = send(sock, pkt, len, 0);
- if (len < 0)
- error("Error %s(%d)", strerror(errno), errno);
+ if (unix_sendmsg_fd(client->sock, client->data_fd) < 0)
+ error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno);
+
+}
- debug("%d bytes sent", len);
+static void handle_streamstop_req(struct unix_client *client,
+ struct bt_streamstop_req *req)
+{
+ /* FIXME : to be implemented */
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_streamstop_rsp *rsp = (void *) buf;
- return 0;
+ memset(buf, 0, sizeof(buf));
+ rsp->h.msg_type = BT_STREAMSTOP_RSP;
+ rsp->posix_errno = 0;
+
+ unix_ipc_sendmsg(client, &rsp->h);
}
-static void state_event(struct unix_client *client,
- struct ipc_packet *pkt, int len)
+static void handle_control_req(struct unix_client *client,
+ struct bt_control_req *req)
{
-#if 0
- struct ipc_data_state *state = (struct ipc_data_state *) pkt->data;
- struct device *dev = client->dev;
+ /* FIXME: really implement that */
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ struct bt_setconfiguration_rsp *rsp = (void *) buf;
- if (len > sizeof(struct ipc_packet))
- device_set_state(dev, state->state);
- else
- state->state = device_get_state(dev);
-#endif
+ memset(buf, 0, sizeof(buf));
+ rsp->h.msg_type = BT_CONTROL_RSP;
+ rsp->posix_errno = 0;
- reply_state(client->sock, pkt);
+ unix_ipc_sendmsg(client, &rsp->h);
}
static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
{
- char buf[IPC_MTU];
- struct ipc_packet *pkt = (void *) buf;
+ char buf[BT_AUDIO_IPC_PACKET_SIZE];
+ bt_audio_msg_header_t *msghdr = (void *) buf;
struct unix_client *client = data;
- int len, len_check;
+ int len;
struct a2dp_data *a2dp = &client->d.a2dp;
struct headset_data *hs = &client->d.hs;
+ const char *type;
if (cond & G_IO_NVAL)
return FALSE;
@@ -709,31 +572,39 @@ static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
memset(buf, 0, sizeof(buf));
- len = recv(client->sock, buf, sizeof(buf), 0);
+ len = recv(client->sock, buf, sizeof(buf), MSG_WAITALL);
if (len < 0) {
error("recv: %s (%d)", strerror(errno), errno);
goto failed;
}
- len_check = pkt->length + sizeof(struct ipc_packet);
- if (len != len_check) {
- error("Packet lenght doesn't match");
- goto failed;
- }
+ if ((type = bt_audio_strmsg(msghdr->msg_type)))
+ info("Audio API: received %s", type);
- switch (pkt->type) {
- case PKT_TYPE_CFG_REQ:
- info("Package PKT_TYPE_CFG_REQ:%u", pkt->role);
- cfg_event(client, pkt, len);
+ switch (msghdr->msg_type) {
+ case BT_GETCAPABILITIES_REQ:
+ handle_getcapabilities_req(client,
+ (struct bt_getcapabilities_req *) msghdr);
break;
- case PKT_TYPE_STATE_REQ:
- info("Package PKT_TYPE_STATE_REQ");
- state_event(client, pkt, len);
+ case BT_SETCONFIGURATION_REQ:
+ handle_setconfiguration_req(client,
+ (struct bt_setconfiguration_req *) msghdr);
break;
- case PKT_TYPE_CTL_REQ:
- info("Package PKT_TYPE_CTL_REQ");
- ctl_event(client, pkt, len);
+ case BT_STREAMSTART_REQ:
+ handle_streamstart_req(client,
+ (struct bt_streamstart_req *) msghdr);
break;
+ case BT_STREAMSTOP_REQ:
+ handle_streamstop_req(client,
+ (struct bt_streamstop_req *) msghdr);
+ break;
+ case BT_CONTROL_REQ:
+ handle_control_req(client,
+ (struct bt_control_req *) msghdr);
+ break;
+ default:
+ error("Audio API: received unexpected packet type %d",
+ msghdr->msg_type);
}
return TRUE;
@@ -789,7 +660,7 @@ int unix_init(void)
{
GIOChannel *io;
struct sockaddr_un addr = {
- AF_UNIX, IPC_SOCKET_NAME
+ AF_UNIX, BT_IPC_SOCKET_NAME
};
int sk, err;