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

Commit 49fa4015 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add audio channel of Bluetooth Audio Hal v2 for Hearing Aid"

parents e40c66a6 895430b2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ cc_library_static {
    srcs: [
        "a2dp_software_encoding.cc",
        "client_interface.cc",
        "hearing_aid_software_encoding.cc",
    ],
    shared_libs: [
        "android.hardware.bluetooth.audio@2.0",
+205 −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 "BTAudioClientHearingAid"

#include "hearing_aid_software_encoding.h"
#include "client_interface.h"

#include "audio_hearing_aid_hw/include/audio_hearing_aid_hw.h"
#include "osi/include/log.h"
#include "osi/include/properties.h"

namespace {

using ::android::hardware::bluetooth::audio::V2_0::CodecType;
using ::bluetooth::audio::AudioConfiguration;
using ::bluetooth::audio::BitsPerSample;
using ::bluetooth::audio::BluetoothAudioCtrlAck;
using ::bluetooth::audio::ChannelMode;
using ::bluetooth::audio::PcmParameters;
using ::bluetooth::audio::SampleRate;
using ::bluetooth::audio::SessionType;
using ::bluetooth::audio::hearing_aid::StreamCallbacks;

// Transport implementation for Hearing Aids
class HearingAidTransport
    : public bluetooth::audio::IBluetoothTransportInstance {
 public:
  HearingAidTransport(StreamCallbacks stream_cb)
      : IBluetoothTransportInstance(
            SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH, {}),
        stream_cb_(std::move(stream_cb)),
        total_bytes_read_(0),
        data_position_({}){};

  BluetoothAudioCtrlAck StartRequest() override {
    LOG(INFO) << __func__;
    if (stream_cb_.on_resume_(true)) {
      return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
    }
    return BluetoothAudioCtrlAck::FAILURE;
  }

  BluetoothAudioCtrlAck SuspendRequest() override {
    LOG(INFO) << __func__;
    if (stream_cb_.on_suspend_()) {
      uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2];
      ::bluetooth::audio::hearing_aid::read(p_buf, sizeof(p_buf));
      return BluetoothAudioCtrlAck::SUCCESS_FINISHED;
    } else {
      return BluetoothAudioCtrlAck::FAILURE;
    }
  }

  void StopRequest() override {
    LOG(INFO) << __func__;
    stream_cb_.on_suspend_();

    // flush
    uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2];
    ::bluetooth::audio::hearing_aid::read(p_buf, sizeof(p_buf));
  }

  bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
                               uint64_t* total_bytes_read,
                               timespec* data_position) override {
    VLOG(2) << __func__ << ": data=" << total_bytes_read_
            << " byte(s), timestamp=" << data_position_.tv_sec << "."
            << data_position_.tv_nsec << "s";
    if (remote_delay_report_ns != nullptr) *remote_delay_report_ns = 0;
    if (total_bytes_read != nullptr) *total_bytes_read = total_bytes_read_;
    if (data_position != nullptr) *data_position = data_position_;
    return true;
  }

  void MetadataChanged(const source_metadata_t& source_metadata) override {
    auto track_count = source_metadata.track_count;
    auto tracks = source_metadata.tracks;
    LOG(INFO) << __func__ << ": " << track_count << " track(s) received";
    while (track_count) {
      VLOG(1) << __func__ << ": usage=" << tracks->usage
              << ", content_type=" << tracks->content_type
              << ", gain=" << tracks->gain;
      --track_count;
      ++tracks;
    }
  }

  void ResetPresentationPosition() override {
    total_bytes_read_ = 0;
    data_position_ = {};
  }

  void LogBytesRead(size_t bytes_read) override {
    if (bytes_read) {
      total_bytes_read_ += bytes_read;
      clock_gettime(CLOCK_MONOTONIC, &data_position_);
    }
  }

 private:
  StreamCallbacks stream_cb_;
  uint64_t total_bytes_read_;
  timespec data_position_;
};

bool HearingAidGetSelectedHalPcmConfig(PcmParameters* hal_pcm_config) {
  if (hal_pcm_config == nullptr) return false;
  // TODO: we only support one config for now!
  hal_pcm_config->sampleRate = SampleRate::RATE_16000;
  hal_pcm_config->bitsPerSample = BitsPerSample::BITS_16;
  hal_pcm_config->channelMode = ChannelMode::STEREO;
  return true;
}

// Sink instance of Hearing Aids to provide call-in APIs for Bluetooth Audio Hal
HearingAidTransport* hearing_aid_sink = nullptr;
// Common interface to call-out into Bluetooth Audio Hal
bluetooth::audio::BluetoothAudioClientInterface*
    hearing_aid_hal_clientinterface = nullptr;
