pcm_bluetooth.c revision f1a8e719f5687bb32f2f5ed59f26a3203ad43efb
1e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann/*
2e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
3e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  BlueZ - Bluetooth protocol stack for Linux
4e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
5e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org>
6e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
7e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
8e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  This library is free software; you can redistribute it and/or
9e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  modify it under the terms of the GNU Lesser General Public
10e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  License as published by the Free Software Foundation; either
11e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  version 2.1 of the License, or (at your option) any later version.
12e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
13e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  This library is distributed in the hope that it will be useful,
14e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  Lesser General Public License for more details.
17e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
18e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  You should have received a copy of the GNU Lesser General Public
19e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  License along with this library; if not, write to the Free Software
20e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann *
22e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann */
23e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann
24e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann#ifdef HAVE_CONFIG_H
25e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann#include <config.h>
26e7bd84e89e0af0cd2c2390bf7a173f90a473fc62Marcel Holtmann#endif
275ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann
28b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#include <sys/socket.h>
29b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#include <sys/un.h>
30b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
315ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann#include <alsa/asoundlib.h>
325ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann#include <alsa/pcm_external.h>
335ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann
348742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#include <bluetooth/bluetooth.h>
358742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#include <bluetooth/sco.h>
368742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
37b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#include "ipc.h"
38b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
39b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
40b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
418742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#ifndef SCO_TXBUFS
428742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#define SCO_TXBUFS 0x03
438742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#endif
448742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
458742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#ifndef SCO_RXBUFS
468742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#define SCO_RXBUFS 0x04
478742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#endif
488742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
49b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstruct bluetooth_data {
50b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	snd_pcm_ioplug_t io;
51b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	snd_pcm_sframes_t hw_ptr;
528742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct ipc_data_cfg cfg;	/* Bluetooth device config */
538742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	int sock;			/* Daemon unix socket */
548742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	uint8_t *buffer;		/* Transfer buffer */
558742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	uint8_t count;			/* Transfer buffer counter */
56b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann};
57b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
58b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_start(snd_pcm_ioplug_t *io)
59b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
60b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	DBG("io %p", io);
61b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
62b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
63b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
64b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
65b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_stop(snd_pcm_ioplug_t *io)
66b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
67b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	DBG("io %p", io);
68b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
69b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
70b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
71b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
72b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic snd_pcm_sframes_t bluetooth_pointer(snd_pcm_ioplug_t *io)
73b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
74b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	struct bluetooth_data *data = io->private_data;
75b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
768742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("io %p", io);
77b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
788742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("hw_ptr=%lu", data->hw_ptr);
79b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
80b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return data->hw_ptr;
81b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
82b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
83b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_close(snd_pcm_ioplug_t *io)
84b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
85b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	struct bluetooth_data *data = io->private_data;
86b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
87b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	DBG("io %p", io);
88b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
89b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	free(data);
90b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
91b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
92b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
93b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
948742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
958742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic int bluetooth_prepare(snd_pcm_ioplug_t *io)
968742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
978742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
988742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
998742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Preparing with io->period_size = %lu, io->buffer_size = %lu", io->period_size, io->buffer_size);
1008742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1018742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if (io->stream == SND_PCM_STREAM_PLAYBACK) {
1028742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		/* If not null for playback, xmms doesn't display time correctly */
1038742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->hw_ptr = 0;
1048742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
1058742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	else {
1068742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		/* ALSA library is really picky on the fact hw_ptr is not null. If it is, capture won't start */
1078742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->hw_ptr = io->period_size;
1088742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
1098742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	return 0;
1108742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
1118742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1128742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic int bluetooth_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params)
1138742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
1148742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
1158742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct ipc_data_cfg cfg = data->cfg;
1168742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	uint32_t period_count = io->buffer_size / io->period_size;
1178742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
118f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	DBG("fd = %d, period_count = %d", cfg.fd, period_count);
1198742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1208742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if(setsockopt(cfg.fd, SOL_SCO,
1218742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			io->stream == SND_PCM_STREAM_PLAYBACK ? SCO_TXBUFS : SCO_RXBUFS,
1228742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			&period_count,
1238742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			sizeof(period_count)) == 0) {
1248742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		return 0;
1258742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	} else if(setsockopt(cfg.fd, SOL_SCO,
1268742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			io->stream == SND_PCM_STREAM_PLAYBACK ? SO_SNDBUF : SO_RCVBUF,
1278742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			&period_count,
1288742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			sizeof(period_count)) == 0) {
1298742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz                return 0;
1308742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz        } else {
1318742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		SNDERR("Unable to set number of SCO buffers : please upgrade your Kernel !");
1328742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		return -EINVAL;
1338742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
1348742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
1358742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1368742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic snd_pcm_sframes_t bluetooth_read(snd_pcm_ioplug_t *io,
1378742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					const snd_pcm_channel_area_t *areas,
1388742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					snd_pcm_uframes_t offset,
1398742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					snd_pcm_uframes_t size)
1408742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
1418742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
1428742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct ipc_data_cfg cfg = data->cfg;
1438742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1448742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	snd_pcm_sframes_t ret = 0;
1458742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1468742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu, io->nonblock=%u",
1478742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		areas->step, areas->first, offset, size, io->nonblock);
1488742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1498742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if (data->count == 0) {
1508742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		int nrecv;
1518742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1528742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		nrecv = recv(cfg.fd, data->buffer, cfg.pkt_len,
1538742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			MSG_WAITALL | (io->nonblock ? MSG_DONTWAIT : 0 ));
1548742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1558742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		if (nrecv == cfg.pkt_len) {
1568742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			ret = 0;
1578742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			/* Increment hardware transmition pointer */
1588742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % io->buffer_size;
1598742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		}
1608742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		else if (nrecv > 0) {
1618742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			ret = -EIO;
1628742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			SNDERR(strerror(-ret));
1638742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		}
1648742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		else if (nrecv == -1 && errno == EAGAIN) {
1658742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			ret = -EAGAIN;
1668742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		}
1678742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		else { /* nrecv < 0 */
1688742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			/* EPIPE means device underrun in ALSA world. But we mean we lost contact
1698742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			with server, so we have to find another error code */
1708742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			ret = (errno == EPIPE ? -EIO : -errno);
1718742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			SYSERR("Lost contact with headsetd");
1728742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		}
1738742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
1748742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if(ret == 0) { /* Still ok, proceed */
1758742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		snd_pcm_uframes_t frames_to_write;
1768742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		unsigned char *buff;
1778742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1788742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8;
1798742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1808742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		if((data->count + cfg.sample_size * size) <= cfg.pkt_len)
1818742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			frames_to_write = size;
1828742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		else
1838742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			frames_to_write = (cfg.pkt_len - data->count) / cfg.sample_size;
1848742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1858742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		memcpy(buff, data->buffer + data->count, areas->step / 8 * frames_to_write);
1868742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->count += (areas->step / 8 * frames_to_write);
1878742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->count %= cfg.pkt_len;
1888742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		/* Return written frames count */
1898742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		ret = frames_to_write;
1908742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
1918742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1928742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("returning %d", (int)ret);
1938742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	return ret;
1948742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
1958742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1968742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic snd_pcm_sframes_t bluetooth_write(snd_pcm_ioplug_t *io,
1978742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					const snd_pcm_channel_area_t *areas,
1988742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					snd_pcm_uframes_t offset,
1998742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz					snd_pcm_uframes_t size)
2008742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
2018742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
2028742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct ipc_data_cfg cfg = data->cfg;
2038742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	snd_pcm_sframes_t ret = 0;
2048742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	snd_pcm_uframes_t frames_to_read;
2058742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	unsigned char *buff;
2068742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
2078742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu, io->nonblock=%u",
2088742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		areas->step, areas->first, offset, size, io->nonblock);
2098742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
2108742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if ((data->count + cfg.sample_size * size) <= cfg.pkt_len)
2118742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		frames_to_read = size;
2128742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	else
2138742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		frames_to_read = (cfg.pkt_len - data->count) / cfg.sample_size;
2148742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
2158742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	/* Ready for more data */
2168742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8;
2178742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	memcpy(data->buffer + data->count, buff, areas->step / 8 * frames_to_read);
2188742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
2198742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if ((data->count + areas->step / 8 * frames_to_read) == cfg.pkt_len) {
2208742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		int rsend;
2218742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		/* Actually send packet */
2228742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		rsend = send(cfg.fd, data->buffer, cfg.pkt_len, io->nonblock ? MSG_DONTWAIT : 0);
2238742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		if (rsend > 0) {
2248742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			/* Reset count pointer */
2258742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			data->count = 0;
2268742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
2278742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			/* Increment hardware transmition pointer */
2288742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % io->buffer_size;
2298742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
2308742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			ret = frames_to_read;
2318742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		}
2328742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		else {
2338742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			/* EPIPE means device underrun in ALSA world. But we mean we lost contact
2348742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz                           with server, so we have to find another error code */
2358742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			ret = (errno == EPIPE ? -EIO : -errno);
2368742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz			if(errno == EPIPE)
2378742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz				SYSERR("Lost contact with headsetd");
2388742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		}
2398742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
2408742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	else {
2418742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		/* Remember we have some frame in the pipe now */
2428742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->count += areas->step / 8 * frames_to_read;
2438742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		/* Ask for more */
2448742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		ret = frames_to_read;
2458742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
2468742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
2478742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("returning %d", (int)ret);
2488742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	return ret;
2498742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
2508742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
251b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic snd_pcm_ioplug_callback_t bluetooth_playback_callback = {
252b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.start		= bluetooth_start,
253b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.stop		= bluetooth_stop,
254b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.pointer	= bluetooth_pointer,
255b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.close		= bluetooth_close,
256b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.hw_params	= bluetooth_hw_params,
257b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.prepare	= bluetooth_prepare,
258b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.transfer	= bluetooth_write,
259b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann};
260b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
261b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic snd_pcm_ioplug_callback_t bluetooth_capture_callback = {
262b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.start		= bluetooth_start,
263b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.stop		= bluetooth_stop,
264b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.pointer	= bluetooth_pointer,
265b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.close		= bluetooth_close,
266b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.hw_params	= bluetooth_hw_params,
267b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.prepare	= bluetooth_prepare,
268b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	.transfer	= bluetooth_read,
269b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann};
270b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
271b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0]))
272b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
273b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_hw_constraint(snd_pcm_ioplug_t *io)
274b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
275b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	snd_pcm_access_t access_list[] = {
276b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SND_PCM_ACCESS_RW_INTERLEAVED,
277b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		/* Mmap access is really useless fo this driver, but we
278b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		 * support it because some pieces of software out there
279b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		 * insist on using it */
280b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SND_PCM_ACCESS_MMAP_INTERLEAVED
281b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	};
282b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	unsigned int format_list[] = {
283b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SND_PCM_FORMAT_S16_LE
284b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	};
285b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	int err;
286b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
287b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
288b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann					ARRAY_NELEMS(access_list), access_list);
289b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
290b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
291b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
292b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
293b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann					ARRAY_NELEMS(format_list), format_list);
294b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
295b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
296b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
297b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, 1, 1);
298b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
299b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
300b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
301b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 8000);
302b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
303b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
304b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
305b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 48, 48);
306b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
307b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
308b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
309b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 200);
310b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
311b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
312b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
313b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
314b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
315b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
3168742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic int bluetooth_cfg(struct bluetooth_data *data)
3175ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann{
3188742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	int res;
319f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	int len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_cfg);
320f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	struct ipc_packet *pkt;
3218742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
3228742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Sending PKT_TYPE_CFG_REQ...");
323f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	pkt = malloc(len);
324f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	memset(pkt, 0, len);
325f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	pkt->type = PKT_TYPE_CFG_REQ;
326f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	pkt->role = PKT_ROLE_NONE;
327f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	pkt->error = PKT_ERROR_NONE;
328f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	res = send(data->sock, pkt, len, 0);
3298742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if (res < 0)
3308742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		return errno;
3318742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("OK - %d bytes sent", res);
3328742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
3338742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Waiting for response...");
3348742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
335f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	memset(pkt, 0, len);
336f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	res = recv(data->sock, pkt, len, 0);
337f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz
3388742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if (res < 0)
3398742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		return -errno;
3408742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("OK - %d bytes received", res);
341b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
342f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (pkt->type != PKT_TYPE_CFG_RSP) {
343f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		SNDERR("Unexpected packet type received: type = %d", pkt->type);
3448742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		return -EINVAL;
3458742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
346b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
347f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (pkt->error != PKT_ERROR_NONE) {
348f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		SNDERR("Error while configuring device: error = %d", pkt->error);
349f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		return pkt->error;
3508742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
351b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
352f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (pkt->length != sizeof(struct ipc_data_cfg)) {
3538742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		SNDERR("Error while configuring device: packet size doesn't match");
3548742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		return -EINVAL;
3558742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
356b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
357f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	memcpy(&data->cfg, pkt->data, sizeof(struct ipc_data_cfg));
358b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
3598742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Device configuration:");
360f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz
3618742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("fd=%d, fd_opt=%u, channels=%u, pkt_len=%u, sample_size=%u, rate=%u",
3628742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->cfg.fd, data->cfg.fd_opt, data->cfg.channels,
3638742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->cfg.pkt_len, data->cfg.sample_size, data->cfg.rate);
3648742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
365f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (data->cfg.fd == -1) {
366f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		SNDERR("Error while configuring device: could not acquire audio socket");
367f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		return -EINVAL;
368f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	}
369f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz
370f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	free(pkt);
3718742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	return 0;
3728742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
3738742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
3748742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic int bluetooth_init(struct bluetooth_data *data)
3758742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
3768742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	int sk, err, id;
3778742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct sockaddr_un addr;
3788742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
379f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (!data)
380f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		return -EINVAL;
381f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz
382b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	id = abs(getpid() * rand());
383b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
384b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	sk = socket(PF_LOCAL, SOCK_DGRAM, 0);
385b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (sk < 0) {
386b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SNDERR("Can't open socket");
387b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return -errno;
388b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	}
389b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
390b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	memset(&addr, 0, sizeof(addr));
391b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	addr.sun_family = AF_UNIX;
392e343f2b21a2209d5713e20ad38bbcc862897380bJohan Hedberg	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s/%d",
393e343f2b21a2209d5713e20ad38bbcc862897380bJohan Hedberg			IPC_SOCKET_NAME, id);
394b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
3958742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Binding address: %s", addr.sun_path + 1);
396b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
397b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SNDERR("Can't bind socket");
398b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		close(sk);
399b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return -errno;
400b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	}
401b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
402b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	memset(&addr, 0, sizeof(addr));
403b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	addr.sun_family = AF_UNIX;
404e343f2b21a2209d5713e20ad38bbcc862897380bJohan Hedberg	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", IPC_SOCKET_NAME);
405b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
4068742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Connecting to address: %s", addr.sun_path + 1);
407b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
408b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SNDERR("Can't connect socket");
409b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		close(sk);
410b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return -errno;
411b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	}
412b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
413b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	data->sock = sk;
414b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
415f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if ((err = bluetooth_cfg(data)) < 0) {
416f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		free(data);
4178742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		return err;
418f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	}
4198742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4208742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	data->buffer = malloc(data->cfg.pkt_len);
4218742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4228742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	memset(data->buffer, 0, data->cfg.pkt_len);
423b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
4248742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	return 0;
4258742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
4268742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4278742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von DentzSND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
4288742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
4298742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz//	snd_config_iterator_t iter, next;
430f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	struct bluetooth_data *data;
4318742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	int err;
4328742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4338742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Bluetooth PCM plugin blablabla (%s)",
4348742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture");
4358742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4368742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz//	snd_config_for_each(iter, next, conf) {
4378742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz//	}
4388742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4398742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Initing Bluetooth...");
440f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data = malloc(sizeof(struct bluetooth_data));
441f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	memset(data, 0, sizeof(struct bluetooth_data));
442f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	err = bluetooth_init(data);
4438742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if (err < 0)
4448742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		goto error;
4458742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Done");
4468742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
447f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.version = SND_PCM_IOPLUG_VERSION;
448f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.name = "Bluetooth Audio Device";
449f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.mmap_rw =  0; /* No direct mmap communication */
4508742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
451f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
452b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		&bluetooth_playback_callback : &bluetooth_capture_callback;
453f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.poll_fd = data->cfg.fd;
454f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ?
455f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		POLLOUT : POLLIN;
456f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.private_data = data;
457b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
458f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	err = snd_pcm_ioplug_create(&data->io, name, stream, mode);
459b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
460b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		goto error;
461b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
462f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	err = bluetooth_hw_constraint(&data->io);
463b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0) {
464f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		snd_pcm_ioplug_delete(&data->io);
4658742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		goto error;
466b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	}
467b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
468f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	*pcmp = data->io.pcm;
469b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
470b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
471b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
472b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannerror:
473f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	close(data->sock);
474f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	free(data);
4755ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann
476b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return err;
4775ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann}
4785ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann
4795ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel HoltmannSND_PCM_PLUGIN_SYMBOL(bluetooth);
480