diff options
Diffstat (limited to 'cras/src/server/cras_bt_transport.c')
-rw-r--r-- | cras/src/server/cras_bt_transport.c | 634 |
1 files changed, 0 insertions, 634 deletions
diff --git a/cras/src/server/cras_bt_transport.c b/cras/src/server/cras_bt_transport.c deleted file mode 100644 index 402cd75a..00000000 --- a/cras/src/server/cras_bt_transport.c +++ /dev/null @@ -1,634 +0,0 @@ -/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include <dbus/dbus.h> - -#include <errno.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> - -#include "cras_bt_device.h" -#include "cras_bt_endpoint.h" -#include "cras_bt_log.h" -#include "cras_bt_transport.h" -#include "cras_bt_constants.h" -#include "cras_system_state.h" -#include "utlist.h" - -struct cras_bt_transport { - DBusConnection *conn; - char *object_path; - struct cras_bt_device *device; - enum cras_bt_device_profile profile; - int codec; - void *configuration; - int configuration_len; - enum cras_bt_transport_state state; - int fd; - uint16_t read_mtu; - uint16_t write_mtu; - int volume; - int removed; - - struct cras_bt_endpoint *endpoint; - struct cras_bt_transport *prev, *next; -}; - -static struct cras_bt_transport *transports; - -struct cras_bt_transport *cras_bt_transport_create(DBusConnection *conn, - const char *object_path) -{ - struct cras_bt_transport *transport; - - transport = calloc(1, sizeof(*transport)); - if (transport == NULL) - return NULL; - - transport->object_path = strdup(object_path); - if (transport->object_path == NULL) { - free(transport); - return NULL; - } - - transport->conn = conn; - dbus_connection_ref(transport->conn); - - transport->fd = -1; - transport->volume = -1; - - DL_APPEND(transports, transport); - - return transport; -} - -void cras_bt_transport_set_endpoint(struct cras_bt_transport *transport, - struct cras_bt_endpoint *endpoint) -{ - transport->endpoint = endpoint; -} - -int cras_bt_transport_is_removed(struct cras_bt_transport *transport) -{ - return transport->removed; -} - -void cras_bt_transport_remove(struct cras_bt_transport *transport) -{ - /* - * If the transport object is still associated with a valid - * endpoint. Flag it as removed and wait for the ClearConfiguration - * message from BT to actually suspend this A2DP connection and - * destroy the transport. - */ - if (transport->endpoint) - transport->removed = 1; - else - cras_bt_transport_destroy(transport); -} - -void cras_bt_transport_destroy(struct cras_bt_transport *transport) -{ - DL_DELETE(transports, transport); - - dbus_connection_unref(transport->conn); - - if (transport->fd >= 0) - close(transport->fd); - - cras_bt_device_set_use_hardware_volume(transport->device, 0); - - free(transport->object_path); - free(transport->configuration); - free(transport); -} - -void cras_bt_transport_reset() -{ - while (transports) { - syslog(LOG_INFO, "Bluetooth Transport: %s removed", - transports->object_path); - cras_bt_transport_destroy(transports); - } -} - -struct cras_bt_transport *cras_bt_transport_get(const char *object_path) -{ - struct cras_bt_transport *transport; - - DL_FOREACH (transports, transport) { - if (strcmp(transport->object_path, object_path) == 0) - return transport; - } - - return NULL; -} - -size_t -cras_bt_transport_get_list(struct cras_bt_transport ***transport_list_out) -{ - struct cras_bt_transport *transport; - struct cras_bt_transport **transport_list = NULL; - size_t num_transports = 0; - - DL_FOREACH (transports, transport) { - struct cras_bt_transport **tmp; - - tmp = realloc(transport_list, - sizeof(transport_list[0]) * (num_transports + 1)); - if (!tmp) { - free(transport_list); - return -ENOMEM; - } - - transport_list = tmp; - transport_list[num_transports++] = transport; - } - - *transport_list_out = transport_list; - return num_transports; -} - -const char * -cras_bt_transport_object_path(const struct cras_bt_transport *transport) -{ - return transport->object_path; -} - -struct cras_bt_device * -cras_bt_transport_device(const struct cras_bt_transport *transport) -{ - return transport->device; -} - -enum cras_bt_device_profile -cras_bt_transport_profile(const struct cras_bt_transport *transport) -{ - return transport->profile; -} - -int cras_bt_transport_configuration(const struct cras_bt_transport *transport, - void *configuration, int len) -{ - if (len < transport->configuration_len) - return -ENOSPC; - - memcpy(configuration, transport->configuration, - transport->configuration_len); - - return 0; -} - -enum cras_bt_transport_state -cras_bt_transport_state(const struct cras_bt_transport *transport) -{ - return transport->state; -} - -int cras_bt_transport_fd(const struct cras_bt_transport *transport) -{ - return transport->fd; -} - -uint16_t cras_bt_transport_write_mtu(const struct cras_bt_transport *transport) -{ - return transport->write_mtu; -} - -static enum cras_bt_transport_state -cras_bt_transport_state_from_string(const char *value) -{ - if (strcmp("idle", value) == 0) - return CRAS_BT_TRANSPORT_STATE_IDLE; - else if (strcmp("pending", value) == 0) - return CRAS_BT_TRANSPORT_STATE_PENDING; - else if (strcmp("active", value) == 0) - return CRAS_BT_TRANSPORT_STATE_ACTIVE; - else - return CRAS_BT_TRANSPORT_STATE_IDLE; -} - -static void cras_bt_transport_state_changed(struct cras_bt_transport *transport) -{ - if (transport->endpoint && transport->endpoint->transport_state_changed) - transport->endpoint->transport_state_changed( - transport->endpoint, transport); -} - -/* Updates bt_device when certain transport property has changed. */ -static void cras_bt_transport_update_device(struct cras_bt_transport *transport) -{ - if (!transport->device) - return; - - /* When the transport has non-negaive volume, it means the remote - * BT audio devices supports AVRCP absolute volume. Set the flag in bt - * device to use hardware volume. Also map the volume value from 0-127 - * to 0-100. - */ - if (transport->volume != -1) { - cras_bt_device_set_use_hardware_volume(transport->device, 1); - cras_bt_device_update_hardware_volume( - transport->device, transport->volume * 100 / 127); - } -} - -void cras_bt_transport_update_properties(struct cras_bt_transport *transport, - DBusMessageIter *properties_array_iter, - DBusMessageIter *invalidated_array_iter) -{ - while (dbus_message_iter_get_arg_type(properties_array_iter) != - DBUS_TYPE_INVALID) { - DBusMessageIter properties_dict_iter, variant_iter; - const char *key; - int type; - - dbus_message_iter_recurse(properties_array_iter, - &properties_dict_iter); - - dbus_message_iter_get_basic(&properties_dict_iter, &key); - dbus_message_iter_next(&properties_dict_iter); - - dbus_message_iter_recurse(&properties_dict_iter, &variant_iter); - type = dbus_message_iter_get_arg_type(&variant_iter); - - if (type == DBUS_TYPE_STRING) { - const char *value; - - dbus_message_iter_get_basic(&variant_iter, &value); - - if (strcmp(key, "UUID") == 0) { - transport->profile = - cras_bt_device_profile_from_uuid(value); - - } else if (strcmp(key, "State") == 0) { - enum cras_bt_transport_state old_state = - transport->state; - transport->state = - cras_bt_transport_state_from_string( - value); - if (transport->state != old_state) - cras_bt_transport_state_changed( - transport); - } - - } else if (type == DBUS_TYPE_BYTE) { - int value; - - dbus_message_iter_get_basic(&variant_iter, &value); - - if (strcmp(key, "Codec") == 0) - transport->codec = value; - } else if (type == DBUS_TYPE_OBJECT_PATH) { - const char *obj_path; - - if (strcmp(key, "Device") == 0) { - /* Property: object Device [readonly] */ - dbus_message_iter_get_basic(&variant_iter, - &obj_path); - transport->device = - cras_bt_device_get(obj_path); - if (!transport->device) { - syslog(LOG_ERR, - "Device %s not found at update " - "transport properties", - obj_path); - transport->device = - cras_bt_device_create( - transport->conn, - obj_path); - cras_bt_transport_update_device( - transport); - } - } - } else if (strcmp(dbus_message_iter_get_signature(&variant_iter), - "ay") == 0 && - strcmp(key, "Configuration") == 0) { - DBusMessageIter value_iter; - char *value; - int len; - - dbus_message_iter_recurse(&variant_iter, &value_iter); - dbus_message_iter_get_fixed_array(&value_iter, &value, - &len); - - free(transport->configuration); - transport->configuration_len = 0; - - transport->configuration = malloc(len); - if (transport->configuration) { - memcpy(transport->configuration, value, len); - transport->configuration_len = len; - } - - } else if (strcmp(key, "Volume") == 0) { - uint16_t volume; - - dbus_message_iter_get_basic(&variant_iter, &volume); - transport->volume = volume; - BTLOG(btlog, BT_TRANSPORT_UPDATE_VOLUME, volume, 0); - cras_bt_transport_update_device(transport); - } - - dbus_message_iter_next(properties_array_iter); - } - - while (invalidated_array_iter && - dbus_message_iter_get_arg_type(invalidated_array_iter) != - DBUS_TYPE_INVALID) { - const char *key; - - dbus_message_iter_get_basic(invalidated_array_iter, &key); - - if (strcmp(key, "Device") == 0) { - transport->device = NULL; - } else if (strcmp(key, "UUID") == 0) { - transport->profile = 0; - } else if (strcmp(key, "State") == 0) { - transport->state = CRAS_BT_TRANSPORT_STATE_IDLE; - } else if (strcmp(key, "Codec") == 0) { - transport->codec = 0; - } else if (strcmp(key, "Configuration") == 0) { - free(transport->configuration); - transport->configuration = NULL; - transport->configuration_len = 0; - } - - dbus_message_iter_next(invalidated_array_iter); - } -} - -static void on_transport_volume_set(DBusPendingCall *pending_call, void *data) -{ - DBusMessage *reply; - - reply = dbus_pending_call_steal_reply(pending_call); - dbus_pending_call_unref(pending_call); - - if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) - syslog(LOG_ERR, "Set absolute volume returned error: %s", - dbus_message_get_error_name(reply)); - dbus_message_unref(reply); -} - -int cras_bt_transport_set_volume(struct cras_bt_transport *transport, - uint16_t volume) -{ - const char *key = "Volume"; - const char *interface = BLUEZ_INTERFACE_MEDIA_TRANSPORT; - DBusMessage *method_call; - DBusMessageIter message_iter, variant; - DBusPendingCall *pending_call; - - BTLOG(btlog, BT_TRANSPORT_SET_VOLUME, volume, 0); - method_call = - dbus_message_new_method_call(BLUEZ_SERVICE, - transport->object_path, - DBUS_INTERFACE_PROPERTIES, "Set"); - if (!method_call) - return -ENOMEM; - - dbus_message_iter_init_append(method_call, &message_iter); - - dbus_message_iter_append_basic(&message_iter, DBUS_TYPE_STRING, - &interface); - dbus_message_iter_append_basic(&message_iter, DBUS_TYPE_STRING, &key); - - dbus_message_iter_open_container(&message_iter, DBUS_TYPE_VARIANT, - DBUS_TYPE_UINT16_AS_STRING, &variant); - dbus_message_iter_append_basic(&variant, DBUS_TYPE_UINT16, &volume); - dbus_message_iter_close_container(&message_iter, &variant); - - if (!dbus_connection_send_with_reply(transport->conn, method_call, - &pending_call, - DBUS_TIMEOUT_USE_DEFAULT)) { - dbus_message_unref(method_call); - return -ENOMEM; - } - - dbus_message_unref(method_call); - if (!pending_call) - return -EIO; - - if (!dbus_pending_call_set_notify(pending_call, on_transport_volume_set, - NULL, NULL)) { - dbus_pending_call_cancel(pending_call); - dbus_pending_call_unref(pending_call); - return -ENOMEM; - } - - return 0; -} - -int cras_bt_transport_acquire(struct cras_bt_transport *transport) -{ - DBusMessage *method_call, *reply; - DBusError dbus_error; - int rc = 0; - - if (transport->fd >= 0) - return 0; - - method_call = dbus_message_new_method_call( - BLUEZ_SERVICE, transport->object_path, - BLUEZ_INTERFACE_MEDIA_TRANSPORT, "Acquire"); - if (!method_call) - return -ENOMEM; - - dbus_error_init(&dbus_error); - - reply = dbus_connection_send_with_reply_and_block( - transport->conn, method_call, DBUS_TIMEOUT_USE_DEFAULT, - &dbus_error); - if (!reply) { - syslog(LOG_ERR, "Failed to acquire transport %s: %s", - transport->object_path, dbus_error.message); - dbus_error_free(&dbus_error); - dbus_message_unref(method_call); - rc = -EIO; - goto acquire_fail; - } - - dbus_message_unref(method_call); - - if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { - syslog(LOG_ERR, "Acquire returned error: %s", - dbus_message_get_error_name(reply)); - dbus_message_unref(reply); - rc = -EIO; - goto acquire_fail; - } - - if (!dbus_message_get_args( - reply, &dbus_error, DBUS_TYPE_UNIX_FD, &(transport->fd), - DBUS_TYPE_UINT16, &(transport->read_mtu), DBUS_TYPE_UINT16, - &(transport->write_mtu), DBUS_TYPE_INVALID)) { - syslog(LOG_ERR, "Bad Acquire reply received: %s", - dbus_error.message); - dbus_error_free(&dbus_error); - dbus_message_unref(reply); - rc = -EINVAL; - goto acquire_fail; - } - - if (cras_system_get_bt_fix_a2dp_packet_size_enabled() && - transport->write_mtu > A2DP_FIX_PACKET_SIZE) - transport->write_mtu = A2DP_FIX_PACKET_SIZE; - - BTLOG(btlog, BT_TRANSPORT_ACQUIRE, 1, transport->fd); - dbus_message_unref(reply); - return 0; - -acquire_fail: - BTLOG(btlog, BT_TRANSPORT_ACQUIRE, 0, 0); - return rc; -} - -int cras_bt_transport_try_acquire(struct cras_bt_transport *transport) -{ - DBusMessage *method_call, *reply; - DBusError dbus_error; - int fd, read_mtu, write_mtu; - - method_call = dbus_message_new_method_call( - BLUEZ_SERVICE, transport->object_path, - BLUEZ_INTERFACE_MEDIA_TRANSPORT, "TryAcquire"); - if (!method_call) - return -ENOMEM; - - dbus_error_init(&dbus_error); - - reply = dbus_connection_send_with_reply_and_block( - transport->conn, method_call, DBUS_TIMEOUT_USE_DEFAULT, - &dbus_error); - if (!reply) { - syslog(LOG_ERR, "Failed to try acquire transport %s: %s", - transport->object_path, dbus_error.message); - dbus_error_free(&dbus_error); - dbus_message_unref(method_call); - return -EIO; - } - - dbus_message_unref(method_call); - - if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { - syslog(LOG_ERR, "TryAcquire returned error: %s", - dbus_message_get_error_name(reply)); - dbus_message_unref(reply); - return -EIO; - } - - if (!dbus_message_get_args(reply, &dbus_error, DBUS_TYPE_UNIX_FD, &fd, - DBUS_TYPE_UINT16, &read_mtu, - DBUS_TYPE_UINT16, &write_mtu, - DBUS_TYPE_INVALID)) { - syslog(LOG_ERR, "Bad TryAcquire reply received: %s", - dbus_error.message); - dbus_error_free(&dbus_error); - dbus_message_unref(reply); - return -EINVAL; - } - - /* Done TryAcquired the transport so it won't be released in bluez, - * no need for the new file descriptor so close it. */ - if (transport->fd != fd) - close(fd); - - dbus_message_unref(reply); - return 0; -} - -/* Callback to trigger when transport release completed. */ -static void cras_bt_on_transport_release(DBusPendingCall *pending_call, - void *data) -{ - DBusMessage *reply; - - reply = dbus_pending_call_steal_reply(pending_call); - dbus_pending_call_unref(pending_call); - - if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { - syslog(LOG_WARNING, "Release transport returned error: %s", - dbus_message_get_error_name(reply)); - dbus_message_unref(reply); - return; - } - - dbus_message_unref(reply); -} - -int cras_bt_transport_release(struct cras_bt_transport *transport, - unsigned int blocking) -{ - DBusMessage *method_call, *reply; - DBusPendingCall *pending_call; - DBusError dbus_error; - - if (transport->fd < 0) - return 0; - - BTLOG(btlog, BT_TRANSPORT_RELEASE, transport->fd, 0); - - /* Close the transport on our end no matter whether or not the server - * gives us an error. - */ - close(transport->fd); - transport->fd = -1; - - method_call = dbus_message_new_method_call( - BLUEZ_SERVICE, transport->object_path, - BLUEZ_INTERFACE_MEDIA_TRANSPORT, "Release"); - if (!method_call) - return -ENOMEM; - - if (blocking) { - dbus_error_init(&dbus_error); - - reply = dbus_connection_send_with_reply_and_block( - transport->conn, method_call, DBUS_TIMEOUT_USE_DEFAULT, - &dbus_error); - if (!reply) { - syslog(LOG_ERR, "Failed to release transport %s: %s", - transport->object_path, dbus_error.message); - dbus_error_free(&dbus_error); - dbus_message_unref(method_call); - return -EIO; - } - - dbus_message_unref(method_call); - - if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { - syslog(LOG_ERR, "Release returned error: %s", - dbus_message_get_error_name(reply)); - dbus_message_unref(reply); - return -EIO; - } - - dbus_message_unref(reply); - } else { - if (!dbus_connection_send_with_reply( - transport->conn, method_call, &pending_call, - DBUS_TIMEOUT_USE_DEFAULT)) { - dbus_message_unref(method_call); - return -ENOMEM; - } - - dbus_message_unref(method_call); - if (!pending_call) - return -EIO; - - if (!dbus_pending_call_set_notify(pending_call, - cras_bt_on_transport_release, - transport, NULL)) { - dbus_pending_call_cancel(pending_call); - dbus_pending_call_unref(pending_call); - return -ENOMEM; - } - } - return 0; -} |