pcm_bluetooth.c revision cae1e4ecd14d380252b0e00f71bc6cf2887ebd31
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>
306763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg#include <sys/time.h>
31e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg#include <pthread.h>
326763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
336763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg#include <netinet/in.h>
34b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
355ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann#include <alsa/asoundlib.h>
365ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann#include <alsa/pcm_external.h>
375ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann
388742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#include <bluetooth/bluetooth.h>
398742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#include <bluetooth/sco.h>
408742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
41b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#include "ipc.h"
426763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg#include "sbc.h"
436763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
44cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg// #define ENABLE_DEBUG
456763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
46d661010f0da37d072e9f3e0adcc94964fea6a054Luiz Augusto von Dentz#define BUFFER_SIZE 2048
47b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
48f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz#ifdef ENABLE_DEBUG
49b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
50f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz#else
51f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz#define DBG(fmt, arg...)
52f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz#endif
53b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
548742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#ifndef SCO_TXBUFS
558742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#define SCO_TXBUFS 0x03
568742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#endif
578742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
588742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#ifndef SCO_RXBUFS
598742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#define SCO_RXBUFS 0x04
608742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz#endif
618742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
626763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstruct rtp_header {
636763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t cc:4;
646763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t x:1;
656763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t p:1;
666763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t v:2;
676763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
686763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t pt:7;
696763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t m:1;
706763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
716763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint16_t sequence_number;
726763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint32_t timestamp;
736763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint32_t ssrc;
746763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint32_t csrc[0];
756763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg} __attribute__ ((packed));
766763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
776763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstruct rtp_payload {
786763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t frame_count:4;
796763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t rfa0:1;
806763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t is_last_fragment:1;
816763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t is_first_fragment:1;
826763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t is_fragmented:1;
836763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg} __attribute__ ((packed));
846763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
856763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstruct bluetooth_a2dp {
866763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	sbc_t sbc;			/* Codec data */
876763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	int samples;			/* Number of encoded samples */
886763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	time_t timestamp;		/* Codec samples timestamp */
896763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t buffer[BUFFER_SIZE];	/* Codec transfer buffer */
906763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	int count;			/* Codec transfer buffer counter */
916763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
926763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	int nsamples;			/* Cumulative number of codec samples */
936763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	struct timeval ntimestamp;	/* Cumulative timeval */
946763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint16_t seq_num;		/* */
956763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	int frame_count;		/* */
966763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
97e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	pthread_t hw_thread;		/* Makes virtual hw pointer move */
98e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	int pipefd[2];			/* Inter thread communication */
996763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg};
1006763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
101b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstruct bluetooth_data {
102b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	snd_pcm_ioplug_t io;
103e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	volatile snd_pcm_sframes_t hw_ptr;
1048742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct ipc_data_cfg cfg;	/* Bluetooth device config */
1059494c146cec1df466c2f331957748beeac8d745aJohan Hedberg	int stream_fd;			/* Audio stream filedescriptor */
1068742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	int sock;			/* Daemon unix socket */
1076763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t buffer[BUFFER_SIZE];	/* Encoded transfer buffer */
1086763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	int count;			/* Transfer buffer counter */
1096763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	struct bluetooth_a2dp a2dp;	/* a2dp data */
110b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann};
111b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
1126763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergvoid memcpy_changeendian(void *dst, const void *src, int size)
1136763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg{
1146763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	int i;
1156763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	const uint16_t *ptrsrc = src;
1166763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint16_t *ptrdst = dst;
117e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
118e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	for (i = 0; i < size / 2; i++)
1196763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		*ptrdst++ = htons(*ptrsrc++);
1206763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg}
1216763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
122b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_start(snd_pcm_ioplug_t *io)
123b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
1249217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg	DBG("bluetooth_start %p", io);
125b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
126b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
127b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
128b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
129b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_stop(snd_pcm_ioplug_t *io)
130b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
1319217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg	DBG("bluetooth_stop %p", io);
132b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
133b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
134b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
135b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
136e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedbergstatic void *a2dp_playback_hw_thread(void *param)
137e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg{
138e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	struct bluetooth_data *data = param;
139e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	unsigned int prev_periods;
140e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	double period_time;
141e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	struct timeval start;
142e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
143e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	prev_periods = 0;
144e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	period_time = 1000000.0 * data->io.period_size / data->io.rate;
145e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
146e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	gettimeofday(&start, 0);
147e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
148e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	while (1) {
149e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		unsigned long long dtime;
150e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		unsigned int periods;
151e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		struct timeval cur, delta;
152e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
153e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		gettimeofday(&cur, 0);
154e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
155e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		timersub(&cur, &start, &delta);
156e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
157e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		dtime = delta.tv_sec * 1000000 + delta.tv_usec;
158e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		periods = 1.0 * dtime / period_time;
159e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
160e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		if (periods > prev_periods) {
161e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg			char c = 'w';
162e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
163e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg			data->hw_ptr += (periods - prev_periods) *
164e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg						data->io.period_size;
165e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg			data->hw_ptr %= data->io.buffer_size;
166e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
167e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg			DBG("pointer = %ld", data->hw_ptr);
168e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
169e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg			/* Notify user that hardware pointer has moved */
170e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg			if (write(data->a2dp.pipefd[1], &c, 1) < 0)
171e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg				pthread_testcancel();
172e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
173e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg			prev_periods = periods;
174e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		}
175e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
176e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		usleep(period_time);
177e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
178e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		/* Offer opportunity to be canceled by main thread */
179e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		pthread_testcancel();
180e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	}
181e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg}
182e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedbergstatic int bluetooth_a2dp_playback_start(snd_pcm_ioplug_t *io)
183e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg{
184e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	struct bluetooth_data *data = io->private_data;
185e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	struct bluetooth_a2dp *a2dp_data = &data->a2dp;
186e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	int err;
187e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
188e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	DBG("%p", io);
189e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
190e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	assert(a2dp_data->hw_thread == 0);
191e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
192e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	err = pthread_create(&a2dp_data->hw_thread, 0,
193e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg				a2dp_playback_hw_thread, data);
194e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
195e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	DBG(" - return %d", -err);
196e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
197e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	return -err;
198e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg}
199e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
200e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedbergstatic int bluetooth_a2dp_playback_stop(snd_pcm_ioplug_t *io)
201e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg{
202e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	struct bluetooth_data *data = io->private_data;
203e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	struct bluetooth_a2dp *a2dp_data = &data->a2dp;
204e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	int err;
205e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
206e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	DBG("%p", io);
207e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
208e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	/* Beware - We can be called more than once */
209e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	if (a2dp_data->hw_thread == 0)
210e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		return 0;
211e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
212e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	err = pthread_cancel(a2dp_data->hw_thread);
213e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	if (err != 0)
214e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		goto failed;
215e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
216e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	err = pthread_join(a2dp_data->hw_thread, 0);
217e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	if (err != 0)
218e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		goto failed;
219e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
220e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	a2dp_data->hw_thread = 0;
221e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
222e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedbergfailed:
223e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	DBG(" - return %d", -err);
224e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	return -err;
225e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg}
226e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
227b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic snd_pcm_sframes_t bluetooth_pointer(snd_pcm_ioplug_t *io)
228b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
229b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	struct bluetooth_data *data = io->private_data;
230b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
2316763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg#if 0
2326763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	DBG("bluetooth_pointer %p, hw_ptr=%lu", io, data->hw_ptr);
2336763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg#endif
234b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
235b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return data->hw_ptr;
236b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
237b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
2385ed2a3ba745856206c66d8ecb98afb8a1f9ec7b5Luiz Augusto von Dentzstatic void bluetooth_exit(struct bluetooth_data *data)
2395ed2a3ba745856206c66d8ecb98afb8a1f9ec7b5Luiz Augusto von Dentz{
2405ed2a3ba745856206c66d8ecb98afb8a1f9ec7b5Luiz Augusto von Dentz	if (data->sock >= 0)
2415ed2a3ba745856206c66d8ecb98afb8a1f9ec7b5Luiz Augusto von Dentz		close(data->sock);
2425ed2a3ba745856206c66d8ecb98afb8a1f9ec7b5Luiz Augusto von Dentz
2439494c146cec1df466c2f331957748beeac8d745aJohan Hedberg	if (data->stream_fd >= 0)
2449494c146cec1df466c2f331957748beeac8d745aJohan Hedberg		close(data->stream_fd);
2452a2c204cd0e4bcf0a603ba72be9a50203a817b54Luiz Augusto von Dentz
246d661010f0da37d072e9f3e0adcc94964fea6a054Luiz Augusto von Dentz	if (data->cfg.codec == CFG_CODEC_SBC)
247d661010f0da37d072e9f3e0adcc94964fea6a054Luiz Augusto von Dentz		sbc_finish(&data->a2dp.sbc);
248d661010f0da37d072e9f3e0adcc94964fea6a054Luiz Augusto von Dentz
249cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg	if (data->a2dp.pipefd[0] > 0)
250e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		close(data->a2dp.pipefd[0]);
251e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
252cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg	if (data->a2dp.pipefd[1] > 0)
253e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		close(data->a2dp.pipefd[1]);
254e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
2555ed2a3ba745856206c66d8ecb98afb8a1f9ec7b5Luiz Augusto von Dentz	free(data);
2565ed2a3ba745856206c66d8ecb98afb8a1f9ec7b5Luiz Augusto von Dentz}
2575ed2a3ba745856206c66d8ecb98afb8a1f9ec7b5Luiz Augusto von Dentz
258b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_close(snd_pcm_ioplug_t *io)
259b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
260b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	struct bluetooth_data *data = io->private_data;
261b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
2626763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	DBG("%p", io);
263b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
2645ed2a3ba745856206c66d8ecb98afb8a1f9ec7b5Luiz Augusto von Dentz	bluetooth_exit(data);
265b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
266b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
267b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
268b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
2698742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentzstatic int bluetooth_prepare(snd_pcm_ioplug_t *io)
2708742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
2718742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
272e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	char c = 'w';
2738742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
27400c71248e732de0230c12df4240087a6b2747179Johan Hedberg	DBG("Preparing with io->period_size = %lu, io->buffer_size = %lu",
27500c71248e732de0230c12df4240087a6b2747179Johan Hedberg			io->period_size, io->buffer_size);
2768742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
2779217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg	if (io->stream == SND_PCM_STREAM_PLAYBACK)
27800c71248e732de0230c12df4240087a6b2747179Johan Hedberg		/* If not null for playback, xmms doesn't display time
27900c71248e732de0230c12df4240087a6b2747179Johan Hedberg		 * correctly */
2808742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->hw_ptr = 0;
2819217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg	else
28200c71248e732de0230c12df4240087a6b2747179Johan Hedberg		/* ALSA library is really picky on the fact hw_ptr is not null.
28300c71248e732de0230c12df4240087a6b2747179Johan Hedberg		 * If it is, capture won't start */
2848742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		data->hw_ptr = io->period_size;
2859217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg
286e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	/* a2dp : wake up any client polling at us */
287e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	return write(data->a2dp.pipefd[1], &c, 1);
2888742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
2898742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
290afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentzstatic int bluetooth_hsp_hw_params(snd_pcm_ioplug_t *io,
291afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz					snd_pcm_hw_params_t *params)
2928742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
2938742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
2948742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	uint32_t period_count = io->buffer_size / io->period_size;
295c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	int opt_name, err;
2969217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg
2976e1dd6ef0f595cf51204545e2aa5d6b90225fee4Marcel Holtmann	DBG("fd = %d, period_count = %d", data->stream_fd, period_count);
298ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz
29900c71248e732de0230c12df4240087a6b2747179Johan Hedberg	opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
30000c71248e732de0230c12df4240087a6b2747179Johan Hedberg			SCO_TXBUFS : SCO_RXBUFS;
3018742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
3029494c146cec1df466c2f331957748beeac8d745aJohan Hedberg	if (setsockopt(data->stream_fd, SOL_SCO, opt_name, &period_count,
3039217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg			sizeof(period_count)) == 0)
3048742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		return 0;
3059217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg
30600c71248e732de0230c12df4240087a6b2747179Johan Hedberg	opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
3076763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg			SO_SNDBUF : SO_RCVBUF;
30800c71248e732de0230c12df4240087a6b2747179Johan Hedberg
3099494c146cec1df466c2f331957748beeac8d745aJohan Hedberg	if (setsockopt(data->stream_fd, SOL_SCO, opt_name, &period_count,
31000c71248e732de0230c12df4240087a6b2747179Johan Hedberg			sizeof(period_count)) == 0)
3119217b7d4f85216946943ab588e06b6bcd2f1b5bcJohan Hedberg		return 0;
31200c71248e732de0230c12df4240087a6b2747179Johan Hedberg
313c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	err = errno;
314c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	SNDERR("%s (%d)", strerror(err), err);
31500c71248e732de0230c12df4240087a6b2747179Johan Hedberg
316c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	return -err;
3178742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
3188742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
319afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentzstatic int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io,
320afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz					snd_pcm_hw_params_t *params)
321afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz{
322afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
323afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz	uint32_t period_count = io->buffer_size / io->period_size;
324afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz	int opt_name, err;
325afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz	struct timeval t = { 0, period_count };
326afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz
327afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz	DBG("fd = %d, period_count = %d", data->stream_fd, period_count);
328afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz
329afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz	opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
330afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz			SO_SNDTIMEO : SO_RCVTIMEO;
331afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz
332afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz	if (setsockopt(data->stream_fd, SOL_SOCKET, opt_name, &t,
333afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz			sizeof(t)) == 0)
334afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz		return 0;
335afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz
336afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz	err = errno;
337e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
338afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz	SNDERR("%s (%d)", strerror(err), err);
339afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz
340afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz	return -err;
341afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz}
342afc2f9e31b18b2572e90902c86d6b75368e1e9c6Luiz Augusto von Dentz
343e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedbergstatic int bluetooth_poll_descriptors(snd_pcm_ioplug_t *io,
344e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg					struct pollfd *pfd,
345e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg					unsigned int space)
346e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg{
347e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	struct bluetooth_data *data = io->private_data;
348e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
349e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	assert(io);
350e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
351e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	if (space < 1)
352e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		return 0;
353e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
354e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	pfd[0].fd = data->stream_fd;
355e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	pfd[0].events = POLLIN;
356e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	pfd[0].revents = 0;
357e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
358e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	return 1;
359e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg}
360e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
361e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedbergstatic int bluetooth_poll_revents(snd_pcm_ioplug_t *io ATTRIBUTE_UNUSED,
362e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg					struct pollfd *pfds, unsigned int nfds,
363e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg					unsigned short *revents)
364e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg{
365e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	assert(pfds && nfds == 1 && revents);
366e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
367e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	*revents = pfds[0].revents;
368e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
369e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	return 0;
370e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg}
371e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
372e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedbergstatic int bluetooth_a2dp_playback_poll_descriptors(snd_pcm_ioplug_t *io,
373e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg							struct pollfd *pfd,
374e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg							unsigned int space)
375e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg{
376e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	struct bluetooth_data *data = io->private_data;
377e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
378e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	DBG("");
379e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
380e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	assert(data->a2dp.pipefd[0] >= 0);
381e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
382e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	if (space < 1)
383e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		return 0;
384e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
385e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	pfd[0].fd = data->a2dp.pipefd[0];
386e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	pfd[0].events = POLLIN;
387e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	pfd[0].revents = 0;
388e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
389e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	return 1;
390e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg}
391e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
392e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedbergstatic int bluetooth_a2dp_playback_poll_revents(snd_pcm_ioplug_t *io,
393e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg						struct pollfd *pfds,
394e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg						unsigned int nfds,
395e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg						unsigned short *revents)
396e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg{
397e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	static char buf[1];
398e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	int ret;
399e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
400e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	DBG("");
401e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
402e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	assert(pfds);
403e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	assert(nfds == 1);
404e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	assert(revents);
405e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	assert(pfds[0].fd >= 0);
406e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
407e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	if (io->state != SND_PCM_STATE_PREPARED)
408e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		ret = read(pfds[0].fd, buf, 1);
409e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
410e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	*revents = (pfds[0].revents & ~POLLIN) | POLLOUT;
411e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
412e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	return 0;
413e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg}
414e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
415e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
4166763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstatic snd_pcm_sframes_t bluetooth_hsp_read(snd_pcm_ioplug_t *io,
4176763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						const snd_pcm_channel_area_t *areas,
4186763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						snd_pcm_uframes_t offset,
4196763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						snd_pcm_uframes_t size)
4208742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
4218742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
4228742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct ipc_data_cfg cfg = data->cfg;
42300c71248e732de0230c12df4240087a6b2747179Johan Hedberg	snd_pcm_uframes_t frames_to_write, ret;
42400c71248e732de0230c12df4240087a6b2747179Johan Hedberg	unsigned char *buff;
425f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz	int nrecv, frame_size = 0;
4268742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4276763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu,"
4286763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		"io->nonblock=%u", areas->step, areas->first, offset, size,
4296763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		io->nonblock);
4308742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
43100c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (data->count > 0)
43200c71248e732de0230c12df4240087a6b2747179Johan Hedberg		goto proceed;
43300c71248e732de0230c12df4240087a6b2747179Johan Hedberg
434f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz	frame_size = areas->step / 8;
435f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz
4369494c146cec1df466c2f331957748beeac8d745aJohan Hedberg	nrecv = recv(data->stream_fd, data->buffer, cfg.pkt_len,
43700c71248e732de0230c12df4240087a6b2747179Johan Hedberg			MSG_WAITALL | (io->nonblock ? MSG_DONTWAIT : 0));
43800c71248e732de0230c12df4240087a6b2747179Johan Hedberg
43900c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (nrecv < 0) {
44000c71248e732de0230c12df4240087a6b2747179Johan Hedberg		ret = (errno == EPIPE) ? -EIO : -errno;
44100c71248e732de0230c12df4240087a6b2747179Johan Hedberg		goto done;
4428742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
44300c71248e732de0230c12df4240087a6b2747179Johan Hedberg
44400c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (nrecv != cfg.pkt_len) {
44500c71248e732de0230c12df4240087a6b2747179Johan Hedberg		ret = -EIO;
44600c71248e732de0230c12df4240087a6b2747179Johan Hedberg		SNDERR(strerror(-ret));
44700c71248e732de0230c12df4240087a6b2747179Johan Hedberg		goto done;
4488742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
4498742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
45000c71248e732de0230c12df4240087a6b2747179Johan Hedberg	/* Increment hardware transmition pointer */
4516763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) %
4526763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg			io->buffer_size;
45300c71248e732de0230c12df4240087a6b2747179Johan Hedberg
45400c71248e732de0230c12df4240087a6b2747179Johan Hedbergproceed:
4556763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	buff = (unsigned char *) areas->addr +
4566763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg			(areas->first + areas->step * offset) / 8;
45700c71248e732de0230c12df4240087a6b2747179Johan Hedberg
4582a2c204cd0e4bcf0a603ba72be9a50203a817b54Luiz Augusto von Dentz	if ((data->count + size * frame_size) <= cfg.pkt_len)
45900c71248e732de0230c12df4240087a6b2747179Johan Hedberg		frames_to_write = size;
46000c71248e732de0230c12df4240087a6b2747179Johan Hedberg	else
461f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz		frames_to_write = (cfg.pkt_len - data->count) / frame_size;
46200c71248e732de0230c12df4240087a6b2747179Johan Hedberg
463f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz	memcpy(buff, data->buffer + data->count, frame_size * frames_to_write);
464f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz	data->count += (frame_size * frames_to_write);
46500c71248e732de0230c12df4240087a6b2747179Johan Hedberg	data->count %= cfg.pkt_len;
46600c71248e732de0230c12df4240087a6b2747179Johan Hedberg
46700c71248e732de0230c12df4240087a6b2747179Johan Hedberg	/* Return written frames count */
46800c71248e732de0230c12df4240087a6b2747179Johan Hedberg	ret = frames_to_write;
46900c71248e732de0230c12df4240087a6b2747179Johan Hedberg
47000c71248e732de0230c12df4240087a6b2747179Johan Hedbergdone:
47100c71248e732de0230c12df4240087a6b2747179Johan Hedberg	DBG("returning %lu", ret);
4728742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	return ret;
4738742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
4748742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
4756763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstatic snd_pcm_sframes_t bluetooth_hsp_write(snd_pcm_ioplug_t *io,
4766763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						const snd_pcm_channel_area_t *areas,
4776763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						snd_pcm_uframes_t offset,
4786763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						snd_pcm_uframes_t size)
4798742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
4808742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
4818742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	struct ipc_data_cfg cfg = data->cfg;
4828742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	snd_pcm_sframes_t ret = 0;
4838742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	snd_pcm_uframes_t frames_to_read;
484c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	uint8_t *buff;
485f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz	int rsend, frame_size;
4868742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
48700c71248e732de0230c12df4240087a6b2747179Johan Hedberg	DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu,"
48800c71248e732de0230c12df4240087a6b2747179Johan Hedberg			"io->nonblock=%u", areas->step, areas->first,
48900c71248e732de0230c12df4240087a6b2747179Johan Hedberg			offset, size, io->nonblock);
4908742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
491f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz	frame_size = areas->step / 8;
492f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz	if ((data->count + size * frame_size) <= cfg.pkt_len)
4938742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		frames_to_read = size;
4948742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	else
495f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz		frames_to_read = (cfg.pkt_len - data->count) / frame_size;
4968742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
497c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	DBG("count = %d, frames_to_read = %lu", data->count, frames_to_read);
498c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz
4998742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	/* Ready for more data */
5006763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	buff = (uint8_t *) areas->addr +
5016763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg			(areas->first + areas->step * offset) / 8;
502f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz	memcpy(data->buffer + data->count, buff, frame_size * frames_to_read);
5038742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
5046763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	/* Remember we have some frames in the pipe now */
5052a2c204cd0e4bcf0a603ba72be9a50203a817b54Luiz Augusto von Dentz	data->count += frames_to_read * frame_size;
5062a2c204cd0e4bcf0a603ba72be9a50203a817b54Luiz Augusto von Dentz	if (data->count != cfg.pkt_len) {
5078742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		ret = frames_to_read;
50800c71248e732de0230c12df4240087a6b2747179Johan Hedberg		goto done;
5098742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
5108742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
5119494c146cec1df466c2f331957748beeac8d745aJohan Hedberg	rsend = send(data->stream_fd, data->buffer, cfg.pkt_len,
512c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz			io->nonblock ? MSG_DONTWAIT : 0);
51300c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (rsend > 0) {
51400c71248e732de0230c12df4240087a6b2747179Johan Hedberg		/* Reset count pointer */
51500c71248e732de0230c12df4240087a6b2747179Johan Hedberg		data->count = 0;
51600c71248e732de0230c12df4240087a6b2747179Johan Hedberg
51700c71248e732de0230c12df4240087a6b2747179Johan Hedberg		/* Increment hardware transmition pointer */
518f6ca761e65a9318e0173ade27501fb41604ee14cLuiz Augusto von Dentz		data->hw_ptr = (data->hw_ptr + cfg.pkt_len / frame_size)
519c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz				% io->buffer_size;
52000c71248e732de0230c12df4240087a6b2747179Johan Hedberg
52100c71248e732de0230c12df4240087a6b2747179Johan Hedberg		ret = frames_to_read;
52200c71248e732de0230c12df4240087a6b2747179Johan Hedberg	} else if (rsend < 0)
52300c71248e732de0230c12df4240087a6b2747179Johan Hedberg		ret = (errno == EPIPE) ? -EIO : -errno;
52400c71248e732de0230c12df4240087a6b2747179Johan Hedberg	else
52500c71248e732de0230c12df4240087a6b2747179Johan Hedberg		ret = -EIO;
52600c71248e732de0230c12df4240087a6b2747179Johan Hedberg
52700c71248e732de0230c12df4240087a6b2747179Johan Hedbergdone:
5286763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	DBG("returning %lu", ret);
5296763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	return ret;
5306763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg}
5316763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
5326763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstatic snd_pcm_sframes_t bluetooth_a2dp_read(snd_pcm_ioplug_t *io,
5336763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						const snd_pcm_channel_area_t *areas,
5346763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						snd_pcm_uframes_t offset,
5356763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						snd_pcm_uframes_t size)
5366763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg{
5376763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	snd_pcm_uframes_t ret = 0;
5386763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	return ret;
5396763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg}
5406763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
541e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedbergstatic int avdtp_write(struct bluetooth_data *data)
5426763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg{
543e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	int ret = 0;
5446763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	struct rtp_header *header;
5456763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	struct rtp_payload *payload;
5469494c146cec1df466c2f331957748beeac8d745aJohan Hedberg	struct bluetooth_a2dp *a2dp = &data->a2dp;
5476763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
548e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	DBG("");
5496763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	header = (void *) a2dp->buffer;
5506763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	payload = (void *) (a2dp->buffer + sizeof(*header));
5516763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
5526763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	memset(a2dp->buffer, 0, sizeof(*header) + sizeof(*payload));
5536763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
5546763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	payload->frame_count = a2dp->frame_count;
5556763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	header->v = 2;
5566763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	header->pt = 1;
5576763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	header->sequence_number = htons(a2dp->seq_num);
5586763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	header->timestamp = htonl(a2dp->nsamples);
5596763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	header->ssrc = htonl(1);
5606763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
561e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	ret = send(data->stream_fd, a2dp->buffer, a2dp->count,
562e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg				MSG_DONTWAIT);
563cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg	if (ret == -1)
564e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		ret = -errno;
5658905b2bad9aebd0911d452b53b9cbe975ad5bdccJohan Hedberg
566e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	/* Kernel side l2cap socket layer makes sure either everything
567e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	   is buffered for sending, or nothing is buffered.
568e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	   This assertion is to remind people of this fact (and be noticed
569e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	   the day that changes)
570e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg 	   */
571e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	assert(ret < 0 || ret == a2dp->count);
5728905b2bad9aebd0911d452b53b9cbe975ad5bdccJohan Hedberg
5736763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	/* Reset buffer of data to send */
5746763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
5756763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->frame_count = 0;
5766763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->samples = 0;
5776763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->seq_num++;
5786763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
579f802c1c270aadd8e6c019cce1ee6a89f5c784a65Johan Hedberg	return ret;
5806763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg}
5816763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
5826763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstatic snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,
5836763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						const snd_pcm_channel_area_t *areas,
5846763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						snd_pcm_uframes_t offset,
5856763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg						snd_pcm_uframes_t size)
5866763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg{
5876763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	struct bluetooth_data *data = io->private_data;
5886763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	struct bluetooth_a2dp *a2dp = &data->a2dp;
5896763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	snd_pcm_sframes_t ret = 0;
5906763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	snd_pcm_uframes_t frames_to_read;
5916763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	int frame_size, encoded;
5926763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	uint8_t *buff;
5936763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	static int codesize = 0;
5946763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
595e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu"
596e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg			, areas->step, areas->first, offset, size);
597e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	DBG("hw_ptr = %lu, appl_ptr = %lu"
598e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg			, io->hw_ptr, io->appl_ptr);
599e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
600cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg	if (io->hw_ptr > io->appl_ptr) {
601e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		ret = bluetooth_a2dp_playback_stop(io);
602cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg		if (ret == 0)
603e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg			ret = -EPIPE;
604e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		goto done;
605e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	}
606e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
607e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	/* Check if we should autostart */
608cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg	if (io->state == SND_PCM_STATE_PREPARED) {
609e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		snd_pcm_sw_params_t *swparams;
610e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		snd_pcm_uframes_t threshold;
611e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
612e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		snd_pcm_sw_params_malloc(&swparams);
613cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg		if (!snd_pcm_sw_params_current(io->pcm, swparams)
614e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		   && !snd_pcm_sw_params_get_start_threshold(swparams,
615e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		       &threshold) ) {
616cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg			if (io->appl_ptr >= threshold) {
617e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg				ret = snd_pcm_start(io->pcm);
618cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg				if (ret != 0)
619e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg					goto done;
620e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg			}
621e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		}
622e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		snd_pcm_sw_params_free(swparams);
623e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	}
6246763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6256763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (codesize == 0) {
6266763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		/* How much data can be encoded by sbc at a time? */
6276763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		codesize = a2dp->sbc.subbands * a2dp->sbc.blocks *
6286763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg				a2dp->sbc.channels * 2;
6296763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		/* Reserv header space in outgoing buffer */
6306763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		a2dp->count = sizeof(struct rtp_header) +
6316763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg				sizeof(struct rtp_payload);
6326763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		gettimeofday(&a2dp->ntimestamp, NULL);
6336763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	}
6346763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6356763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	frame_size = areas->step / 8;
6366763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if ((data->count + size * frame_size) <= codesize)
6376763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		frames_to_read = size;
6386763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	else
6396763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		frames_to_read = (codesize - data->count) / frame_size;
6406763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6416763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	DBG("count = %d, frames_to_read = %lu", data->count, frames_to_read);
6426763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	DBG("a2dp.count = %d cfg.pkt_len = %d", a2dp->count,
6436763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg			data->cfg.pkt_len);
6446763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6456763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	/* FIXME: If state is not streaming then return */
6466763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6476763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	/* Ready for more data */
6486763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	buff = (uint8_t *) areas->addr +
6496763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		(areas->first + areas->step * offset) / 8;
6506763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	memcpy_changeendian(data->buffer + data->count, buff,
6516763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg				frame_size * frames_to_read);
6526763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6536763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	/* Remember we have some frames in the pipe now */
6546763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	data->count += frames_to_read * frame_size;
6556763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (data->count != codesize) {
6566763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		ret = frames_to_read;
6576763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		goto done;
6586763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	}
6596763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6606763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	/* Enough data to encode (sbc wants 1k blocks) */
6616763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	encoded = sbc_encode(&(a2dp->sbc), data->buffer, codesize);
6626763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (encoded <= 0) {
6636763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		DBG("Encoding error %d", encoded);
6646763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		goto done;
6656763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	}
6666763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6676763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	data->count -= encoded;
6686763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6696763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	DBG("encoded = %d  a2dp.sbc.len= %d", encoded, a2dp->sbc.len);
6706763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
671f802c1c270aadd8e6c019cce1ee6a89f5c784a65Johan Hedberg	if (a2dp->count + a2dp->sbc.len >= data->cfg.pkt_len) {
672e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		ret = avdtp_write(data);
673f802c1c270aadd8e6c019cce1ee6a89f5c784a65Johan Hedberg		if (ret < 0) {
674f802c1c270aadd8e6c019cce1ee6a89f5c784a65Johan Hedberg			if (-ret == EPIPE)
675f802c1c270aadd8e6c019cce1ee6a89f5c784a65Johan Hedberg				ret = -EIO;
676f802c1c270aadd8e6c019cce1ee6a89f5c784a65Johan Hedberg			goto done;
677f802c1c270aadd8e6c019cce1ee6a89f5c784a65Johan Hedberg		}
678f802c1c270aadd8e6c019cce1ee6a89f5c784a65Johan Hedberg	}
6796763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6806763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	memcpy(a2dp->buffer + a2dp->count, a2dp->sbc.data, a2dp->sbc.len);
6816763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->count += a2dp->sbc.len;
6826763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->frame_count++;
6836763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->samples += encoded / frame_size;
6846763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->nsamples += encoded / frame_size;
6856763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6866763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	ret = frames_to_read;
6876763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
6886763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergdone:
689e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	DBG("returning %ld", ret);
6908742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	return ret;
6918742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
6928742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
6936763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstatic snd_pcm_ioplug_callback_t bluetooth_hsp_playback = {
694e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.start			= bluetooth_start,
695e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.stop			= bluetooth_stop,
696e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.pointer		= bluetooth_pointer,
697e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.close			= bluetooth_close,
698e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.hw_params		= bluetooth_hsp_hw_params,
699e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.prepare		= bluetooth_prepare,
700e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.transfer		= bluetooth_hsp_write,
701e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.poll_descriptors	= bluetooth_poll_descriptors,
702e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.poll_revents		= bluetooth_poll_revents,
7036763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg};
7046763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
7056763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstatic snd_pcm_ioplug_callback_t bluetooth_hsp_capture = {
706e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.start			= bluetooth_start,
707e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.stop			= bluetooth_stop,
708e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.pointer		= bluetooth_pointer,
709e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.close			= bluetooth_close,
710e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.hw_params		= bluetooth_hsp_hw_params,
711e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.prepare		= bluetooth_prepare,
712e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.transfer		= bluetooth_hsp_read,
713e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.poll_descriptors	= bluetooth_poll_descriptors,
714e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.poll_revents		= bluetooth_poll_revents,
715b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann};
716b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
7176763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstatic snd_pcm_ioplug_callback_t bluetooth_a2dp_playback = {
718e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.start			= bluetooth_a2dp_playback_start,
719e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.stop			= bluetooth_a2dp_playback_stop,
720e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.pointer		= bluetooth_pointer,
721e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.close			= bluetooth_close,
722e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.hw_params		= bluetooth_a2dp_hw_params,
723e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.prepare		= bluetooth_prepare,
724e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.transfer		= bluetooth_a2dp_write,
725e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.poll_descriptors	= bluetooth_a2dp_playback_poll_descriptors,
726e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.poll_revents		= bluetooth_a2dp_playback_poll_revents,
7276763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg};
7286763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
7296763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstatic snd_pcm_ioplug_callback_t bluetooth_a2dp_capture = {
730e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.start			= bluetooth_start,
731e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.stop			= bluetooth_stop,
732e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.pointer		= bluetooth_pointer,
733e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.close			= bluetooth_close,
734e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.hw_params		= bluetooth_a2dp_hw_params,
735e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.prepare		= bluetooth_prepare,
736e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.transfer		= bluetooth_a2dp_read,
737e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.poll_descriptors	= bluetooth_poll_descriptors,
738e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	.poll_revents		= bluetooth_poll_revents,
739b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann};
740b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
741b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann#define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0]))
742b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
743b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannstatic int bluetooth_hw_constraint(snd_pcm_ioplug_t *io)
744b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann{
745c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	struct bluetooth_data *data = io->private_data;
746c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	struct ipc_data_cfg cfg = data->cfg;
747b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	snd_pcm_access_t access_list[] = {
748b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SND_PCM_ACCESS_RW_INTERLEAVED,
749b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		/* Mmap access is really useless fo this driver, but we
750b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		 * support it because some pieces of software out there
751b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		 * insist on using it */
752b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SND_PCM_ACCESS_MMAP_INTERLEAVED
753b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	};
754b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	unsigned int format_list[] = {
755b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		SND_PCM_FORMAT_S16_LE
756b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	};
757b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	int err;
758b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
759c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	/* access type */
760b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
761b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann					ARRAY_NELEMS(access_list), access_list);
762b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
763b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
764b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
765c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	/* supported formats */
766b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
767b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann					ARRAY_NELEMS(format_list), format_list);
768b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
769b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
770b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
771c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	/* supported channels */
772c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
773c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz					cfg.channels, cfg.channels);
774b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
775b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
776b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
77735b7eb29eebf1a85fce60aa0b946ff2e04ebf684Luiz Augusto von Dentz	/* supported rate */
778c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,
779c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz					cfg.rate, cfg.rate);
780b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
781b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
782b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
78335b7eb29eebf1a85fce60aa0b946ff2e04ebf684Luiz Augusto von Dentz	/* supported block size */
784c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
785c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz					cfg.pkt_len, cfg.pkt_len);
786b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
787b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
788b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
789c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS,
790e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg					2, 50);
791b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
792b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		return err;
793b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
794b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
795b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann}
796b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
797ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentzstatic int bluetooth_recvmsg_fd(struct bluetooth_data *data)
798ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz{
799ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	char cmsg_b[CMSG_SPACE(sizeof(int))];
800ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	struct ipc_packet pkt;
801ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	int err, ret;
802ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	struct iovec iov = {
803ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz		.iov_base = &pkt,
804ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz		.iov_len  = sizeof(pkt)
805ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz        };
806ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	struct msghdr msgh = {
807e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		.msg_name	= 0,
808e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		.msg_namelen	= 0,
809e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		.msg_iov	= &iov,
810e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		.msg_iovlen	= 1,
811e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		.msg_control	= &cmsg_b,
812e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		.msg_controllen	= CMSG_LEN(sizeof(int)),
813e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		.msg_flags	= 0
814ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	};
815ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz
816ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	ret = recvmsg(data->sock, &msgh, 0);
817ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	if (ret < 0) {
818ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz		err = errno;
819ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz		SNDERR("Unable to receive fd: %s (%d)", strerror(err), err);
820ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz		return -err;
821ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	}
822ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz
823e703434f83af5a41cb2f27604aedc8b2d15024e2Johan Hedberg	if (pkt.type == PKT_TYPE_CFG_RSP) {
824ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz		struct cmsghdr *cmsg;
825ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz		/* Receive auxiliary data in msgh */
826ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz		for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
827e703434f83af5a41cb2f27604aedc8b2d15024e2Johan Hedberg				cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
828ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz			if (cmsg->cmsg_level == SOL_SOCKET
829ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz				&& cmsg->cmsg_type == SCM_RIGHTS)
8309494c146cec1df466c2f331957748beeac8d745aJohan Hedberg				data->stream_fd = (*(int *) CMSG_DATA(cmsg));
8319494c146cec1df466c2f331957748beeac8d745aJohan Hedberg				DBG("stream_fd = %d", data->stream_fd);
832ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz				return 0;
833ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz		}
834ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	}
835ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	else
836ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz		SNDERR("Unexpected packet type received: type = %d", pkt.type);
837ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz
838ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	return -EINVAL;
839ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz}
840ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz
8416763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstatic int bluetooth_a2dp_init(struct bluetooth_data *data,
8426763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg				struct ipc_codec_sbc *sbc)
8435ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann{
8446763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	struct bluetooth_a2dp *a2dp = &data->a2dp;
8456763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	struct ipc_data_cfg *cfg = &data->cfg;
8468742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
8476763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (cfg == NULL) {
8486763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		SNDERR("Error getting codec parameters");
8496763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -1;
8506763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	}
85100c71248e732de0230c12df4240087a6b2747179Johan Hedberg
8526763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (cfg->codec != CFG_CODEC_SBC)
8536763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -1;
8546763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
8556763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	/* FIXME: init using flags? */
8566763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	sbc_init(&a2dp->sbc, 0);
8576763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->sbc.rate = cfg->rate;
8586763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->sbc.channels = cfg->channels;
8596763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (cfg->channel_mode == CFG_CHANNEL_MODE_MONO ||
8606763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg			cfg->channel_mode == CFG_CHANNEL_MODE_JOINT_STEREO)
8616763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		a2dp->sbc.joint = 1;
8626763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->sbc.allocation = sbc->allocation;
8636763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->sbc.subbands = sbc->subbands;
8646763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->sbc.blocks = sbc->blocks;
8656763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	a2dp->sbc.bitpool = sbc->bitpool;
86600c71248e732de0230c12df4240087a6b2747179Johan Hedberg
867e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
868cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg	if (pipe(a2dp->pipefd) != 0)
869e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		return -errno;
870cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg	if (fcntl(a2dp->pipefd[0], F_SETFL, O_NONBLOCK) != 0)
871e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		return -errno;
872cae1e4ecd14d380252b0e00f71bc6cf2887ebd31Johan Hedberg	if (fcntl(a2dp->pipefd[1], F_SETFL, O_NONBLOCK) != 0)
873e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg		return -errno;
874e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg
8756763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	return 0;
8766763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg}
8776763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
8786763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstatic int bluetooth_cfg(struct bluetooth_data *data, snd_config_t *conf)
8796763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg{
8806763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	int ret, total;
8816763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	char buf[IPC_MTU];
8826763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	struct ipc_packet *pkt = (void *) buf;
8836763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	struct ipc_data_cfg *cfg = (void *) pkt->data;
8846763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	struct ipc_codec_sbc *sbc = (void *) cfg->data;
8856763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
8866763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	DBG("Sending PKT_TYPE_CFG_REQ...");
8876763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
8886763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	memset(buf, 0, sizeof(buf));
889f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	pkt->type = PKT_TYPE_CFG_REQ;
890f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	pkt->role = PKT_ROLE_NONE;
891f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	pkt->error = PKT_ERROR_NONE;
89200c71248e732de0230c12df4240087a6b2747179Johan Hedberg
8936763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	ret = send(data->sock, pkt, sizeof(struct ipc_packet), 0);
8946763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (ret < 0)
8956763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -errno;
8966763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	else if (ret == 0)
8976763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -EIO;
89800c71248e732de0230c12df4240087a6b2747179Johan Hedberg
8996763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	DBG("OK - %d bytes sent. Waiting for response...", ret);
9008742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
9016763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	memset(buf, 0, sizeof(buf));
9028742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
9036763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	ret = recv(data->sock, buf, sizeof(*pkt) + sizeof(*cfg), 0);
9046763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (ret < 0)
9056763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -errno;
9066763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	else if (ret == 0)
9076763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -EIO;
90800c71248e732de0230c12df4240087a6b2747179Johan Hedberg
9096763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	total = ret;
910b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
911f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (pkt->type != PKT_TYPE_CFG_RSP) {
91200c71248e732de0230c12df4240087a6b2747179Johan Hedberg		SNDERR("Unexpected packet type received: type = %d",
91300c71248e732de0230c12df4240087a6b2747179Johan Hedberg				pkt->type);
9146763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -EINVAL;
9158742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
916b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
917f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (pkt->error != PKT_ERROR_NONE) {
91800c71248e732de0230c12df4240087a6b2747179Johan Hedberg		SNDERR("Error while configuring device: error = %d",
91900c71248e732de0230c12df4240087a6b2747179Johan Hedberg				pkt->error);
9206763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return pkt->error;
9218742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
922b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
9236763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (cfg->codec != CFG_CODEC_SBC)
9246763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		goto done;
9256763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
9266763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	ret = recv(data->sock, sbc, sizeof(*sbc), 0);
9276763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (ret < 0)
9286763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -errno;
9296763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	else if (ret == 0)
9306763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -EIO;
9316763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
9326763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	total += ret;
9336763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
9346763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergdone:
9356763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	DBG("OK - %d bytes received", total);
9366763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
9376763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (pkt->length != (total - sizeof(struct ipc_packet))) {
938019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley		SNDERR("Error while configuring device: packet size doesn't "
93900c71248e732de0230c12df4240087a6b2747179Johan Hedberg				"match");
9406763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -EINVAL;
9418742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	}
942b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
9436763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	memcpy(&data->cfg, cfg, sizeof(*cfg));
944b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
9458742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Device configuration:");
946f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz
9476763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	DBG("\n\tfd=%d\n\tfd_opt=%u\n\tchannels=%u\n\tpkt_len=%u\n"
9486e1dd6ef0f595cf51204545e2aa5d6b90225fee4Marcel Holtmann		"\tsample_size=%u\n\trate=%u", data->stream_fd,
9496763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		data->cfg.fd_opt, data->cfg.channels, data->cfg.pkt_len,
9506763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		data->cfg.sample_size, data->cfg.rate);
9516763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
9526763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (data->cfg.codec == CFG_CODEC_SBC) {
9536763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		struct bluetooth_a2dp *a2dp = &data->a2dp;
9546763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		ret = bluetooth_a2dp_init(data, sbc);
9556763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		if (ret < 0)
9566763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg			return ret;
9576763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		printf("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\t"
9586763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg				"bitpool=%u\n", a2dp->sbc.allocation,
9596763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg				a2dp->sbc.subbands, a2dp->sbc.blocks,
9606763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg				a2dp->sbc.bitpool);
9616763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	}
9628742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
9639494c146cec1df466c2f331957748beeac8d745aJohan Hedberg	if (data->stream_fd == -1) {
964019dd58ff876fcdaae5a7cd257822955d28b5b96Brad Midgley		SNDERR("Error while configuring device: could not acquire "
96500c71248e732de0230c12df4240087a6b2747179Johan Hedberg				"audio socket");
9666763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -EINVAL;
967f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	}
968f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz
9696763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	ret = bluetooth_recvmsg_fd(data);
9706763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (ret < 0)
9716763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return ret;
972c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz
973ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	/* It is possible there is some outstanding
974ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	data in the pipe - we have to empty it */
9759494c146cec1df466c2f331957748beeac8d745aJohan Hedberg	while (recv(data->stream_fd, data->buffer, data->cfg.pkt_len,
9766763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg				MSG_DONTWAIT) > 0);
97700c71248e732de0230c12df4240087a6b2747179Johan Hedberg
978c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz	memset(data->buffer, 0, data->cfg.pkt_len);
979c6136c57053db24e9c4e2448f25bd46f6a90b053Luiz Augusto von Dentz
9806763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	return 0;
9818742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
9828742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
9836763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedbergstatic int bluetooth_init(struct bluetooth_data *data, snd_config_t *conf)
9848742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
9856763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	int sk, err;
986ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	struct sockaddr_un addr = {
987ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz		AF_UNIX, IPC_SOCKET_NAME
988ddf8edc54d666f9b6f75f28b6db5375e2f0982a8Luiz Augusto von Dentz	};
9898742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
990f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	if (!data)
991f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		return -EINVAL;
992f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz
99300c71248e732de0230c12df4240087a6b2747179Johan Hedberg	memset(data, 0, sizeof(struct bluetooth_data));
99400c71248e732de0230c12df4240087a6b2747179Johan Hedberg
99500c71248e732de0230c12df4240087a6b2747179Johan Hedberg	data->sock = -1;
99600c71248e732de0230c12df4240087a6b2747179Johan Hedberg
9976763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	sk = socket(PF_LOCAL, SOCK_STREAM, 0);
9986763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (sk < 0) {
9996763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		err = errno;
10006763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		SNDERR("Cannot open socket: %s (%d)", strerror(err), err);
10016763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -err;
1002b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	}
1003b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
10048742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	DBG("Connecting to address: %s", addr.sun_path + 1);
1005b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
10066763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		err = errno;
10076763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		SNDERR("Connection fail", strerror(err), err);
1008b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		close(sk);
10096763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		return -err;
1010b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	}
1011b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
1012b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	data->sock = sk;
1013b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
10146763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	return bluetooth_cfg(data, conf);
10158742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz}
10168742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
10178742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von DentzSND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
10188742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz{
1019f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	struct bluetooth_data *data;
10208742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	int err;
10218742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
102200c71248e732de0230c12df4240087a6b2747179Johan Hedberg	DBG("Bluetooth PCM plugin (%s)",
10238742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture");
10248742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1025e7407648f54c18f4995eff0dc4c809b33a306fcdJohan Hedberg	data = calloc(1, sizeof(struct bluetooth_data));
102600c71248e732de0230c12df4240087a6b2747179Johan Hedberg	if (!data) {
102700c71248e732de0230c12df4240087a6b2747179Johan Hedberg		err = -ENOMEM;
102800c71248e732de0230c12df4240087a6b2747179Johan Hedberg		goto error;
102900c71248e732de0230c12df4240087a6b2747179Johan Hedberg	}
103000c71248e732de0230c12df4240087a6b2747179Johan Hedberg
10316763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	err = bluetooth_init(data, conf);
10328742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz	if (err < 0)
10338742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		goto error;
10348742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz
1035f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.version = SND_PCM_IOPLUG_VERSION;
1036f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.name = "Bluetooth Audio Device";
103700c71248e732de0230c12df4240087a6b2747179Johan Hedberg	data->io.mmap_rw = 0; /* No direct mmap communication */
1038f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	data->io.private_data = data;
1039b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
10406763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	if (data->cfg.codec == CFG_CODEC_SBC)
10416763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
10426763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg			&bluetooth_a2dp_playback :
10436763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg			&bluetooth_a2dp_capture;
10446763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg	else
10456763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg		data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
10466763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg			&bluetooth_hsp_playback :
10476763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg			&bluetooth_hsp_capture;
10486763ebb3c231740c66a235f94d56e8d8cc213d90Johan Hedberg
1049f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	err = snd_pcm_ioplug_create(&data->io, name, stream, mode);
1050b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0)
1051b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann		goto error;
1052b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
1053f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	err = bluetooth_hw_constraint(&data->io);
1054b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	if (err < 0) {
1055f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz		snd_pcm_ioplug_delete(&data->io);
10568742ce7c3e92a57cde47481281a4928f8d41a771Luiz Augusto von Dentz		goto error;
1057b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	}
1058b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
1059f1a8e719f5687bb32f2f5ed59f26a3203ad43efbLuiz Augusto von Dentz	*pcmp = data->io.pcm;
1060b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
1061b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return 0;
1062b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann
1063b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmannerror:
10645ed2a3ba745856206c66d8ecb98afb8a1f9ec7b5Luiz Augusto von Dentz	bluetooth_exit(data);
10655ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann
1066b8a407aa8470ad8d92d9142edb41c17548b0cb2cMarcel Holtmann	return err;
10675ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann}
10685ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel Holtmann
10695ad9e0ec87dd078dc2a4e70967f1e9ace1ebf43fMarcel HoltmannSND_PCM_PLUGIN_SYMBOL(bluetooth);
1070