1 /******************************************************************************
2 *
3 * Copyright 2018 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #define LOG_TAG "bluetooth-asha"
20
21 #include <base/files/file_util.h>
22 #include <bluetooth/log.h>
23 #include <stdio.h>
24
25 #include <chrono>
26 #include <cstddef>
27 #include <cstdint>
28 #include <memory>
29 #include <ostream>
30 #include <sstream>
31 #include <vector>
32
33 #include "audio_hal_interface/hearing_aid_software_encoding.h"
34 #include "bta/include/bta_hearing_aid_api.h"
35 #include "common/message_loop_thread.h"
36 #include "common/repeating_timer.h"
37 #include "common/time_util.h"
38 #include "hardware/bluetooth.h"
39 #include "hardware/bt_av.h"
40 #include "osi/include/wakelock.h"
41 #include "stack/include/main_thread.h"
42
43 using namespace bluetooth;
44
45 namespace {
46
47 int bit_rate = -1;
48 int sample_rate = -1;
49 int data_interval_ms = -1;
50 int num_channels = 2;
51 bluetooth::common::RepeatingTimer audio_timer;
52 HearingAidAudioReceiver* localAudioReceiver = nullptr;
53
54 struct AudioHalStats {
55 size_t media_read_total_underflow_bytes;
56 size_t media_read_total_underflow_count;
57 uint64_t media_read_last_underflow_us;
58
AudioHalStats__anonda370f840111::AudioHalStats59 AudioHalStats() { Reset(); }
60
Reset__anonda370f840111::AudioHalStats61 void Reset() {
62 media_read_total_underflow_bytes = 0;
63 media_read_total_underflow_count = 0;
64 media_read_last_underflow_us = 0;
65 }
66 };
67
68 AudioHalStats stats;
69
70 bool hearing_aid_on_resume_req(bool start_media_task);
71 bool hearing_aid_on_suspend_req();
72
send_audio_data()73 void send_audio_data() {
74 uint32_t bytes_per_tick = (num_channels * sample_rate * data_interval_ms * (bit_rate / 8)) / 1000;
75
76 uint8_t p_buf[bytes_per_tick];
77
78 uint32_t bytes_read = 0;
79 if (bluetooth::audio::hearing_aid::is_hal_enabled()) {
80 bytes_read = bluetooth::audio::hearing_aid::read(p_buf, bytes_per_tick);
81 }
82
83 log::debug("bytes_read: {}", bytes_read);
84 if (bytes_read < bytes_per_tick) {
85 stats.media_read_total_underflow_bytes += bytes_per_tick - bytes_read;
86 stats.media_read_total_underflow_count++;
87 stats.media_read_last_underflow_us = bluetooth::common::time_get_os_boottime_us();
88 }
89
90 std::vector<uint8_t> data(p_buf, p_buf + bytes_read);
91
92 if (localAudioReceiver != nullptr) {
93 localAudioReceiver->OnAudioDataReady(data);
94 }
95 }
96
start_audio_ticks()97 void start_audio_ticks() {
98 if (data_interval_ms != HA_INTERVAL_10_MS && data_interval_ms != HA_INTERVAL_20_MS) {
99 log::fatal("Unsupported data interval: {}", data_interval_ms);
100 }
101
102 wakelock_acquire();
103 audio_timer.SchedulePeriodic(get_main_thread()->GetWeakPtr(),
104 base::BindRepeating(&send_audio_data),
105 std::chrono::milliseconds(data_interval_ms));
106 log::info("running with data interval: {}", data_interval_ms);
107 }
108
stop_audio_ticks()109 void stop_audio_ticks() {
110 log::info("stopped");
111 audio_timer.CancelAndWait();
112 wakelock_release();
113 }
114
hearing_aid_on_resume_req(bool start_media_task)115 bool hearing_aid_on_resume_req(bool start_media_task) {
116 if (localAudioReceiver == nullptr) {
117 log::error("HEARING_AID_CTRL_CMD_START: audio receiver not started");
118 return false;
119 }
120 bt_status_t status;
121 if (start_media_task) {
122 status = do_in_main_thread(base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
123 base::Unretained(localAudioReceiver),
124 start_audio_ticks));
125 } else {
126 auto start_dummy_ticks = []() { log::info("start_audio_ticks: waiting for data path opened"); };
127 status = do_in_main_thread(base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
128 base::Unretained(localAudioReceiver),
129 start_dummy_ticks));
130 }
131 if (status != BT_STATUS_SUCCESS) {
132 log::error("HEARING_AID_CTRL_CMD_START: do_in_main_thread err={}", status);
133 return false;
134 }
135 return true;
136 }
137
hearing_aid_on_suspend_req()138 bool hearing_aid_on_suspend_req() {
139 if (localAudioReceiver == nullptr) {
140 log::error("HEARING_AID_CTRL_CMD_SUSPEND: audio receiver not started");
141 return false;
142 }
143 bt_status_t status =
144 do_in_main_thread(base::BindOnce(&HearingAidAudioReceiver::OnAudioSuspend,
145 base::Unretained(localAudioReceiver), stop_audio_ticks));
146 if (status != BT_STATUS_SUCCESS) {
147 log::error("HEARING_AID_CTRL_CMD_SUSPEND: do_in_main_thread err={}", status);
148 return false;
149 }
150 return true;
151 }
152 } // namespace
153
Start(const CodecConfiguration & codecConfiguration,HearingAidAudioReceiver * audioReceiver,uint16_t remote_delay_ms)154 void HearingAidAudioSource::Start(const CodecConfiguration& codecConfiguration,
155 HearingAidAudioReceiver* audioReceiver,
156 uint16_t remote_delay_ms) {
157 log::info("Hearing Aid Source Open");
158
159 bit_rate = codecConfiguration.bit_rate;
160 sample_rate = codecConfiguration.sample_rate;
161 data_interval_ms = codecConfiguration.data_interval_ms;
162
163 stats.Reset();
164
165 if (bluetooth::audio::hearing_aid::is_hal_enabled()) {
166 bluetooth::audio::hearing_aid::start_session();
167 bluetooth::audio::hearing_aid::set_remote_delay(remote_delay_ms);
168 }
169 localAudioReceiver = audioReceiver;
170 }
171
Stop()172 void HearingAidAudioSource::Stop() {
173 log::info("Hearing Aid Source Close");
174
175 localAudioReceiver = nullptr;
176 if (bluetooth::audio::hearing_aid::is_hal_enabled()) {
177 bluetooth::audio::hearing_aid::end_session();
178 }
179
180 stop_audio_ticks();
181 }
182
Initialize()183 void HearingAidAudioSource::Initialize() {
184 auto stream_cb = bluetooth::audio::hearing_aid::StreamCallbacks{
185 .on_resume_ = hearing_aid_on_resume_req,
186 .on_suspend_ = hearing_aid_on_suspend_req,
187 };
188 if (!bluetooth::audio::hearing_aid::init(stream_cb, get_main_thread())) {
189 log::error("Hearing AID HAL failed to initialize");
190 }
191 }
192
CleanUp()193 void HearingAidAudioSource::CleanUp() {
194 if (bluetooth::audio::hearing_aid::is_hal_enabled()) {
195 bluetooth::audio::hearing_aid::cleanup();
196 }
197 }
198
DebugDump(int fd)199 void HearingAidAudioSource::DebugDump(int fd) {
200 uint64_t now_us = bluetooth::common::time_get_os_boottime_us();
201 std::stringstream stream;
202 stream << " Hearing Aid Audio HAL:"
203 << "\n Counts (underflow) : "
204 << stats.media_read_total_underflow_count
205 << "\n Bytes (underflow) : "
206 << stats.media_read_total_underflow_bytes
207 << "\n Last update time ago in ms (underflow) : "
208 << (stats.media_read_last_underflow_us > 0
209 ? (now_us - stats.media_read_last_underflow_us) / 1000
210 : 0)
211 << std::endl;
212 dprintf(fd, "%s", stream.str().c_str());
213 }
214