1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "BTAudioHalDeviceProxy"
18 
19 #include <android-base/logging.h>
20 #include <android-base/stringprintf.h>
21 #include <audio_utils/primitives.h>
22 #include <inttypes.h>
23 #include <log/log.h>
24 #include <stdlib.h>
25 
26 #include "BluetoothAudioSessionControl.h"
27 #include "device_port_proxy.h"
28 #include "stream_apis.h"
29 #include "utils.h"
30 
31 namespace android {
32 namespace bluetooth {
33 namespace audio {
34 
35 using ::android::base::StringPrintf;
36 using ::android::bluetooth::audio::BluetoothAudioSessionControl;
37 using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
38 using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
39 using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
40 using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
41 using BluetoothAudioStatus =
42     ::android::hardware::bluetooth::audio::V2_0::Status;
43 using ControlResultCallback = std::function<void(
44     uint16_t cookie, bool start_resp, const BluetoothAudioStatus& status)>;
45 using SessionChangedCallback = std::function<void(uint16_t cookie)>;
46 
47 namespace {
48 
SampleRateToAudioFormat(SampleRate sample_rate)49 unsigned int SampleRateToAudioFormat(SampleRate sample_rate) {
50   switch (sample_rate) {
51     case SampleRate::RATE_16000:
52       return 16000;
53     case SampleRate::RATE_24000:
54       return 24000;
55     case SampleRate::RATE_44100:
56       return 44100;
57     case SampleRate::RATE_48000:
58       return 48000;
59     case SampleRate::RATE_88200:
60       return 88200;
61     case SampleRate::RATE_96000:
62       return 96000;
63     case SampleRate::RATE_176400:
64       return 176400;
65     case SampleRate::RATE_192000:
66       return 192000;
67     default:
68       return kBluetoothDefaultSampleRate;
69   }
70 }
ChannelModeToAudioFormat(ChannelMode channel_mode)71 audio_channel_mask_t ChannelModeToAudioFormat(ChannelMode channel_mode) {
72   switch (channel_mode) {
73     case ChannelMode::MONO:
74       return AUDIO_CHANNEL_OUT_MONO;
75     case ChannelMode::STEREO:
76       return AUDIO_CHANNEL_OUT_STEREO;
77     default:
78       return kBluetoothDefaultOutputChannelModeMask;
79   }
80 }
81 
BitsPerSampleToAudioFormat(BitsPerSample bits_per_sample)82 audio_format_t BitsPerSampleToAudioFormat(BitsPerSample bits_per_sample) {
83   switch (bits_per_sample) {
84     case BitsPerSample::BITS_16:
85       return AUDIO_FORMAT_PCM_16_BIT;
86     case BitsPerSample::BITS_24:
87       return AUDIO_FORMAT_PCM_24_BIT_PACKED;
88     case BitsPerSample::BITS_32:
89       return AUDIO_FORMAT_PCM_32_BIT;
90     default:
91       return kBluetoothDefaultAudioFormatBitsPerSample;
92   }
93 }
94 
95 // The maximum time to wait in std::condition_variable::wait_for()
96 constexpr unsigned int kMaxWaitingTimeMs = 4500;
97 
98 }  // namespace
99 
BluetoothAudioPortOut()100 BluetoothAudioPortOut::BluetoothAudioPortOut()
101     : state_(BluetoothStreamState::DISABLED),
102       session_type_(SessionType::UNKNOWN),
103       cookie_(android::bluetooth::audio::kObserversCookieUndefined) {}
104 
SetUp(audio_devices_t devices)105 bool BluetoothAudioPortOut::SetUp(audio_devices_t devices) {
106   if (!init_session_type(devices)) return false;
107 
108   state_ = BluetoothStreamState::STANDBY;
109 
110   auto control_result_cb = [port = this](uint16_t cookie, bool start_resp,
111                                          const BluetoothAudioStatus& status) {
112     if (!port->in_use()) {
113       LOG(ERROR) << "control_result_cb: BluetoothAudioPortOut is not in use";
114       return;
115     }
116     if (port->cookie_ != cookie) {
117       LOG(ERROR) << "control_result_cb: proxy of device port (cookie=" << StringPrintf("%#hx", cookie)
118                  << ") is corrupted";
119       return;
120     }
121     port->ControlResultHandler(status);
122   };
123   auto session_changed_cb = [port = this](uint16_t cookie) {
124     if (!port->in_use()) {
125       LOG(ERROR) << "session_changed_cb: BluetoothAudioPortOut is not in use";
126       return;
127     }
128     if (port->cookie_ != cookie) {
129       LOG(ERROR) << "session_changed_cb: proxy of device port (cookie=" << StringPrintf("%#hx", cookie)
130                  << ") is corrupted";
131       return;
132     }
133     port->SessionChangedHandler();
134   };
135   ::android::bluetooth::audio::PortStatusCallbacks cbacks = {
136       .control_result_cb_ = control_result_cb,
137       .session_changed_cb_ = session_changed_cb};
138   cookie_ = BluetoothAudioSessionControl::RegisterControlResultCback(
139       session_type_, cbacks);
140   LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_);
141 
142   return (cookie_ != android::bluetooth::audio::kObserversCookieUndefined);
143 }
144 
init_session_type(audio_devices_t device)145 bool BluetoothAudioPortOut::init_session_type(audio_devices_t device) {
146   switch (device) {
147     case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
148     case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
149     case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
150       LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLUETOOTH_A2DP (HEADPHONES/SPEAKER) ("
151                    << StringPrintf("%#x", device) << ")";
152       session_type_ = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
153       break;
154     case AUDIO_DEVICE_OUT_HEARING_AID:
155       LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_HEARING_AID (MEDIA/VOICE) (" << StringPrintf("%#x", device)
156                    << ")";
157       session_type_ = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
158       break;
159     default:
160       LOG(ERROR) << __func__ << ": unknown device=" << StringPrintf("%#x", device);
161       return false;
162   }
163 
164   if (!BluetoothAudioSessionControl::IsSessionReady(session_type_)) {
165     LOG(ERROR) << __func__ << ": device=" << StringPrintf("%#x", device) << ", session_type=" << toString(session_type_)
166                << " is not ready";
167     return false;
168   }
169   return true;
170 }
171 
TearDown()172 void BluetoothAudioPortOut::TearDown() {
173   if (!in_use()) {
174     LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
175                << ", cookie=" << StringPrintf("%#hx", cookie_) << " unknown monitor";
176     return;
177   }
178 
179   LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_);
180   BluetoothAudioSessionControl::UnregisterControlResultCback(session_type_,
181                                                              cookie_);
182   cookie_ = android::bluetooth::audio::kObserversCookieUndefined;
183 }
184 
ControlResultHandler(const BluetoothAudioStatus & status)185 void BluetoothAudioPortOut::ControlResultHandler(
186     const BluetoothAudioStatus& status) {
187   if (!in_use()) {
188     LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
189     return;
190   }
191   std::unique_lock<std::mutex> port_lock(cv_mutex_);
192   BluetoothStreamState previous_state = state_;
193   LOG(INFO) << "control_result_cb: session_type=" << toString(session_type_)
194             << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state
195             << ", status=" << toString(status);
196 
197   switch (previous_state) {
198     case BluetoothStreamState::STARTING:
199       if (status == BluetoothAudioStatus::SUCCESS) {
200         state_ = BluetoothStreamState::STARTED;
201       } else {
202         // Set to standby since the stack may be busy switching between outputs
203         LOG(WARNING) << "control_result_cb: status=" << toString(status)
204                      << " failure for session_type=" << toString(session_type_)
205                      << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state;
206         state_ = BluetoothStreamState::STANDBY;
207       }
208       break;
209     case BluetoothStreamState::SUSPENDING:
210       if (status == BluetoothAudioStatus::SUCCESS) {
211         state_ = BluetoothStreamState::STANDBY;
212       } else {
213         // It will be failed if the headset is disconnecting, and set to disable
214         // to wait for re-init again
215         LOG(WARNING) << "control_result_cb: status=" << toString(status)
216                      << " failure for session_type=" << toString(session_type_)
217                      << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state;
218         state_ = BluetoothStreamState::DISABLED;
219       }
220       break;
221     default:
222       LOG(ERROR) << "control_result_cb: unexpected status=" << toString(status)
223                  << " for session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
224                  << ", previous_state=" << previous_state;
225       return;
226   }
227   port_lock.unlock();
228   internal_cv_.notify_all();
229 }
230 
SessionChangedHandler()231 void BluetoothAudioPortOut::SessionChangedHandler() {
232   if (!in_use()) {
233     LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
234     return;
235   }
236   std::unique_lock<std::mutex> port_lock(cv_mutex_);
237   BluetoothStreamState previous_state = state_;
238   LOG(INFO) << "session_changed_cb: session_type=" << toString(session_type_)
239             << ", cookie=" << StringPrintf("%#hx", cookie_) << ", previous_state=" << previous_state;
240   if (previous_state != BluetoothStreamState::DISABLED) {
241     state_ = BluetoothStreamState::DISABLED;
242   } else {
243     state_ = BluetoothStreamState::STANDBY;
244   }
245   port_lock.unlock();
246   internal_cv_.notify_all();
247 }
248 
in_use() const249 bool BluetoothAudioPortOut::in_use() const {
250   return (cookie_ != android::bluetooth::audio::kObserversCookieUndefined);
251 }
252 
LoadAudioConfig(audio_config_t * audio_cfg) const253 bool BluetoothAudioPortOut::LoadAudioConfig(audio_config_t* audio_cfg) const {
254   if (!in_use()) {
255     LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
256     audio_cfg->sample_rate = kBluetoothDefaultSampleRate;
257     audio_cfg->channel_mask = kBluetoothDefaultOutputChannelModeMask;
258     audio_cfg->format = kBluetoothDefaultAudioFormatBitsPerSample;
259     return false;
260   }
261 
262   const AudioConfiguration& hal_audio_cfg =
263       BluetoothAudioSessionControl::GetAudioConfig(session_type_);
264   if (hal_audio_cfg.getDiscriminator() !=
265       AudioConfiguration::hidl_discriminator::pcmConfig) {
266     audio_cfg->sample_rate = kBluetoothDefaultSampleRate;
267     audio_cfg->channel_mask = kBluetoothDefaultOutputChannelModeMask;
268     audio_cfg->format = kBluetoothDefaultAudioFormatBitsPerSample;
269     return false;
270   }
271   const PcmParameters& pcm_cfg = hal_audio_cfg.pcmConfig();
272   LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
273                << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << ", PcmConfig=["
274                << toString(pcm_cfg) << "]";
275   if (pcm_cfg.sampleRate == SampleRate::RATE_UNKNOWN ||
276       pcm_cfg.channelMode == ChannelMode::UNKNOWN ||
277       pcm_cfg.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
278     return false;
279   }
280   audio_cfg->sample_rate = SampleRateToAudioFormat(pcm_cfg.sampleRate);
281   audio_cfg->channel_mask =
282       (is_stereo_to_mono_ ? AUDIO_CHANNEL_OUT_STEREO : ChannelModeToAudioFormat(pcm_cfg.channelMode));
283   audio_cfg->format = BitsPerSampleToAudioFormat(pcm_cfg.bitsPerSample);
284   return true;
285 }
286 
CondwaitState(BluetoothStreamState state)287 bool BluetoothAudioPortOut::CondwaitState(BluetoothStreamState state) {
288   bool retval;
289   std::unique_lock<std::mutex> port_lock(cv_mutex_);
290   switch (state) {
291     case BluetoothStreamState::STARTING:
292       LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
293                    << ", cookie=" << StringPrintf("%#hx", cookie_) << " waiting for STARTED";
294       retval = internal_cv_.wait_for(
295           port_lock, std::chrono::milliseconds(kMaxWaitingTimeMs),
296           [this] { return this->state_ != BluetoothStreamState::STARTING; });
297       retval = retval && state_ == BluetoothStreamState::STARTED;
298       break;
299     case BluetoothStreamState::SUSPENDING:
300       LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
301                    << ", cookie=" << StringPrintf("%#hx", cookie_) << " waiting for SUSPENDED";
302       retval = internal_cv_.wait_for(
303           port_lock, std::chrono::milliseconds(kMaxWaitingTimeMs),
304           [this] { return this->state_ != BluetoothStreamState::SUSPENDING; });
305       retval = retval && state_ == BluetoothStreamState::STANDBY;
306       break;
307     default:
308       LOG(WARNING) << __func__ << ": session_type=" << toString(session_type_)
309                    << ", cookie=" << StringPrintf("%#hx", cookie_) << " waiting for KNOWN";
310       return false;
311   }
312 
313   return retval;  // false if any failure like timeout
314 }
315 
Start()316 bool BluetoothAudioPortOut::Start() {
317   if (!in_use()) {
318     LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
319     return false;
320   }
321 
322   LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
323             << ", state=" << state_ << ", mono=" << (is_stereo_to_mono_ ? "true" : "false") << " request";
324   bool retval = false;
325   if (state_ == BluetoothStreamState::STANDBY) {
326     state_ = BluetoothStreamState::STARTING;
327     if (BluetoothAudioSessionControl::StartStream(session_type_)) {
328       retval = CondwaitState(BluetoothStreamState::STARTING);
329     } else {
330       LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
331                  << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " Hal fails";
332     }
333   }
334 
335   if (retval) {
336     LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
337               << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_
338               << ", mono=" << (is_stereo_to_mono_ ? "true" : "false") << " done";
339   } else {
340     LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
341                << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " failure";
342   }
343 
344   return retval;  // false if any failure like timeout
345 }
346 
Suspend()347 bool BluetoothAudioPortOut::Suspend() {
348   if (!in_use()) {
349     LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
350     return false;
351   }
352 
353   LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
354             << ", state=" << state_ << " request";
355   bool retval = false;
356   if (state_ == BluetoothStreamState::STARTED) {
357     state_ = BluetoothStreamState::SUSPENDING;
358     if (BluetoothAudioSessionControl::SuspendStream(session_type_)) {
359       retval = CondwaitState(BluetoothStreamState::SUSPENDING);
360     } else {
361       LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
362                  << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " Hal fails";
363     }
364   }
365 
366   if (retval) {
367     LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
368               << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " done";
369   } else {
370     LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
371                << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << " failure";
372   }
373 
374   return retval;  // false if any failure like timeout
375 }
376 
Stop()377 void BluetoothAudioPortOut::Stop() {
378   if (!in_use()) {
379     LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
380     return;
381   }
382   LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
383             << ", state=" << state_ << " request";
384   state_ = BluetoothStreamState::DISABLED;
385   BluetoothAudioSessionControl::StopStream(session_type_);
386   LOG(INFO) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
387             << ", state=" << state_ << " done";
388 }
389 
WriteData(const void * buffer,size_t bytes) const390 size_t BluetoothAudioPortOut::WriteData(const void* buffer, size_t bytes) const {
391   if (!in_use()) return 0;
392   if (!is_stereo_to_mono_) {
393     return BluetoothAudioSessionControl::OutWritePcmData(session_type_, buffer, bytes);
394   }
395 
396   // WAR to mix the stereo into Mono (16 bits per sample)
397   const size_t write_frames = bytes >> 2;
398   if (write_frames == 0) return 0;
399   auto src = static_cast<const int16_t*>(buffer);
400   std::unique_ptr<int16_t[]> dst{new int16_t[write_frames]};
401   downmix_to_mono_i16_from_stereo_i16(dst.get(), src, write_frames);
402   // a frame is 16 bits, and the size of a mono frame is equal to half a stereo.
403   return BluetoothAudioSessionControl::OutWritePcmData(session_type_, dst.get(), write_frames * 2) * 2;
404 }
405 
GetPresentationPosition(uint64_t * delay_ns,uint64_t * bytes,timespec * timestamp) const406 bool BluetoothAudioPortOut::GetPresentationPosition(uint64_t* delay_ns,
407                                                     uint64_t* bytes,
408                                                     timespec* timestamp) const {
409   if (!in_use()) {
410     LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
411     return false;
412   }
413   bool retval = BluetoothAudioSessionControl::GetPresentationPosition(
414       session_type_, delay_ns, bytes, timestamp);
415   LOG(VERBOSE) << __func__ << ": session_type=" << StringPrintf("%#hhx", session_type_)
416                << ", cookie=" << StringPrintf("%#hx", cookie_) << ", state=" << state_ << ", delay=" << *delay_ns
417                << "ns, data=" << *bytes << " bytes, timestamp=" << timestamp->tv_sec << "."
418                << StringPrintf("%09ld", timestamp->tv_nsec) << "s";
419 
420   return retval;
421 }
422 
UpdateMetadata(const source_metadata * source_metadata) const423 void BluetoothAudioPortOut::UpdateMetadata(
424     const source_metadata* source_metadata) const {
425   if (!in_use()) {
426     LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
427     return;
428   }
429   LOG(DEBUG) << __func__ << ": session_type=" << toString(session_type_) << ", cookie=" << StringPrintf("%#hx", cookie_)
430              << ", state=" << state_ << ", " << source_metadata->track_count << " track(s)";
431   if (source_metadata->track_count == 0) return;
432   BluetoothAudioSessionControl::UpdateTracksMetadata(session_type_,
433                                                      source_metadata);
434 }
435 
GetState() const436 BluetoothStreamState BluetoothAudioPortOut::GetState() const { return state_; }
437 
SetState(BluetoothStreamState state)438 void BluetoothAudioPortOut::SetState(BluetoothStreamState state) {
439   state_ = state;
440 }
441 
442 }  // namespace audio
443 }  // namespace bluetooth
444 }  // namespace android
445