diff options
-rw-r--r-- | TEST_MAPPING | 9 | ||||
-rw-r--r-- | system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc | 3 | ||||
-rw-r--r-- | system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc | 3 | ||||
-rw-r--r-- | system/audio_hearing_aid_hw/Android.bp | 63 | ||||
-rw-r--r-- | system/audio_hearing_aid_hw/include/audio_hearing_aid_hw.h | 146 | ||||
-rw-r--r-- | system/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc | 1925 | ||||
-rw-r--r-- | system/audio_hearing_aid_hw/src/audio_hearing_aid_hw_utils.cc | 44 | ||||
-rw-r--r-- | system/audio_hearing_aid_hw/test/audio_hearing_aid_hw_test.cc | 140 | ||||
-rw-r--r-- | system/bta/hearing_aid/hearing_aid_audio_source.cc | 237 | ||||
-rw-r--r-- | system/btif/BUILD.gn | 4 |
10 files changed, 6 insertions, 2568 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING index 15894058b7..34772b59b0 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -21,9 +21,6 @@ // "name": "bluetooth-test-audio-hal-interface" //}, { - "name": "net_test_audio_hearing_aid_hw" - }, - { "name": "net_test_bluetooth" }, { @@ -259,9 +256,6 @@ // "name": "bluetooth-test-audio-hal-interface" //}, { - "name": "net_test_audio_hearing_aid_hw" - }, - { "name": "net_test_bluetooth" }, { @@ -493,9 +487,6 @@ // "name": "bluetooth-test-audio-hal-interface" //}, { - "name": "net_test_audio_hearing_aid_hw" - }, - { "name": "net_test_bluetooth" }, { diff --git a/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc b/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc index 0cf9d824ee..ec9f3a5bf2 100644 --- a/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc +++ b/system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc @@ -20,10 +20,11 @@ #include <bluetooth/log.h> -#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h" #include "client_interface_aidl.h" #include "osi/include/properties.h" +#define AUDIO_STREAM_OUTPUT_BUFFER_SZ (28 * 512) + namespace std { template <> struct formatter<audio_usage_t> : enum_formatter<audio_usage_t> {}; diff --git a/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc b/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc index b745914999..a129917f8f 100644 --- a/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc +++ b/system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc @@ -20,10 +20,11 @@ #include <bluetooth/log.h> -#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h" #include "client_interface_hidl.h" #include "osi/include/properties.h" +#define AUDIO_STREAM_OUTPUT_BUFFER_SZ (28 * 512) + namespace std { template <> struct formatter<audio_usage_t> : enum_formatter<audio_usage_t> {}; diff --git a/system/audio_hearing_aid_hw/Android.bp b/system/audio_hearing_aid_hw/Android.bp deleted file mode 100644 index afc160d599..0000000000 --- a/system/audio_hearing_aid_hw/Android.bp +++ /dev/null @@ -1,63 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "system_bt_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["system_bt_license"], -} - -cc_defaults { - name: "audio_hearing_aid_hw_defaults", - defaults: ["bluetooth_cflags"], - shared_libs: ["libchrome"], - include_dirs: [ - "packages/modules/Bluetooth/system", - "packages/modules/Bluetooth/system/gd", - "packages/modules/Bluetooth/system/include", - ], -} - -// Audio A2DP shared library for target -cc_library { - name: "audio.hearing_aid.default", - defaults: ["audio_hearing_aid_hw_defaults"], - relative_install_path: "hw", - srcs: [ - "src/audio_hearing_aid_hw.cc", - "src/audio_hearing_aid_hw_utils.cc", - ], - apex_available: ["com.android.bt"], - shared_libs: [ - "libbase", - "liblog", - ], - static_libs: [ - "libbluetooth_log", - "libosi", - ], -} - -// Audio A2DP library unit tests for target and host -cc_test { - name: "net_test_audio_hearing_aid_hw", - test_suites: ["general-tests"], - defaults: [ - "audio_hearing_aid_hw_defaults", - "mts_defaults", - ], - srcs: [ - "test/audio_hearing_aid_hw_test.cc", - ], - shared_libs: [ - "libbase", - "liblog", - ], - static_libs: [ - "audio.hearing_aid.default", - "libbluetooth_log", - "libcom.android.sysprop.bluetooth.wrapped", - "libosi", - ], - min_sdk_version: "29", -} diff --git a/system/audio_hearing_aid_hw/include/audio_hearing_aid_hw.h b/system/audio_hearing_aid_hw/include/audio_hearing_aid_hw.h deleted file mode 100644 index 7283079b33..0000000000 --- a/system/audio_hearing_aid_hw/include/audio_hearing_aid_hw.h +++ /dev/null @@ -1,146 +0,0 @@ -/****************************************************************************** - * - * Copyright 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -/***************************************************************************** - * - * Filename: audio_hearing_aid_hw.h - * - * Description: - * - *****************************************************************************/ - -#ifndef AUDIO_HEARING_AID_HW_H -#define AUDIO_HEARING_AID_HW_H - -#include <hardware/bt_av.h> -#include <stdint.h> - -/***************************************************************************** - * Constants & Macros - *****************************************************************************/ - -#define HEARING_AID_AUDIO_HARDWARE_INTERFACE "audio.hearing_aid" -#define HEARING_AID_CTRL_PATH "/data/misc/bluedroid/.hearing_aid_ctrl" -#define HEARING_AID_DATA_PATH "/data/misc/bluedroid/.hearing_aid_data" - -// AUDIO_STREAM_OUTPUT_BUFFER_SZ controls the size of the audio socket buffer. -// If one assumes the write buffer is always full during normal BT playback, -// then increasing this value increases our playback latency. -// -// FIXME: The BT HAL should consume data at a constant rate. -// AudioFlinger assumes that the HAL draws data at a constant rate, which is -// true for most audio devices; however, the BT engine reads data at a variable -// rate (over the short term), which confuses both AudioFlinger as well as -// applications which deliver data at a (generally) fixed rate. -// -// 20 * 512 is not sufficient to smooth the variability for some BT devices, -// resulting in mixer sleep and throttling. We increase this to 28 * 512 to help -// reduce the effect of variable data consumption. -#define AUDIO_STREAM_OUTPUT_BUFFER_SZ (28 * 512) -#define AUDIO_STREAM_CONTROL_OUTPUT_BUFFER_SZ 256 - -// AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is divided -// for AudioFlinger data delivery. The AudioFlinger mixer delivers data in -// chunks of AUDIO_STREAM_OUTPUT_BUFFER_SZ / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS. -// If the number of periods is 2, the socket buffer represents "double -// buffering" of the AudioFlinger mixer buffer. -// -// In general, AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * 16 * 4 should be a divisor -// of AUDIO_STREAM_OUTPUT_BUFFER_SZ. -// -// These values should be chosen such that -// -// AUDIO_STREAM_BUFFER_SIZE * 1000 / (AUDIO_STREAM_OUTPUT_BUFFER_PERIODS -// * AUDIO_STREAM_DEFAULT_RATE * 4) > 20 (ms) -// -// to avoid introducing the FastMixer in AudioFlinger. Using the FastMixer -// results in unnecessary latency and CPU overhead for Bluetooth. -#define AUDIO_STREAM_OUTPUT_BUFFER_PERIODS 2 - -#define AUDIO_SKT_DISCONNECTED (-1) - -typedef enum { - HEARING_AID_CTRL_CMD_NONE, - HEARING_AID_CTRL_CMD_CHECK_READY, - HEARING_AID_CTRL_CMD_START, - HEARING_AID_CTRL_CMD_STOP, - HEARING_AID_CTRL_CMD_SUSPEND, - HEARING_AID_CTRL_GET_INPUT_AUDIO_CONFIG, - HEARING_AID_CTRL_GET_OUTPUT_AUDIO_CONFIG, - HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG, - HEARING_AID_CTRL_CMD_OFFLOAD_START, -} tHEARING_AID_CTRL_CMD; - -typedef enum { - HEARING_AID_CTRL_ACK_SUCCESS, - HEARING_AID_CTRL_ACK_FAILURE, - HEARING_AID_CTRL_ACK_INCALL_FAILURE, /* Failure when in Call*/ - HEARING_AID_CTRL_ACK_UNSUPPORTED -} tHEARING_AID_CTRL_ACK; - -typedef uint32_t tHA_SAMPLE_RATE; -typedef uint8_t tHA_CHANNEL_COUNT; - -/***************************************************************************** - * Type definitions for callback functions - *****************************************************************************/ - -/***************************************************************************** - * Type definitions and return values - *****************************************************************************/ - -/***************************************************************************** - * Extern variables and functions - *****************************************************************************/ - -/***************************************************************************** - * Functions - *****************************************************************************/ - -// Computes the Audio Hearing Aid HAL output buffer size. -// |codec_sample_rate| is the sample rate of the output stream. -// |codec_bits_per_sample| is the number of bits per sample of the output -// stream. -// |codec_channel_mode| is the channel mode of the output stream. -// -// The buffer size is computed by using the following formula: -// -// AUDIO_STREAM_OUTPUT_BUFFER_SIZE = -// (TIME_PERIOD_MS * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * -// SAMPLE_RATE_HZ * NUMBER_OF_CHANNELS * (BITS_PER_SAMPLE / 8)) / 1000 -// -// AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is -// divided for AudioFlinger data delivery. The AudioFlinger mixer delivers -// data in chunks of -// (AUDIO_STREAM_OUTPUT_BUFFER_SIZE / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS) . -// If the number of periods is 2, the socket buffer represents "double -// buffering" of the AudioFlinger mixer buffer. -// -// Furthermore, the AudioFlinger expects the buffer size to be a multiple -// of 16 frames. -// -// NOTE: Currently, the computation uses the conservative 20ms time period. -// -// Returns the computed buffer size. If any of the input parameters is -// invalid, the return value is the default |AUDIO_STREAM_OUTPUT_BUFFER_SZ|. -size_t audio_ha_hw_stream_compute_buffer_size( - btav_a2dp_codec_sample_rate_t codec_sample_rate, - btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample, - btav_a2dp_codec_channel_mode_t codec_channel_mode); - -#endif /* AUDIO_HEARING_AID_HW_H */ diff --git a/system/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc b/system/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc deleted file mode 100644 index ac63105662..0000000000 --- a/system/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc +++ /dev/null @@ -1,1925 +0,0 @@ -/****************************************************************************** - * - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -/* Implements hal for bluedroid ha audio device */ - -#define LOG_TAG "bt_hearing_aid_hw" - -#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h" - -#include <fcntl.h> -#include <hardware/audio.h> -#include <hardware/hardware.h> -#include <inttypes.h> -#include <log/log.h> -#include <stdint.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/un.h> -#include <system/audio.h> -#include <unistd.h> - -#include <cerrno> -#include <mutex> - -#include "osi/include/hash_map_utils.h" -#include "osi/include/osi.h" -#include "osi/include/socket_utils/sockets.h" - -/***************************************************************************** - * Constants & Macros - *****************************************************************************/ - -#define CTRL_CHAN_RETRY_COUNT 3 -#define USEC_PER_SEC 1000000L -#define SOCK_SEND_TIMEOUT_MS 2000 /* Timeout for sending */ -#define SOCK_RECV_TIMEOUT_MS 5000 /* Timeout for receiving */ - -// set WRITE_POLL_MS to 0 for blocking sockets, nonzero for polled non-blocking -// sockets -#define WRITE_POLL_MS 20 - -#define FNLOG() ALOGV("%s:%d %s: ", __FILE__, __LINE__, __func__) -#define DEBUG(fmt, args...) ALOGD("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args) -#define INFO(fmt, args...) ALOGI("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args) -#define WARN(fmt, args...) ALOGW("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args) -#define ERROR(fmt, args...) ALOGE("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args) - -#define ASSERTC(cond, msg, val) \ - if (!(cond)) { \ - ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val); \ - } - -#define CASE_RETURN_STR(const) \ - case const: \ - return #const; - -static const char* audio_ha_hw_dump_ctrl_event(tHEARING_AID_CTRL_CMD event) { - switch (event) { - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_NONE) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_CHECK_READY) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_START) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_STOP) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_SUSPEND) - CASE_RETURN_STR(HEARING_AID_CTRL_GET_INPUT_AUDIO_CONFIG) - CASE_RETURN_STR(HEARING_AID_CTRL_GET_OUTPUT_AUDIO_CONFIG) - CASE_RETURN_STR(HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_OFFLOAD_START) - default: - break; - } - - return "UNKNOWN HEARING_AID_CTRL_CMD"; -} - -/***************************************************************************** - * Local type definitions - *****************************************************************************/ - -typedef enum { - AUDIO_HA_STATE_STARTING, - AUDIO_HA_STATE_STARTED, - AUDIO_HA_STATE_STOPPING, - AUDIO_HA_STATE_STOPPED, - /* need explicit set param call to resume (suspend=false) */ - AUDIO_HA_STATE_SUSPENDED, - AUDIO_HA_STATE_STANDBY /* allows write to autoresume */ -} ha_state_t; - -struct ha_stream_in; -struct ha_stream_out; - -struct ha_audio_device { - // Important: device must be first as an audio_hw_device* may be cast to - // ha_audio_device* when the type is implicitly known. - struct audio_hw_device device; - std::recursive_mutex* mutex; // See note below on mutex acquisition order. - struct ha_stream_in* input; - struct ha_stream_out* output; -}; - -struct ha_config { - uint32_t rate; - uint32_t channel_mask; - bool is_stereo_to_mono; // True if fetching Stereo and mixing into Mono - int format; -}; - -/* move ctrl_fd outside output stream and keep open until HAL unloaded ? */ - -struct ha_stream_common { - std::recursive_mutex* mutex; // See note below on mutex acquisition order. - int ctrl_fd; - int audio_fd; - size_t buffer_sz; - struct ha_config cfg; - ha_state_t state; -}; - -struct ha_stream_out { - struct audio_stream_out stream; - struct ha_stream_common common; - uint64_t frames_presented; // frames written, never reset - uint64_t frames_rendered; // frames written, reset on standby -}; - -struct ha_stream_in { - struct audio_stream_in stream; - struct ha_stream_common common; -}; - -/* - * Mutex acquisition order: - * - * The ha_audio_device (adev) mutex must be acquired before - * the ha_stream_common (out or in) mutex. - * - * This may differ from other audio HALs. - */ - -/***************************************************************************** - * Static variables - *****************************************************************************/ - -/***************************************************************************** - * Static functions - *****************************************************************************/ -static void hash_map_utils_dump_string_keys_string_values( - std::unordered_map<std::string, std::string>& map) { - for (const auto& ptr : map) { - INFO("key: '%s' value: '%s'\n", ptr.first.c_str(), ptr.second.c_str()); - } -} - -static size_t out_get_buffer_size(const struct audio_stream* stream); - -/***************************************************************************** - * Externs - *****************************************************************************/ - -/***************************************************************************** - * Functions - *****************************************************************************/ -static void ha_open_ctrl_path(struct ha_stream_common* common); - -/***************************************************************************** - * Miscellaneous helper functions - *****************************************************************************/ - -/* logs timestamp with microsec precision - pprev is optional in case a dedicated diff is required */ -static void ts_log(UNUSED_ATTR const char* tag, UNUSED_ATTR int val, struct timespec* pprev_opt) { - struct timespec now; - static struct timespec prev = {0, 0}; - unsigned long long now_us; - unsigned long long diff_us; - - clock_gettime(CLOCK_MONOTONIC, &now); - - now_us = now.tv_sec * USEC_PER_SEC + now.tv_nsec / 1000; - - if (pprev_opt) { - diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec) / 1000; - *pprev_opt = now; - DEBUG("[%s] ts %08lld, *diff %08lld, val %d", tag, now_us, diff_us, val); - } else { - diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec) / 1000; - prev = now; - DEBUG("[%s] ts %08lld, diff %08lld, val %d", tag, now_us, diff_us, val); - } -} - -static int calc_audiotime_usec(struct ha_config cfg, int bytes) { - int chan_count = audio_channel_count_from_out_mask(cfg.channel_mask); - int bytes_per_sample; - - switch (cfg.format) { - case AUDIO_FORMAT_PCM_8_BIT: - bytes_per_sample = 1; - break; - case AUDIO_FORMAT_PCM_16_BIT: - bytes_per_sample = 2; - break; - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - bytes_per_sample = 3; - break; - case AUDIO_FORMAT_PCM_8_24_BIT: - bytes_per_sample = 4; - break; - case AUDIO_FORMAT_PCM_32_BIT: - bytes_per_sample = 4; - break; - default: - ASSERTC(false, "unsupported sample format", cfg.format); - bytes_per_sample = 2; - break; - } - - return (int)(((int64_t)bytes * (USEC_PER_SEC / (chan_count * bytes_per_sample))) / cfg.rate); -} - -/***************************************************************************** - * - * bluedroid stack adaptation - * - ****************************************************************************/ - -static int skt_connect(const char* path, size_t buffer_sz) { - int ret; - int skt_fd; - int len; - - INFO("connect to %s (sz %zu)", path, buffer_sz); - - skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0); - - if (osi_socket_local_client_connect(skt_fd, path, ANDROID_SOCKET_NAMESPACE_ABSTRACT, - SOCK_STREAM) < 0) { - ERROR("failed to connect (%s)", strerror(errno)); - close(skt_fd); - return -1; - } - - len = buffer_sz; - ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, (int)sizeof(len)); - if (ret < 0) { - ERROR("setsockopt failed (%s)", strerror(errno)); - } - - ret = setsockopt(skt_fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, (int)sizeof(len)); - if (ret < 0) { - ERROR("setsockopt failed (%s)", strerror(errno)); - } - - /* Socket send/receive timeout value */ - struct timeval tv; - tv.tv_sec = SOCK_SEND_TIMEOUT_MS / 1000; - tv.tv_usec = (SOCK_SEND_TIMEOUT_MS % 1000) * 1000; - - ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - if (ret < 0) { - ERROR("setsockopt failed (%s)", strerror(errno)); - } - - tv.tv_sec = SOCK_RECV_TIMEOUT_MS / 1000; - tv.tv_usec = (SOCK_RECV_TIMEOUT_MS % 1000) * 1000; - - ret = setsockopt(skt_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - if (ret < 0) { - ERROR("setsockopt failed (%s)", strerror(errno)); - } - - INFO("connected to stack fd = %d", skt_fd); - - return skt_fd; -} - -static int skt_read(int fd, void* p, size_t len) { - ssize_t read; - - FNLOG(); - - ts_log("skt_read recv", len, NULL); - - OSI_NO_INTR(read = recv(fd, p, len, MSG_NOSIGNAL)); - if (read == -1) { - ERROR("read failed with errno=%d\n", errno); - } - - return (int)read; -} - -static int skt_write(int fd, const void* p, size_t len) { - ssize_t sent; - FNLOG(); - - ts_log("skt_write", len, NULL); - - if (WRITE_POLL_MS == 0) { - // do not poll, use blocking send - OSI_NO_INTR(sent = send(fd, p, len, MSG_NOSIGNAL)); - if (sent == -1) { - ERROR("write failed with error(%s)", strerror(errno)); - } - - return (int)sent; - } - - // use non-blocking send, poll - int ms_timeout = SOCK_SEND_TIMEOUT_MS; - size_t count = 0; - while (count < len) { - OSI_NO_INTR(sent = send(fd, p, len - count, MSG_NOSIGNAL | MSG_DONTWAIT)); - if (sent == -1) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - ERROR("write failed with error(%s)", strerror(errno)); - return -1; - } - if (ms_timeout >= WRITE_POLL_MS) { - usleep(WRITE_POLL_MS * 1000); - ms_timeout -= WRITE_POLL_MS; - continue; - } - WARN("write timeout exceeded, sent %zu bytes", count); - return -1; - } - count += sent; - p = (const uint8_t*)p + sent; - } - return (int)count; -} - -static int skt_disconnect(int fd) { - INFO("fd %d", fd); - - if (fd != AUDIO_SKT_DISCONNECTED) { - shutdown(fd, SHUT_RDWR); - close(fd); - } - return 0; -} - -/***************************************************************************** - * - * AUDIO CONTROL PATH - * - ****************************************************************************/ - -static int ha_ctrl_receive(struct ha_stream_common* common, void* buffer, size_t length) { - ssize_t ret; - int i; - - for (i = 0;; i++) { - OSI_NO_INTR(ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL)); - if (ret > 0) { - break; - } - if (ret == 0) { - ERROR("receive control data failed: peer closed"); - break; - } - if (errno != EWOULDBLOCK && errno != EAGAIN) { - ERROR("receive control data failed: error(%s)", strerror(errno)); - break; - } - if (i == (CTRL_CHAN_RETRY_COUNT - 1)) { - ERROR("receive control data failed: max retry count"); - break; - } - INFO("receive control data failed (%s), retrying", strerror(errno)); - } - if (ret <= 0) { - skt_disconnect(common->ctrl_fd); - common->ctrl_fd = AUDIO_SKT_DISCONNECTED; - } - return ret; -} - -// Sends control info for stream |common|. The data to send is stored in -// |buffer| and has size |length|. -// On success, returns the number of octets sent, otherwise -1. -static int ha_ctrl_send(struct ha_stream_common* common, const void* buffer, size_t length) { - ssize_t sent; - size_t remaining = length; - int i; - - if (length == 0) { - return 0; // Nothing to do - } - - for (i = 0;; i++) { - OSI_NO_INTR(sent = send(common->ctrl_fd, buffer, remaining, MSG_NOSIGNAL)); - if (sent == static_cast<ssize_t>(remaining)) { - remaining = 0; - break; - } - if (sent > 0) { - buffer = (static_cast<const char*>(buffer) + sent); - remaining -= sent; - continue; - } - if (sent < 0) { - if (errno != EWOULDBLOCK && errno != EAGAIN) { - ERROR("send control data failed: error(%s)", strerror(errno)); - break; - } - INFO("send control data failed (%s), retrying", strerror(errno)); - } - if (i >= (CTRL_CHAN_RETRY_COUNT - 1)) { - ERROR("send control data failed: max retry count"); - break; - } - } - if (remaining > 0) { - skt_disconnect(common->ctrl_fd); - common->ctrl_fd = AUDIO_SKT_DISCONNECTED; - return -1; - } - return length; -} - -static int ha_command(struct ha_stream_common* common, tHEARING_AID_CTRL_CMD cmd) { - char ack; - - DEBUG("HEARING_AID COMMAND %s", audio_ha_hw_dump_ctrl_event(cmd)); - - if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) { - INFO("starting up or recovering from previous error"); - ha_open_ctrl_path(common); - if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) { - ERROR("failure to open ctrl path"); - return -1; - } - } - - /* send command */ - ssize_t sent; - OSI_NO_INTR(sent = send(common->ctrl_fd, &cmd, 1, MSG_NOSIGNAL)); - if (sent == -1) { - ERROR("cmd failed (%s)", strerror(errno)); - skt_disconnect(common->ctrl_fd); - common->ctrl_fd = AUDIO_SKT_DISCONNECTED; - return -1; - } - - /* wait for ack byte */ - if (ha_ctrl_receive(common, &ack, 1) < 0) { - ERROR("HEARING_AID COMMAND %s: no ACK", audio_ha_hw_dump_ctrl_event(cmd)); - return -1; - } - - DEBUG("HEARING_AID COMMAND %s DONE STATUS %d", audio_ha_hw_dump_ctrl_event(cmd), ack); - - if (ack == HEARING_AID_CTRL_ACK_INCALL_FAILURE) { - return ack; - } - if (ack != HEARING_AID_CTRL_ACK_SUCCESS) { - ERROR("HEARING_AID COMMAND %s error %d", audio_ha_hw_dump_ctrl_event(cmd), ack); - return -1; - } - - return 0; -} - -static int check_ha_ready(struct ha_stream_common* common) { - if (ha_command(common, HEARING_AID_CTRL_CMD_CHECK_READY) < 0) { - ERROR("check ha ready failed"); - return -1; - } - return 0; -} - -static int ha_read_input_audio_config(struct ha_stream_common* common) { - tHA_SAMPLE_RATE sample_rate; - tHA_CHANNEL_COUNT channel_count; - - if (ha_command(common, HEARING_AID_CTRL_GET_INPUT_AUDIO_CONFIG) < 0) { - ERROR("get ha input audio config failed"); - return -1; - } - - if (ha_ctrl_receive(common, &sample_rate, sizeof(tHA_SAMPLE_RATE)) < 0) { - return -1; - } - if (ha_ctrl_receive(common, &channel_count, sizeof(tHA_CHANNEL_COUNT)) < 0) { - return -1; - } - - switch (sample_rate) { - case 16000: - case 24000: - case 44100: - case 48000: - common->cfg.rate = sample_rate; - break; - default: - ERROR("Invalid sample rate: %" PRIu32, sample_rate); - return -1; - } - - switch (channel_count) { - case 1: - common->cfg.channel_mask = AUDIO_CHANNEL_IN_MONO; - break; - case 2: - common->cfg.channel_mask = AUDIO_CHANNEL_IN_STEREO; - break; - default: - ERROR("Invalid channel count: %" PRIu32, channel_count); - return -1; - } - - // TODO: For now input audio format is always hard-coded as PCM 16-bit - common->cfg.format = AUDIO_FORMAT_PCM_16_BIT; - - INFO("got input audio config %d %d", common->cfg.format, common->cfg.rate); - - return 0; -} - -static int ha_read_output_audio_config(struct ha_stream_common* common, - btav_a2dp_codec_config_t* codec_config, - btav_a2dp_codec_config_t* codec_capability, - bool update_stream_config) { - struct ha_config stream_config; - - if (ha_command(common, HEARING_AID_CTRL_GET_OUTPUT_AUDIO_CONFIG) < 0) { - ERROR("get ha output audio config failed"); - return -1; - } - - // Receive the current codec config - if (ha_ctrl_receive(common, &codec_config->sample_rate, sizeof(btav_a2dp_codec_sample_rate_t)) < - 0) { - return -1; - } - if (ha_ctrl_receive(common, &codec_config->bits_per_sample, - sizeof(btav_a2dp_codec_bits_per_sample_t)) < 0) { - return -1; - } - if (ha_ctrl_receive(common, &codec_config->channel_mode, sizeof(btav_a2dp_codec_channel_mode_t)) < - 0) { - return -1; - } - - // Receive the current codec capability - if (ha_ctrl_receive(common, &codec_capability->sample_rate, - sizeof(btav_a2dp_codec_sample_rate_t)) < 0) { - return -1; - } - if (ha_ctrl_receive(common, &codec_capability->bits_per_sample, - sizeof(btav_a2dp_codec_bits_per_sample_t)) < 0) { - return -1; - } - if (ha_ctrl_receive(common, &codec_capability->channel_mode, - sizeof(btav_a2dp_codec_channel_mode_t)) < 0) { - return -1; - } - - // Check the codec config sample rate - switch (codec_config->sample_rate) { - case BTAV_A2DP_CODEC_SAMPLE_RATE_44100: - stream_config.rate = 44100; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_48000: - stream_config.rate = 48000; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_88200: - stream_config.rate = 88200; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_96000: - stream_config.rate = 96000; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_176400: - stream_config.rate = 176400; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_192000: - stream_config.rate = 192000; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_16000: - stream_config.rate = 16000; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_24000: - stream_config.rate = 24000; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE: - default: - ERROR("Invalid sample rate: 0x%x", codec_config->sample_rate); - return -1; - } - - // Check the codec config bits per sample - switch (codec_config->bits_per_sample) { - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16: - stream_config.format = AUDIO_FORMAT_PCM_16_BIT; - break; - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24: - stream_config.format = AUDIO_FORMAT_PCM_24_BIT_PACKED; - break; - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32: - stream_config.format = AUDIO_FORMAT_PCM_32_BIT; - break; - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE: - default: - ERROR("Invalid bits per sample: 0x%x", codec_config->bits_per_sample); - return -1; - } - - // Check the codec config channel mode - switch (codec_config->channel_mode) { - case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO: - stream_config.channel_mask = AUDIO_CHANNEL_OUT_MONO; - stream_config.is_stereo_to_mono = true; - break; - case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO: - stream_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO; - stream_config.is_stereo_to_mono = false; - break; - case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE: - default: - ERROR("Invalid channel mode: 0x%x", codec_config->channel_mode); - return -1; - } - if (stream_config.is_stereo_to_mono) { - stream_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO; - } - - // Update the output stream configuration - if (update_stream_config) { - common->cfg.rate = stream_config.rate; - common->cfg.channel_mask = stream_config.channel_mask; - common->cfg.is_stereo_to_mono = stream_config.is_stereo_to_mono; - common->cfg.format = stream_config.format; - common->buffer_sz = audio_ha_hw_stream_compute_buffer_size( - codec_config->sample_rate, codec_config->bits_per_sample, codec_config->channel_mode); - if (common->cfg.is_stereo_to_mono) { - // We need to fetch twice as much data from the Audio framework - common->buffer_sz *= 2; - } - } - - INFO("got output codec config (update_stream_config=%s): " - "sample_rate=0x%x bits_per_sample=0x%x channel_mode=0x%x", - update_stream_config ? "true" : "false", codec_config->sample_rate, - codec_config->bits_per_sample, codec_config->channel_mode); - - INFO("got output codec capability: sample_rate=0x%x bits_per_sample=0x%x channel_mode=0x%x", - codec_capability->sample_rate, codec_capability->bits_per_sample, - codec_capability->channel_mode); - - return 0; -} - -static int ha_write_output_audio_config(struct ha_stream_common* common) { - btav_a2dp_codec_config_t codec_config; - - if (ha_command(common, HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG) < 0) { - ERROR("set ha output audio config failed"); - return -1; - } - - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE; - codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE; - codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE; - - switch (common->cfg.rate) { - case 44100: - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100; - break; - case 48000: - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000; - break; - case 88200: - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_88200; - break; - case 96000: - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_96000; - break; - case 176400: - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_176400; - break; - case 192000: - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_192000; - break; - case 16000: - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_16000; - break; - case 24000: - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_24000; - break; - default: - ERROR("Invalid sample rate: %" PRIu32, common->cfg.rate); - return -1; - } - - switch (common->cfg.format) { - case AUDIO_FORMAT_PCM_16_BIT: - codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16; - break; - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24; - break; - case AUDIO_FORMAT_PCM_32_BIT: - codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32; - break; - case AUDIO_FORMAT_PCM_8_24_BIT: - // All 24-bit audio is expected in AUDIO_FORMAT_PCM_24_BIT_PACKED format - FALLTHROUGH_INTENDED; /* FALLTHROUGH */ - default: - ERROR("Invalid audio format: 0x%x", common->cfg.format); - return -1; - } - - switch (common->cfg.channel_mask) { - case AUDIO_CHANNEL_OUT_MONO: - codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; - break; - case AUDIO_CHANNEL_OUT_STEREO: - if (common->cfg.is_stereo_to_mono) { - codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; - } else { - codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; - } - break; - default: - ERROR("Invalid channel mask: 0x%x", common->cfg.channel_mask); - return -1; - } - - // Send the current codec config that has been selected by us - if (ha_ctrl_send(common, &codec_config.sample_rate, sizeof(btav_a2dp_codec_sample_rate_t)) < 0) { - return -1; - } - if (ha_ctrl_send(common, &codec_config.bits_per_sample, - sizeof(btav_a2dp_codec_bits_per_sample_t)) < 0) { - return -1; - } - if (ha_ctrl_send(common, &codec_config.channel_mode, sizeof(btav_a2dp_codec_channel_mode_t)) < - 0) { - return -1; - } - - INFO("sent output codec config: sample_rate=0x%x bits_per_sample=0x%x channel_mode=0x%x", - codec_config.sample_rate, codec_config.bits_per_sample, codec_config.channel_mode); - - return 0; -} - -static void ha_open_ctrl_path(struct ha_stream_common* common) { - int i; - - if (common->ctrl_fd != AUDIO_SKT_DISCONNECTED) { - return; // already connected - } - - /* retry logic to catch any timing variations on control channel */ - for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++) { - /* connect control channel if not already connected */ - if ((common->ctrl_fd = - skt_connect(HEARING_AID_CTRL_PATH, AUDIO_STREAM_CONTROL_OUTPUT_BUFFER_SZ)) >= 0) { - /* success, now check if stack is ready */ - if (check_ha_ready(common) == 0) { - break; - } - - ERROR("error : ha not ready, wait 250 ms and retry"); - usleep(250000); - skt_disconnect(common->ctrl_fd); - common->ctrl_fd = AUDIO_SKT_DISCONNECTED; - } - - /* ctrl channel not ready, wait a bit */ - usleep(250000); - } -} - -/***************************************************************************** - * - * AUDIO DATA PATH - * - ****************************************************************************/ - -static void ha_stream_common_init(struct ha_stream_common* common) { - FNLOG(); - - common->mutex = new std::recursive_mutex; - - common->ctrl_fd = AUDIO_SKT_DISCONNECTED; - common->audio_fd = AUDIO_SKT_DISCONNECTED; - common->state = AUDIO_HA_STATE_STOPPED; - - /* manages max capacity of socket pipe */ - common->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ; -} - -static void ha_stream_common_destroy(struct ha_stream_common* common) { - FNLOG(); - - delete common->mutex; - common->mutex = NULL; -} - -static int start_audio_datapath(struct ha_stream_common* common) { - INFO("state %d", common->state); - - int oldstate = common->state; - common->state = AUDIO_HA_STATE_STARTING; - - int ha_status = ha_command(common, HEARING_AID_CTRL_CMD_START); - if (ha_status < 0) { - ERROR("Audiopath start failed (status %d)", ha_status); - goto error; - } else if (ha_status == HEARING_AID_CTRL_ACK_INCALL_FAILURE) { - ERROR("Audiopath start failed - in call, move to suspended"); - goto error; - } - - /* connect socket if not yet connected */ - if (common->audio_fd == AUDIO_SKT_DISCONNECTED) { - common->audio_fd = skt_connect(HEARING_AID_DATA_PATH, common->buffer_sz); - if (common->audio_fd < 0) { - ERROR("Audiopath start failed - error opening data socket"); - goto error; - } - } - common->state = (ha_state_t)AUDIO_HA_STATE_STARTED; - return 0; - -error: - common->state = (ha_state_t)oldstate; - return -1; -} - -static int stop_audio_datapath(struct ha_stream_common* common) { - int oldstate = common->state; - - INFO("state %d", common->state); - - /* prevent any stray output writes from autostarting the stream - while stopping audiopath */ - common->state = AUDIO_HA_STATE_STOPPING; - - if (ha_command(common, HEARING_AID_CTRL_CMD_STOP) < 0) { - ERROR("audiopath stop failed"); - common->state = (ha_state_t)oldstate; - return -1; - } - - common->state = (ha_state_t)AUDIO_HA_STATE_STOPPED; - - /* disconnect audio path */ - skt_disconnect(common->audio_fd); - common->audio_fd = AUDIO_SKT_DISCONNECTED; - - return 0; -} - -static int suspend_audio_datapath(struct ha_stream_common* common, bool standby) { - INFO("state %d", common->state); - - if (common->state == AUDIO_HA_STATE_STOPPING) { - return -1; - } - - if (ha_command(common, HEARING_AID_CTRL_CMD_SUSPEND) < 0) { - return -1; - } - - if (standby) { - common->state = AUDIO_HA_STATE_STANDBY; - } else { - common->state = AUDIO_HA_STATE_SUSPENDED; - } - - /* disconnect audio path */ - skt_disconnect(common->audio_fd); - - common->audio_fd = AUDIO_SKT_DISCONNECTED; - - return 0; -} - -/***************************************************************************** - * - * audio output callbacks - * - ****************************************************************************/ - -static ssize_t out_write(struct audio_stream_out* stream, const void* buffer, size_t bytes) { - struct ha_stream_out* out = (struct ha_stream_out*)stream; - int sent = -1; - size_t write_bytes = bytes; - - DEBUG("write %zu bytes (fd %d)", bytes, out->common.audio_fd); - - std::unique_lock<std::recursive_mutex> lock(*out->common.mutex); - if (out->common.state == AUDIO_HA_STATE_SUSPENDED || - out->common.state == AUDIO_HA_STATE_STOPPING) { - DEBUG("stream suspended or closing"); - goto finish; - } - - /* only allow autostarting if we are in stopped or standby */ - if ((out->common.state == AUDIO_HA_STATE_STOPPED) || - (out->common.state == AUDIO_HA_STATE_STANDBY)) { - if (start_audio_datapath(&out->common) < 0) { - goto finish; - } - } else if (out->common.state != AUDIO_HA_STATE_STARTED) { - ERROR("stream not in stopped or standby"); - goto finish; - } - - // Mix the stereo into mono if necessary - if (out->common.cfg.is_stereo_to_mono) { - const size_t frames = bytes / audio_stream_out_frame_size(stream); - int16_t* src = (int16_t*)buffer; - int16_t* dst = (int16_t*)buffer; - for (size_t i = 0; i < frames; i++, dst++, src += 2) { - *dst = (int16_t)(((int32_t)src[0] + (int32_t)src[1]) >> 1); - } - write_bytes /= 2; - DEBUG("stereo-to-mono mixing: write %zu bytes (fd %d)", write_bytes, out->common.audio_fd); - } - - lock.unlock(); - sent = skt_write(out->common.audio_fd, buffer, write_bytes); - lock.lock(); - - if (sent == -1) { - skt_disconnect(out->common.audio_fd); - out->common.audio_fd = AUDIO_SKT_DISCONNECTED; - if ((out->common.state != AUDIO_HA_STATE_SUSPENDED) && - (out->common.state != AUDIO_HA_STATE_STOPPING)) { - out->common.state = AUDIO_HA_STATE_STOPPED; - } else { - ERROR("write failed : stream suspended, avoid resetting state"); - } - goto finish; - } - -finish:; - const size_t frames = bytes / audio_stream_out_frame_size(stream); - out->frames_rendered += frames; - out->frames_presented += frames; - lock.unlock(); - - // If send didn't work out, sleep to emulate write delay. - if (sent == -1) { - const int us_delay = calc_audiotime_usec(out->common.cfg, bytes); - DEBUG("emulate ha write delay (%d us)", us_delay); - usleep(us_delay); - } - return bytes; -} - -static uint32_t out_get_sample_rate(const struct audio_stream* stream) { - struct ha_stream_out* out = (struct ha_stream_out*)stream; - - DEBUG("rate %" PRIu32, out->common.cfg.rate); - - return out->common.cfg.rate; -} - -static int out_set_sample_rate(struct audio_stream* stream, uint32_t rate) { - struct ha_stream_out* out = (struct ha_stream_out*)stream; - - DEBUG("out_set_sample_rate : %" PRIu32, rate); - - out->common.cfg.rate = rate; - - return 0; -} - -static size_t out_get_buffer_size(const struct audio_stream* stream) { - struct ha_stream_out* out = (struct ha_stream_out*)stream; - // period_size is the AudioFlinger mixer buffer size. - const size_t period_size = out->common.buffer_sz / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS; - - DEBUG("socket buffer size: %zu period size: %zu", out->common.buffer_sz, period_size); - - return period_size; -} - -size_t audio_ha_hw_stream_compute_buffer_size( - btav_a2dp_codec_sample_rate_t codec_sample_rate, - btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample, - btav_a2dp_codec_channel_mode_t codec_channel_mode) { - size_t buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ; // Default value - const uint64_t time_period_ms = 20; // Conservative 20ms - uint32_t sample_rate; - uint32_t bits_per_sample; - uint32_t number_of_channels; - - // Check the codec config sample rate - switch (codec_sample_rate) { - case BTAV_A2DP_CODEC_SAMPLE_RATE_44100: - sample_rate = 44100; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_48000: - sample_rate = 48000; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_88200: - sample_rate = 88200; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_96000: - sample_rate = 96000; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_176400: - sample_rate = 176400; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_192000: - sample_rate = 192000; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_16000: - sample_rate = 16000; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_24000: - sample_rate = 24000; - break; - case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE: - default: - ERROR("Invalid sample rate: 0x%x", codec_sample_rate); - return buffer_sz; - } - - // Check the codec config bits per sample - switch (codec_bits_per_sample) { - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16: - bits_per_sample = 16; - break; - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24: - bits_per_sample = 24; - break; - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32: - bits_per_sample = 32; - break; - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE: - default: - ERROR("Invalid bits per sample: 0x%x", codec_bits_per_sample); - return buffer_sz; - } - - // Check the codec config channel mode - switch (codec_channel_mode) { - case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO: - number_of_channels = 1; - break; - case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO: - number_of_channels = 2; - break; - case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE: - default: - ERROR("Invalid channel mode: 0x%x", codec_channel_mode); - return buffer_sz; - } - - // - // The buffer size is computed by using the following formula: - // - // AUDIO_STREAM_OUTPUT_BUFFER_SIZE = - // (TIME_PERIOD_MS * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * - // SAMPLE_RATE_HZ * NUMBER_OF_CHANNELS * (BITS_PER_SAMPLE / 8)) / 1000 - // - // AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is - // divided for AudioFlinger data delivery. The AudioFlinger mixer delivers - // data in chunks of - // (AUDIO_STREAM_OUTPUT_BUFFER_SIZE / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS) . - // If the number of periods is 2, the socket buffer represents "double - // buffering" of the AudioFlinger mixer buffer. - // - // Furthermore, the AudioFlinger expects the buffer size to be a multiple - // of 16 frames. - const size_t divisor = - (AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * 16 * number_of_channels * bits_per_sample) / 8; - - buffer_sz = (time_period_ms * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * sample_rate * - number_of_channels * (bits_per_sample / 8)) / - 1000; - - // Adjust the buffer size so it can be divided by the divisor - const size_t remainder = buffer_sz % divisor; - if (remainder != 0) { - buffer_sz += divisor - remainder; - } - - return buffer_sz; -} - -static audio_channel_mask_t out_get_channels(const struct audio_stream* stream) { - struct ha_stream_out* out = (struct ha_stream_out*)stream; - - DEBUG("channels 0x%" PRIx32, out->common.cfg.channel_mask); - - return (audio_channel_mask_t)out->common.cfg.channel_mask; -} - -static audio_format_t out_get_format(const struct audio_stream* stream) { - struct ha_stream_out* out = (struct ha_stream_out*)stream; - DEBUG("format 0x%x", out->common.cfg.format); - return (audio_format_t)out->common.cfg.format; -} - -static int out_set_format(UNUSED_ATTR struct audio_stream* stream, - UNUSED_ATTR audio_format_t format) { - DEBUG("setting format not yet supported (0x%x)", format); - return -ENOSYS; -} - -static int out_standby(struct audio_stream* stream) { - struct ha_stream_out* out = (struct ha_stream_out*)stream; - int retVal = 0; - - FNLOG(); - - std::lock_guard<std::recursive_mutex> lock(*out->common.mutex); - // Do nothing in SUSPENDED state. - if (out->common.state != AUDIO_HA_STATE_SUSPENDED) { - retVal = suspend_audio_datapath(&out->common, true); - } - out->frames_rendered = 0; // rendered is reset, presented is not - - return retVal; -} - -static int out_dump(UNUSED_ATTR const struct audio_stream* stream, UNUSED_ATTR int fd) { - FNLOG(); - return 0; -} - -static int out_set_parameters(struct audio_stream* stream, const char* kvpairs) { - struct ha_stream_out* out = (struct ha_stream_out*)stream; - - INFO("state %d kvpairs %s", out->common.state, kvpairs); - - std::unordered_map<std::string, std::string> params = - hash_map_utils_new_from_string_params(kvpairs); - int status = 0; - - if (params.empty()) { - return status; - } - - std::lock_guard<std::recursive_mutex> lock(*out->common.mutex); - - /* dump params */ - hash_map_utils_dump_string_keys_string_values(params); - - if (params[AUDIO_PARAMETER_KEY_CLOSING].compare("true") == 0) { - DEBUG("stream closing, disallow any writes"); - out->common.state = AUDIO_HA_STATE_STOPPING; - } - - if (params["HearingAidSuspended"].compare("true") == 0) { - if (out->common.state == AUDIO_HA_STATE_STARTED) { - status = suspend_audio_datapath(&out->common, false); - } - } else { - /* Do not start the streaming automatically. If the phone was streaming - * prior to being suspended, the next out_write shall trigger the - * AVDTP start procedure */ - if (out->common.state == AUDIO_HA_STATE_SUSPENDED) { - out->common.state = AUDIO_HA_STATE_STANDBY; - } - /* Irrespective of the state, return 0 */ - } - - return status; -} - -static char* out_get_parameters(const struct audio_stream* stream, const char* keys) { - FNLOG(); - - btav_a2dp_codec_config_t codec_config; - btav_a2dp_codec_config_t codec_capability; - - struct ha_stream_out* out = (struct ha_stream_out*)stream; - - std::unordered_map<std::string, std::string> params = hash_map_utils_new_from_string_params(keys); - std::unordered_map<std::string, std::string> return_params; - - if (params.empty()) { - return strdup(""); - } - - std::lock_guard<std::recursive_mutex> lock(*out->common.mutex); - - if (ha_read_output_audio_config(&out->common, &codec_config, &codec_capability, - false /* update_stream_config */) < 0) { - ERROR("ha_read_output_audio_config failed"); - goto done; - } - - // Add the format - if (params.find(AUDIO_PARAMETER_STREAM_SUP_FORMATS) != params.end()) { - std::string param; - if (codec_capability.bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) { - if (!param.empty()) { - param += "|"; - } - param += "AUDIO_FORMAT_PCM_16_BIT"; - } - if (codec_capability.bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) { - if (!param.empty()) { - param += "|"; - } - param += "AUDIO_FORMAT_PCM_24_BIT_PACKED"; - } - if (codec_capability.bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) { - if (!param.empty()) { - param += "|"; - } - param += "AUDIO_FORMAT_PCM_32_BIT"; - } - if (param.empty()) { - ERROR("Invalid codec capability bits_per_sample=0x%x", codec_capability.bits_per_sample); - goto done; - } else { - return_params[AUDIO_PARAMETER_STREAM_SUP_FORMATS] = param; - } - } - - // Add the sample rate - if (params.find(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES) != params.end()) { - std::string param; - if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_44100) { - if (!param.empty()) { - param += "|"; - } - param += "44100"; - } - if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_48000) { - if (!param.empty()) { - param += "|"; - } - param += "48000"; - } - if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_88200) { - if (!param.empty()) { - param += "|"; - } - param += "88200"; - } - if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_96000) { - if (!param.empty()) { - param += "|"; - } - param += "96000"; - } - if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_176400) { - if (!param.empty()) { - param += "|"; - } - param += "176400"; - } - if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_192000) { - if (!param.empty()) { - param += "|"; - } - param += "192000"; - } - if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_16000) { - if (!param.empty()) { - param += "|"; - } - param += "16000"; - } - if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_24000) { - if (!param.empty()) { - param += "|"; - } - param += "24000"; - } - if (param.empty()) { - ERROR("Invalid codec capability sample_rate=0x%x", codec_capability.sample_rate); - goto done; - } else { - return_params[AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES] = param; - } - } - - // Add the channel mask - if (params.find(AUDIO_PARAMETER_STREAM_SUP_CHANNELS) != params.end()) { - std::string param; - if (codec_capability.channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_MONO) { - if (!param.empty()) { - param += "|"; - } - param += "AUDIO_CHANNEL_OUT_MONO"; - } - if (codec_capability.channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO) { - if (!param.empty()) { - param += "|"; - } - param += "AUDIO_CHANNEL_OUT_STEREO"; - } - if (param.empty()) { - ERROR("Invalid codec capability channel_mode=0x%x", codec_capability.channel_mode); - goto done; - } else { - return_params[AUDIO_PARAMETER_STREAM_SUP_CHANNELS] = param; - } - } - -done: - std::string result; - for (const auto& ptr : return_params) { - result += ptr.first + "=" + ptr.second + ";"; - } - - INFO("get parameters result = %s", result.c_str()); - - return strdup(result.c_str()); -} - -static uint32_t out_get_latency(const struct audio_stream_out* stream) { - int latency_us; - - struct ha_stream_out* out = (struct ha_stream_out*)stream; - - FNLOG(); - - latency_us = ((out->common.buffer_sz * 1000) / audio_stream_out_frame_size(&out->stream) / - out->common.cfg.rate) * - 1000; - - return (latency_us / 1000) + 200; -} - -static int out_set_volume(UNUSED_ATTR struct audio_stream_out* stream, UNUSED_ATTR float left, - UNUSED_ATTR float right) { - FNLOG(); - - /* volume controlled in audioflinger mixer (digital) */ - - return -ENOSYS; -} - -static int out_get_presentation_position(const struct audio_stream_out* stream, uint64_t* frames, - struct timespec* timestamp) { - struct ha_stream_out* out = (struct ha_stream_out*)stream; - - FNLOG(); - if (stream == NULL || frames == NULL || timestamp == NULL) { - return -EINVAL; - } - - int ret = -EWOULDBLOCK; - std::lock_guard<std::recursive_mutex> lock(*out->common.mutex); - uint64_t latency_frames = (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000; - if (out->frames_presented >= latency_frames) { - *frames = out->frames_presented - latency_frames; - clock_gettime(CLOCK_MONOTONIC, - timestamp); // could also be associated with out_write(). - ret = 0; - } - return ret; -} - -static int out_get_render_position(const struct audio_stream_out* stream, uint32_t* dsp_frames) { - struct ha_stream_out* out = (struct ha_stream_out*)stream; - - FNLOG(); - if (stream == NULL || dsp_frames == NULL) { - return -EINVAL; - } - - std::lock_guard<std::recursive_mutex> lock(*out->common.mutex); - uint64_t latency_frames = (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000; - if (out->frames_rendered >= latency_frames) { - *dsp_frames = (uint32_t)(out->frames_rendered - latency_frames); - } else { - *dsp_frames = 0; - } - return 0; -} - -static int out_add_audio_effect(UNUSED_ATTR const struct audio_stream* stream, - UNUSED_ATTR effect_handle_t effect) { - FNLOG(); - return 0; -} - -static int out_remove_audio_effect(UNUSED_ATTR const struct audio_stream* stream, - UNUSED_ATTR effect_handle_t effect) { - FNLOG(); - return 0; -} - -/* - * AUDIO INPUT STREAM - */ - -static uint32_t in_get_sample_rate(const struct audio_stream* stream) { - struct ha_stream_in* in = (struct ha_stream_in*)stream; - - FNLOG(); - return in->common.cfg.rate; -} - -static int in_set_sample_rate(struct audio_stream* stream, uint32_t rate) { - struct ha_stream_in* in = (struct ha_stream_in*)stream; - - FNLOG(); - - if (in->common.cfg.rate > 0 && in->common.cfg.rate == rate) { - return 0; - } else { - return -1; - } -} - -static size_t in_get_buffer_size(UNUSED_ATTR const struct audio_stream* stream) { - FNLOG(); - return 320; -} - -static audio_channel_mask_t in_get_channels(const struct audio_stream* stream) { - struct ha_stream_in* in = (struct ha_stream_in*)stream; - - FNLOG(); - return (audio_channel_mask_t)in->common.cfg.channel_mask; -} - -static audio_format_t in_get_format(UNUSED_ATTR const struct audio_stream* stream) { - FNLOG(); - return AUDIO_FORMAT_PCM_16_BIT; -} - -static int in_set_format(UNUSED_ATTR struct audio_stream* stream, - UNUSED_ATTR audio_format_t format) { - FNLOG(); - if (format == AUDIO_FORMAT_PCM_16_BIT) { - return 0; - } else { - return -1; - } -} - -static int in_standby(UNUSED_ATTR struct audio_stream* stream) { - FNLOG(); - return 0; -} - -static int in_dump(UNUSED_ATTR const struct audio_stream* stream, UNUSED_ATTR int fd) { - FNLOG(); - return 0; -} - -static int in_set_parameters(UNUSED_ATTR struct audio_stream* stream, - UNUSED_ATTR const char* kvpairs) { - FNLOG(); - return 0; -} - -static char* in_get_parameters(UNUSED_ATTR const struct audio_stream* stream, - UNUSED_ATTR const char* keys) { - FNLOG(); - return strdup(""); -} - -static int in_set_gain(UNUSED_ATTR struct audio_stream_in* stream, UNUSED_ATTR float gain) { - FNLOG(); - return 0; -} - -static ssize_t in_read(struct audio_stream_in* stream, void* buffer, size_t bytes) { - struct ha_stream_in* in = (struct ha_stream_in*)stream; - int read; - int us_delay; - - DEBUG("read %zu bytes, state: %d", bytes, in->common.state); - - std::unique_lock<std::recursive_mutex> lock(*in->common.mutex); - if (in->common.state == AUDIO_HA_STATE_SUSPENDED || in->common.state == AUDIO_HA_STATE_STOPPING) { - DEBUG("stream suspended"); - goto error; - } - - /* only allow autostarting if we are in stopped or standby */ - if ((in->common.state == AUDIO_HA_STATE_STOPPED) || - (in->common.state == AUDIO_HA_STATE_STANDBY)) { - if (start_audio_datapath(&in->common) < 0) { - goto error; - } - } else if (in->common.state != AUDIO_HA_STATE_STARTED) { - ERROR("stream not in stopped or standby"); - goto error; - } - - lock.unlock(); - read = skt_read(in->common.audio_fd, buffer, bytes); - lock.lock(); - if (read == -1) { - skt_disconnect(in->common.audio_fd); - in->common.audio_fd = AUDIO_SKT_DISCONNECTED; - if ((in->common.state != AUDIO_HA_STATE_SUSPENDED) && - (in->common.state != AUDIO_HA_STATE_STOPPING)) { - in->common.state = AUDIO_HA_STATE_STOPPED; - } else { - ERROR("read failed : stream suspended, avoid resetting state"); - } - goto error; - } else if (read == 0) { - DEBUG("read time out - return zeros"); - memset(buffer, 0, bytes); - read = bytes; - } - lock.unlock(); - - DEBUG("read %d bytes out of %zu bytes", read, bytes); - return read; - -error: - memset(buffer, 0, bytes); - us_delay = calc_audiotime_usec(in->common.cfg, bytes); - DEBUG("emulate ha read delay (%d us)", us_delay); - - usleep(us_delay); - return bytes; -} - -static uint32_t in_get_input_frames_lost(UNUSED_ATTR struct audio_stream_in* stream) { - FNLOG(); - return 0; -} - -static int in_add_audio_effect(UNUSED_ATTR const struct audio_stream* stream, - UNUSED_ATTR effect_handle_t effect) { - FNLOG(); - return 0; -} - -static int in_remove_audio_effect(UNUSED_ATTR const struct audio_stream* stream, - UNUSED_ATTR effect_handle_t effect) { - FNLOG(); - - return 0; -} - -static int adev_open_output_stream(struct audio_hw_device* dev, - UNUSED_ATTR audio_io_handle_t handle, - UNUSED_ATTR audio_devices_t devices, - UNUSED_ATTR audio_output_flags_t flags, - struct audio_config* config, - struct audio_stream_out** stream_out, - UNUSED_ATTR const char* address) - -{ - struct ha_audio_device* ha_dev = (struct ha_audio_device*)dev; - struct ha_stream_out* out; - int ret = 0; - - INFO("opening output"); - // protect against adev->output and stream_out from being inconsistent - std::lock_guard<std::recursive_mutex> lock(*ha_dev->mutex); - out = (struct ha_stream_out*)calloc(1, sizeof(struct ha_stream_out)); - - if (!out) { - return -ENOMEM; - } - - out->stream.common.get_sample_rate = out_get_sample_rate; - out->stream.common.set_sample_rate = out_set_sample_rate; - out->stream.common.get_buffer_size = out_get_buffer_size; - out->stream.common.get_channels = out_get_channels; - out->stream.common.get_format = out_get_format; - out->stream.common.set_format = out_set_format; - out->stream.common.standby = out_standby; - out->stream.common.dump = out_dump; - out->stream.common.set_parameters = out_set_parameters; - out->stream.common.get_parameters = out_get_parameters; - out->stream.common.add_audio_effect = out_add_audio_effect; - out->stream.common.remove_audio_effect = out_remove_audio_effect; - out->stream.get_latency = out_get_latency; - out->stream.set_volume = out_set_volume; - out->stream.write = out_write; - out->stream.get_render_position = out_get_render_position; - out->stream.get_presentation_position = out_get_presentation_position; - - /* initialize ha specifics */ - ha_stream_common_init(&out->common); - - // Make sure we always have the feeding parameters configured - btav_a2dp_codec_config_t codec_config; - btav_a2dp_codec_config_t codec_capability; - if (ha_read_output_audio_config(&out->common, &codec_config, &codec_capability, - true /* update_stream_config */) < 0) { - ERROR("ha_read_output_audio_config failed"); - ret = -1; - goto err_open; - } - // ha_read_output_audio_config() opens the socket control path (or fails) - - /* set output config values */ - if (config != nullptr) { - // Try to use the config parameters and send it to the remote side - // TODO: Shall we use out_set_format() and similar? - if (config->format != 0) { - out->common.cfg.format = config->format; - } - if (config->sample_rate != 0) { - out->common.cfg.rate = config->sample_rate; - } - if (config->channel_mask != 0) { - out->common.cfg.channel_mask = config->channel_mask; - } - if ((out->common.cfg.format != 0) || (out->common.cfg.rate != 0) || - (out->common.cfg.channel_mask != 0)) { - if (ha_write_output_audio_config(&out->common) < 0) { - ERROR("ha_write_output_audio_config failed"); - ret = -1; - goto err_open; - } - // Read again and make sure we use the same parameters as the remote side - if (ha_read_output_audio_config(&out->common, &codec_config, &codec_capability, - true /* update_stream_config */) < 0) { - ERROR("ha_read_output_audio_config failed"); - ret = -1; - goto err_open; - } - } - config->format = out_get_format((const struct audio_stream*)&out->stream); - config->sample_rate = out_get_sample_rate((const struct audio_stream*)&out->stream); - config->channel_mask = out_get_channels((const struct audio_stream*)&out->stream); - - INFO("Output stream config: format=0x%x sample_rate=%d channel_mask=0x%x buffer_sz=%zu", - config->format, config->sample_rate, config->channel_mask, out->common.buffer_sz); - } - *stream_out = &out->stream; - ha_dev->output = out; - - DEBUG("success"); - /* Delay to ensure Headset is in proper state when START is initiated from - * DUT immediately after the connection due to ongoing music playback. */ - usleep(250000); - return 0; - -err_open: - ha_stream_common_destroy(&out->common); - free(out); - *stream_out = NULL; - ha_dev->output = NULL; - ERROR("failed"); - return ret; -} - -static void adev_close_output_stream(struct audio_hw_device* dev, struct audio_stream_out* stream) { - struct ha_audio_device* ha_dev = (struct ha_audio_device*)dev; - struct ha_stream_out* out = (struct ha_stream_out*)stream; - - // prevent interference with adev_set_parameters. - std::lock_guard<std::recursive_mutex> lock(*ha_dev->mutex); - { - std::lock_guard<std::recursive_mutex> lock(*out->common.mutex); - const ha_state_t state = out->common.state; - INFO("closing output (state %d)", (int)state); - if ((state == AUDIO_HA_STATE_STARTED) || (state == AUDIO_HA_STATE_STOPPING)) { - stop_audio_datapath(&out->common); - } - - skt_disconnect(out->common.ctrl_fd); - out->common.ctrl_fd = AUDIO_SKT_DISCONNECTED; - } - - ha_stream_common_destroy(&out->common); - free(stream); - ha_dev->output = NULL; - - DEBUG("done"); -} - -static int adev_set_parameters(struct audio_hw_device* dev, const char* kvpairs) { - struct ha_audio_device* ha_dev = (struct ha_audio_device*)dev; - int retval = 0; - - // prevent interference with adev_close_output_stream - std::lock_guard<std::recursive_mutex> lock(*ha_dev->mutex); - struct ha_stream_out* out = ha_dev->output; - - if (out == NULL) { - return retval; - } - - INFO("state %d", out->common.state); - - retval = out->stream.common.set_parameters((struct audio_stream*)out, kvpairs); - - return retval; -} - -static char* adev_get_parameters(UNUSED_ATTR const struct audio_hw_device* dev, const char* keys) { - FNLOG(); - - std::unordered_map<std::string, std::string> params = hash_map_utils_new_from_string_params(keys); - hash_map_utils_dump_string_keys_string_values(params); - - return strdup(""); -} - -static int adev_init_check(UNUSED_ATTR const struct audio_hw_device* dev) { - FNLOG(); - - return 0; -} - -static int adev_set_voice_volume(UNUSED_ATTR struct audio_hw_device* dev, - UNUSED_ATTR float volume) { - FNLOG(); - - return -ENOSYS; -} - -static int adev_set_master_volume(UNUSED_ATTR struct audio_hw_device* dev, - UNUSED_ATTR float volume) { - FNLOG(); - - return -ENOSYS; -} - -static int adev_set_mode(UNUSED_ATTR struct audio_hw_device* dev, UNUSED_ATTR audio_mode_t mode) { - FNLOG(); - - return 0; -} - -static int adev_set_mic_mute(UNUSED_ATTR struct audio_hw_device* dev, UNUSED_ATTR bool state) { - FNLOG(); - - return -ENOSYS; -} - -static int adev_get_mic_mute(UNUSED_ATTR const struct audio_hw_device* dev, - UNUSED_ATTR bool* state) { - FNLOG(); - - return -ENOSYS; -} - -static size_t adev_get_input_buffer_size(UNUSED_ATTR const struct audio_hw_device* dev, - UNUSED_ATTR const struct audio_config* config) { - FNLOG(); - - return 320; -} - -static int adev_open_input_stream(struct audio_hw_device* dev, UNUSED_ATTR audio_io_handle_t handle, - UNUSED_ATTR audio_devices_t devices, - UNUSED_ATTR struct audio_config* config, - struct audio_stream_in** stream_in, - UNUSED_ATTR audio_input_flags_t flags, - UNUSED_ATTR const char* address, - UNUSED_ATTR audio_source_t source) { - struct ha_audio_device* ha_dev = (struct ha_audio_device*)dev; - struct ha_stream_in* in; - int ret; - - FNLOG(); - - // protect against adev->input and stream_in from being inconsistent - std::lock_guard<std::recursive_mutex> lock(*ha_dev->mutex); - in = (struct ha_stream_in*)calloc(1, sizeof(struct ha_stream_in)); - - if (!in) { - return -ENOMEM; - } - - in->stream.common.get_sample_rate = in_get_sample_rate; - in->stream.common.set_sample_rate = in_set_sample_rate; - in->stream.common.get_buffer_size = in_get_buffer_size; - in->stream.common.get_channels = in_get_channels; - in->stream.common.get_format = in_get_format; - in->stream.common.set_format = in_set_format; - in->stream.common.standby = in_standby; - in->stream.common.dump = in_dump; - in->stream.common.set_parameters = in_set_parameters; - in->stream.common.get_parameters = in_get_parameters; - in->stream.common.add_audio_effect = in_add_audio_effect; - in->stream.common.remove_audio_effect = in_remove_audio_effect; - in->stream.set_gain = in_set_gain; - in->stream.read = in_read; - in->stream.get_input_frames_lost = in_get_input_frames_lost; - - /* initialize ha specifics */ - ha_stream_common_init(&in->common); - - *stream_in = &in->stream; - ha_dev->input = in; - - if (ha_read_input_audio_config(&in->common) < 0) { - ERROR("ha_read_input_audio_config failed (%s)", strerror(errno)); - ret = -1; - goto err_open; - } - // ha_read_input_audio_config() opens socket control path (or fails) - - DEBUG("success"); - return 0; - -err_open: - ha_stream_common_destroy(&in->common); - free(in); - *stream_in = NULL; - ha_dev->input = NULL; - ERROR("failed"); - return ret; -} - -static void adev_close_input_stream(struct audio_hw_device* dev, struct audio_stream_in* stream) { - struct ha_audio_device* ha_dev = (struct ha_audio_device*)dev; - struct ha_stream_in* in = (struct ha_stream_in*)stream; - - std::lock_guard<std::recursive_mutex> lock(*ha_dev->mutex); - { - std::lock_guard<std::recursive_mutex> lock(*in->common.mutex); - const ha_state_t state = in->common.state; - INFO("closing input (state %d)", (int)state); - - if ((state == AUDIO_HA_STATE_STARTED) || (state == AUDIO_HA_STATE_STOPPING)) { - stop_audio_datapath(&in->common); - } - - skt_disconnect(in->common.ctrl_fd); - in->common.ctrl_fd = AUDIO_SKT_DISCONNECTED; - } - ha_stream_common_destroy(&in->common); - free(stream); - ha_dev->input = NULL; - - DEBUG("done"); -} - -static int adev_dump(UNUSED_ATTR const audio_hw_device_t* device, UNUSED_ATTR int fd) { - FNLOG(); - - return 0; -} - -static int adev_close(hw_device_t* device) { - struct ha_audio_device* ha_dev = (struct ha_audio_device*)device; - FNLOG(); - - delete ha_dev->mutex; - ha_dev->mutex = nullptr; - free(device); - return 0; -} - -static int adev_open(const hw_module_t* module, const char* name, hw_device_t** device) { - struct ha_audio_device* adev; - - INFO(" adev_open in ha_hw module"); - FNLOG(); - - if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) { - ERROR("interface %s not matching [%s]", name, AUDIO_HARDWARE_INTERFACE); - return -EINVAL; - } - - adev = (struct ha_audio_device*)calloc(1, sizeof(struct ha_audio_device)); - - if (!adev) { - return -ENOMEM; - } - - adev->mutex = new std::recursive_mutex; - - adev->device.common.tag = HARDWARE_DEVICE_TAG; - adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; - adev->device.common.module = (struct hw_module_t*)module; - adev->device.common.close = adev_close; - - adev->device.init_check = adev_init_check; - adev->device.set_voice_volume = adev_set_voice_volume; - adev->device.set_master_volume = adev_set_master_volume; - adev->device.set_mode = adev_set_mode; - adev->device.set_mic_mute = adev_set_mic_mute; - adev->device.get_mic_mute = adev_get_mic_mute; - adev->device.set_parameters = adev_set_parameters; - adev->device.get_parameters = adev_get_parameters; - adev->device.get_input_buffer_size = adev_get_input_buffer_size; - adev->device.open_output_stream = adev_open_output_stream; - adev->device.close_output_stream = adev_close_output_stream; - adev->device.open_input_stream = adev_open_input_stream; - adev->device.close_input_stream = adev_close_input_stream; - adev->device.dump = adev_dump; - - adev->output = NULL; - - *device = &adev->device.common; - - return 0; -} - -static struct hw_module_methods_t hal_module_methods = { - .open = adev_open, -}; - -__attribute__((visibility("default"))) struct audio_module HAL_MODULE_INFO_SYM = { - .common = - { - .tag = HARDWARE_MODULE_TAG, - .version_major = 1, - .version_minor = 0, - .id = AUDIO_HARDWARE_MODULE_ID, - .name = "Hearing Aid Audio HW HAL", - .author = "The Android Open Source Project", - .methods = &hal_module_methods, - }, -}; diff --git a/system/audio_hearing_aid_hw/src/audio_hearing_aid_hw_utils.cc b/system/audio_hearing_aid_hw/src/audio_hearing_aid_hw_utils.cc deleted file mode 100644 index 1553b05d3e..0000000000 --- a/system/audio_hearing_aid_hw/src/audio_hearing_aid_hw_utils.cc +++ /dev/null @@ -1,44 +0,0 @@ -/****************************************************************************** - * - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h" - -#define CASE_RETURN_STR(const) \ - case const: \ - return #const; - -// TODO(b/369381361) Enfore -Wmissing-prototypes -#pragma GCC diagnostic ignored "-Wmissing-prototypes" - -const char* audio_ha_hw_dump_ctrl_event(tHEARING_AID_CTRL_CMD event) { - switch (event) { - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_NONE) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_CHECK_READY) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_START) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_STOP) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_SUSPEND) - CASE_RETURN_STR(HEARING_AID_CTRL_GET_INPUT_AUDIO_CONFIG) - CASE_RETURN_STR(HEARING_AID_CTRL_GET_OUTPUT_AUDIO_CONFIG) - CASE_RETURN_STR(HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_OFFLOAD_START) - default: - break; - } - - return "UNKNOWN HEARING_AID_CTRL_CMD"; -} diff --git a/system/audio_hearing_aid_hw/test/audio_hearing_aid_hw_test.cc b/system/audio_hearing_aid_hw/test/audio_hearing_aid_hw_test.cc deleted file mode 100644 index 95f3dc6288..0000000000 --- a/system/audio_hearing_aid_hw/test/audio_hearing_aid_hw_test.cc +++ /dev/null @@ -1,140 +0,0 @@ -/****************************************************************************** - * - * Copyright 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h" - -#include <gtest/gtest.h> - -namespace { -static uint32_t codec_sample_rate2value(btav_a2dp_codec_sample_rate_t codec_sample_rate) { - switch (codec_sample_rate) { - case BTAV_A2DP_CODEC_SAMPLE_RATE_44100: - return 44100; - case BTAV_A2DP_CODEC_SAMPLE_RATE_48000: - return 48000; - case BTAV_A2DP_CODEC_SAMPLE_RATE_88200: - return 88200; - case BTAV_A2DP_CODEC_SAMPLE_RATE_96000: - return 96000; - case BTAV_A2DP_CODEC_SAMPLE_RATE_176400: - return 176400; - case BTAV_A2DP_CODEC_SAMPLE_RATE_192000: - return 192000; - case BTAV_A2DP_CODEC_SAMPLE_RATE_16000: - return 16000; - case BTAV_A2DP_CODEC_SAMPLE_RATE_24000: - return 24000; - case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE: - break; - } - return 0; -} - -static uint32_t codec_bits_per_sample2value( - btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample) { - switch (codec_bits_per_sample) { - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16: - return 16; - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24: - return 24; - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32: - return 32; - case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE: - break; - } - return 0; -} - -static uint32_t codec_channel_mode2value(btav_a2dp_codec_channel_mode_t codec_channel_mode) { - switch (codec_channel_mode) { - case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO: - return 1; - case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO: - return 2; - case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE: - break; - } - return 0; -} - -} // namespace - -class AudioA2dpHwTest : public ::testing::Test { -protected: - AudioA2dpHwTest() {} - -private: -}; - -TEST_F(AudioA2dpHwTest, test_compute_buffer_size) { - const btav_a2dp_codec_sample_rate_t codec_sample_rate_array[] = { - BTAV_A2DP_CODEC_SAMPLE_RATE_NONE, BTAV_A2DP_CODEC_SAMPLE_RATE_44100, - BTAV_A2DP_CODEC_SAMPLE_RATE_48000, BTAV_A2DP_CODEC_SAMPLE_RATE_88200, - BTAV_A2DP_CODEC_SAMPLE_RATE_96000, BTAV_A2DP_CODEC_SAMPLE_RATE_176400, - BTAV_A2DP_CODEC_SAMPLE_RATE_192000}; - - const btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample_array[] = { - BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE, BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16, - BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24, BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32}; - - const btav_a2dp_codec_channel_mode_t codec_channel_mode_array[] = { - BTAV_A2DP_CODEC_CHANNEL_MODE_NONE, BTAV_A2DP_CODEC_CHANNEL_MODE_MONO, - BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO}; - - for (const auto codec_sample_rate : codec_sample_rate_array) { - for (const auto codec_bits_per_sample : codec_bits_per_sample_array) { - for (const auto codec_channel_mode : codec_channel_mode_array) { - size_t buffer_size = audio_ha_hw_stream_compute_buffer_size( - codec_sample_rate, codec_bits_per_sample, codec_channel_mode); - - // Check for invalid input - if ((codec_sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) || - (codec_bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) || - (codec_channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE)) { - EXPECT_EQ(buffer_size, static_cast<size_t>(AUDIO_STREAM_OUTPUT_BUFFER_SZ)); - continue; - } - - uint32_t sample_rate = codec_sample_rate2value(codec_sample_rate); - EXPECT_NE(0u, sample_rate); - - uint32_t bits_per_sample = codec_bits_per_sample2value(codec_bits_per_sample); - EXPECT_NE(0u, bits_per_sample); - - uint32_t number_of_channels = codec_channel_mode2value(codec_channel_mode); - EXPECT_NE(0u, number_of_channels); - - const uint64_t time_period_ms = 20; // TODO: Must be a parameter - size_t expected_buffer_size = (time_period_ms * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * - sample_rate * number_of_channels * (bits_per_sample / 8)) / - 1000; - - // Compute the divisor and adjust the buffer size - const size_t divisor = - (AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * 16 * number_of_channels * bits_per_sample) / - 8; - const size_t remainder = expected_buffer_size % divisor; - if (remainder != 0) { - expected_buffer_size += divisor - remainder; - } - - EXPECT_EQ(buffer_size, expected_buffer_size); - } - } - } -} diff --git a/system/bta/hearing_aid/hearing_aid_audio_source.cc b/system/bta/hearing_aid/hearing_aid_audio_source.cc index ffb9ff9eef..1f4c68e516 100644 --- a/system/bta/hearing_aid/hearing_aid_audio_source.cc +++ b/system/bta/hearing_aid/hearing_aid_audio_source.cc @@ -31,7 +31,6 @@ #include <vector> #include "audio_hal_interface/hearing_aid_software_encoding.h" -#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h" #include "bta/include/bta_hearing_aid_api.h" #include "common/message_loop_thread.h" #include "common/repeating_timer.h" @@ -40,41 +39,10 @@ #include "hardware/bt_av.h" #include "osi/include/wakelock.h" #include "stack/include/main_thread.h" -#include "udrv/include/uipc.h" using namespace bluetooth; -namespace std { -template <> -struct formatter<tUIPC_EVENT> : enum_formatter<tUIPC_EVENT> {}; -template <> -struct formatter<tHEARING_AID_CTRL_ACK> : enum_formatter<tHEARING_AID_CTRL_ACK> {}; -template <> -struct formatter<tHEARING_AID_CTRL_CMD> : enum_formatter<tHEARING_AID_CTRL_CMD> {}; -} // namespace std - namespace { -#define CASE_RETURN_STR(const) \ - case const: \ - return #const; - -const char* audio_ha_hw_dump_ctrl_event(tHEARING_AID_CTRL_CMD event) { - switch (event) { - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_NONE) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_CHECK_READY) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_START) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_STOP) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_SUSPEND) - CASE_RETURN_STR(HEARING_AID_CTRL_GET_INPUT_AUDIO_CONFIG) - CASE_RETURN_STR(HEARING_AID_CTRL_GET_OUTPUT_AUDIO_CONFIG) - CASE_RETURN_STR(HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG) - CASE_RETURN_STR(HEARING_AID_CTRL_CMD_OFFLOAD_START) - default: - break; - } - - return "UNKNOWN HEARING_AID_CTRL_CMD"; -} int bit_rate = -1; int sample_rate = -1; @@ -82,7 +50,6 @@ int data_interval_ms = -1; int num_channels = 2; bluetooth::common::RepeatingTimer audio_timer; HearingAidAudioReceiver* localAudioReceiver = nullptr; -std::unique_ptr<tUIPC_STATE> uipc_hearing_aid = nullptr; struct AudioHalStats { size_t media_read_total_underflow_bytes; @@ -108,11 +75,9 @@ void send_audio_data() { uint8_t p_buf[bytes_per_tick]; - uint32_t bytes_read; + uint32_t bytes_read = 0; if (bluetooth::audio::hearing_aid::is_hal_enabled()) { bytes_read = bluetooth::audio::hearing_aid::read(p_buf, bytes_per_tick); - } else { - bytes_read = UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, p_buf, bytes_per_tick); } log::debug("bytes_read: {}", bytes_read); @@ -129,12 +94,6 @@ void send_audio_data() { } } -void hearing_aid_send_ack(tHEARING_AID_CTRL_ACK status) { - uint8_t ack = status; - log::debug("Hearing Aid audio ctrl ack: {}", status); - UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack)); -} - void start_audio_ticks() { if (data_interval_ms != HA_INTERVAL_10_MS && data_interval_ms != HA_INTERVAL_20_MS) { log::fatal("Unsupported data interval: {}", data_interval_ms); @@ -153,193 +112,6 @@ void stop_audio_ticks() { wakelock_release(); } -void hearing_aid_data_cb(tUIPC_CH_ID, tUIPC_EVENT event) { - log::debug("Hearing Aid audio data event: {}", event); - switch (event) { - case UIPC_OPEN_EVT: - log::info("UIPC_OPEN_EVT"); - /* - * Read directly from media task from here on (keep callback for - * connection events. - */ - UIPC_Ioctl(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, UIPC_REG_REMOVE_ACTIVE_READSET, NULL); - UIPC_Ioctl(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO, - reinterpret_cast<void*>(0)); - - do_in_main_thread(base::BindOnce(start_audio_ticks)); - break; - case UIPC_CLOSE_EVT: - log::info("UIPC_CLOSE_EVT"); - hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS); - do_in_main_thread(base::BindOnce(stop_audio_ticks)); - break; - default: - log::error("Hearing Aid audio data event not recognized: {}", event); - } -} - -void hearing_aid_recv_ctrl_data() { - tHEARING_AID_CTRL_CMD cmd = HEARING_AID_CTRL_CMD_NONE; - int n; - - uint8_t read_cmd = 0; /* The read command size is one octet */ - n = UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, &read_cmd, 1); - cmd = static_cast<tHEARING_AID_CTRL_CMD>(read_cmd); - - /* detach on ctrl channel means audioflinger process was terminated */ - if (n == 0) { - log::warn("CTRL CH DETACHED"); - UIPC_Close(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL); - return; - } - - log::info("{}", audio_ha_hw_dump_ctrl_event(cmd)); - // a2dp_cmd_pending = cmd; - - tHEARING_AID_CTRL_ACK ctrl_ack_status; - - switch (cmd) { - case HEARING_AID_CTRL_CMD_CHECK_READY: - hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS); - break; - - case HEARING_AID_CTRL_CMD_START: - ctrl_ack_status = HEARING_AID_CTRL_ACK_SUCCESS; - // timer is restarted in UIPC_Open - if (!hearing_aid_on_resume_req(false)) { - ctrl_ack_status = HEARING_AID_CTRL_ACK_FAILURE; - } else { - UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, hearing_aid_data_cb, - HEARING_AID_DATA_PATH); - } - hearing_aid_send_ack(ctrl_ack_status); - break; - - case HEARING_AID_CTRL_CMD_STOP: - if (!hearing_aid_on_suspend_req()) { - log::info("HEARING_AID_CTRL_CMD_STOP: hearing_aid_on_suspend_req() errs, but ignored."); - } - hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS); - break; - - case HEARING_AID_CTRL_CMD_SUSPEND: - ctrl_ack_status = HEARING_AID_CTRL_ACK_SUCCESS; - if (!hearing_aid_on_suspend_req()) { - ctrl_ack_status = HEARING_AID_CTRL_ACK_FAILURE; - } - hearing_aid_send_ack(ctrl_ack_status); - break; - - case HEARING_AID_CTRL_GET_OUTPUT_AUDIO_CONFIG: { - btav_a2dp_codec_config_t codec_config; - btav_a2dp_codec_config_t codec_capability; - if (sample_rate == 16000) { - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_16000; - codec_capability.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_16000; - } else if (sample_rate == 24000) { - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_24000; - codec_capability.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_24000; - } else { - log::fatal("unsupported sample rate: {}", sample_rate); - } - - codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16; - codec_capability.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16; - - codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; - codec_capability.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; - - hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS); - // Send the current codec config - UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, - reinterpret_cast<const uint8_t*>(&codec_config.sample_rate), - sizeof(btav_a2dp_codec_sample_rate_t)); - UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, - reinterpret_cast<const uint8_t*>(&codec_config.bits_per_sample), - sizeof(btav_a2dp_codec_bits_per_sample_t)); - UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, - reinterpret_cast<const uint8_t*>(&codec_config.channel_mode), - sizeof(btav_a2dp_codec_channel_mode_t)); - // Send the current codec capability - UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, - reinterpret_cast<const uint8_t*>(&codec_capability.sample_rate), - sizeof(btav_a2dp_codec_sample_rate_t)); - UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, - reinterpret_cast<const uint8_t*>(&codec_capability.bits_per_sample), - sizeof(btav_a2dp_codec_bits_per_sample_t)); - UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, - reinterpret_cast<const uint8_t*>(&codec_capability.channel_mode), - sizeof(btav_a2dp_codec_channel_mode_t)); - break; - } - - case HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG: { - // TODO: we only support one config for now! - btav_a2dp_codec_config_t codec_config; - codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE; - codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE; - codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE; - - hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS); - // Send the current codec config - if (UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, - reinterpret_cast<uint8_t*>(&codec_config.sample_rate), - sizeof(btav_a2dp_codec_sample_rate_t)) != - sizeof(btav_a2dp_codec_sample_rate_t)) { - log::error("Error reading sample rate from audio HAL"); - break; - } - if (UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, - reinterpret_cast<uint8_t*>(&codec_config.bits_per_sample), - sizeof(btav_a2dp_codec_bits_per_sample_t)) != - sizeof(btav_a2dp_codec_bits_per_sample_t)) { - log::error("Error reading bits per sample from audio HAL"); - - break; - } - if (UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, - reinterpret_cast<uint8_t*>(&codec_config.channel_mode), - sizeof(btav_a2dp_codec_channel_mode_t)) != - sizeof(btav_a2dp_codec_channel_mode_t)) { - log::error("Error reading channel mode from audio HAL"); - - break; - } - log::info( - "HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG: sample_rate={}, " - "bits_per_sample={},channel_mode={}", - codec_config.sample_rate, codec_config.bits_per_sample, codec_config.channel_mode); - break; - } - - default: - log::error("UNSUPPORTED CMD: {}", cmd); - hearing_aid_send_ack(HEARING_AID_CTRL_ACK_FAILURE); - break; - } - log::info("a2dp-ctrl-cmd : {} DONE", audio_ha_hw_dump_ctrl_event(cmd)); -} - -void hearing_aid_ctrl_cb(tUIPC_CH_ID, tUIPC_EVENT event) { - log::debug("Hearing Aid audio ctrl event: {}", event); - switch (event) { - case UIPC_OPEN_EVT: - break; - case UIPC_CLOSE_EVT: - /* restart ctrl server unless we are shutting down */ - if (HearingAid::IsHearingAidRunning()) { - UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb, - HEARING_AID_CTRL_PATH); - } - break; - case UIPC_RX_DATA_READY_EVT: - hearing_aid_recv_ctrl_data(); - break; - default: - log::error("Hearing Aid audio ctrl unrecognized event: {}", event); - } -} - bool hearing_aid_on_resume_req(bool start_media_task) { if (localAudioReceiver == nullptr) { log::error("HEARING_AID_CTRL_CMD_START: audio receiver not started"); @@ -414,18 +186,13 @@ void HearingAidAudioSource::Initialize() { .on_suspend_ = hearing_aid_on_suspend_req, }; if (!bluetooth::audio::hearing_aid::init(stream_cb, get_main_thread())) { - log::warn("Using legacy HAL"); - uipc_hearing_aid = UIPC_Init(); - UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb, HEARING_AID_CTRL_PATH); + log::error("Hearing AID HAL failed to initialize"); } } void HearingAidAudioSource::CleanUp() { if (bluetooth::audio::hearing_aid::is_hal_enabled()) { bluetooth::audio::hearing_aid::cleanup(); - } else { - UIPC_Close(*uipc_hearing_aid, UIPC_CH_ID_ALL); - uipc_hearing_aid = nullptr; } } diff --git a/system/btif/BUILD.gn b/system/btif/BUILD.gn index 38b8fa9c6a..ea6a0f6fbc 100644 --- a/system/btif/BUILD.gn +++ b/system/btif/BUILD.gn @@ -16,9 +16,6 @@ static_library("btif") { sources = [ - # TODO(abps) - Do we need this? - "//bt/system/audio_hearing_aid_hw/src/audio_hearing_aid_hw_utils.cc", - # AVRCP Target Service "avrcp/avrcp_service.cc", @@ -94,7 +91,6 @@ static_library("btif") { "//bt/system/", "//bt/system/bta/dm", "//bt/system/linux_include", - "//bt/system/audio_hearing_aid_hw/include", "//bt/system/bta/aics/include", "//bt/system/bta/include", "//bt/system/bta/sys", |