bool btaudio_hearing_aid_supported = false;
bool is_configured = false;

}  // namespace

namespace bluetooth {
namespace audio {
namespace hearing_aid {

bool is_hal_2_0_supported() {
  if (!is_configured) {
    btaudio_hearing_aid_supported =
        osi_property_get_bool(BLUETOOTH_AUDIO_PROP_ENABLED, false);
    is_configured = true;
  }
  return btaudio_hearing_aid_supported;
}

bool is_hal_2_0_enabled() { return hearing_aid_hal_clientinterface != nullptr; }

bool init(StreamCallbacks stream_cb,
          bluetooth::common::MessageLoopThread* message_loop) {
  LOG(INFO) << __func__;

  if (!is_hal_2_0_supported()) return false;

  hearing_aid_sink = new HearingAidTransport(std::move(stream_cb));
  hearing_aid_hal_clientinterface =
      new bluetooth::audio::BluetoothAudioClientInterface(hearing_aid_sink,
                                                          message_loop);
  return true;
}

void cleanup() {
  LOG(INFO) << __func__;
  if (!is_hal_2_0_enabled()) return;
  end_session();
  hearing_aid_hal_clientinterface = nullptr;
  hearing_aid_sink = nullptr;
}

void start_session() {
  LOG(INFO) << __func__;
  if (!is_hal_2_0_enabled()) return;
  AudioConfiguration audio_config;
  PcmParameters pcm_config{};
  if (!HearingAidGetSelectedHalPcmConfig(&pcm_config)) {
    LOG(ERROR) << __func__ << ": cannot get PCM config";
    return;
  }
  audio_config.pcmConfig(pcm_config);
  if (!hearing_aid_hal_clientinterface->UpdateAudioConfig(audio_config)) {
    LOG(ERROR) << __func__ << ": cannot update audio config to HAL";
    return;
  }
  hearing_aid_hal_clientinterface->StartSession();
}

void end_session() {
  LOG(INFO) << __func__;
  if (!is_hal_2_0_enabled()) return;
  hearing_aid_hal_clientinterface->EndSession();
}

size_t read(uint8_t* p_buf, uint32_t len) {
  if (!is_hal_2_0_enabled()) return 0;
  return hearing_aid_hal_clientinterface->ReadAudioData(p_buf, len);
}

}  // namespace hearing_aid
}  // namespace audio
}  // namespace bluetooth
+52 −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.
 */

#pragma once

#include <functional>
#include "common/message_loop_thread.h"

namespace bluetooth {
namespace audio {
namespace hearing_aid {

struct StreamCallbacks {
  std::function<bool(bool start_media_task)> on_resume_;
  std::function<bool(void)> on_suspend_;
};

bool is_hal_2_0_supported();

// Check if new bluetooth_audio is enabled
bool is_hal_2_0_enabled();

// Initialize BluetoothAudio HAL: openProvider
bool init(StreamCallbacks stream_cb,
          bluetooth::common::MessageLoopThread* message_loop);

// Clean up BluetoothAudio HAL
void cleanup();

// Send command to the BluetoothAudio HAL: StartSession, EndSession
void start_session();
void end_session();

// Read from the FMQ of BluetoothAudio HAL
size_t read(uint8_t* p_buf, uint32_t len);

}  // namespace hearing_aid
}  // namespace audio
}  // namespace bluetooth
+1 −0
Original line number Diff line number Diff line
@@ -135,6 +135,7 @@ cc_test {
    static_libs: [
        "libbtcore",
        "libbt-bta",
        "libbt-audio-hal-interface",
        "libbluetooth-types",
        "libbt-protos-lite",
        "libosi",
+8 −2
Original line number Diff line number Diff line
@@ -901,9 +901,9 @@ class HearingAidImpl : public HearingAid {
    if (encoder_state_left != nullptr) {
      g722_encode_release(encoder_state_left);
      g722_encode_release(encoder_state_right);
    }
    encoder_state_left = g722_encode_init(nullptr, 64000, G722_PACKED);
    encoder_state_right = g722_encode_init(nullptr, 64000, G722_PACKED);
    }
    seq_counter = 0;

    for (auto& device : hearingDevices.devices) {
@@ -991,6 +991,12 @@ class HearingAidImpl : public HearingAid {

    if (left == nullptr && right == nullptr) {
      HearingAidAudioSource::Stop();
      if (encoder_state_left != nullptr) {
        g722_encode_release(encoder_state_left);
        encoder_state_left = nullptr;
        g722_encode_release(encoder_state_right);
        encoder_state_right = nullptr;
      }
      current_volume = VOLUME_UNKNOWN;
      return;
    }
Loading