device.c revision dad4c62b54ab078c1d5525e80be9c6391ea1731a
1/*
2 *
3 *  BlueZ - Bluetooth protocol stack for Linux
4 *
5 *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org>
6 *
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation; either version 2 of the License, or
11 *  (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program; if not, write to the Free Software
20 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <stdio.h>
29#include <errno.h>
30#include <unistd.h>
31#include <sys/stat.h>
32#include <netinet/in.h>
33
34#include <glib.h>
35#include <dbus/dbus.h>
36
37#include <bluetooth/bluetooth.h>
38#include <bluetooth/hci.h>
39#include <bluetooth/hci_lib.h>
40#include <bluetooth/sdp.h>
41#include <bluetooth/sdp_lib.h>
42
43#include "dbus.h"
44#include "dbus-helper.h"
45#include "logging.h"
46#include "textfile.h"
47
48#include "error.h"
49#include "ipc.h"
50#include "device.h"
51#include "avdtp.h"
52#include "headset.h"
53#include "sink.h"
54
55static DBusHandlerResult device_get_address(DBusConnection *conn,
56						DBusMessage *msg, void *data)
57{
58	struct device *device = data;
59	DBusMessage *reply;
60	char address[18], *ptr = address;
61
62	reply = dbus_message_new_method_return(msg);
63	if (!reply)
64		return DBUS_HANDLER_RESULT_NEED_MEMORY;
65
66	ba2str(&device->dst, address);
67
68	dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr,
69							DBUS_TYPE_INVALID);
70
71	return send_message_and_unref(conn, reply);
72}
73
74static DBusHandlerResult device_get_name(DBusConnection *conn,
75						DBusMessage *msg, void *data)
76{
77	struct device *device = data;
78	DBusMessage *reply, *reply2, *msg2;
79	DBusError derr;
80	const char *name;
81	char address[18], *addr_ptr = address;
82
83	msg2 = dbus_message_new_method_call("org.bluez", device->adapter_path,
84					"org.bluez.Adapter", "GetRemoteName");
85	if (!msg2)
86		return DBUS_HANDLER_RESULT_NEED_MEMORY;
87
88	ba2str(&device->dst, address);
89	dbus_message_append_args(msg2, DBUS_TYPE_STRING, &addr_ptr,
90					DBUS_TYPE_INVALID);
91
92	dbus_error_init(&derr);
93	reply2 = dbus_connection_send_with_reply_and_block(conn, msg2, -1,
94								&derr);
95
96	dbus_message_unref(msg2);
97
98	if (dbus_error_is_set(&derr)) {
99		error("%s GetRemoteName(): %s", device->adapter_path,
100				derr.message);
101		dbus_error_free(&derr);
102		return err_failed(conn, msg, "Unable to get remote name");
103	}
104
105
106	reply = dbus_message_new_method_return(msg);
107	if (!reply)
108		return DBUS_HANDLER_RESULT_NEED_MEMORY;
109
110	dbus_message_get_args(reply2, NULL,
111		       		DBUS_TYPE_STRING, &name,
112				DBUS_TYPE_INVALID);
113
114	dbus_message_append_args(reply, DBUS_TYPE_STRING, &name,
115					DBUS_TYPE_INVALID);
116
117	dbus_message_unref(reply2);
118
119	return send_message_and_unref(conn, reply);
120}
121
122static DBusHandlerResult device_get_connected(DBusConnection *conn,
123						DBusMessage *msg, void *data)
124{
125	DBusMessageIter iter, array_iter;
126	struct device *device = data;
127	DBusMessage *reply;
128	const char *iface;
129
130	reply = dbus_message_new_method_return(msg);
131	if (!reply)
132		return DBUS_HANDLER_RESULT_NEED_MEMORY;
133
134	dbus_message_iter_init_append(reply, &iter);
135
136	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
137						DBUS_TYPE_STRING_AS_STRING,
138						&array_iter);
139
140	if (device->headset &&
141			headset_get_state(device) >= HEADSET_STATE_CONNECTED) {
142		iface = AUDIO_HEADSET_INTERFACE;
143		dbus_message_iter_append_basic(&array_iter,
144						DBUS_TYPE_STRING, &iface);
145	}
146
147	dbus_message_iter_close_container(&iter, &array_iter);
148
149	return send_message_and_unref(conn, reply);
150}
151
152static DBusMethodVTable device_methods[] = {
153	{ "GetAddress",			device_get_address,	"",	"s" },
154	{ "GetName",			device_get_name,	"",	"s" },
155	{ "GetConnectedInterfaces",	device_get_connected,	"",	"as" },
156	{ NULL, NULL, NULL, NULL }
157};
158
159static void device_free(struct device *dev)
160{
161	if (dev->headset)
162		headset_free(dev);
163
164	if (dev->sink)
165		sink_free(dev);
166
167	if (dev->conn)
168		dbus_connection_unref(dev->conn);
169
170	if (dev->adapter_path)
171		g_free(dev->adapter_path);
172
173	if (dev->path)
174		g_free(dev->path);
175
176	g_free(dev);
177}
178
179static void device_unregister(DBusConnection *conn, void *data)
180{
181	struct device *device = data;
182
183	info("Unregistered device path:%s", device->path);
184
185	device_free(device);
186}
187
188char *find_adapter(DBusConnection *conn, bdaddr_t *src)
189{
190	DBusMessage *msg, *reply;
191	DBusError derr;
192	char address[18], *addr_ptr = address;
193	char *path, *ret;
194
195	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
196						"org.bluez.Manager",
197						"FindAdapter");
198	if (!msg) {
199		error("Unable to allocate new method call");
200		return NULL;
201	}
202
203	ba2str(src, address);
204
205	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,
206				 DBUS_TYPE_INVALID);
207
208	dbus_error_init(&derr);
209	reply = dbus_connection_send_with_reply_and_block(conn, msg, -1,
210								&derr);
211
212	dbus_message_unref(msg);
213
214	if (dbus_error_is_set(&derr) ||
215				dbus_set_error_from_message(&derr, reply)) {
216		error("FindAdapter(%s) failed: %s", address, derr.message);
217		dbus_error_free(&derr);
218		return NULL;
219	}
220
221	dbus_error_init(&derr);
222	dbus_message_get_args(reply, &derr,
223				DBUS_TYPE_STRING, &path,
224				DBUS_TYPE_INVALID);
225
226	if (dbus_error_is_set(&derr)) {
227		error("Unable to get message args");
228		dbus_message_unref(reply);
229		dbus_error_free(&derr);
230		return FALSE;
231	}
232
233	ret = g_strdup(path);
234
235	dbus_message_unref(reply);
236
237	debug("Got path %s for adapter with address %s", ret, address);
238
239	return ret;
240}
241
242struct device *device_register(DBusConnection *conn,
243					const char *path, bdaddr_t *bda)
244{
245	struct device *dev;
246	bdaddr_t src;
247	int dev_id;
248
249	if (!conn || !path)
250		return NULL;
251
252	bacpy(&src, BDADDR_ANY);
253	dev_id = hci_get_route(&src);
254	if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0))
255		return NULL;
256
257	dev = g_new0(struct device, 1);
258
259	dev->adapter_path = find_adapter(conn, &src);
260	if (!dev->adapter_path) {
261		device_free(dev);
262		return NULL;
263	}
264
265	if (!dbus_connection_create_object_path(conn, path, dev,
266							device_unregister)) {
267		error("D-Bus failed to register %s path", path);
268		device_free(dev);
269		return NULL;
270	}
271
272	if (!dbus_connection_register_interface(conn, path,
273			AUDIO_DEVICE_INTERFACE, device_methods, NULL, NULL)) {
274		error("Failed to register %s interface to %s",
275					AUDIO_DEVICE_INTERFACE, path);
276		dbus_connection_destroy_object_path(conn, path);
277		return NULL;
278	}
279
280	dev->path = g_strdup(path);
281	bacpy(&dev->dst, bda);
282	bacpy(&dev->src, &src);
283	dev->conn = dbus_connection_ref(conn);
284
285	return dev;
286}
287
288int device_store(struct device *dev, gboolean is_default)
289{
290	char value[64];
291	char filename[PATH_MAX + 1];
292	char src_addr[18], dst_addr[18];
293	int offset = 0;
294
295	if (!dev->path)
296		return -EINVAL;
297
298	ba2str(&dev->dst, dst_addr);
299	ba2str(&dev->src, src_addr);
300
301	create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio");
302	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
303
304	if (is_default)
305		textfile_put(filename, "default", dst_addr);
306	if (dev->headset) {
307		snprintf(value, 64, "headset ");
308		offset += strlen("headset ");
309	}
310	if (dev->gateway) {
311		snprintf(value + offset, 64 - offset, "gateway ");
312		offset += strlen("gateway ");
313	}
314	if (dev->sink) {
315		snprintf(value + offset, 64 - offset, "sink ");
316		offset += strlen("sink ");
317	}
318	if (dev->source) {
319		snprintf(value + offset, 64 - offset, "source ");
320		offset += strlen("source ");
321	}
322	if (dev->control) {
323		snprintf(value + offset, 64 - offset, "control ");
324		offset += strlen("control ");
325	}
326	if (dev->target)
327		snprintf(value + offset, 64 - offset, "target");
328
329	return textfile_put(filename, dst_addr, value);
330}
331
332int device_remove_stored(struct device *dev)
333{
334	char filename[PATH_MAX + 1];
335	char src_addr[18], dst_addr[18];
336
337	ba2str(&dev->dst, dst_addr);
338	ba2str(&dev->src, src_addr);
339
340	create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio");
341
342	return textfile_del(filename, dst_addr);
343}
344
345void device_finish_sdp_transaction(struct device *dev)
346{
347	char address[18], *addr_ptr = address;
348	DBusMessage *msg, *reply;
349	DBusError derr;
350
351	ba2str(&dev->dst, address);
352
353	msg = dbus_message_new_method_call("org.bluez", dev->adapter_path,
354						"org.bluez.Adapter",
355						"FinishRemoteServiceTransaction");
356	if (!msg) {
357		error("Unable to allocate new method call");
358		return;
359	}
360
361	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,
362				 DBUS_TYPE_INVALID);
363
364	dbus_error_init(&derr);
365	reply = dbus_connection_send_with_reply_and_block(dev->conn,
366							msg, -1, &derr);
367
368	dbus_message_unref(msg);
369
370	if (dbus_error_is_set(&derr) ||
371				dbus_set_error_from_message(&derr, reply)) {
372		error("FinishRemoteServiceTransaction(%s) failed: %s",
373						address, derr.message);
374		dbus_error_free(&derr);
375		return;
376	}
377
378	dbus_message_unref(reply);
379}
380
381#if 0
382static avdtp_state_t ipc_to_avdtp_state(uint8_t ipc_state)
383{
384	switch (ipc_state) {
385	case STATE_DISCONNECTED:
386		return AVDTP_STATE_IDLE;
387	case STATE_CONNECTING:
388		return AVDTP_STATE_CONFIGURED;
389	case STATE_CONNECTED:
390		return AVDTP_STATE_OPEN;
391	case STATE_STREAM_STARTING:
392	case STATE_STREAMING:
393		return AVDTP_STATE_STREAMING;
394	default:
395		error("Unknown ipc state");
396		return AVDTP_STATE_IDLE;
397	}
398}
399
400static headset_state_t ipc_to_hs_state(uint8_t ipc_state)
401{
402	switch (ipc_state) {
403	case STATE_DISCONNECTED:
404		return HEADSET_STATE_DISCONNECTED;
405	case STATE_CONNECTING:
406		return HEADSET_STATE_CONNECT_IN_PROGRESS;
407	case STATE_CONNECTED:
408		return HEADSET_STATE_CONNECTED;
409	case STATE_STREAM_STARTING:
410		return HEADSET_STATE_PLAY_IN_PROGRESS;
411	case STATE_STREAMING:
412		return HEADSET_STATE_PLAYING;
413	default:
414		error("Unknown ipc state");
415		return HEADSET_STATE_DISCONNECTED;
416	}
417}
418#endif
419
420static uint8_t avdtp_to_ipc_state(avdtp_state_t state)
421{
422	switch (state) {
423	case AVDTP_STATE_IDLE:
424		return STATE_DISCONNECTED;
425	case AVDTP_STATE_CONFIGURED:
426		return STATE_CONNECTING;
427	case AVDTP_STATE_OPEN:
428		return STATE_CONNECTED;
429	case AVDTP_STATE_STREAMING:
430		return STATE_STREAMING;
431	default:
432		error("Unknown avdt state");
433		return AVDTP_STATE_IDLE;
434	}
435}
436
437static uint8_t hs_to_ipc_state(headset_state_t state)
438{
439	switch (state) {
440	case HEADSET_STATE_DISCONNECTED:
441		return STATE_DISCONNECTED;
442	case HEADSET_STATE_CONNECT_IN_PROGRESS:
443		return STATE_CONNECTING;
444	case HEADSET_STATE_CONNECTED:
445		return STATE_CONNECTED;
446	case HEADSET_STATE_PLAY_IN_PROGRESS:
447		return STATE_STREAMING;
448	default:
449		error("Unknown headset state");
450		return AVDTP_STATE_IDLE;
451	}
452}
453
454uint8_t device_get_state(struct device *dev)
455{
456	avdtp_state_t sink_state;
457	headset_state_t hs_state;
458
459	if (dev->sink && sink_is_active(dev)) {
460		sink_state = sink_get_state(dev);
461		return avdtp_to_ipc_state(sink_state);
462	}
463	else if (dev->headset && headset_is_active(dev)) {
464		hs_state = headset_get_state(dev);
465		return hs_to_ipc_state(hs_state);
466	}
467
468	return STATE_DISCONNECTED;
469}
470
471gboolean device_is_connected(struct device *dev, const char *interface)
472{
473	if (!interface) {
474		if ((dev->sink || dev->source) &&
475			avdtp_is_connected(&dev->src, &dev->dst))
476			return TRUE;
477
478		if (dev->headset && headset_is_active(dev))
479			return TRUE;
480	}
481	else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink &&
482			avdtp_is_connected(&dev->src, &dev->dst))
483		return TRUE;
484	else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source &&
485			avdtp_is_connected(&dev->src, &dev->dst))
486		return TRUE;
487	else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset &&
488			headset_is_active(dev))
489		return TRUE;
490
491	return FALSE;
492}
493