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

Commit a81a3cbe authored by Jeremy Wu's avatar Jeremy Wu Committed by Automerger Merge Worker
Browse files

Merge "Floss: replace HFP LC3 codec libraries with CodecClient." into main am: e46fa9c1

parents 62e99815 e46fa9c1
Loading
Loading
Loading
Loading
+17 −4
Original line number Diff line number Diff line
@@ -130,8 +130,6 @@ source_set("stack") {
    "btm/btm_sec.cc",
    "btm/hfp_msbc_encoder.cc",
    "btm/hfp_msbc_decoder.cc",
    "btm/hfp_lc3_encoder.cc",
    "btm/hfp_lc3_decoder.cc",
    "btu/btu_hcif.cc",
    "btu/btu_task.cc",
    "eatt/eatt.cc",
@@ -226,7 +224,6 @@ source_set("stack") {
    "//bt/system/udrv/include",
    "//bt/system/vnd/ble",
    "//bt/system/vnd/include",
    "//bt/system/embdrv/lc3/include",
  ]

  deps = [
@@ -238,7 +235,23 @@ source_set("stack") {
    "//bt/system/types",
  ]

  configs += [ "//bt/system:target_defaults" ]
  configs += [
    "//bt/system:target_defaults",
  ]

  if (defined(use.floss_mmc) && use.floss_mmc) {
    sources += [
      "btm/hfp_lc3_encoder_linux.cc",
      "btm/hfp_lc3_decoder_linux.cc",
    ]
    deps += [ "//bt/system/stack/mmc" ]
  } else {
    sources += [
      "btm/hfp_lc3_encoder.cc",
      "btm/hfp_lc3_decoder.cc",
    ]
    libs = [ "lc3" ]
  }
}

if (use.test) {
+109 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 "hfp_lc3_decoder"

#include <algorithm>

#include "hfp_lc3_decoder.h"
#include "mmc/codec_client/codec_client.h"
#include "mmc/proto/mmc_config.pb.h"
#include "osi/include/log.h"

const int HFP_LC3_H2_HEADER_LEN = 2;
const int HFP_LC3_PKT_FRAME_LEN = 58;
const int HFP_LC3_PCM_BYTES = 480;

static mmc::CodecClient* client = nullptr;
static const uint8_t plc_buf[HFP_LC3_H2_HEADER_LEN + HFP_LC3_PKT_FRAME_LEN] = {
    0};

bool hfp_lc3_decoder_init() {
  hfp_lc3_decoder_cleanup();
  client = new mmc::CodecClient;

  const int dt_us = 7500;
  const int sr_hz = 32000;
  const int sr_pcm_hz = 32000;

  mmc::Lc3Param param;
  param.set_dt_us(dt_us);
  param.set_sr_hz(sr_hz);
  param.set_sr_pcm_hz(sr_pcm_hz);
  param.set_stride(1);
  param.set_fmt(mmc::Lc3Param::kLc3PcmFormatS16);

  mmc::ConfigParam config;
  *config.mutable_hfp_lc3_decoder_param() = param;

  int ret = client->init(config);
  if (ret < 0) {
    LOG_ERROR("%s: Init failed with error message, %s", __func__,
              strerror(-ret));
    return false;
  }

  return true;
}

void hfp_lc3_decoder_cleanup() {
  if (client) {
    client->cleanup();
    delete client;
    client = nullptr;
  }
}

bool hfp_lc3_decoder_decode_packet(const uint8_t* i_buf, int16_t* o_buf,
                                   size_t out_len) {
  if (o_buf == nullptr || out_len < HFP_LC3_PCM_BYTES) {
    LOG_ERROR("%s: Output buffer size %zu is less than LC3 frame size %d",
              __func__, out_len, HFP_LC3_PCM_BYTES);
    return false;
  }

  if (!client) {
    LOG_ERROR("%s: CodecClient has not been initialized", __func__);
    return false;
  }

  // Pass zeros to MMC when i_buf is nullptr.
  const uint8_t* frame = i_buf ? i_buf : plc_buf;

  // One extra byte in the beginning to indicate whether PLC was conducted.
  uint8_t* o_packet = new uint8_t[out_len + 1];

  int rc = client->transcode((uint8_t*)frame,
                             HFP_LC3_PKT_FRAME_LEN + HFP_LC3_H2_HEADER_LEN,
                             o_packet, out_len + 1);

  if (rc < 0) {
    LOG_WARN("%s: Decode failed with error message, %s", __func__,
             strerror(-rc));
    return false;
  }

  bool plc_conducted = o_packet[0];

  if (plc_conducted == 1) {
    LOG_DEBUG("%s: PLC conducted", __func__);
  }

  std::copy(o_packet + 1, o_packet + 1 + out_len, (uint8_t*)o_buf);

  delete[] o_packet;
  return !plc_conducted;
}
+84 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 "hfp_lc3_encoder"

#include "hfp_lc3_encoder.h"
#include "mmc/codec_client/codec_client.h"
#include "mmc/proto/mmc_config.pb.h"
#include "osi/include/log.h"

const int HFP_LC3_PCM_BYTES = 480;
const int HFP_LC3_PKT_FRAME_LEN = 58;

static mmc::CodecClient* client = nullptr;

void hfp_lc3_encoder_init() {
  hfp_lc3_encoder_cleanup();
  client = new mmc::CodecClient;

  const int dt_us = 7500;
  const int sr_hz = 32000;
  const int sr_pcm_hz = 32000;

  mmc::Lc3Param param;
  param.set_dt_us(dt_us);
  param.set_sr_hz(sr_hz);
  param.set_sr_pcm_hz(sr_pcm_hz);
  param.set_stride(1);
  param.set_fmt(mmc::Lc3Param::kLc3PcmFormatS16);

  mmc::ConfigParam config;
  *config.mutable_hfp_lc3_encoder_param() = param;

  int ret = client->init(config);
  if (ret < 0) {
    LOG_ERROR("%s: Init failed with error message, %s", __func__,
              strerror(-ret));
  }
  return;
}

void hfp_lc3_encoder_cleanup() {
  if (client) {
    client->cleanup();
    delete client;
    client = nullptr;
  }
}

uint32_t hfp_lc3_encode_frames(int16_t* input, uint8_t* output) {
  if (input == nullptr || output == nullptr) {
    LOG_ERROR("%s: Buffer is null", __func__);
    return 0;
  }

  if (!client) {
    LOG_ERROR("%s: CodecClient has not been initialized", __func__);
    return 0;
  }

  int rc = client->transcode((uint8_t*)input, HFP_LC3_PCM_BYTES, output,
                             HFP_LC3_PKT_FRAME_LEN);

  if (rc < 0) {
    LOG_WARN("%s: Encode failed with error message, %s", __func__,
             strerror(-rc));
    return 0;
  }

  return HFP_LC3_PCM_BYTES;
}
+2 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ group("mmc") {
    ":install_system_service",
    ":install_tmpfiles_config",
    ":mmc_service",
    "//bt/system/stack/mmc/codec_client:libcodec_client",
    "//bt/system/stack/mmc/proto:mmc_config_proto",
  ]
}

+27 −0
Original line number Diff line number Diff line
#
#  Copyright 2023 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.
#

source_set("libcodec_client"){
  configs += [ "//bt/system/stack/mmc:target_defaults" ]
  sources = [
    "codec_client.cc",
  ]

  deps = [
    "//bt/system/stack/mmc/proto:mmc_service_proto",
    "//bt/system/stack/mmc/proto:mmc_config_proto",
  ]
}
Loading