diff options
Diffstat (limited to 'cras/src/server/cras_hfp_ag_profile.c')
-rw-r--r-- | cras/src/server/cras_hfp_ag_profile.c | 466 |
1 files changed, 0 insertions, 466 deletions
diff --git a/cras/src/server/cras_hfp_ag_profile.c b/cras/src/server/cras_hfp_ag_profile.c deleted file mode 100644 index b5fcecc3..00000000 --- a/cras/src/server/cras_hfp_ag_profile.c +++ /dev/null @@ -1,466 +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 <stdint.h> -#include <syslog.h> -#include <sys/socket.h> -#include <unistd.h> - -#include "cras_a2dp_endpoint.h" -#include "cras_bt_adapter.h" -#include "cras_bt_constants.h" -#include "cras_bt_log.h" -#include "cras_bt_profile.h" -#include "cras_hfp_ag_profile.h" -#include "cras_hfp_info.h" -#include "cras_hfp_iodev.h" -#include "cras_hfp_alsa_iodev.h" -#include "cras_server_metrics.h" -#include "cras_system_state.h" -#include "cras_iodev_list.h" -#include "utlist.h" -#include "packet_status_logger.h" - -#define HFP_AG_PROFILE_NAME "Hands-Free Voice gateway" -#define HFP_AG_PROFILE_PATH "/org/chromium/Cras/Bluetooth/HFPAG" -#define HFP_VERSION 0x0107 -#define HSP_AG_PROFILE_NAME "Headset Voice gateway" -#define HSP_AG_PROFILE_PATH "/org/chromium/Cras/Bluetooth/HSPAG" -#define HSP_VERSION_1_2 0x0102 -#define HSP_VERSION_1_2_STR "0x0102" - -#define HSP_AG_RECORD \ - "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" \ - "<record>" \ - " <attribute id=\"0x0001\">" \ - " <sequence>" \ - " <uuid value=\"" HSP_AG_UUID "\" />" \ - " <uuid value=\"" GENERIC_AUDIO_UUID "\" />" \ - " </sequence>" \ - " </attribute>" \ - " <attribute id=\"0x0004\">" \ - " <sequence>" \ - " <sequence>" \ - " <uuid value=\"0x0100\" />" \ - " </sequence>" \ - " <sequence>" \ - " <uuid value=\"0x0003\" />" \ - " <uint8 value=\"0x0c\" />" \ - " </sequence>" \ - " </sequence>" \ - " </attribute>" \ - " <attribute id=\"0x0005\">" \ - " <sequence>" \ - " <uuid value=\"0x1002\" />" \ - " </sequence>" \ - " </attribute>" \ - " <attribute id=\"0x0009\">" \ - " <sequence>" \ - " <sequence>" \ - " <uuid value=\"" HSP_HS_UUID "\" />" \ - " <uint16 value=\"" HSP_VERSION_1_2_STR "\" />" \ - " </sequence>" \ - " </sequence>" \ - " </attribute>" \ - " <attribute id=\"0x0100\">" \ - " <text value=\"" HSP_AG_PROFILE_NAME "\" />" \ - " </attribute>" \ - " <attribute id=\"0x0301\" >" \ - " <uint8 value=\"0x01\" />" \ - " </attribute>" \ - "</record>" - -/* The supported features value in +BSRF command response of HFP AG in CRAS */ -#define BSRF_SUPPORTED_FEATURES (AG_ENHANCED_CALL_STATUS | AG_HF_INDICATORS) - -/* The "SupportedFeatures" attribute value of HFP AG service record in CRAS. */ -#define SDP_SUPPORTED_FEATURES FEATURES_AG_WIDE_BAND_SPEECH - -/* Object representing the audio gateway role for HFP/HSP. - * Members: - * idev - The input iodev for HFP/HSP. - * odev - The output iodev for HFP/HSP. - * info - The hfp_info object for SCO audio. - * slc_handle - The service level connection. - * device - The bt device associated with this audio gateway. - * a2dp_delay_retries - The number of retries left to delay starting - * the hfp/hsp audio gateway to wait for a2dp connection. - * conn - The dbus connection used to send message to bluetoothd. - * profile - The profile enum of this audio gateway. - */ -struct audio_gateway { - struct cras_iodev *idev; - struct cras_iodev *odev; - struct hfp_info *info; - struct hfp_slc_handle *slc_handle; - struct cras_bt_device *device; - int a2dp_delay_retries; - DBusConnection *conn; - enum cras_bt_device_profile profile; - struct audio_gateway *prev, *next; -}; - -static struct audio_gateway *connected_ags; -static struct packet_status_logger wbs_logger; - -static int need_go_sco_pcm(struct cras_bt_device *device) -{ - return cras_iodev_list_get_sco_pcm_iodev(CRAS_STREAM_INPUT) || - cras_iodev_list_get_sco_pcm_iodev(CRAS_STREAM_OUTPUT); -} - -static void destroy_audio_gateway(struct audio_gateway *ag) -{ - DL_DELETE(connected_ags, ag); - - cras_server_metrics_hfp_battery_indicator( - hfp_slc_get_hf_supports_battery_indicator(ag->slc_handle)); - - if (need_go_sco_pcm(ag->device)) { - if (ag->idev) - hfp_alsa_iodev_destroy(ag->idev); - if (ag->odev) - hfp_alsa_iodev_destroy(ag->odev); - } else { - if (ag->idev) - hfp_iodev_destroy(ag->idev); - if (ag->odev) - hfp_iodev_destroy(ag->odev); - } - - if (ag->info) { - if (hfp_info_running(ag->info)) - hfp_info_stop(ag->info); - hfp_info_destroy(ag->info); - } - if (ag->slc_handle) - hfp_slc_destroy(ag->slc_handle); - - free(ag); -} - -/* Checks if there already a audio gateway connected for device. */ -static int has_audio_gateway(struct cras_bt_device *device) -{ - struct audio_gateway *ag; - DL_FOREACH (connected_ags, ag) { - if (ag->device == device) - return 1; - } - return 0; -} - -static void cras_hfp_ag_release(struct cras_bt_profile *profile) -{ - struct audio_gateway *ag; - - DL_FOREACH (connected_ags, ag) - destroy_audio_gateway(ag); -} - -/* Callback triggered when SLC is initialized. */ -static int cras_hfp_ag_slc_initialized(struct hfp_slc_handle *handle) -{ - struct audio_gateway *ag; - - DL_SEARCH_SCALAR(connected_ags, ag, slc_handle, handle); - if (!ag) - return -EINVAL; - - /* Log if the hands-free device supports WBS or not. Assuming the - * codec negotiation feature means the WBS capability on headset. - */ - cras_server_metrics_hfp_wideband_support( - hfp_slc_get_hf_codec_negotiation_supported(handle)); - - /* Log the final selected codec given that codec negotiation is - * supported. - */ - if (hfp_slc_get_hf_codec_negotiation_supported(handle) && - hfp_slc_get_ag_codec_negotiation_supported(handle)) - cras_server_metrics_hfp_wideband_selected_codec( - hfp_slc_get_selected_codec(handle)); - - /* Defer the starting of audio gateway to bt_device. */ - return cras_bt_device_audio_gateway_initialized(ag->device); -} - -static int cras_hfp_ag_slc_disconnected(struct hfp_slc_handle *handle) -{ - struct audio_gateway *ag; - - DL_SEARCH_SCALAR(connected_ags, ag, slc_handle, handle); - if (!ag) - return -EINVAL; - - destroy_audio_gateway(ag); - cras_bt_device_notify_profile_dropped( - ag->device, CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE); - return 0; -} - -static int check_for_conflict_ag(struct cras_bt_device *new_connected) -{ - struct audio_gateway *ag; - - /* Check if there's already an A2DP/HFP device. */ - DL_FOREACH (connected_ags, ag) { - if (cras_bt_device_has_a2dp(ag->device)) - return -1; - } - - /* Check if there's already an A2DP-only device. */ - if (cras_a2dp_connected_device() && - cras_bt_device_supports_profile(new_connected, - CRAS_BT_DEVICE_PROFILE_A2DP_SINK)) - return -1; - - return 0; -} - -int cras_hfp_ag_remove_conflict(struct cras_bt_device *device) -{ - struct audio_gateway *ag; - - DL_FOREACH (connected_ags, ag) { - if (ag->device == device) - continue; - cras_bt_device_notify_profile_dropped( - ag->device, CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE); - destroy_audio_gateway(ag); - } - return 0; -} - -static int cras_hfp_ag_new_connection(DBusConnection *conn, - struct cras_bt_profile *profile, - struct cras_bt_device *device, - int rfcomm_fd) -{ - struct cras_bt_adapter *adapter; - struct audio_gateway *ag; - int ag_features; - - BTLOG(btlog, BT_HFP_NEW_CONNECTION, 0, 0); - - if (has_audio_gateway(device)) { - syslog(LOG_ERR, - "Audio gateway exists when %s connects for profile %s", - cras_bt_device_name(device), profile->name); - close(rfcomm_fd); - return 0; - } - - if (check_for_conflict_ag(device)) - return -1; - - ag = (struct audio_gateway *)calloc(1, sizeof(*ag)); - ag->device = device; - ag->conn = conn; - ag->profile = cras_bt_device_profile_from_uuid(profile->uuid); - - adapter = cras_bt_device_adapter(device); - /* - * If the WBS enabled flag is set and adapter reports wbs capability - * then add codec negotiation feature. - * TODO(hychao): AND the two conditions to let bluetooth daemon - * control whether to turn on WBS feature. - */ - ag_features = BSRF_SUPPORTED_FEATURES; - if (cras_system_get_bt_wbs_enabled() && adapter && - cras_bt_adapter_wbs_supported(adapter)) - ag_features |= AG_CODEC_NEGOTIATION; - - ag->slc_handle = hfp_slc_create(rfcomm_fd, 0, ag_features, device, - cras_hfp_ag_slc_initialized, - cras_hfp_ag_slc_disconnected); - DL_APPEND(connected_ags, ag); - return 0; -} - -static void cras_hfp_ag_request_disconnection(struct cras_bt_profile *profile, - struct cras_bt_device *device) -{ - struct audio_gateway *ag; - - BTLOG(btlog, BT_HFP_REQUEST_DISCONNECT, 0, 0); - - DL_FOREACH (connected_ags, ag) { - if (ag->slc_handle && ag->device == device) { - cras_bt_device_notify_profile_dropped( - ag->device, - CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE); - destroy_audio_gateway(ag); - } - } -} - -static void cras_hfp_ag_cancel(struct cras_bt_profile *profile) -{ -} - -static struct cras_bt_profile cras_hfp_ag_profile = { - .name = HFP_AG_PROFILE_NAME, - .object_path = HFP_AG_PROFILE_PATH, - .uuid = HFP_AG_UUID, - .version = HFP_VERSION, - .role = NULL, - .features = SDP_SUPPORTED_FEATURES, - .record = NULL, - .release = cras_hfp_ag_release, - .new_connection = cras_hfp_ag_new_connection, - .request_disconnection = cras_hfp_ag_request_disconnection, - .cancel = cras_hfp_ag_cancel -}; - -int cras_hfp_ag_profile_create(DBusConnection *conn) -{ - return cras_bt_add_profile(conn, &cras_hfp_ag_profile); -} - -static int cras_hsp_ag_new_connection(DBusConnection *conn, - struct cras_bt_profile *profile, - struct cras_bt_device *device, - int rfcomm_fd) -{ - struct audio_gateway *ag; - - BTLOG(btlog, BT_HSP_NEW_CONNECTION, 0, 0); - - if (has_audio_gateway(device)) { - syslog(LOG_ERR, - "Audio gateway exists when %s connects for profile %s", - cras_bt_device_name(device), profile->name); - close(rfcomm_fd); - return 0; - } - - if (check_for_conflict_ag(device)) - return -1; - - ag = (struct audio_gateway *)calloc(1, sizeof(*ag)); - ag->device = device; - ag->conn = conn; - ag->profile = cras_bt_device_profile_from_uuid(profile->uuid); - ag->slc_handle = - hfp_slc_create(rfcomm_fd, 1, BSRF_SUPPORTED_FEATURES, device, - NULL, cras_hfp_ag_slc_disconnected); - DL_APPEND(connected_ags, ag); - cras_hfp_ag_slc_initialized(ag->slc_handle); - return 0; -} - -static void cras_hsp_ag_request_disconnection(struct cras_bt_profile *profile, - struct cras_bt_device *device) -{ - struct audio_gateway *ag; - - BTLOG(btlog, BT_HSP_REQUEST_DISCONNECT, 0, 0); - - DL_FOREACH (connected_ags, ag) { - if (ag->slc_handle && ag->device == device) { - cras_bt_device_notify_profile_dropped( - ag->device, CRAS_BT_DEVICE_PROFILE_HSP_HEADSET); - destroy_audio_gateway(ag); - } - } -} - -static struct cras_bt_profile cras_hsp_ag_profile = { - .name = HSP_AG_PROFILE_NAME, - .object_path = HSP_AG_PROFILE_PATH, - .uuid = HSP_AG_UUID, - .version = HSP_VERSION_1_2, - .role = NULL, - .record = HSP_AG_RECORD, - .release = cras_hfp_ag_release, - .new_connection = cras_hsp_ag_new_connection, - .request_disconnection = cras_hsp_ag_request_disconnection, - .cancel = cras_hfp_ag_cancel -}; - -int cras_hfp_ag_start(struct cras_bt_device *device) -{ - struct audio_gateway *ag; - - BTLOG(btlog, BT_AUDIO_GATEWAY_START, 0, 0); - - DL_SEARCH_SCALAR(connected_ags, ag, device, device); - if (ag == NULL) - return -EEXIST; - - /* - * There is chance that bluetooth stack notifies us about remote - * device's capability incrementally in multiple events. That could - * cause hfp_ag_start be called more than once. Check if the input - * HFP iodev is already created so we don't re-create HFP resources. - */ - if (ag->idev) - return 0; - - if (need_go_sco_pcm(device)) { - struct cras_iodev *in_aio, *out_aio; - - in_aio = cras_iodev_list_get_sco_pcm_iodev(CRAS_STREAM_INPUT); - out_aio = cras_iodev_list_get_sco_pcm_iodev(CRAS_STREAM_OUTPUT); - - ag->idev = hfp_alsa_iodev_create(in_aio, ag->device, - ag->slc_handle, ag->profile); - ag->odev = hfp_alsa_iodev_create(out_aio, ag->device, - ag->slc_handle, ag->profile); - } else { - ag->info = hfp_info_create(); - hfp_info_set_wbs_logger(ag->info, &wbs_logger); - ag->idev = - hfp_iodev_create(CRAS_STREAM_INPUT, ag->device, - ag->slc_handle, ag->profile, ag->info); - ag->odev = - hfp_iodev_create(CRAS_STREAM_OUTPUT, ag->device, - ag->slc_handle, ag->profile, ag->info); - } - - if (!ag->idev && !ag->odev) { - destroy_audio_gateway(ag); - return -ENOMEM; - } - - return 0; -} - -void cras_hfp_ag_suspend_connected_device(struct cras_bt_device *device) -{ - struct audio_gateway *ag; - - DL_SEARCH_SCALAR(connected_ags, ag, device, device); - if (ag) - destroy_audio_gateway(ag); -} - -struct hfp_slc_handle *cras_hfp_ag_get_active_handle() -{ - /* Returns the first handle for HFP qualification. In future we - * might want this to return the HFP device user is selected. */ - return connected_ags ? connected_ags->slc_handle : NULL; -} - -struct hfp_slc_handle *cras_hfp_ag_get_slc(struct cras_bt_device *device) -{ - struct audio_gateway *ag; - DL_FOREACH (connected_ags, ag) { - if (ag->device == device) - return ag->slc_handle; - } - return NULL; -} - -struct packet_status_logger *cras_hfp_ag_get_wbs_logger() -{ - return &wbs_logger; -} - -int cras_hsp_ag_profile_create(DBusConnection *conn) -{ - return cras_bt_add_profile(conn, &cras_hsp_ag_profile); -} |