Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1697d2b2 authored by Cheney Ni's avatar Cheney Ni Committed by android-build-merger
Browse files

Add generic audio HW module for Bluetooth audio HAL V2

am: b9a84c27

Change-Id: I05e5eeea39f01834ac490973047475d818b86a76
parents 0fc00e07 b9a84c27
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ subdirs = [
    "btcore",
    "common",
    "audio_a2dp_hw",
    "audio_bluetooth_hw",
    "audio_hearing_aid_hw",
    "hci",
    "utils",
+49 −0
Original line number Diff line number Diff line
// The format of the name is audio.<type>.<hardware/etc>.so

cc_library_shared {
    name: "audio.bluetooth.default",
    relative_install_path: "hw",
    proprietary: true,
    srcs: [
        "audio_bluetooth_hw.cc",
        "stream_apis.cc",
        "device_port_proxy.cc",
        "utils.cc",
    ],
    header_libs: ["libhardware_headers"],
    shared_libs: [
        "android.hardware.bluetooth.audio@2.0",
        "libbase",
        "libbluetooth_audio_session",
        "libcutils",
        "libfmq",
        "libhidlbase",
        "libhidltransport",
        "liblog",
        "libutils",
    ],
    cflags: [
        "-Wall",
        "-Werror",
        "-Wno-unused-parameter",
    ],
}

cc_test {
    name: "audio_bluetooth_hw_test",
    srcs: [
        "utils.cc",
        "utils_unittest.cc",
    ],
    shared_libs: [
        "libbase",
        "libcutils",
        "liblog",
        "libutils",
    ],
    cflags: [
        "-Wall",
        "-Werror",
        "-Wno-unused-parameter",
    ],
}
+140 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 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.
 */

#define LOG_TAG "BTAudioHw"

#include <android-base/logging.h>
#include <errno.h>
#include <hardware/audio.h>
#include <hardware/hardware.h>
#include <log/log.h>
#include <malloc.h>
#include <string.h>
#include <system/audio.h>

#include "stream_apis.h"
#include "utils.h"

static int adev_set_parameters(struct audio_hw_device* dev,
                               const char* kvpairs) {
  LOG(VERBOSE) << __func__ << ": kevpairs=[" << kvpairs << "]";
  return -ENOSYS;
}

static char* adev_get_parameters(const struct audio_hw_device* dev,
                                 const char* keys) {
  LOG(VERBOSE) << __func__ << ": keys=[" << keys << "]";
  return strdup("");
}

static int adev_init_check(const struct audio_hw_device* dev) { return 0; }

static int adev_set_voice_volume(struct audio_hw_device* dev, float volume) {
  LOG(VERBOSE) << __func__ << ": volume=" << volume;
  return -ENOSYS;
}

static int adev_set_master_volume(struct audio_hw_device* dev, float volume) {
  LOG(VERBOSE) << __func__ << ": volume=" << volume;
  return -ENOSYS;
}

static int adev_get_master_volume(struct audio_hw_device* dev, float* volume) {
  return -ENOSYS;
}

static int adev_set_master_mute(struct audio_hw_device* dev, bool muted) {
  LOG(VERBOSE) << __func__ << ": mute=" << muted;
  return -ENOSYS;
}

static int adev_get_master_mute(struct audio_hw_device* dev, bool* muted) {
  return -ENOSYS;
}

static int adev_set_mode(struct audio_hw_device* dev, audio_mode_t mode) {
  LOG(VERBOSE) << __func__ << ": mode=" << mode;
  return 0;
}

static int adev_set_mic_mute(struct audio_hw_device* dev, bool state) {
  LOG(VERBOSE) << __func__ << ": state=" << state;
  return -ENOSYS;
}

static int adev_get_mic_mute(const struct audio_hw_device* dev, bool* state) {
  return -ENOSYS;
}

static int adev_dump(const audio_hw_device_t* device, int fd) { return 0; }

static int adev_close(hw_device_t* device) {
  free(device);
  return 0;
}

static int adev_open(const hw_module_t* module, const char* name,
                     hw_device_t** device) {
  LOG(VERBOSE) << __func__ << ": name=[" << name << "]";
  if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;

  struct audio_hw_device* adev =
      (struct audio_hw_device*)calloc(1, sizeof(struct audio_hw_device));
  if (!adev) return -ENOMEM;

  adev->common.tag = HARDWARE_DEVICE_TAG;
  adev->common.version = AUDIO_DEVICE_API_VERSION_2_0;
  adev->common.module = (struct hw_module_t*)module;
  adev->common.close = adev_close;

  adev->init_check = adev_init_check;
  adev->set_voice_volume = adev_set_voice_volume;
  adev->set_master_volume = adev_set_master_volume;
  adev->get_master_volume = adev_get_master_volume;
  adev->set_mode = adev_set_mode;
  adev->set_mic_mute = adev_set_mic_mute;
  adev->get_mic_mute = adev_get_mic_mute;
  adev->set_parameters = adev_set_parameters;
  adev->get_parameters = adev_get_parameters;
  adev->get_input_buffer_size = adev_get_input_buffer_size;
  adev->open_output_stream = adev_open_output_stream;
  adev->close_output_stream = adev_close_output_stream;
  adev->open_input_stream = adev_open_input_stream;
  adev->close_input_stream = adev_close_input_stream;
  adev->dump = adev_dump;
  adev->set_master_mute = adev_set_master_mute;
  adev->get_master_mute = adev_get_master_mute;

  *device = &adev->common;
  return 0;
}

static struct hw_module_methods_t hal_module_methods = {
    .open = adev_open,
};

struct audio_module HAL_MODULE_INFO_SYM = {
    .common =
        {
            .tag = HARDWARE_MODULE_TAG,
            .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
            .hal_api_version = HARDWARE_HAL_API_VERSION,
            .id = AUDIO_HARDWARE_MODULE_ID,
            .name = "Bluetooth Audio HW HAL",
            .author = "The Android Open Source Project",
            .methods = &hal_module_methods,
        },
};
+473 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 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.
 */

#define LOG_TAG "BTAudioHalDeviceProxy"

#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <inttypes.h>
#include <log/log.h>
#include <stdlib.h>

#include "BluetoothAudioSessionControl.h"
#include "device_port_proxy.h"
#include "stream_apis.h"
#include "utils.h"

namespace android {
namespace bluetooth {
namespace audio {

using ::android::bluetooth::audio::BluetoothAudioSessionControl;
using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
using ::android::hardware::bluetooth::audio::V2_0::SessionType;
using BluetoothAudioStatus =
    ::android::hardware::bluetooth::audio::V2_0::Status;
using ControlResultCallback = std::function<void(
    uint16_t cookie, bool start_resp, const BluetoothAudioStatus& status)>;
using SessionChangedCallback = std::function<void(uint16_t cookie)>;

namespace {

unsigned int SampleRateToAudioFormat(SampleRate sample_rate) {
  switch (sample_rate) {
    case SampleRate::RATE_16000:
      return 16000;
    case SampleRate::RATE_24000:
      return 24000;
    case SampleRate::RATE_44100:
      return 44100;
    case SampleRate::RATE_48000:
      return 48000;
    case SampleRate::RATE_88200:
      return 88200;
    case SampleRate::RATE_96000:
      return 96000;
    case SampleRate::RATE_176400:
      return 176400;
    case SampleRate::RATE_192000:
      return 192000;
    default:
      return kBluetoothDefaultSampleRate;
  }
}
audio_channel_mask_t ChannelModeToAudioFormat(ChannelMode channel_mode) {
  switch (channel_mode) {
    case ChannelMode::MONO:
      return AUDIO_CHANNEL_OUT_MONO;
    case ChannelMode::STEREO:
      return AUDIO_CHANNEL_OUT_STEREO;
    default:
      return kBluetoothDefaultOutputChannelModeMask;
  }
}

audio_format_t BitsPerSampleToAudioFormat(BitsPerSample bits_per_sample) {
  switch (bits_per_sample) {
    case BitsPerSample::BITS_16:
      return AUDIO_FORMAT_PCM_16_BIT;
    case BitsPerSample::BITS_24:
      return AUDIO_FORMAT_PCM_24_BIT_PACKED;
    case BitsPerSample::BITS_32:
      return AUDIO_FORMAT_PCM_32_BIT;
    default:
      return kBluetoothDefaultAudioFormatBitsPerSample;
  }
}

// The maximum time to wait in std::condition_variable::wait_for()
constexpr unsigned int kMaxWaitingTimeMs = 4500;

}  // namespace

BluetoothAudioPortOut::BluetoothAudioPortOut()
    : state_(BluetoothStreamState::DISABLED),
      session_type_(SessionType::UNKNOWN),
      cookie_(android::bluetooth::audio::kObserversCookieUndefined) {}

bool BluetoothAudioPortOut::SetUp(audio_devices_t devices) {
  if (!init_session_type(devices)) return false;

  state_ = BluetoothStreamState::STANDBY;

  auto control_result_cb = [port = this](uint16_t cookie, bool start_resp,
                                         const BluetoothAudioStatus& status) {
    if (!port->in_use()) {
      LOG(ERROR) << ": BluetoothAudioPortOut is not in use";
      return;
    }
    if (port->cookie_ != cookie) {
      LOG(ERROR) << "control_result_cb: proxy of device port (cookie=0x"
                 << android::base::StringPrintf("%04hx", cookie)
                 << ") is corrupted";
      return;
    }
    port->ControlResultHandler(status);
  };
  auto session_changed_cb = [port = this](uint16_t cookie) {
    if (!port->in_use()) {
      LOG(ERROR) << ": BluetoothAudioPortOut is not in use";
      return;
    }
    if (port->cookie_ != cookie) {
      LOG(ERROR) << "session_changed_cb: proxy of device port (cookie=0x"
                 << android::base::StringPrintf("%04hx", cookie)
                 << ") is corrupted";
      return;
    }
    port->SessionChangedHandler();
  };
  ::android::bluetooth::audio::PortStatusCallbacks cbacks = {
      .control_result_cb_ = control_result_cb,
      .session_changed_cb_ = session_changed_cb};
  cookie_ = BluetoothAudioSessionControl::RegisterControlResultCback(
      session_type_, cbacks);
  LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
            << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_);

  return (cookie_ != android::bluetooth::audio::kObserversCookieUndefined);
}

bool BluetoothAudioPortOut::init_session_type(audio_devices_t device) {
  switch (device) {
    case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
    case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
    case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
      LOG(VERBOSE)
          << __func__
          << "device=AUDIO_DEVICE_OUT_BLUETOOTH_A2DP (HEADPHONES/SPEAKER) (0x"
          << android::base::StringPrintf("%08x", device) << ")";
      session_type_ = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
      break;
    case AUDIO_DEVICE_OUT_HEARING_AID:
      LOG(VERBOSE) << __func__
                   << "device=AUDIO_DEVICE_OUT_HEARING_AID (MEDIA/VOICE) (0x"
                   << android::base::StringPrintf("%08x", device) << ")";
      session_type_ = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
      break;
    default:
      LOG(ERROR) << __func__ << "unknown device=0x"
                 << android::base::StringPrintf("%08x", device);
      return false;
  }

  if (!BluetoothAudioSessionControl::IsSessionReady(session_type_)) {
    LOG(ERROR) << __func__ << "device=0x"
               << android::base::StringPrintf("%08x", device)
               << ", session_type=" << toString(session_type_)
               << " is not ready";
    return false;
  }
  return true;
}

void BluetoothAudioPortOut::TearDown() {
  if (!in_use()) {
    LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
               << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
               << " unknown monitor";
    return;
  }

  LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
            << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_);
  BluetoothAudioSessionControl::UnregisterControlResultCback(session_type_,
                                                             cookie_);
  cookie_ = android::bluetooth::audio::kObserversCookieUndefined;
}

void BluetoothAudioPortOut::ControlResultHandler(
    const BluetoothAudioStatus& status) {
  if (!in_use()) {
    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
    return;
  }
  std::unique_lock<std::mutex> port_lock(cv_mutex_);
  BluetoothStreamState previous_state = state_;
  LOG(INFO) << "control_result_cb: session_type=" << toString(session_type_)
            << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
            << ", previous_state=" << previous_state
            << ", status=" << toString(status);

  switch (previous_state) {
    case BluetoothStreamState::STARTING:
      if (status == BluetoothAudioStatus::SUCCESS) {
        state_ = BluetoothStreamState::STARTED;
      } else {
        // Set to standby since the stack may be busy switching
        LOG(ERROR) << "control_result_cb: status=" << toString(status)
                   << " failure for session_type=" << toString(session_type_)
                   << ", cookie=0x"
                   << android::base::StringPrintf("%04hx", cookie_)
                   << ", previous_state=" << previous_state;
        state_ = BluetoothStreamState::STANDBY;
      }
      break;
    case BluetoothStreamState::SUSPENDING:
      if (status == BluetoothAudioStatus::SUCCESS) {
        state_ = BluetoothStreamState::STANDBY;
      } else {
        // This should never fail and we need to recover
        LOG(FATAL) << "control_result_cb: status=" << toString(status)
                   << " failure for session_type=" << toString(session_type_)
                   << ", cookie=0x"
                   << android::base::StringPrintf("%04hx", cookie_)
                   << ", previous_state=" << previous_state;
        state_ = BluetoothStreamState::DISABLED;
      }
      break;
    default:
      LOG(ERROR) << "control_result_cb: unexpected status=" << toString(status)
                 << " for session_type=" << toString(session_type_)
                 << ", cookie=0x"
                 << android::base::StringPrintf("%04hx", cookie_)
                 << ", previous_state=" << previous_state;
      return;
  }
  port_lock.unlock();
  internal_cv_.notify_all();
}

void BluetoothAudioPortOut::SessionChangedHandler() {
  if (!in_use()) {
    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
    return;
  }
  std::unique_lock<std::mutex> port_lock(cv_mutex_);
  BluetoothStreamState previous_state = state_;
  LOG(INFO) << "session_changed_cb: session_type=" << toString(session_type_)
            << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
            << ", previous_state=" << previous_state;
  if (previous_state != BluetoothStreamState::DISABLED) {
    state_ = BluetoothStreamState::DISABLED;
  } else {
    state_ = BluetoothStreamState::STANDBY;
  }
  port_lock.unlock();
  internal_cv_.notify_all();
}

bool BluetoothAudioPortOut::in_use() const {
  return (cookie_ != android::bluetooth::audio::kObserversCookieUndefined);
}

bool BluetoothAudioPortOut::LoadAudioConfig(audio_config_t* audio_cfg) const {
  if (!in_use()) {
    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
    audio_cfg->sample_rate = kBluetoothDefaultSampleRate;
    audio_cfg->channel_mask = kBluetoothDefaultOutputChannelModeMask;
    audio_cfg->format = kBluetoothDefaultAudioFormatBitsPerSample;
    return false;
  }

  const AudioConfiguration& hal_audio_cfg =
      BluetoothAudioSessionControl::GetAudioConfig(session_type_);
  if (hal_audio_cfg.getDiscriminator() !=
      AudioConfiguration::hidl_discriminator::pcmConfig) {
    audio_cfg->sample_rate = kBluetoothDefaultSampleRate;
    audio_cfg->channel_mask = kBluetoothDefaultOutputChannelModeMask;
    audio_cfg->format = kBluetoothDefaultAudioFormatBitsPerSample;
    return false;
  }
  const PcmParameters& pcm_cfg = hal_audio_cfg.pcmConfig();
  LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
               << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
               << ", state=" << state_ << ", PcmConfig=[" << toString(pcm_cfg)
               << "]";
  if (pcm_cfg.sampleRate == SampleRate::RATE_UNKNOWN ||
      pcm_cfg.channelMode == ChannelMode::UNKNOWN ||
      pcm_cfg.bitsPerSample == BitsPerSample::BITS_UNKNOWN) {
    return false;
  }
  audio_cfg->sample_rate = SampleRateToAudioFormat(pcm_cfg.sampleRate);
  audio_cfg->channel_mask = ChannelModeToAudioFormat(pcm_cfg.channelMode);
  audio_cfg->format = BitsPerSampleToAudioFormat(pcm_cfg.bitsPerSample);
  return true;
}

bool BluetoothAudioPortOut::CondwaitState(BluetoothStreamState state) {
  bool retval;
  std::unique_lock<std::mutex> port_lock(cv_mutex_);
  switch (state) {
    case BluetoothStreamState::STARTING:
      LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
                   << ", cookie=0x"
                   << android::base::StringPrintf("%04hx", cookie_)
                   << " waiting for STARTED";
      retval = internal_cv_.wait_for(
          port_lock, std::chrono::milliseconds(kMaxWaitingTimeMs),
          [this] { return this->state_ == BluetoothStreamState::STARTED; });
      break;
    case BluetoothStreamState::SUSPENDING:
      LOG(VERBOSE) << __func__ << ": session_type=" << toString(session_type_)
                   << ", cookie=0x"
                   << android::base::StringPrintf("%04hx", cookie_)
                   << " waiting for SUSPENDED";
      retval = internal_cv_.wait_for(
          port_lock, std::chrono::milliseconds(kMaxWaitingTimeMs),
          [this] { return this->state_ == BluetoothStreamState::STANDBY; });
      break;
    default:
      LOG(WARNING) << __func__ << ": session_type=" << toString(session_type_)
                   << ", cookie=0x"
                   << android::base::StringPrintf("%04hx", cookie_)
                   << " waiting for KNOWN";
      return false;
  }

  return retval;  // false if any failure like timeout
}

bool BluetoothAudioPortOut::Start() {
  if (!in_use()) {
    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
    return false;
  }

  LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
            << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
            << ", state=" << state_ << " request";
  bool retval = false;
  if (state_ == BluetoothStreamState::STANDBY) {
    state_ = BluetoothStreamState::STARTING;
    if (BluetoothAudioSessionControl::StartStream(session_type_)) {
      retval = CondwaitState(BluetoothStreamState::STARTING);
    } else {
      LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
                 << ", cookie=0x"
                 << android::base::StringPrintf("%04hx", cookie_)
                 << ", state=" << state_ << " Hal fails";
    }
  }

  if (retval) {
    LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
              << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
              << ", state=" << state_ << " done";
  } else {
    LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
               << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
               << ", state=" << state_ << " failure";
  }

  return retval;  // false if any failure like timeout
}

bool BluetoothAudioPortOut::Suspend() {
  if (!in_use()) {
    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
    return false;
  }

  LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
            << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
            << ", state=" << state_ << " request";
  bool retval = false;
  if (state_ == BluetoothStreamState::STARTED) {
    state_ = BluetoothStreamState::SUSPENDING;
    if (BluetoothAudioSessionControl::SuspendStream(session_type_)) {
      retval = CondwaitState(BluetoothStreamState::SUSPENDING);
    } else {
      LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
                 << ", cookie=0x"
                 << android::base::StringPrintf("%04hx", cookie_)
                 << ", state=" << state_ << " Hal fails";
    }
  }

  if (retval) {
    LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
              << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
              << ", state=" << state_ << " done";
  } else {
    LOG(ERROR) << __func__ << ": session_type=" << toString(session_type_)
               << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
               << ", state=" << state_ << " failure";
  }

  return retval;  // false if any failure like timeout
}

void BluetoothAudioPortOut::Stop() {
  if (!in_use()) {
    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
    return;
  }
  LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
            << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
            << ", state=" << state_ << " request";
  state_ = BluetoothStreamState::DISABLED;
  BluetoothAudioSessionControl::StopStream(session_type_);
  LOG(INFO) << __func__ << ": session_type=" << toString(session_type_)
            << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
            << ", state=" << state_ << " done";
}

size_t BluetoothAudioPortOut::WriteData(const void* buffer,
                                        size_t bytes) const {
  if (!in_use()) return 0;
  return BluetoothAudioSessionControl::OutWritePcmData(session_type_, buffer,
                                                       bytes);
}

bool BluetoothAudioPortOut::GetPresentationPosition(uint64_t* delay_ns,
                                                    uint64_t* bytes,
                                                    timespec* timestamp) const {
  if (!in_use()) {
    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
    return false;
  }
  bool retval = BluetoothAudioSessionControl::GetPresentationPosition(
      session_type_, delay_ns, bytes, timestamp);
  LOG(VERBOSE) << __func__ << ": session_type=0x"
               << android::base::StringPrintf("%02hhx", session_type_)
               << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
               << ", state=" << state_ << ", delay=" << *delay_ns
               << "ns, data=" << *bytes
               << " bytes, timestamp=" << timestamp->tv_sec << "."
               << android::base::StringPrintf("%09ld", timestamp->tv_nsec)
               << "s";

  return retval;
}

void BluetoothAudioPortOut::UpdateMetadata(
    const source_metadata* source_metadata) const {
  if (!in_use()) {
    LOG(ERROR) << __func__ << ": BluetoothAudioPortOut is not in use";
    return;
  }
  LOG(DEBUG) << __func__ << ": session_type=" << toString(session_type_)
             << ", cookie=0x" << android::base::StringPrintf("%04hx", cookie_)
             << ", state=" << state_ << ", " << source_metadata->track_count
             << " track(s)";
  if (source_metadata->track_count == 0) return;
  BluetoothAudioSessionControl::UpdateTracksMetadata(session_type_,
                                                     source_metadata);
}

BluetoothStreamState BluetoothAudioPortOut::GetState() const { return state_; }

void BluetoothAudioPortOut::SetState(BluetoothStreamState state) {
  state_ = state;
}

}  // namespace audio
}  // namespace bluetooth
}  // namespace android
+104 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading