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