diff options
author | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2013-07-02 18:31:59 +0300 |
---|---|---|
committer | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2013-07-12 15:05:49 +0300 |
commit | fe4cbedb1e084b644038937caab0b15fcf8d662b (patch) | |
tree | b5a1dbe41550563b83b2fce3070b3c9fe92c8d64 /plugins/policy.c | |
parent | 138481c9f4305de2dce5234951938dfdbe53218f (diff) | |
download | bluez-fe4cbedb1e084b644038937caab0b15fcf8d662b.tar.gz |
plugins/policy: Reword audio policy code in a simple plugin
This moves audio device policy to a plugin and removes any dependency of
audio plugin to it.
Diffstat (limited to 'plugins/policy.c')
-rw-r--r-- | plugins/policy.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/plugins/policy.c b/plugins/policy.c new file mode 100644 index 000000000..b0679f8fb --- /dev/null +++ b/plugins/policy.c @@ -0,0 +1,330 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2013 Intel Corporation. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> + +#include <glib.h> + +#include "lib/uuid.h" +#include "src/log.h" +#include "src/plugin.h" +#include "src/adapter.h" +#include "src/device.h" +#include "src/service.h" +#include "src/profile.h" + +#define CONTROL_CONNECT_TIMEOUT 2 + +static unsigned int service_id = 0; +static GSList *devices = NULL; + +struct policy_data { + struct btd_device *dev; + + guint ct_timer; + guint tg_timer; +}; + +static void policy_connect(struct policy_data *data, + struct btd_service *service) +{ + struct btd_profile *profile = btd_service_get_profile(service); + + DBG("%s profile %s", device_get_path(data->dev), profile->name); + + btd_service_connect(service); +} + +static void policy_disconnect(struct policy_data *data, + struct btd_service *service) +{ + struct btd_profile *profile = btd_service_get_profile(service); + + DBG("%s profile %s", device_get_path(data->dev), profile->name); + + btd_service_disconnect(service); +} + +static gboolean policy_connect_ct(gpointer user_data) +{ + struct policy_data *data = user_data; + struct btd_service *service; + + data->ct_timer = 0; + + service = btd_device_get_service(data->dev, AVRCP_REMOTE_UUID); + if (service != NULL) + policy_connect(data, service); + + return FALSE; +} + +static void policy_set_ct_timer(struct policy_data *data) +{ + if (data->ct_timer > 0) + g_source_remove(data->ct_timer); + + data->ct_timer = g_timeout_add_seconds(CONTROL_CONNECT_TIMEOUT, + policy_connect_ct, data); +} + +static struct policy_data *find_data(struct btd_device *dev) +{ + GSList *l; + + for (l = devices; l; l = l->next) { + struct policy_data *data = l->data; + + if (data->dev == dev) + return data; + } + + return NULL; +} + +static void policy_remove(void *user_data) +{ + struct policy_data *data = user_data; + + if (data->ct_timer > 0) + g_source_remove(data->ct_timer); + + if (data->tg_timer > 0) + g_source_remove(data->tg_timer); + + g_free(data); +} + +static struct policy_data *policy_get_data(struct btd_device *dev) +{ + struct policy_data *data; + + data = find_data(dev); + if (data != NULL) + return data; + + data = g_new0(struct policy_data, 1); + data->dev = dev; + + devices = g_slist_prepend(devices, data); + + return data; +} + +static void sink_cb(struct btd_device *dev, btd_service_state_t old_state, + btd_service_state_t new_state) +{ + struct policy_data *data; + struct btd_service *controller; + + controller = btd_device_get_service(dev, AVRCP_REMOTE_UUID); + if (controller == NULL) + return; + + data = policy_get_data(dev); + + switch (new_state) { + case BTD_SERVICE_STATE_UNAVAILABLE: + case BTD_SERVICE_STATE_DISCONNECTED: + if (data->ct_timer > 0) { + g_source_remove(data->ct_timer); + data->ct_timer = 0; + } else if (btd_service_get_state(controller) != + BTD_SERVICE_STATE_DISCONNECTED) + policy_disconnect(data, controller); + break; + case BTD_SERVICE_STATE_CONNECTING: + break; + case BTD_SERVICE_STATE_CONNECTED: + /* Check if service initiate the connection then proceed + * immediatelly otherwise set timer + */ + if (old_state == BTD_SERVICE_STATE_CONNECTING) + policy_connect(data, controller); + else if (btd_service_get_state(controller) != + BTD_SERVICE_STATE_CONNECTED) + policy_set_ct_timer(data); + break; + case BTD_SERVICE_STATE_DISCONNECTING: + break; + } +} + +static gboolean policy_connect_tg(gpointer user_data) +{ + struct policy_data *data = user_data; + struct btd_service *service; + + data->tg_timer = 0; + + service = btd_device_get_service(data->dev, AVRCP_TARGET_UUID); + if (service != NULL) + policy_connect(data, service); + + return FALSE; +} + +static void policy_set_tg_timer(struct policy_data *data) +{ + if (data->tg_timer > 0) + g_source_remove(data->tg_timer); + + data->tg_timer = g_timeout_add_seconds(CONTROL_CONNECT_TIMEOUT, + policy_connect_tg, + data); +} + +static void source_cb(struct btd_device *dev, btd_service_state_t old_state, + btd_service_state_t new_state) +{ + struct policy_data *data; + struct btd_service *target; + + target = btd_device_get_service(dev, AVRCP_TARGET_UUID); + if (target == NULL) + return; + + data = policy_get_data(dev); + + switch (new_state) { + case BTD_SERVICE_STATE_UNAVAILABLE: + case BTD_SERVICE_STATE_DISCONNECTED: + if (data->tg_timer > 0) { + g_source_remove(data->tg_timer); + data->tg_timer = 0; + } else if (btd_service_get_state(target) != + BTD_SERVICE_STATE_DISCONNECTED) + policy_disconnect(data, target); + break; + case BTD_SERVICE_STATE_CONNECTING: + break; + case BTD_SERVICE_STATE_CONNECTED: + /* Check if service initiate the connection then proceed + * immediatelly otherwise set timer + */ + if (old_state == BTD_SERVICE_STATE_CONNECTING) + policy_connect(data, target); + else if (btd_service_get_state(target) != + BTD_SERVICE_STATE_CONNECTED) + policy_set_tg_timer(data); + break; + case BTD_SERVICE_STATE_DISCONNECTING: + break; + } +} + +static void controller_cb(struct btd_service *service, + btd_service_state_t old_state, + btd_service_state_t new_state) +{ + struct btd_device *dev = btd_service_get_device(service); + struct policy_data *data; + + data = find_data(dev); + if (data == NULL) + return; + + switch (new_state) { + case BTD_SERVICE_STATE_UNAVAILABLE: + case BTD_SERVICE_STATE_DISCONNECTED: + break; + case BTD_SERVICE_STATE_CONNECTING: + break; + case BTD_SERVICE_STATE_CONNECTED: + if (data->ct_timer > 0) { + g_source_remove(data->ct_timer); + data->ct_timer = 0; + } + break; + case BTD_SERVICE_STATE_DISCONNECTING: + break; + } +} + +static void target_cb(struct btd_service *service, + btd_service_state_t old_state, + btd_service_state_t new_state) +{ + struct btd_device *dev = btd_service_get_device(service); + struct policy_data *data; + + data = find_data(dev); + if (data == NULL) + return; + + switch (new_state) { + case BTD_SERVICE_STATE_UNAVAILABLE: + case BTD_SERVICE_STATE_DISCONNECTED: + break; + case BTD_SERVICE_STATE_CONNECTING: + break; + case BTD_SERVICE_STATE_CONNECTED: + if (data->tg_timer > 0) { + g_source_remove(data->tg_timer); + data->tg_timer = 0; + } + break; + case BTD_SERVICE_STATE_DISCONNECTING: + break; + } +} + +static void service_cb(struct btd_service *service, + btd_service_state_t old_state, + btd_service_state_t new_state, + void *user_data) +{ + struct btd_profile *profile = btd_service_get_profile(service); + + if (g_str_equal(profile->remote_uuid, A2DP_SINK_UUID)) + sink_cb(dev, old_state, new_state); + else if (g_str_equal(profile->remote_uuid, A2DP_SOURCE_UUID)) + source_cb(dev, old_state, new_state); + else if (g_str_equal(profile->remote_uuid, AVRCP_REMOTE_UUID)) + controller_cb(service, old_state, new_state); + else if (g_str_equal(profile->remote_uuid, AVRCP_TARGET_UUID)) + target_cb(service, old_state, new_state); +} + +static int policy_init(void) +{ + service_id = btd_service_add_state_cb(service_cb, NULL); + + return 0; +} + +static void policy_exit(void) +{ + g_slist_free_full(devices, policy_remove); + + btd_service_remove_state_cb(service_id); +} + +BLUETOOTH_PLUGIN_DEFINE(policy, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, + policy_init, policy_exit) |