HearingAidAudioSource implementation
am: be754da679
Change-Id: Ib20c46f34578b77f6541963714080aa115fb9775
diff --git a/bta/Android.bp b/bta/Android.bp
index 0aac124..5759183 100644
--- a/bta/Android.bp
+++ b/bta/Android.bp
@@ -67,6 +67,7 @@
"gatt/bta_gatts_main.cc",
"gatt/bta_gatts_utils.cc",
"hearing_aid/hearing_aid.cc",
+ "hearing_aid/hearing_aid_audio_source.cc",
"hf_client/bta_hf_client_act.cc",
"hf_client/bta_hf_client_api.cc",
"hf_client/bta_hf_client_at.cc",
@@ -108,6 +109,10 @@
"sys/bta_sys_main.cc",
"sys/utl.cc",
],
+
+ whole_static_libs: [
+ "libaudio-hearing-aid-hw-utils",
+ ],
}
// bta unit tests for target
diff --git a/bta/hearing_aid/hearing_aid_audio_source.cc b/bta/hearing_aid/hearing_aid_audio_source.cc
new file mode 100644
index 0000000..276957b
--- /dev/null
+++ b/bta/hearing_aid/hearing_aid_audio_source.cc
@@ -0,0 +1,262 @@
+/******************************************************************************
+ *
+ * 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"
+#include "bta_hearing_aid_api.h"
+#include "osi/include/alarm.h"
+#include "uipc.h"
+
+#include <base/files/file_util.h>
+#include <base/strings/string_number_conversions.h>
+#include <include/hardware/bt_av.h>
+
+using base::FilePath;
+extern const char* audio_ha_hw_dump_ctrl_event(tHEARING_AID_CTRL_CMD event);
+
+namespace {
+int bit_rate = 16;
+int sample_rate = 16000;
+int data_interval_ms = 20 /* msec */;
+int num_channels = 2;
+alarm_t* audio_timer = nullptr;
+
+HearingAidAudioReceiver* localAudioReceiver;
+std::unique_ptr<tUIPC_STATE> uipc_hearing_aid;
+
+void send_audio_data(void*) {
+ int bytes_per_tick =
+ (num_channels * sample_rate * data_interval_ms * (bit_rate / 8)) / 1000;
+
+ uint16_t event;
+ uint8_t p_buf[bytes_per_tick];
+
+ uint32_t bytes_read = UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO,
+ &event, p_buf, bytes_per_tick);
+
+ VLOG(2) << "bytes_read: " << bytes_read;
+
+ std::vector<uint8_t> data(p_buf, p_buf + bytes_read);
+
+ localAudioReceiver->OnAudioDataReady(data);
+}
+
+void hearing_aid_send_ack(tHEARING_AID_CTRL_ACK status) {
+ uint8_t ack = status;
+ DVLOG(2) << "Hearing Aid audio ctrl ack: " << status;
+ UIPC_Send(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
+}
+
+void hearing_aid_data_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
+ DVLOG(2) << "Hearing Aid audio data event: " << event;
+ switch (event) {
+ case 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));
+
+ audio_timer = alarm_new_periodic("hearing_aid_data_timer");
+ alarm_set_on_mloop(audio_timer, data_interval_ms, send_audio_data,
+ nullptr);
+ break;
+ case UIPC_CLOSE_EVT:
+ hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+ if (audio_timer) {
+ alarm_cancel(audio_timer);
+ }
+ 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, NULL, &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(WARNING) << __func__ << "CTRL CH DETACHED";
+ UIPC_Close(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL);
+ return;
+ }
+
+ VLOG(2) << __func__ << " " << audio_ha_hw_dump_ctrl_event(cmd);
+ // a2dp_cmd_pending = cmd;
+
+ 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:
+ localAudioReceiver->OnAudioResume();
+ // timer is restarted in UIPC_Open
+ UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, hearing_aid_data_cb);
+ hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+ break;
+
+ case HEARING_AID_CTRL_CMD_STOP:
+ hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+ break;
+
+ case HEARING_AID_CTRL_CMD_SUSPEND:
+ if (audio_timer) alarm_cancel(audio_timer);
+ localAudioReceiver->OnAudioSuspend();
+ hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
+ 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, 0,
+ reinterpret_cast<uint8_t*>(&codec_config.sample_rate),
+ sizeof(btav_a2dp_codec_sample_rate_t)) !=
+ sizeof(btav_a2dp_codec_sample_rate_t)) {
+ LOG(ERROR) << __func__ << "Error reading sample rate from audio HAL";
+ break;
+ }
+ if (UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0,
+ 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) << __func__
+ << "Error reading bits per sample from audio HAL";
+
+ break;
+ }
+ if (UIPC_Read(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, 0,
+ reinterpret_cast<uint8_t*>(&codec_config.channel_mode),
+ sizeof(btav_a2dp_codec_channel_mode_t)) !=
+ sizeof(btav_a2dp_codec_channel_mode_t)) {
+ LOG(ERROR) << __func__ << "Error reading channel mode from audio HAL";
+
+ break;
+ }
+ LOG(INFO) << __func__ << " HEARING_AID_CTRL_SET_OUTPUT_AUDIO_CONFIG: "
+ << "sample_rate=" << codec_config.sample_rate
+ << "bits_per_sample=" << codec_config.bits_per_sample
+ << "channel_mode=" << codec_config.channel_mode;
+ break;
+ }
+
+ default:
+ LOG(ERROR) << __func__ << "UNSUPPORTED CMD: " << cmd;
+ hearing_aid_send_ack(HEARING_AID_CTRL_ACK_FAILURE);
+ break;
+ }
+ VLOG(2) << __func__ << " a2dp-ctrl-cmd : " << audio_ha_hw_dump_ctrl_event(cmd)
+ << " DONE";
+}
+
+void hearing_aid_ctrl_cb(tUIPC_CH_ID, tUIPC_EVENT event) {
+ VLOG(2) << "Hearing Aid audio ctrl event: " << event;
+ switch (event) {
+ case UIPC_OPEN_EVT:
+ break;
+ case UIPC_CLOSE_EVT:
+ UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb);
+ break;
+ case UIPC_RX_DATA_READY_EVT:
+ hearing_aid_recv_ctrl_data();
+ break;
+ default:
+ LOG(ERROR) << "Hearing Aid audio ctrl unrecognized event: " << event;
+ }
+}
+} // namespace
+
+void HearingAidAudioSource::Start(const CodecConfiguration& codecConfiguration,
+ HearingAidAudioReceiver* audioReceiver) {
+ localAudioReceiver = audioReceiver;
+ VLOG(2) << "Hearing Aid UIPC Open";
+}
+
+void HearingAidAudioSource::Stop() {
+ if (audio_timer) {
+ alarm_cancel(audio_timer);
+ }
+}
+
+void HearingAidAudioSource::Initialize() {
+ uipc_hearing_aid = UIPC_Init();
+ UIPC_Open(*uipc_hearing_aid, UIPC_CH_ID_AV_CTRL, hearing_aid_ctrl_cb);
+}
+
+void HearingAidAudioSource::CleanUp() {
+ UIPC_Close(*uipc_hearing_aid, UIPC_CH_ID_ALL);
+}
diff --git a/udrv/include/uipc.h b/udrv/include/uipc.h
index b5540b2..bd1c8bf 100644
--- a/udrv/include/uipc.h
+++ b/udrv/include/uipc.h
@@ -18,6 +18,8 @@
#ifndef UIPC_H
#define UIPC_H
+#include <mutex>
+
#define UIPC_CH_ID_AV_CTRL 0
#define UIPC_CH_ID_AV_AUDIO 1
#define UIPC_CH_NUM 2