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