summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TEST_MAPPING9
-rw-r--r--system/audio_hal_interface/aidl/hearing_aid_software_encoding_aidl.cc3
-rw-r--r--system/audio_hal_interface/hidl/hearing_aid_software_encoding_hidl.cc3
-rw-r--r--system/audio_hearing_aid_hw/Android.bp63
-rw-r--r--system/audio_hearing_aid_hw/include/audio_hearing_aid_hw.h146
-rw-r--r--system/audio_hearing_aid_hw/src/audio_hearing_aid_hw.cc1925
-rw-r--r--system/audio_hearing_aid_hw/src/audio_hearing_aid_hw_utils.cc44
-rw-r--r--system/audio_hearing_aid_hw/test/audio_hearing_aid_hw_test.cc140
-rw-r--r--system/bta/hearing_aid/hearing_aid_audio_source.cc237
-rw-r--r--system/btif/BUILD.gn4
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",