xref: /freebsd/usr.sbin/virtual_oss/virtual_bt_speaker/bt_speaker.c (revision 9cab9fde5edad9b409dd2317a2aec7815e6d6bed)
1*9cab9fdeSChristos Margiolis /*-
2*9cab9fdeSChristos Margiolis  * Copyright (c) 2019 Google LLC, written by Richard Kralovic <riso@google.com>
3*9cab9fdeSChristos Margiolis  *
4*9cab9fdeSChristos Margiolis  * Redistribution and use in source and binary forms, with or without
5*9cab9fdeSChristos Margiolis  * modification, are permitted provided that the following conditions
6*9cab9fdeSChristos Margiolis  * are met:
7*9cab9fdeSChristos Margiolis  * 1. Redistributions of source code must retain the above copyright
8*9cab9fdeSChristos Margiolis  *    notice, this list of conditions and the following disclaimer.
9*9cab9fdeSChristos Margiolis  * 2. Redistributions in binary form must reproduce the above copyright
10*9cab9fdeSChristos Margiolis  *    notice, this list of conditions and the following disclaimer in the
11*9cab9fdeSChristos Margiolis  *    documentation and/or other materials provided with the distribution.
12*9cab9fdeSChristos Margiolis  *
13*9cab9fdeSChristos Margiolis  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14*9cab9fdeSChristos Margiolis  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*9cab9fdeSChristos Margiolis  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*9cab9fdeSChristos Margiolis  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17*9cab9fdeSChristos Margiolis  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*9cab9fdeSChristos Margiolis  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*9cab9fdeSChristos Margiolis  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*9cab9fdeSChristos Margiolis  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*9cab9fdeSChristos Margiolis  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*9cab9fdeSChristos Margiolis  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*9cab9fdeSChristos Margiolis  * SUCH DAMAGE.
24*9cab9fdeSChristos Margiolis  */
25*9cab9fdeSChristos Margiolis 
26*9cab9fdeSChristos Margiolis #include <sys/types.h>
27*9cab9fdeSChristos Margiolis #include <sys/rtprio.h>
28*9cab9fdeSChristos Margiolis #include <sys/soundcard.h>
29*9cab9fdeSChristos Margiolis 
30*9cab9fdeSChristos Margiolis #include <dlfcn.h>
31*9cab9fdeSChristos Margiolis #include <err.h>
32*9cab9fdeSChristos Margiolis #include <fcntl.h>
33*9cab9fdeSChristos Margiolis #include <stdarg.h>
34*9cab9fdeSChristos Margiolis #include <stdint.h>
35*9cab9fdeSChristos Margiolis #include <stdio.h>
36*9cab9fdeSChristos Margiolis #include <stdlib.h>
37*9cab9fdeSChristos Margiolis #include <string.h>
38*9cab9fdeSChristos Margiolis #include <sysexits.h>
39*9cab9fdeSChristos Margiolis #include <time.h>
40*9cab9fdeSChristos Margiolis #include <unistd.h>
41*9cab9fdeSChristos Margiolis #include <poll.h>
42*9cab9fdeSChristos Margiolis #include <getopt.h>
43*9cab9fdeSChristos Margiolis 
44*9cab9fdeSChristos Margiolis #define	L2CAP_SOCKET_CHECKED
45*9cab9fdeSChristos Margiolis #include <bluetooth.h>
46*9cab9fdeSChristos Margiolis #include <sdp.h>
47*9cab9fdeSChristos Margiolis 
48*9cab9fdeSChristos Margiolis #include "avdtp_signal.h"
49*9cab9fdeSChristos Margiolis #include "bt.h"
50*9cab9fdeSChristos Margiolis #include "utils.h"
51*9cab9fdeSChristos Margiolis 
52*9cab9fdeSChristos Margiolis static int (*bt_receive_f)(struct bt_config *, void *, int, int);
53*9cab9fdeSChristos Margiolis static int (*avdtpACPHandlePacket_f)(struct bt_config *cfg);
54*9cab9fdeSChristos Margiolis static void (*avdtpACPFree_f)(struct bt_config *);
55*9cab9fdeSChristos Margiolis 
56*9cab9fdeSChristos Margiolis static int bt_in_background;
57*9cab9fdeSChristos Margiolis 
58*9cab9fdeSChristos Margiolis static void
message(const char * fmt,...)59*9cab9fdeSChristos Margiolis message(const char *fmt,...)
60*9cab9fdeSChristos Margiolis {
61*9cab9fdeSChristos Margiolis 	va_list list;
62*9cab9fdeSChristos Margiolis 
63*9cab9fdeSChristos Margiolis 	if (bt_in_background)
64*9cab9fdeSChristos Margiolis 		return;
65*9cab9fdeSChristos Margiolis 
66*9cab9fdeSChristos Margiolis 	va_start(list, fmt);
67*9cab9fdeSChristos Margiolis 	vfprintf(stderr, fmt, list);
68*9cab9fdeSChristos Margiolis 	va_end(list);
69*9cab9fdeSChristos Margiolis }
70*9cab9fdeSChristos Margiolis 
71*9cab9fdeSChristos Margiolis struct bt_audio_receiver {
72*9cab9fdeSChristos Margiolis 	const char *devname;
73*9cab9fdeSChristos Margiolis 	const char *sdp_socket_path;
74*9cab9fdeSChristos Margiolis 	uint16_t l2cap_psm;
75*9cab9fdeSChristos Margiolis 	int	fd_listen;
76*9cab9fdeSChristos Margiolis 	void   *sdp_session;
77*9cab9fdeSChristos Margiolis 	uint32_t sdp_handle;
78*9cab9fdeSChristos Margiolis };
79*9cab9fdeSChristos Margiolis 
80*9cab9fdeSChristos Margiolis static int
register_sdp(struct bt_audio_receiver * r)81*9cab9fdeSChristos Margiolis register_sdp(struct bt_audio_receiver *r)
82*9cab9fdeSChristos Margiolis {
83*9cab9fdeSChristos Margiolis 	struct sdp_audio_sink_profile record = {};
84*9cab9fdeSChristos Margiolis 
85*9cab9fdeSChristos Margiolis 	r->sdp_session = sdp_open_local(r->sdp_socket_path);
86*9cab9fdeSChristos Margiolis 	if (r->sdp_session == NULL || sdp_error(r->sdp_session)) {
87*9cab9fdeSChristos Margiolis 		sdp_close(r->sdp_session);
88*9cab9fdeSChristos Margiolis 		r->sdp_session = NULL;
89*9cab9fdeSChristos Margiolis 		return (0);
90*9cab9fdeSChristos Margiolis 	}
91*9cab9fdeSChristos Margiolis 
92*9cab9fdeSChristos Margiolis 	record.psm = r->l2cap_psm;
93*9cab9fdeSChristos Margiolis 	record.protover = 0x100;
94*9cab9fdeSChristos Margiolis 	record.features = 0x01;		/* player only */
95*9cab9fdeSChristos Margiolis 
96*9cab9fdeSChristos Margiolis 	if (sdp_register_service(r->sdp_session, SDP_SERVICE_CLASS_AUDIO_SINK,
97*9cab9fdeSChristos Margiolis 	    NG_HCI_BDADDR_ANY, (const uint8_t *)&record, sizeof(record),
98*9cab9fdeSChristos Margiolis 	    &r->sdp_handle)) {
99*9cab9fdeSChristos Margiolis 		message("SDP failed to register: %s\n",
100*9cab9fdeSChristos Margiolis 		    strerror(sdp_error(r->sdp_session)));
101*9cab9fdeSChristos Margiolis 		sdp_close(r->sdp_session);
102*9cab9fdeSChristos Margiolis 		r->sdp_session = NULL;
103*9cab9fdeSChristos Margiolis 		return (0);
104*9cab9fdeSChristos Margiolis 	}
105*9cab9fdeSChristos Margiolis 	return (1);
106*9cab9fdeSChristos Margiolis }
107*9cab9fdeSChristos Margiolis 
108*9cab9fdeSChristos Margiolis static void
unregister_sdp(struct bt_audio_receiver * r)109*9cab9fdeSChristos Margiolis unregister_sdp(struct bt_audio_receiver *r)
110*9cab9fdeSChristos Margiolis {
111*9cab9fdeSChristos Margiolis 	sdp_unregister_service(r->sdp_session, r->sdp_handle);
112*9cab9fdeSChristos Margiolis 	sdp_close(r->sdp_session);
113*9cab9fdeSChristos Margiolis 	r->sdp_session = NULL;
114*9cab9fdeSChristos Margiolis }
115*9cab9fdeSChristos Margiolis 
116*9cab9fdeSChristos Margiolis static int
start_listen(struct bt_audio_receiver * r)117*9cab9fdeSChristos Margiolis start_listen(struct bt_audio_receiver *r)
118*9cab9fdeSChristos Margiolis {
119*9cab9fdeSChristos Margiolis 	struct sockaddr_l2cap addr = {};
120*9cab9fdeSChristos Margiolis 
121*9cab9fdeSChristos Margiolis 	r->fd_listen = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
122*9cab9fdeSChristos Margiolis 	if (r->fd_listen < 0)
123*9cab9fdeSChristos Margiolis 		return (0);
124*9cab9fdeSChristos Margiolis 
125*9cab9fdeSChristos Margiolis 	addr.l2cap_len = sizeof(addr);
126*9cab9fdeSChristos Margiolis 	addr.l2cap_family = AF_BLUETOOTH;
127*9cab9fdeSChristos Margiolis 	addr.l2cap_psm = r->l2cap_psm;
128*9cab9fdeSChristos Margiolis 
129*9cab9fdeSChristos Margiolis 	if (bind(r->fd_listen, (struct sockaddr *)&addr, sizeof(addr)) < 0 ||
130*9cab9fdeSChristos Margiolis 	    listen(r->fd_listen, 4) < 0) {
131*9cab9fdeSChristos Margiolis 		close(r->fd_listen);
132*9cab9fdeSChristos Margiolis 		return (0);
133*9cab9fdeSChristos Margiolis 	}
134*9cab9fdeSChristos Margiolis 	return (1);
135*9cab9fdeSChristos Margiolis }
136*9cab9fdeSChristos Margiolis 
137*9cab9fdeSChristos Margiolis static void
stop_listen(struct bt_audio_receiver * r)138*9cab9fdeSChristos Margiolis stop_listen(struct bt_audio_receiver *r)
139*9cab9fdeSChristos Margiolis {
140*9cab9fdeSChristos Margiolis 	close(r->fd_listen);
141*9cab9fdeSChristos Margiolis }
142*9cab9fdeSChristos Margiolis 
143*9cab9fdeSChristos Margiolis struct bt_audio_connection {
144*9cab9fdeSChristos Margiolis 	struct bt_audio_receiver *r;
145*9cab9fdeSChristos Margiolis 	struct sockaddr_l2cap peer_addr;
146*9cab9fdeSChristos Margiolis 	struct bt_config cfg;
147*9cab9fdeSChristos Margiolis 	int	oss_fd;
148*9cab9fdeSChristos Margiolis };
149*9cab9fdeSChristos Margiolis 
150*9cab9fdeSChristos Margiolis static void
close_connection(struct bt_audio_connection * c)151*9cab9fdeSChristos Margiolis close_connection(struct bt_audio_connection *c)
152*9cab9fdeSChristos Margiolis {
153*9cab9fdeSChristos Margiolis 	avdtpACPFree_f(&c->cfg);
154*9cab9fdeSChristos Margiolis 	if (c->cfg.fd != -1)
155*9cab9fdeSChristos Margiolis 		close(c->cfg.fd);
156*9cab9fdeSChristos Margiolis 	if (c->cfg.hc != -1)
157*9cab9fdeSChristos Margiolis 		close(c->cfg.hc);
158*9cab9fdeSChristos Margiolis 	if (c->oss_fd != -1)
159*9cab9fdeSChristos Margiolis 		close(c->oss_fd);
160*9cab9fdeSChristos Margiolis 	free(c);
161*9cab9fdeSChristos Margiolis }
162*9cab9fdeSChristos Margiolis 
163*9cab9fdeSChristos Margiolis static struct bt_audio_connection *
wait_for_connection(struct bt_audio_receiver * r)164*9cab9fdeSChristos Margiolis wait_for_connection(struct bt_audio_receiver *r)
165*9cab9fdeSChristos Margiolis {
166*9cab9fdeSChristos Margiolis 	struct bt_audio_connection *c =
167*9cab9fdeSChristos Margiolis 	malloc(sizeof(struct bt_audio_connection));
168*9cab9fdeSChristos Margiolis 	socklen_t addrlen;
169*9cab9fdeSChristos Margiolis 
170*9cab9fdeSChristos Margiolis 	memset(c, 0, sizeof(*c));
171*9cab9fdeSChristos Margiolis 
172*9cab9fdeSChristos Margiolis 	c->r = r;
173*9cab9fdeSChristos Margiolis 	c->cfg.fd = -1;
174*9cab9fdeSChristos Margiolis 	c->oss_fd = -1;
175*9cab9fdeSChristos Margiolis 
176*9cab9fdeSChristos Margiolis 	addrlen = sizeof(c->peer_addr);
177*9cab9fdeSChristos Margiolis 	c->cfg.hc = accept(r->fd_listen, (struct sockaddr *)&c->peer_addr, &addrlen);
178*9cab9fdeSChristos Margiolis 
179*9cab9fdeSChristos Margiolis 	message("Accepted control connection, %d\n", c->cfg.hc);
180*9cab9fdeSChristos Margiolis 	if (c->cfg.hc < 0) {
181*9cab9fdeSChristos Margiolis 		close_connection(c);
182*9cab9fdeSChristos Margiolis 		return NULL;
183*9cab9fdeSChristos Margiolis 	}
184*9cab9fdeSChristos Margiolis 	c->cfg.sep = 0;			/* to be set later */
185*9cab9fdeSChristos Margiolis 	c->cfg.media_Type = mediaTypeAudio;
186*9cab9fdeSChristos Margiolis 	c->cfg.chmode = MODE_DUAL;
187*9cab9fdeSChristos Margiolis 	c->cfg.aacMode1 = 0;		/* TODO: support AAC */
188*9cab9fdeSChristos Margiolis 	c->cfg.aacMode2 = 0;
189*9cab9fdeSChristos Margiolis 	c->cfg.acceptor_state = acpInitial;
190*9cab9fdeSChristos Margiolis 
191*9cab9fdeSChristos Margiolis 	return (c);
192*9cab9fdeSChristos Margiolis }
193*9cab9fdeSChristos Margiolis 
194*9cab9fdeSChristos Margiolis static void
setup_oss(struct bt_audio_connection * c)195*9cab9fdeSChristos Margiolis setup_oss(struct bt_audio_connection *c)
196*9cab9fdeSChristos Margiolis {
197*9cab9fdeSChristos Margiolis 	c->oss_fd = open(c->r->devname, O_WRONLY);
198*9cab9fdeSChristos Margiolis 
199*9cab9fdeSChristos Margiolis 	if (c->oss_fd < 0)
200*9cab9fdeSChristos Margiolis 		goto err;
201*9cab9fdeSChristos Margiolis 
202*9cab9fdeSChristos Margiolis 	int v;
203*9cab9fdeSChristos Margiolis 
204*9cab9fdeSChristos Margiolis 	switch (c->cfg.chmode) {
205*9cab9fdeSChristos Margiolis 	case MODE_STEREO:
206*9cab9fdeSChristos Margiolis 	case MODE_JOINT:
207*9cab9fdeSChristos Margiolis 	case MODE_DUAL:
208*9cab9fdeSChristos Margiolis 		v = 2;
209*9cab9fdeSChristos Margiolis 		break;
210*9cab9fdeSChristos Margiolis 	case MODE_MONO:
211*9cab9fdeSChristos Margiolis 		v = 1;
212*9cab9fdeSChristos Margiolis 		break;
213*9cab9fdeSChristos Margiolis 	default:
214*9cab9fdeSChristos Margiolis 		message("Wrong chmode\n");
215*9cab9fdeSChristos Margiolis 		goto err;
216*9cab9fdeSChristos Margiolis 	}
217*9cab9fdeSChristos Margiolis 
218*9cab9fdeSChristos Margiolis 	if (ioctl(c->oss_fd, SNDCTL_DSP_CHANNELS, &v) < 0) {
219*9cab9fdeSChristos Margiolis 		message("SNDCTL_DSP_CHANNELS failed\n");
220*9cab9fdeSChristos Margiolis 		goto err;
221*9cab9fdeSChristos Margiolis 	}
222*9cab9fdeSChristos Margiolis 	v = AFMT_S16_NE;
223*9cab9fdeSChristos Margiolis 	if (ioctl(c->oss_fd, SNDCTL_DSP_SETFMT, &v) < 0) {
224*9cab9fdeSChristos Margiolis 		message("SNDCTL_DSP_SETFMT failed\n");
225*9cab9fdeSChristos Margiolis 		goto err;
226*9cab9fdeSChristos Margiolis 	}
227*9cab9fdeSChristos Margiolis 	switch (c->cfg.freq) {
228*9cab9fdeSChristos Margiolis 	case FREQ_16K:
229*9cab9fdeSChristos Margiolis 		v = 16000;
230*9cab9fdeSChristos Margiolis 		break;
231*9cab9fdeSChristos Margiolis 	case FREQ_32K:
232*9cab9fdeSChristos Margiolis 		v = 32000;
233*9cab9fdeSChristos Margiolis 		break;
234*9cab9fdeSChristos Margiolis 	case FREQ_44_1K:
235*9cab9fdeSChristos Margiolis 		v = 44100;
236*9cab9fdeSChristos Margiolis 		break;
237*9cab9fdeSChristos Margiolis 	case FREQ_48K:
238*9cab9fdeSChristos Margiolis 		v = 48000;
239*9cab9fdeSChristos Margiolis 		break;
240*9cab9fdeSChristos Margiolis 	default:
241*9cab9fdeSChristos Margiolis 		message("Wrong freq\n");
242*9cab9fdeSChristos Margiolis 		goto err;
243*9cab9fdeSChristos Margiolis 	}
244*9cab9fdeSChristos Margiolis 
245*9cab9fdeSChristos Margiolis 	if (ioctl(c->oss_fd, SNDCTL_DSP_SPEED, &v) < 0) {
246*9cab9fdeSChristos Margiolis 		message("SNDCTL_DSP_SETFMT failed\n");
247*9cab9fdeSChristos Margiolis 		goto err;
248*9cab9fdeSChristos Margiolis 	}
249*9cab9fdeSChristos Margiolis 	v = (2 << 16) | 15;		/* 2 fragments of 32k each */
250*9cab9fdeSChristos Margiolis 	if (ioctl(c->oss_fd, SNDCTL_DSP_SETFRAGMENT, &v) < 0) {
251*9cab9fdeSChristos Margiolis 		message("SNDCTL_DSP_SETFRAGMENT failed\n");
252*9cab9fdeSChristos Margiolis 		goto err;
253*9cab9fdeSChristos Margiolis 	}
254*9cab9fdeSChristos Margiolis 	return;
255*9cab9fdeSChristos Margiolis 
256*9cab9fdeSChristos Margiolis err:
257*9cab9fdeSChristos Margiolis 	c->oss_fd = -1;
258*9cab9fdeSChristos Margiolis 	message("Cannot open oss device %s\n", c->r->devname);
259*9cab9fdeSChristos Margiolis }
260*9cab9fdeSChristos Margiolis 
261*9cab9fdeSChristos Margiolis static void
process_connection(struct bt_audio_connection * c)262*9cab9fdeSChristos Margiolis process_connection(struct bt_audio_connection *c)
263*9cab9fdeSChristos Margiolis {
264*9cab9fdeSChristos Margiolis 	struct pollfd pfd[3] = {};
265*9cab9fdeSChristos Margiolis 	time_t oss_attempt = 0;
266*9cab9fdeSChristos Margiolis 
267*9cab9fdeSChristos Margiolis 	while (c->cfg.acceptor_state != acpStreamClosed) {
268*9cab9fdeSChristos Margiolis 		int np;
269*9cab9fdeSChristos Margiolis 
270*9cab9fdeSChristos Margiolis 		pfd[0].fd = c->r->fd_listen;
271*9cab9fdeSChristos Margiolis 		pfd[0].events = POLLIN | POLLRDNORM;
272*9cab9fdeSChristos Margiolis 		pfd[0].revents = 0;
273*9cab9fdeSChristos Margiolis 
274*9cab9fdeSChristos Margiolis 		pfd[1].fd = c->cfg.hc;
275*9cab9fdeSChristos Margiolis 		pfd[1].events = POLLIN | POLLRDNORM;
276*9cab9fdeSChristos Margiolis 		pfd[1].revents = 0;
277*9cab9fdeSChristos Margiolis 
278*9cab9fdeSChristos Margiolis 		pfd[2].fd = c->cfg.fd;
279*9cab9fdeSChristos Margiolis 		pfd[2].events = POLLIN | POLLRDNORM;
280*9cab9fdeSChristos Margiolis 		pfd[2].revents = 0;
281*9cab9fdeSChristos Margiolis 
282*9cab9fdeSChristos Margiolis 		if (c->cfg.fd != -1)
283*9cab9fdeSChristos Margiolis 			np = 3;
284*9cab9fdeSChristos Margiolis 		else
285*9cab9fdeSChristos Margiolis 			np = 2;
286*9cab9fdeSChristos Margiolis 
287*9cab9fdeSChristos Margiolis 		if (poll(pfd, np, INFTIM) < 0)
288*9cab9fdeSChristos Margiolis 			return;
289*9cab9fdeSChristos Margiolis 
290*9cab9fdeSChristos Margiolis 		if (pfd[1].revents != 0) {
291*9cab9fdeSChristos Margiolis 			int retval;
292*9cab9fdeSChristos Margiolis 
293*9cab9fdeSChristos Margiolis 			message("Handling packet: state = %d, ",
294*9cab9fdeSChristos Margiolis 			    c->cfg.acceptor_state);
295*9cab9fdeSChristos Margiolis 			retval = avdtpACPHandlePacket_f(&c->cfg);
296*9cab9fdeSChristos Margiolis 			message("retval = %d\n", retval);
297*9cab9fdeSChristos Margiolis 			if (retval < 0)
298*9cab9fdeSChristos Margiolis 				return;
299*9cab9fdeSChristos Margiolis 		}
300*9cab9fdeSChristos Margiolis 		if (pfd[0].revents != 0) {
301*9cab9fdeSChristos Margiolis 			socklen_t addrlen = sizeof(c->peer_addr);
302*9cab9fdeSChristos Margiolis 			int fd = accept4(c->r->fd_listen,
303*9cab9fdeSChristos Margiolis 			    (struct sockaddr *)&c->peer_addr, &addrlen,
304*9cab9fdeSChristos Margiolis 			    SOCK_NONBLOCK);
305*9cab9fdeSChristos Margiolis 
306*9cab9fdeSChristos Margiolis 			if (fd < 0)
307*9cab9fdeSChristos Margiolis 				return;
308*9cab9fdeSChristos Margiolis 
309*9cab9fdeSChristos Margiolis 			if (c->cfg.fd < 0) {
310*9cab9fdeSChristos Margiolis 				if (c->cfg.acceptor_state == acpStreamOpened) {
311*9cab9fdeSChristos Margiolis 					socklen_t mtusize = sizeof(uint16_t);
312*9cab9fdeSChristos Margiolis 					c->cfg.fd = fd;
313*9cab9fdeSChristos Margiolis 
314*9cab9fdeSChristos Margiolis 					if (getsockopt(c->cfg.fd, SOL_L2CAP, SO_L2CAP_IMTU, &c->cfg.mtu, &mtusize) == -1) {
315*9cab9fdeSChristos Margiolis 						message("Could not get MTU size\n");
316*9cab9fdeSChristos Margiolis 						return;
317*9cab9fdeSChristos Margiolis 					}
318*9cab9fdeSChristos Margiolis 
319*9cab9fdeSChristos Margiolis 					int temp = c->cfg.mtu * 32;
320*9cab9fdeSChristos Margiolis 
321*9cab9fdeSChristos Margiolis 					if (setsockopt(c->cfg.fd, SOL_SOCKET, SO_RCVBUF, &temp, sizeof(temp)) == -1) {
322*9cab9fdeSChristos Margiolis 						message("Could not set send buffer size\n");
323*9cab9fdeSChristos Margiolis 						return;
324*9cab9fdeSChristos Margiolis 					}
325*9cab9fdeSChristos Margiolis 
326*9cab9fdeSChristos Margiolis 					temp = 1;
327*9cab9fdeSChristos Margiolis 					if (setsockopt(c->cfg.fd, SOL_SOCKET, SO_RCVLOWAT, &temp, sizeof(temp)) == -1) {
328*9cab9fdeSChristos Margiolis 						message("Could not set low water mark\n");
329*9cab9fdeSChristos Margiolis 						return;
330*9cab9fdeSChristos Margiolis 					}
331*9cab9fdeSChristos Margiolis 					message("Accepted data connection, %d\n", c->cfg.fd);
332*9cab9fdeSChristos Margiolis 				}
333*9cab9fdeSChristos Margiolis 			} else {
334*9cab9fdeSChristos Margiolis 				close(fd);
335*9cab9fdeSChristos Margiolis 			}
336*9cab9fdeSChristos Margiolis 		}
337*9cab9fdeSChristos Margiolis 		if (pfd[2].revents != 0) {
338*9cab9fdeSChristos Margiolis 			uint8_t data[65536];
339*9cab9fdeSChristos Margiolis 			int len;
340*9cab9fdeSChristos Margiolis 
341*9cab9fdeSChristos Margiolis 			if ((len = bt_receive_f(&c->cfg, data, sizeof(data), 0)) < 0) {
342*9cab9fdeSChristos Margiolis 				return;
343*9cab9fdeSChristos Margiolis 			}
344*9cab9fdeSChristos Margiolis 			if (c->cfg.acceptor_state != acpStreamSuspended &&
345*9cab9fdeSChristos Margiolis 			    c->oss_fd < 0 &&
346*9cab9fdeSChristos Margiolis 			    time(NULL) != oss_attempt) {
347*9cab9fdeSChristos Margiolis 				message("Trying to open dsp\n");
348*9cab9fdeSChristos Margiolis 				setup_oss(c);
349*9cab9fdeSChristos Margiolis 				oss_attempt = time(NULL);
350*9cab9fdeSChristos Margiolis 			}
351*9cab9fdeSChristos Margiolis 			if (c->oss_fd > -1) {
352*9cab9fdeSChristos Margiolis 				uint8_t *end = data + len;
353*9cab9fdeSChristos Margiolis 				uint8_t *ptr = data;
354*9cab9fdeSChristos Margiolis 				unsigned delay;
355*9cab9fdeSChristos Margiolis 				unsigned jitter_limit;
356*9cab9fdeSChristos Margiolis 
357*9cab9fdeSChristos Margiolis 				switch (c->cfg.freq) {
358*9cab9fdeSChristos Margiolis 				case FREQ_16K:
359*9cab9fdeSChristos Margiolis 					jitter_limit = (16000 / 20);
360*9cab9fdeSChristos Margiolis 					break;
361*9cab9fdeSChristos Margiolis 				case FREQ_32K:
362*9cab9fdeSChristos Margiolis 					jitter_limit = (32000 / 20);
363*9cab9fdeSChristos Margiolis 					break;
364*9cab9fdeSChristos Margiolis 				case FREQ_44_1K:
365*9cab9fdeSChristos Margiolis 					jitter_limit = (44100 / 20);
366*9cab9fdeSChristos Margiolis 					break;
367*9cab9fdeSChristos Margiolis 				default:
368*9cab9fdeSChristos Margiolis 					jitter_limit = (48000 / 20);
369*9cab9fdeSChristos Margiolis 					break;
370*9cab9fdeSChristos Margiolis 				}
371*9cab9fdeSChristos Margiolis 
372*9cab9fdeSChristos Margiolis 				if (c->cfg.chmode == MODE_MONO) {
373*9cab9fdeSChristos Margiolis 					if (len >= 2 &&
374*9cab9fdeSChristos Margiolis 					    ioctl(c->oss_fd, SNDCTL_DSP_GETODELAY, &delay) == 0 &&
375*9cab9fdeSChristos Margiolis 					    delay < (jitter_limit * 2)) {
376*9cab9fdeSChristos Margiolis 						uint8_t jitter[jitter_limit * 4] __aligned(4);
377*9cab9fdeSChristos Margiolis 						size_t x;
378*9cab9fdeSChristos Margiolis 
379*9cab9fdeSChristos Margiolis 						/* repeat last sample */
380*9cab9fdeSChristos Margiolis 						for (x = 0; x != sizeof(jitter); x++)
381*9cab9fdeSChristos Margiolis 							jitter[x] = ptr[x % 2];
382*9cab9fdeSChristos Margiolis 
383*9cab9fdeSChristos Margiolis 						write(c->oss_fd, jitter, sizeof(jitter));
384*9cab9fdeSChristos Margiolis 					}
385*9cab9fdeSChristos Margiolis 				} else {
386*9cab9fdeSChristos Margiolis 					if (len >= 4 &&
387*9cab9fdeSChristos Margiolis 					    ioctl(c->oss_fd, SNDCTL_DSP_GETODELAY, &delay) == 0 &&
388*9cab9fdeSChristos Margiolis 					    delay < (jitter_limit * 4)) {
389*9cab9fdeSChristos Margiolis 						uint8_t jitter[jitter_limit * 8] __aligned(4);
390*9cab9fdeSChristos Margiolis 						size_t x;
391*9cab9fdeSChristos Margiolis 
392*9cab9fdeSChristos Margiolis 						/* repeat last sample */
393*9cab9fdeSChristos Margiolis 						for (x = 0; x != sizeof(jitter); x++)
394*9cab9fdeSChristos Margiolis 							jitter[x] = ptr[x % 4];
395*9cab9fdeSChristos Margiolis 
396*9cab9fdeSChristos Margiolis 						write(c->oss_fd, jitter, sizeof(jitter));
397*9cab9fdeSChristos Margiolis 					}
398*9cab9fdeSChristos Margiolis 				}
399*9cab9fdeSChristos Margiolis 				while (ptr != end) {
400*9cab9fdeSChristos Margiolis 					int written = write(c->oss_fd, ptr, end - ptr);
401*9cab9fdeSChristos Margiolis 
402*9cab9fdeSChristos Margiolis 					if (written < 0) {
403*9cab9fdeSChristos Margiolis 						if (errno != EINTR && errno != EAGAIN)
404*9cab9fdeSChristos Margiolis 							break;
405*9cab9fdeSChristos Margiolis 						written = 0;
406*9cab9fdeSChristos Margiolis 					}
407*9cab9fdeSChristos Margiolis 					ptr += written;
408*9cab9fdeSChristos Margiolis 				}
409*9cab9fdeSChristos Margiolis 				if (ptr != end) {
410*9cab9fdeSChristos Margiolis 					message("Not all written, closing dsp\n");
411*9cab9fdeSChristos Margiolis 					close(c->oss_fd);
412*9cab9fdeSChristos Margiolis 					c->oss_fd = -1;
413*9cab9fdeSChristos Margiolis 					oss_attempt = time(NULL);
414*9cab9fdeSChristos Margiolis 				}
415*9cab9fdeSChristos Margiolis 			}
416*9cab9fdeSChristos Margiolis 		}
417*9cab9fdeSChristos Margiolis 
418*9cab9fdeSChristos Margiolis 		if (c->cfg.acceptor_state == acpStreamSuspended &&
419*9cab9fdeSChristos Margiolis 		    c->oss_fd > -1) {
420*9cab9fdeSChristos Margiolis 			close(c->oss_fd);
421*9cab9fdeSChristos Margiolis 			c->oss_fd = -1;
422*9cab9fdeSChristos Margiolis 		}
423*9cab9fdeSChristos Margiolis 	}
424*9cab9fdeSChristos Margiolis }
425*9cab9fdeSChristos Margiolis 
426*9cab9fdeSChristos Margiolis static struct option bt_speaker_opts[] = {
427*9cab9fdeSChristos Margiolis 	{"device", required_argument, NULL, 'd'},
428*9cab9fdeSChristos Margiolis 	{"sdp_socket_path", required_argument, NULL, 'p'},
429*9cab9fdeSChristos Margiolis 	{"rtprio", required_argument, NULL, 'i'},
430*9cab9fdeSChristos Margiolis 	{"background", no_argument, NULL, 'B'},
431*9cab9fdeSChristos Margiolis 	{"help", no_argument, NULL, 'h'},
432*9cab9fdeSChristos Margiolis 	{NULL, 0, NULL, 0}
433*9cab9fdeSChristos Margiolis };
434*9cab9fdeSChristos Margiolis 
435*9cab9fdeSChristos Margiolis static void
usage(void)436*9cab9fdeSChristos Margiolis usage(void)
437*9cab9fdeSChristos Margiolis {
438*9cab9fdeSChristos Margiolis 	fprintf(stderr, "Usage: virtual_bt_speaker -d /dev/dsp\n"
439*9cab9fdeSChristos Margiolis 	    "\t" "-d, --device [device]\n"
440*9cab9fdeSChristos Margiolis 	    "\t" "-p, --sdp_socket_path [path]\n"
441*9cab9fdeSChristos Margiolis 	    "\t" "-i, --rtprio [priority]\n"
442*9cab9fdeSChristos Margiolis 	    "\t" "-B, --background\n"
443*9cab9fdeSChristos Margiolis 	);
444*9cab9fdeSChristos Margiolis 	exit(EX_USAGE);
445*9cab9fdeSChristos Margiolis }
446*9cab9fdeSChristos Margiolis 
447*9cab9fdeSChristos Margiolis int
main(int argc,char ** argv)448*9cab9fdeSChristos Margiolis main(int argc, char **argv)
449*9cab9fdeSChristos Margiolis {
450*9cab9fdeSChristos Margiolis 	struct bt_audio_receiver r = {};
451*9cab9fdeSChristos Margiolis 	struct rtprio rtp = {};
452*9cab9fdeSChristos Margiolis 	void *hdl;
453*9cab9fdeSChristos Margiolis 	int ch;
454*9cab9fdeSChristos Margiolis 
455*9cab9fdeSChristos Margiolis 	r.devname = NULL;
456*9cab9fdeSChristos Margiolis 	r.sdp_socket_path = NULL;
457*9cab9fdeSChristos Margiolis 	r.l2cap_psm = SDP_UUID_PROTOCOL_AVDTP;
458*9cab9fdeSChristos Margiolis 
459*9cab9fdeSChristos Margiolis 	while ((ch = getopt_long(argc, argv, "p:i:d:Bh", bt_speaker_opts, NULL)) != -1) {
460*9cab9fdeSChristos Margiolis 		switch (ch) {
461*9cab9fdeSChristos Margiolis 		case 'd':
462*9cab9fdeSChristos Margiolis 			r.devname = optarg;
463*9cab9fdeSChristos Margiolis 			break;
464*9cab9fdeSChristos Margiolis 		case 'p':
465*9cab9fdeSChristos Margiolis 			r.sdp_socket_path = optarg;
466*9cab9fdeSChristos Margiolis 			break;
467*9cab9fdeSChristos Margiolis 		case 'B':
468*9cab9fdeSChristos Margiolis 			bt_in_background = 1;
469*9cab9fdeSChristos Margiolis 			break;
470*9cab9fdeSChristos Margiolis 		case 'i':
471*9cab9fdeSChristos Margiolis 			rtp.type = RTP_PRIO_REALTIME;
472*9cab9fdeSChristos Margiolis 			rtp.prio = atoi(optarg);
473*9cab9fdeSChristos Margiolis 			if (rtprio(RTP_SET, getpid(), &rtp) != 0) {
474*9cab9fdeSChristos Margiolis 				message("Cannot set realtime priority\n");
475*9cab9fdeSChristos Margiolis 			}
476*9cab9fdeSChristos Margiolis 			break;
477*9cab9fdeSChristos Margiolis 		default:
478*9cab9fdeSChristos Margiolis 			usage();
479*9cab9fdeSChristos Margiolis 			break;
480*9cab9fdeSChristos Margiolis 		}
481*9cab9fdeSChristos Margiolis 	}
482*9cab9fdeSChristos Margiolis 
483*9cab9fdeSChristos Margiolis 	if (r.devname == NULL)
484*9cab9fdeSChristos Margiolis 		errx(EX_USAGE, "No devicename specified");
485*9cab9fdeSChristos Margiolis 
486*9cab9fdeSChristos Margiolis 	if (bt_in_background) {
487*9cab9fdeSChristos Margiolis 		if (daemon(0, 0) != 0)
488*9cab9fdeSChristos Margiolis 			errx(EX_SOFTWARE, "Cannot become daemon");
489*9cab9fdeSChristos Margiolis 	}
490*9cab9fdeSChristos Margiolis 
491*9cab9fdeSChristos Margiolis 	if ((hdl = dlopen("/usr/lib/virtual_oss/voss_bt.so", RTLD_NOW)) == NULL)
492*9cab9fdeSChristos Margiolis 		errx(1, "%s", dlerror());
493*9cab9fdeSChristos Margiolis 	if ((bt_receive_f = dlsym(hdl, "bt_receive")) == NULL)
494*9cab9fdeSChristos Margiolis 		goto err_dlsym;
495*9cab9fdeSChristos Margiolis 	if ((avdtpACPHandlePacket_f = dlsym(hdl, "avdtpACPHandlePacket")) ==
496*9cab9fdeSChristos Margiolis 	    NULL)
497*9cab9fdeSChristos Margiolis 		goto err_dlsym;
498*9cab9fdeSChristos Margiolis 	if ((avdtpACPFree_f = dlsym(hdl, "avdtpACPFree")) == NULL)
499*9cab9fdeSChristos Margiolis 		goto err_dlsym;
500*9cab9fdeSChristos Margiolis 
501*9cab9fdeSChristos Margiolis 	while (1) {
502*9cab9fdeSChristos Margiolis 		message("Starting to listen\n");
503*9cab9fdeSChristos Margiolis 		if (!start_listen(&r)) {
504*9cab9fdeSChristos Margiolis 			message("Failed to initialize server socket\n");
505*9cab9fdeSChristos Margiolis 			goto err_listen;
506*9cab9fdeSChristos Margiolis 		}
507*9cab9fdeSChristos Margiolis 		message("Registering service via SDP\n");
508*9cab9fdeSChristos Margiolis 		if (!register_sdp(&r)) {
509*9cab9fdeSChristos Margiolis 			message("Failed to register in SDP\n");
510*9cab9fdeSChristos Margiolis 			goto err_sdp;
511*9cab9fdeSChristos Margiolis 		}
512*9cab9fdeSChristos Margiolis 		while (1) {
513*9cab9fdeSChristos Margiolis 			message("Waiting for connection...\n");
514*9cab9fdeSChristos Margiolis 			struct bt_audio_connection *c = wait_for_connection(&r);
515*9cab9fdeSChristos Margiolis 
516*9cab9fdeSChristos Margiolis 			if (c == NULL) {
517*9cab9fdeSChristos Margiolis 				message("Failed to get connection\n");
518*9cab9fdeSChristos Margiolis 				goto err_conn;
519*9cab9fdeSChristos Margiolis 			}
520*9cab9fdeSChristos Margiolis 			message("Got connection...\n");
521*9cab9fdeSChristos Margiolis 
522*9cab9fdeSChristos Margiolis 			process_connection(c);
523*9cab9fdeSChristos Margiolis 
524*9cab9fdeSChristos Margiolis 			message("Connection finished...\n");
525*9cab9fdeSChristos Margiolis 
526*9cab9fdeSChristos Margiolis 			close_connection(c);
527*9cab9fdeSChristos Margiolis 		}
528*9cab9fdeSChristos Margiolis err_conn:
529*9cab9fdeSChristos Margiolis 		message("Unregistering service\n");
530*9cab9fdeSChristos Margiolis 		unregister_sdp(&r);
531*9cab9fdeSChristos Margiolis err_sdp:
532*9cab9fdeSChristos Margiolis 		stop_listen(&r);
533*9cab9fdeSChristos Margiolis err_listen:
534*9cab9fdeSChristos Margiolis 		sleep(5);
535*9cab9fdeSChristos Margiolis 	}
536*9cab9fdeSChristos Margiolis 	return (0);
537*9cab9fdeSChristos Margiolis 
538*9cab9fdeSChristos Margiolis err_dlsym:
539*9cab9fdeSChristos Margiolis 	warnx("%s", dlerror());
540*9cab9fdeSChristos Margiolis 	dlclose(hdl);
541*9cab9fdeSChristos Margiolis 	exit(EXIT_FAILURE);
542*9cab9fdeSChristos Margiolis }
543