1b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau/*
2b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
3b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  BlueZ - Bluetooth protocol stack for Linux
4b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
55592142cb9383df0556b27ac59e96547b380310bJohan Hedberg *  Copyright (C) 2006-2010  Nokia Corporation
69184e2eeb7b97371c6b83b747c8984e2340d2b47Marcel Holtmann *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
7563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau *  Copyright (C) 2009	Lennart Poettering
8563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau *  Copyright (C) 2008	Joao Paulo Rechi Vita
9b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
10b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
11b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  This library is free software; you can redistribute it and/or
12b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  modify it under the terms of the GNU Lesser General Public
13b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  License as published by the Free Software Foundation; either
14b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  version 2.1 of the License, or (at your option) any later version.
15b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
16b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  This library is distributed in the hope that it will be useful,
17b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  Lesser General Public License for more details.
20b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
21b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  You should have received a copy of the GNU Lesser General Public
22b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  License along with this library; if not, write to the Free Software
23b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
25b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau */
26b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
27b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#ifdef HAVE_CONFIG_H
28b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <config.h>
29b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#endif
30b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
31b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <stdlib.h>
32b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <stdio.h>
33b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <errno.h>
34b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <string.h>
35b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <assert.h>
36b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <libgen.h>
37b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#include <unistd.h>
38b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#include <fcntl.h>
39a8eb557ae742f829c641682520b0e6e341caf18cJohan Hedberg#include <signal.h>
40b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
41b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <glib.h>
42b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
43b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include "ipc.h"
44b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include "sbc.h"
45b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
46b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#define DBG(fmt, arg...)				\
47b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	printf("debug %s: " fmt "\n" , __FUNCTION__ , ## arg)
48b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#define ERR(fmt, arg...)				\
49b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	fprintf(stderr, "ERROR %s: " fmt "\n" , __FUNCTION__ , ## arg)
50b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
51b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
52b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
53b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#ifndef MIN
54b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau# define MIN(x, y) ((x) < (y) ? (x) : (y))
55b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#endif
56b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
57b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#ifndef MAX
58b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau# define MAX(x, y) ((x) > (y) ? (x) : (y))
59b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#endif
60b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
61b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#ifndef TRUE
62b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau# define TRUE (1)
63b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#endif
64b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
65b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#ifndef FALSE
66b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau# define FALSE (0)
67b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#endif
68b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
69b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#define YES_NO(t) ((t) ? "yes" : "no")
70b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
71b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#define BUFFER_SIZE 2048
72b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#define MAX_BITPOOL 64
73b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#define MIN_BITPOOL 2
74b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
75b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustruct a2dp_info {
76b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	sbc_capabilities_t sbc_capabilities;
77b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	sbc_t sbc; /* Codec data */
78b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int sbc_initialized; /* Keep track if the encoder is initialized */
79b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	size_t codesize; /* SBC codesize */
80b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
81b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	void* buffer; /* Codec transfer buffer */
82b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	size_t buffer_size; /* Size of the buffer */
83b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
84b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	uint16_t seq_num; /* Cumulative packet sequence */
85b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau};
86b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
87b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustruct hsp_info {
88b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	pcm_capabilities_t pcm_capabilities;
89b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau};
90b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
91b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustruct userdata {
92b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int service_fd;
93b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int stream_fd;
94b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	GIOChannel *stream_channel;
95b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	guint stream_watch;
96563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	GIOChannel *gin; /* dude, I am thirsty now */
97563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	guint gin_watch;
98b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int transport;
99b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	uint32_t rate;
100b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int channels;
10164989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau	char *address;
102b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	struct a2dp_info a2dp;
103b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	struct hsp_info hsp;
104b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	size_t link_mtu;
105b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	size_t block_size;
106454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	gboolean debug_stream_read : 1;
107454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	gboolean debug_stream_write : 1;
108b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau};
109b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
110b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic struct userdata data = {
111b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.service_fd = -1,
112b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.stream_fd = -1,
113b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.transport = BT_CAPABILITIES_TRANSPORT_A2DP,
114b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.rate = 48000,
115b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.channels = 2,
116b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.address = NULL
117b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau};
118b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
119b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int start_stream(struct userdata *u);
120b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int stop_stream(struct userdata *u);
121563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureaustatic gboolean input_cb(GIOChannel *gin, GIOCondition condition, gpointer data);
122b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
123b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic GMainLoop *main_loop;
124b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
125b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic int service_send(struct userdata *u, const bt_audio_msg_header_t *msg)
126b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
127b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int err;
128b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	uint16_t length;
129b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
130b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
131b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
132b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	length = msg->length ? msg->length : BT_SUGGESTED_BUFFER_SIZE;
133b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
134b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	DBG("sending %s:%s", bt_audio_strtype(msg->type),
135b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		bt_audio_strname(msg->name));
136b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
137b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (send(u->service_fd, msg, length, 0) > 0)
138b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		err = 0;
139b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else {
140b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		err = -errno;
141b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		ERR("Error sending data to audio service: %s(%d)",
142b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			strerror(errno), errno);
143b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
144b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
145b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return err;
146b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
147b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
148e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentzstatic int service_recv(struct userdata *u, bt_audio_msg_header_t *rsp)
149b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
150b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int err;
151b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	const char *type, *name;
152b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	uint16_t length;
153b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
154b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
155b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
156e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	length = rsp->length ? : BT_SUGGESTED_BUFFER_SIZE;
157b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
158b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	DBG("trying to receive msg from audio service...");
159b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (recv(u->service_fd, rsp, length, 0) > 0) {
160b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		type = bt_audio_strtype(rsp->type);
161b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		name = bt_audio_strname(rsp->name);
162b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (type && name) {
163b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("Received %s - %s", type, name);
164b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			err = 0;
165b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		} else {
166b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			err = -EINVAL;
167b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			ERR("Bogus message type %d - name %d"
168b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				"received from audio service",
169b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				rsp->type, rsp->name);
170b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
171b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} else {
172b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		err = -errno;
173b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		ERR("Error receiving data from audio service: %s(%d)",
174b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			strerror(errno), errno);
175b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
176b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
177b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return err;
178b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
179b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
180e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentzstatic ssize_t service_expect(struct userdata *u, bt_audio_msg_header_t *rsp,
181e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz				uint8_t expected_name)
182b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
183b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int r;
184b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
185b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
186b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u->service_fd >= 0);
187b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(rsp);
188b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
189e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if ((r = service_recv(u, rsp)) < 0)
190b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return r;
191b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
192b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if ((rsp->type != BT_INDICATION && rsp->type != BT_RESPONSE) ||
193e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz			(rsp->name != expected_name)) {
194b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (rsp->type == BT_ERROR && rsp->length == sizeof(bt_audio_error_t))
195b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			ERR("Received error condition: %s",
196b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				strerror(((bt_audio_error_t*) rsp)->posix_errno));
197b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		else
198b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			ERR("Bogus message %s received while %s was expected",
199b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				bt_audio_strname(rsp->name),
200b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				bt_audio_strname(expected_name));
201b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
202b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
203b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
204b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
205b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
206b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
207b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int init_bt(struct userdata *u)
208b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
209b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
210b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
211b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->service_fd != -1)
212b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return 0;
213b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
214b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	DBG("bt_audio_service_open");
215b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
216b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	u->service_fd = bt_audio_service_open();
217b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->service_fd <= 0) {
218b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		perror(strerror(errno));
219b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return errno;
220b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
221b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
222b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
223b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
224b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
225b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp *rsp)
226b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
227fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann	unsigned char *ptr;
228b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	uint16_t bytes_left;
229fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann	codec_capabilities_t codec;
230b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
231b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
232b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(rsp);
233b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
234b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	bytes_left = rsp->h.length - sizeof(*rsp);
235b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
236b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (bytes_left < sizeof(codec_capabilities_t)) {
237b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		ERR("Packet too small to store codec information.");
238b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
239b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
240b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
241fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann	ptr = ((void *) rsp) + sizeof(*rsp);
242fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann
243fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann	memcpy(&codec, ptr, sizeof(codec)); /** ALIGNMENT? **/
244b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
245b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	DBG("Payload size is %lu %lu",
246fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann		(unsigned long) bytes_left, (unsigned long) sizeof(codec));
247b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
248fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann	if (u->transport != codec.transport) {
249b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		ERR("Got capabilities for wrong codec.");
250b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
251b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
252b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
253b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->transport == BT_CAPABILITIES_TRANSPORT_SCO) {
254b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
255b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (bytes_left <= 0 ||
256fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann				codec.length != sizeof(u->hsp.pcm_capabilities))
257b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return -1;
258b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
259fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann		assert(codec.type == BT_HFP_CODEC_PCM);
260b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
261b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		memcpy(&u->hsp.pcm_capabilities,
262fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann				&codec, sizeof(u->hsp.pcm_capabilities));
263b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
264b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("Has NREC: %s",
265b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			YES_NO(u->hsp.pcm_capabilities.flags & BT_PCM_FLAG_NREC));
266b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
267b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} else if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
268b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
269b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		while (bytes_left > 0) {
270fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann			if (codec.type == BT_A2DP_SBC_SINK &&
271fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann					!(codec.lock & BT_WRITE_LOCK))
272b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				break;
273b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
274fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann			bytes_left -= codec.length;
275fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann			ptr += codec.length;
276fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann			memcpy(&codec, ptr, sizeof(codec));
277b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
278b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
279fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann		DBG("bytes_left = %d, codec.length = %d",
280fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann						bytes_left, codec.length);
281e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
282b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (bytes_left <= 0 ||
283fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann				codec.length != sizeof(u->a2dp.sbc_capabilities))
284b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return -1;
285b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
286fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann		assert(codec.type == BT_A2DP_SBC_SINK);
287b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
288fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann		memcpy(&u->a2dp.sbc_capabilities, &codec,
289fec239062b9126f2092c4d77233ab987ac3b0336Marcel Holtmann					sizeof(u->a2dp.sbc_capabilities));
290b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} else {
291b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
292b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
293b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
294b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
295b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
296b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
297b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic int get_caps(struct userdata *u)
298b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
299b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	union {
300b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		struct bt_get_capabilities_req getcaps_req;
301b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		struct bt_get_capabilities_rsp getcaps_rsp;
302b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		bt_audio_error_t error;
303b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
304b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} msg;
305b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
306b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
307b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
308b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	memset(&msg, 0, sizeof(msg));
309b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.getcaps_req.h.type = BT_REQUEST;
310b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.getcaps_req.h.name = BT_GET_CAPABILITIES;
311b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.getcaps_req.h.length = sizeof(msg.getcaps_req);
312b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
313e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	strncpy(msg.getcaps_req.destination, u->address,
314e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz			sizeof(msg.getcaps_req.destination));
315b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.getcaps_req.transport = u->transport;
316b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.getcaps_req.flags = BT_FLAG_AUTOCONNECT;
317b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
318b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (service_send(u, &msg.getcaps_req.h) < 0)
319b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
320b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
321e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.getcaps_rsp.h.length = 0;
322e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.getcaps_rsp.h, BT_GET_CAPABILITIES) < 0)
323b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
324b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
325b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return parse_caps(u, &msg.getcaps_rsp);
326b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
327b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
328b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode)
329b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
330b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (freq) {
331b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_16000:
332b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_32000:
333b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return 53;
334b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
335b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_44100:
336b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
337b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		switch (mode) {
338b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_MONO:
339b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
340b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 31;
341b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
342b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_STEREO:
343b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
344b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 53;
345b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
346b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		default:
347b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("Invalid channel mode %u", mode);
348b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 53;
349b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
350b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
351b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_48000:
352b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
353b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		switch (mode) {
354b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_MONO:
355b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
356b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 29;
357b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
358b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_STEREO:
359b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
360b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 51;
361b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
362b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		default:
363b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("Invalid channel mode %u", mode);
364b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 51;
365b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
366b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
367b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
368b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("Invalid sampling freq %u", freq);
369b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return 53;
370b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
371b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
372b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
373b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int setup_a2dp(struct userdata *u)
374b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
375b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	sbc_capabilities_t *cap;
376b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int i;
377b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
378b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	static const struct {
379b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		uint32_t rate;
380b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		uint8_t cap;
381b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} freq_table[] = {
382b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		{ 16000U, BT_SBC_SAMPLING_FREQ_16000 },
383b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		{ 32000U, BT_SBC_SAMPLING_FREQ_32000 },
384b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		{ 44100U, BT_SBC_SAMPLING_FREQ_44100 },
385b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		{ 48000U, BT_SBC_SAMPLING_FREQ_48000 }
386b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	};
387b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
388b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
389b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u->transport == BT_CAPABILITIES_TRANSPORT_A2DP);
390b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
391b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	cap = &u->a2dp.sbc_capabilities;
392b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
393b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	/* Find the lowest freq that is at least as high as the requested
394b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	 * sampling rate */
395b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	for (i = 0; (unsigned) i < ARRAY_SIZE(freq_table); i++)
396b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (freq_table[i].rate >= u->rate &&
397b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			(cap->frequency & freq_table[i].cap)) {
398b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->rate = freq_table[i].rate;
399b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->frequency = freq_table[i].cap;
400b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			break;
401b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
402b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
403b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if ((unsigned) i >= ARRAY_SIZE(freq_table)) {
404b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		for (; i >= 0; i--) {
405b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			if (cap->frequency & freq_table[i].cap) {
406b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				u->rate = freq_table[i].rate;
407b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				cap->frequency = freq_table[i].cap;
408b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				break;
409b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			}
410b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
411b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
412b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (i < 0) {
413b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("Not suitable sample rate");
414b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return -1;
415b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
416b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
417b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
418b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->channels <= 1) {
419b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) {
420b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
421b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->channels = 1;
422b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		} else
423b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->channels = 2;
424b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
425b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
426b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->channels >= 2) {
427b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		u->channels = 2;
428b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
429b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)
430b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
431b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO)
432b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;
433b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL)
434b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
435b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) {
436b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
437b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->channels = 1;
438b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		} else {
439b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("No supported channel modes");
440b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return -1;
441b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
442b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
443b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
444b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (cap->block_length & BT_A2DP_BLOCK_LENGTH_16)
445b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->block_length = BT_A2DP_BLOCK_LENGTH_16;
446b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_12)
447b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->block_length = BT_A2DP_BLOCK_LENGTH_12;
448b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_8)
449b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->block_length = BT_A2DP_BLOCK_LENGTH_8;
450b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_4)
451b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->block_length = BT_A2DP_BLOCK_LENGTH_4;
452b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else {
453b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("No supported block lengths");
454b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
455b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
456b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
457b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (cap->subbands & BT_A2DP_SUBBANDS_8)
458b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->subbands = BT_A2DP_SUBBANDS_8;
459b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else if (cap->subbands & BT_A2DP_SUBBANDS_4)
460b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->subbands = BT_A2DP_SUBBANDS_4;
461b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else {
462b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("No supported subbands");
463b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
464b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
465b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
466b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (cap->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS)
467b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
468b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else if (cap->allocation_method & BT_A2DP_ALLOCATION_SNR)
469b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->allocation_method = BT_A2DP_ALLOCATION_SNR;
470b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
471b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	cap->min_bitpool = (uint8_t) MAX(MIN_BITPOOL, cap->min_bitpool);
472b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	cap->max_bitpool = (uint8_t) MIN(
473b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		a2dp_default_bitpool(cap->frequency, cap->channel_mode),
474b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		cap->max_bitpool);
475b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
476b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
477b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
478b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
479b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic void setup_sbc(struct a2dp_info *a2dp)
480b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
481b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	sbc_capabilities_t *active_capabilities;
482b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
483b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(a2dp);
484b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
485b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	active_capabilities = &a2dp->sbc_capabilities;
486b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
487b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (a2dp->sbc_initialized)
488b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		sbc_reinit(&a2dp->sbc, 0);
489b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else
490b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		sbc_init(&a2dp->sbc, 0);
491b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	a2dp->sbc_initialized = TRUE;
492b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
493b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (active_capabilities->frequency) {
494b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_16000:
495b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.frequency = SBC_FREQ_16000;
496b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
497b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_32000:
498b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.frequency = SBC_FREQ_32000;
499b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
500b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_44100:
501b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.frequency = SBC_FREQ_44100;
502b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
503b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_48000:
504b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.frequency = SBC_FREQ_48000;
505b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
506b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
507b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
508b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
509b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
510b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (active_capabilities->channel_mode) {
511b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_CHANNEL_MODE_MONO:
512b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.mode = SBC_MODE_MONO;
513b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
514b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
515b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.mode = SBC_MODE_DUAL_CHANNEL;
516b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
517b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_CHANNEL_MODE_STEREO:
518b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.mode = SBC_MODE_STEREO;
519b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
520b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
521b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.mode = SBC_MODE_JOINT_STEREO;
522b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
523b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
524b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
525b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
526b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
527b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (active_capabilities->allocation_method) {
528b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_ALLOCATION_SNR:
529b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.allocation = SBC_AM_SNR;
530b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
531b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_ALLOCATION_LOUDNESS:
532b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.allocation = SBC_AM_LOUDNESS;
533b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
534b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
535b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
536b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
537b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
538b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (active_capabilities->subbands) {
539b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_SUBBANDS_4:
540b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.subbands = SBC_SB_4;
541b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
542b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_SUBBANDS_8:
543b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.subbands = SBC_SB_8;
544b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
545b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
546b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
547b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
548b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
549b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (active_capabilities->block_length) {
550b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_BLOCK_LENGTH_4:
551b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.blocks = SBC_BLK_4;
552b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
553b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_BLOCK_LENGTH_8:
554b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.blocks = SBC_BLK_8;
555b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
556b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_BLOCK_LENGTH_12:
557b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.blocks = SBC_BLK_12;
558b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
559b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_BLOCK_LENGTH_16:
560b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.blocks = SBC_BLK_16;
561b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
562b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
563b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
564b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
565b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
566b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	a2dp->sbc.bitpool = active_capabilities->max_bitpool;
567b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	a2dp->codesize = (uint16_t) sbc_get_codesize(&a2dp->sbc);
568b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
569b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
570e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentzstatic int bt_open(struct userdata *u)
571e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz{
572e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	union {
573e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		struct bt_open_req open_req;
574e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		struct bt_open_rsp open_rsp;
575e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		bt_audio_error_t error;
576e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
577e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	} msg;
578e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
579e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	memset(&msg, 0, sizeof(msg));
580e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_req.h.type = BT_REQUEST;
581e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_req.h.name = BT_OPEN;
582e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_req.h.length = sizeof(msg.open_req);
583e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
584e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	strncpy(msg.open_req.destination, u->address,
585e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz			sizeof(msg.open_req.destination));
586e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_req.seid = u->transport == BT_CAPABILITIES_TRANSPORT_A2DP ?
587e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz				u->a2dp.sbc_capabilities.capability.seid :
588e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz				BT_A2DP_SEID_RANGE + 1;
589e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_req.lock = u->transport == BT_CAPABILITIES_TRANSPORT_A2DP ?
590e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz				BT_WRITE_LOCK : BT_READ_LOCK | BT_WRITE_LOCK;
591e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
592e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_send(u, &msg.open_req.h) < 0)
593e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		return -1;
594e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
595e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_rsp.h.length = sizeof(msg.open_rsp);
596e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.open_rsp.h, BT_OPEN) < 0)
597e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		return -1;
598e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
599e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	return 0;
600e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz}
601e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
602b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic int set_conf(struct userdata *u)
603b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
604b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	union {
605b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		struct bt_set_configuration_req setconf_req;
606b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		struct bt_set_configuration_rsp setconf_rsp;
607b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		bt_audio_error_t error;
608b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
609b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} msg;
610b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
611b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
612b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (setup_a2dp(u) < 0)
613b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return -1;
614b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
615b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
616b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	memset(&msg, 0, sizeof(msg));
617b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.setconf_req.h.type = BT_REQUEST;
618b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.setconf_req.h.name = BT_SET_CONFIGURATION;
619b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.setconf_req.h.length = sizeof(msg.setconf_req);
620b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
621b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
622b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		memcpy(&msg.setconf_req.codec, &u->a2dp.sbc_capabilities,
623b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			sizeof(u->a2dp.sbc_capabilities));
624b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		msg.setconf_req.h.length += msg.setconf_req.codec.length -
625b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			sizeof(msg.setconf_req.codec);
626e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	} else {
627e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		msg.setconf_req.codec.transport = BT_CAPABILITIES_TRANSPORT_SCO;
628e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		msg.setconf_req.codec.seid = BT_A2DP_SEID_RANGE + 1;
629e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		msg.setconf_req.codec.length = sizeof(pcm_capabilities_t);
630b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
631b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
632b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (service_send(u, &msg.setconf_req.h) < 0)
633b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
634b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
635e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.setconf_rsp.h.length = sizeof(msg.setconf_rsp);
636e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.setconf_rsp.h, BT_SET_CONFIGURATION) < 0)
637b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
638b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
639b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	u->link_mtu = msg.setconf_rsp.link_mtu;
640b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
641b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	/* setup SBC encoder now we agree on parameters */
642b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
643b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		setup_sbc(&u->a2dp);
644b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		u->block_size = u->a2dp.codesize;
645b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("SBC parameters:\n\tallocation=%u\n"
646b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			"\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
647b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->a2dp.sbc.allocation, u->a2dp.sbc.subbands,
648b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->a2dp.sbc.blocks, u->a2dp.sbc.bitpool);
649b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} else
650b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		u->block_size = u->link_mtu;
651b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
652b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
653b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
654b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
655b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic int setup_bt(struct userdata *u)
656b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
657b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
658b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
659b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (get_caps(u) < 0)
660b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
661b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
662b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	DBG("Got device caps");
663b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
664e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (bt_open(u) < 0)
665e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		return -1;
666e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
667b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (set_conf(u) < 0)
668b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
669b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
670b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
671b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
672b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
673b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic int init_profile(struct userdata *u)
674b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
675b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
676b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
677b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return setup_bt(u);
678b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
679b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
680b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic void shutdown_bt(struct userdata *u)
681b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
682b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
683b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
684b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->stream_fd != -1) {
685482feece91818127ce4e6f39dfa555390a31d8abMarc-André Lureau		stop_stream(u);
686b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("close(stream_fd)");
687b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		close(u->stream_fd);
688b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		u->stream_fd = -1;
689b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
690b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
691b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->service_fd != -1) {
692b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("bt_audio_service_close");
693b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		bt_audio_service_close(u->service_fd);
694b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		u->service_fd = -1;
695b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
696b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
697b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
698b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic void make_fd_nonblock(int fd)
699b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
700b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	int v;
701b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
702b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(fd >= 0);
703b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert((v = fcntl(fd, F_GETFL)) >= 0);
704b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
705b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (!(v & O_NONBLOCK))
706b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		assert(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 0);
707b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
708b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
709b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic void make_socket_low_delay(int fd)
710b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
711b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau/* FIXME: is this widely supported? */
712b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#ifdef SO_PRIORITY
713b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	int priority;
714b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(fd >= 0);
715b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
716b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	priority = 6;
717b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority,
718b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			sizeof(priority)) < 0)
719b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		ERR("SO_PRIORITY failed: %s", strerror(errno));
720b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#endif
721b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
722b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
723b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int read_stream(struct userdata *u)
724b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
725b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	int ret = 0;
726b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	ssize_t l;
727b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	char *buf;
728b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
729b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u);
730b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u->stream_fd >= 0);
731b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
732b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	buf = alloca(u->link_mtu);
733b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
734b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	for (;;) {
735b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		l = read(u->stream_fd, buf, u->link_mtu);
736454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		if (u->debug_stream_read)
737454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			DBG("read from socket: %lli bytes", (long long) l);
738b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (l <= 0) {
739b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			if (l < 0 && errno == EINTR)
740b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				continue;
741b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			else {
742b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				ERR("Failed to read date from stream_fd: %s",
743b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau					ret < 0 ? strerror(errno) : "EOF");
7442addc4bdcd68bd26280751f1d1c2dd21d39b1488Luiz Augusto von Dentz				return -1;
745b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			}
746b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		} else {
747b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			break;
748b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		}
749b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
750b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
751b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return ret;
752b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
753b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
754b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau/* It's what PulseAudio is doing, not sure it's necessary for this
755b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau * test */
756b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic ssize_t pa_write(int fd, const void *buf, size_t count)
757b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
758b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	ssize_t r;
759b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
760b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if ((r = send(fd, buf, count, MSG_NOSIGNAL)) >= 0)
761b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return r;
762b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
763b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (errno != ENOTSOCK)
764b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return r;
765b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
766b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return write(fd, buf, count);
767b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
768b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
769b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int write_stream(struct userdata *u)
770b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
771b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	int ret = 0;
772b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	ssize_t l;
773b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	char *buf;
774b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
775b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u);
776b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u->stream_fd >= 0);
777b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	buf = alloca(u->link_mtu);
778b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
779b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	for (;;) {
780b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		l = pa_write(u->stream_fd, buf, u->link_mtu);
781454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		if (u->debug_stream_write)
782454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			DBG("written to socket: %lli bytes", (long long) l);
783b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		assert(l != 0);
784b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (l < 0) {
785b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			if (errno == EINTR)
786b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				continue;
787b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			else {
788b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				ERR("Failed to write data: %s", strerror(errno));
789b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				ret = -1;
790b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				break;
791b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			}
792b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		} else {
793b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			assert((size_t)l <= u->link_mtu);
794b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			break;
795b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		}
796b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
797b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
798b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return ret;
799b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
800b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
801b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic gboolean stream_cb(GIOChannel *gin, GIOCondition condition, gpointer data)
802b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
803b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	struct userdata *u;
804b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
805b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u = data);
806b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
807b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (condition & G_IO_IN) {
808b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (read_stream(u) < 0)
809b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			goto fail;
810b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	} else if (condition & G_IO_OUT) {
811b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (write_stream(u) < 0)
812b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			goto fail;
813b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	} else {
814b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		DBG("Got %d", condition);
815b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		g_main_loop_quit(main_loop);
816b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return FALSE;
817b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
818b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
819b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return TRUE;
820b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
821b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaufail:
822b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	stop_stream(u);
823b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return FALSE;
824b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
825b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
826b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int start_stream(struct userdata *u)
827b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
828b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	union {
829b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		bt_audio_msg_header_t rsp;
830b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		struct bt_start_stream_req start_req;
831b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		struct bt_start_stream_rsp start_rsp;
832b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		struct bt_new_stream_ind streamfd_ind;
833b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		bt_audio_error_t error;
834b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
835b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	} msg;
836b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
837b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u);
8389645bf143db975256d3618594282f4ce3778db42Marc-André Lureau
8399645bf143db975256d3618594282f4ce3778db42Marc-André Lureau	if (u->stream_fd >= 0)
8409645bf143db975256d3618594282f4ce3778db42Marc-André Lureau		return 0;
8419645bf143db975256d3618594282f4ce3778db42Marc-André Lureau	if (u->stream_watch != 0) {
8429645bf143db975256d3618594282f4ce3778db42Marc-André Lureau		g_source_remove(u->stream_watch);
8439645bf143db975256d3618594282f4ce3778db42Marc-André Lureau		u->stream_watch = 0;
8449645bf143db975256d3618594282f4ce3778db42Marc-André Lureau	}
8459645bf143db975256d3618594282f4ce3778db42Marc-André Lureau	if (u->stream_channel != 0) {
8469645bf143db975256d3618594282f4ce3778db42Marc-André Lureau		g_io_channel_unref(u->stream_channel);
8479645bf143db975256d3618594282f4ce3778db42Marc-André Lureau		u->stream_channel = NULL;
8489645bf143db975256d3618594282f4ce3778db42Marc-André Lureau	}
849b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
850b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	memset(msg.buf, 0, BT_SUGGESTED_BUFFER_SIZE);
851b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	msg.start_req.h.type = BT_REQUEST;
852b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	msg.start_req.h.name = BT_START_STREAM;
853b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	msg.start_req.h.length = sizeof(msg.start_req);
854b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
855b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (service_send(u, &msg.start_req.h) < 0)
856b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return -1;
857b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
858e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.rsp.length = sizeof(msg.start_rsp);
859e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.rsp, BT_START_STREAM) < 0)
860b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return -1;
861b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
862e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.rsp.length = sizeof(msg.streamfd_ind);
863e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.rsp, BT_NEW_STREAM) < 0)
864b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return -1;
865b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
866b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if ((u->stream_fd = bt_audio_service_get_data_fd(u->service_fd)) < 0) {
867b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		DBG("Failed to get stream fd from audio service.");
868b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return -1;
869b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
870b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
871b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	make_fd_nonblock(u->stream_fd);
872b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	make_socket_low_delay(u->stream_fd);
873b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
874b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u->stream_channel = g_io_channel_unix_new(u->stream_fd));
875b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
876b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	u->stream_watch = g_io_add_watch(u->stream_channel,
877b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau					G_IO_IN|G_IO_OUT|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
878b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau					stream_cb, u);
879b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
880b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return 0;
881b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
882b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
883b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int stop_stream(struct userdata *u)
884b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
885b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	union {
886b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		bt_audio_msg_header_t rsp;
887e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		struct bt_stop_stream_req stop_req;
888e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		struct bt_stop_stream_rsp stop_rsp;
889b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		bt_audio_error_t error;
890b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
891b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	} msg;
892b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	int r = 0;
893b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
894b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (u->stream_fd < 0)
895b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return 0;
896b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
897b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u);
898b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u->stream_channel);
899b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
900b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	g_source_remove(u->stream_watch);
901482feece91818127ce4e6f39dfa555390a31d8abMarc-André Lureau	u->stream_watch = 0;
902b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	g_io_channel_unref(u->stream_channel);
903b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	u->stream_channel = NULL;
904b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
905b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	memset(msg.buf, 0, BT_SUGGESTED_BUFFER_SIZE);
906e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.stop_req.h.type = BT_REQUEST;
907e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.stop_req.h.name = BT_STOP_STREAM;
908e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.stop_req.h.length = sizeof(msg.stop_req);
909e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
910e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_send(u, &msg.stop_req.h) < 0) {
911e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		r = -1;
912e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		goto done;
913e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	}
914b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
915e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.rsp.length = sizeof(msg.stop_rsp);
916e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.rsp, BT_STOP_STREAM) < 0)
917b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		r = -1;
918b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
919e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentzdone:
920b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	close(u->stream_fd);
921b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	u->stream_fd = -1;
922b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
923b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return r;
924b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
925b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
926563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureaustatic gboolean sleep_cb(gpointer data)
927563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau{
928563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	struct userdata *u;
929563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau
930563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	assert(u = data);
931563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau
932563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	u->gin_watch = g_io_add_watch(u->gin,
933563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau		G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, input_cb, data);
934563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau
935563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	printf(">>> ");
936563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	fflush(stdout);
937563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau
938563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	return FALSE;
939563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau}
940563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau
941b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic gboolean input_cb(GIOChannel *gin, GIOCondition condition, gpointer data)
942b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
943454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	char *line, *tmp;
944b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	gsize term_pos;
945b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	GError *error = NULL;
946b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	struct userdata *u;
947b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int success;
948b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
949b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u = data);
950b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (!(condition & G_IO_IN)) {
951b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("Got %d", condition);
952b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		g_main_loop_quit(main_loop);
953b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return FALSE;
954b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
955b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
956b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (g_io_channel_read_line(gin, &line, NULL, &term_pos, &error) !=
957b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		G_IO_STATUS_NORMAL)
958b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return FALSE;
959b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
960b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	line[term_pos] = '\0';
961b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	g_strstrip(line);
962454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	if ((tmp = strchr(line, '#')))
963454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		*tmp = '\0';
964b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	success = FALSE;
965b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
966b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#define IF_CMD(cmd) \
967b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (!success && (success = (strncmp(line, #cmd, strlen(#cmd)) == 0)))
968b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
969b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(quit) {
970b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		g_main_loop_quit(main_loop);
971b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return FALSE;
972b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
973b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
97464989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau	IF_CMD(sleep) {
97564989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		unsigned int seconds;
97664989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		if (sscanf(line, "%*s %d", &seconds) != 1)
97764989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau			DBG("sleep SECONDS");
978563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau		else {
979563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau			g_source_remove(u->gin_watch);
980563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau			g_timeout_add_seconds(seconds, sleep_cb, u);
981563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau			return FALSE;
982563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau		}
98364989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau	}
98464989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau
985454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	IF_CMD(debug) {
986454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		char *what = NULL;
987454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		int enable;
988454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau
989454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		if (sscanf(line, "%*s %as %d", &what, &enable) != 1)
990454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			DBG("debug [stream_read|stream_write] [0|1]");
991454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		if (strncmp(what, "stream_read", 12) == 0) {
992454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			u->debug_stream_read = enable;
993454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		} else if (strncmp(what, "stream_write", 13) == 0) {
994454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			u->debug_stream_write = enable;
995454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		} else {
996454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			DBG("debug [stream_read|stream_write] [0|1]");
997454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		}
998454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	}
999454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau
1000b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(init_bt) {
1001b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("%d", init_bt(u));
1002b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1003b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1004b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(init_profile) {
1005b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("%d", init_profile(u));
1006b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1007b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1008b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	IF_CMD(start_stream) {
1009b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		DBG("%d", start_stream(u));
1010b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
1011b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1012b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	IF_CMD(stop_stream) {
1013b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		DBG("%d", stop_stream(u));
1014b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
1015b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1016b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(shutdown_bt) {
1017b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		shutdown_bt(u);
1018b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1019b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1020b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(rate) {
1021b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (sscanf(line, "%*s %d", &u->rate) != 1)
1022b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("set with rate RATE");
1023b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("rate %d", u->rate);
1024b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1025b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1026c6e7e1139d85342799c47082355cd9b8b5dbe967Marcel Holtmann	IF_CMD(bdaddr) {
1027204c8e27e2bf736212afe312afeacea6df58a16fLuiz Augusto von Dentz		char *address;
1028204c8e27e2bf736212afe312afeacea6df58a16fLuiz Augusto von Dentz
1029204c8e27e2bf736212afe312afeacea6df58a16fLuiz Augusto von Dentz		if (sscanf(line, "%*s %as", &address) != 1)
1030204c8e27e2bf736212afe312afeacea6df58a16fLuiz Augusto von Dentz			DBG("set with bdaddr BDADDR");
1031204c8e27e2bf736212afe312afeacea6df58a16fLuiz Augusto von Dentz
1032a554d3a656f0b0e3a3d82b68ab61b89f1b876660Gustavo F. Padovan		free(u->address);
1033204c8e27e2bf736212afe312afeacea6df58a16fLuiz Augusto von Dentz
1034204c8e27e2bf736212afe312afeacea6df58a16fLuiz Augusto von Dentz		u->address = address;
1035c6e7e1139d85342799c47082355cd9b8b5dbe967Marcel Holtmann		DBG("bdaddr %s", u->address);
1036b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1037b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1038b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(profile) {
103964989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		char *profile = NULL;
1040b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
104164989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		if (sscanf(line, "%*s %as", &profile) != 1)
1042b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("set with profile [hsp|a2dp]");
1043b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (strncmp(profile, "hsp", 4) == 0) {
1044b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->transport = BT_CAPABILITIES_TRANSPORT_SCO;
1045b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		} else if (strncmp(profile, "a2dp", 5) == 0) {
1046b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
1047b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		} else {
1048b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("set with profile [hsp|a2dp]");
1049b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
1050b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1051a554d3a656f0b0e3a3d82b68ab61b89f1b876660Gustavo F. Padovan		free(profile);
1052b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("profile %s", u->transport == BT_CAPABILITIES_TRANSPORT_SCO ?
1053b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			"hsp" : "a2dp");
1054b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1055b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1056b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (!success && strlen(line) != 0) {
1057b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("%s, unknown command", line);
1058b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1059b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1060b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	printf(">>> ");
1061b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	fflush(stdout);
1062b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return TRUE;
1063b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
1064b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1065b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1066b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic void show_usage(char* prgname)
1067b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
1068c6e7e1139d85342799c47082355cd9b8b5dbe967Marcel Holtmann	printf("%s: ipctest [--interactive] BDADDR\n", basename(prgname));
1069b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
1070b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1071b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic void sig_term(int sig)
1072b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
1073b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	g_main_loop_quit(main_loop);
1074b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
1075b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1076b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureauint main(int argc, char *argv[])
1077b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
1078b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (argc < 2) {
1079b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		show_usage(argv[0]);
1080b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		exit(EXIT_FAILURE);
1081b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1082b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1083b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(main_loop = g_main_loop_new(NULL, FALSE));
1084b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1085b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (strncmp("--interactive", argv[1], 14) == 0) {
1086b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (argc < 3) {
1087b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			show_usage(argv[0]);
1088b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			exit(EXIT_FAILURE);
1089b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
1090b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
109164989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		data.address = strdup(argv[2]);
1092b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1093b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		signal(SIGTERM, sig_term);
1094b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		signal(SIGINT, sig_term);
1095b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1096563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau		assert(data.gin = g_io_channel_unix_new(fileno(stdin)));
1097b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1098563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau		data.gin_watch = g_io_add_watch(data.gin,
1099563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau			G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, input_cb, &data);
1100b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1101b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		printf(">>> ");
1102b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		fflush(stdout);
1103b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1104b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		g_main_loop_run(main_loop);
1105b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1106b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} else {
110764989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		data.address = strdup(argv[1]);
1108b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1109b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(init_bt(&data) == 0);
1110b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1111b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		assert(init_profile(&data) == 0);
1112b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1113b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		assert(start_stream(&data) == 0);
1114b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1115b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		g_main_loop_run(main_loop);
1116b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1117b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		assert(stop_stream(&data) == 0);
1118b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1119b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		shutdown_bt(&data);
1120b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1121b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1122b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	g_main_loop_unref(main_loop);
1123b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1124b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	printf("\nExiting\n");
1125b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1126b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	exit(EXIT_SUCCESS);
1127b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1128b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
1129b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
1130