]> code.delx.au - pulseaudio/blob - src/modules/bluetooth/module-bluez5-device.c
bluetooth: Unload module-bluez5-device on device's disconnection
[pulseaudio] / src / modules / bluetooth / module-bluez5-device.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2008-2013 João Paulo Rechi Vita
5 Copyright 2011-2013 BMW Car IT GmbH.
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <pulsecore/module.h>
28 #include <pulsecore/modargs.h>
29
30 #include "bluez5-util.h"
31
32 #include "module-bluez5-device-symdef.h"
33
34 PA_MODULE_AUTHOR("João Paulo Rechi Vita");
35 PA_MODULE_DESCRIPTION("BlueZ 5 Bluetooth audio sink and source");
36 PA_MODULE_VERSION(PACKAGE_VERSION);
37 PA_MODULE_LOAD_ONCE(false);
38 PA_MODULE_USAGE("path=<device object path>");
39
40 static const char* const valid_modargs[] = {
41 "path",
42 NULL
43 };
44
45 struct userdata {
46 pa_module *module;
47 pa_core *core;
48
49 pa_hook_slot *device_connection_changed_slot;
50
51 pa_bluetooth_discovery *discovery;
52 pa_bluetooth_device *device;
53 };
54
55 /* Run from main thread */
56 static pa_hook_result_t device_connection_changed_cb(pa_bluetooth_discovery *y, const pa_bluetooth_device *d, struct userdata *u) {
57 pa_assert(d);
58 pa_assert(u);
59
60 if (d != u->device || pa_bluetooth_device_any_transport_connected(d))
61 return PA_HOOK_OK;
62
63 pa_log_debug("Unloading module for device %s", d->path);
64 pa_module_unload(u->core, u->module, true);
65
66 return PA_HOOK_OK;
67 }
68
69 int pa__init(pa_module* m) {
70 struct userdata *u;
71 const char *path;
72 pa_modargs *ma;
73
74 pa_assert(m);
75
76 m->userdata = u = pa_xnew0(struct userdata, 1);
77 u->module = m;
78 u->core = m->core;
79
80 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
81 pa_log_error("Failed to parse module arguments");
82 goto fail;
83 }
84
85 if (!(path = pa_modargs_get_value(ma, "path", NULL))) {
86 pa_log_error("Failed to get device path from module arguments");
87 goto fail;
88 }
89
90 if (!(u->discovery = pa_bluetooth_discovery_get(m->core)))
91 goto fail;
92
93 if (!(u->device = pa_bluetooth_discovery_get_device_by_path(u->discovery, path))) {
94 pa_log_error("%s is unknown", path);
95 goto fail;
96 }
97
98 pa_modargs_free(ma);
99
100 u->device_connection_changed_slot =
101 pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED),
102 PA_HOOK_NORMAL, (pa_hook_cb_t) device_connection_changed_cb, u);
103
104 return 0;
105
106 fail:
107
108 if (ma)
109 pa_modargs_free(ma);
110
111 pa__done(m);
112
113 return -1;
114 }
115
116 void pa__done(pa_module *m) {
117 struct userdata *u;
118
119 pa_assert(m);
120
121 if (!(u = m->userdata))
122 return;
123
124 if (u->device_connection_changed_slot)
125 pa_hook_slot_free(u->device_connection_changed_slot);
126
127 if (u->discovery)
128 pa_bluetooth_discovery_unref(u->discovery);
129
130 pa_xfree(u);
131 }