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

Commit 489e0039 authored by Qasim Javed's avatar Qasim Javed
Browse files

AAC codec (wrapper) unit tests.

Bug: 256013806
Tag: #refactor
Test: atest net_test_stack_a2dp_codecs_native
Ignore-AOSP-First: presubmit fails on AOSP because the OPUS codec only
exists on internal master

Change-Id: Ide7f361aab134a4d2579398ad9673f453454afa0
parent edcfbcf3
Loading
Loading
Loading
Loading
+99 −0
Original line number Diff line number Diff line
@@ -612,6 +612,105 @@ cc_test {
    },
}

cc_test {
    name: "net_test_stack_a2dp_codecs_native",
    defaults: [
        "fluoride_defaults",
        "mts_defaults",
    ],
    test_suites: ["device-tests"],
    host_supported: true,
    test_options: {
        unit_test: true,
    },
    include_dirs: [
        "external/aac/libAACenc/include",
        "external/aac/libAACdec/include",
        "external/aac/libSYS/include",
        "external/libldac/inc",
        "external/libldac/abr/inc",
        "external/libopus/include",
        "packages/modules/Bluetooth/system",
        "packages/modules/Bluetooth/system/btif/include",
        "packages/modules/Bluetooth/system/embdrv/encoder_for_aptxhd/include",
        "packages/modules/Bluetooth/system/gd",
        "packages/modules/Bluetooth/system/stack/include",
        "packages/modules/Bluetooth/system/utils/include",
    ],
    target: {
        host: {
            srcs: [
                ":BluetoothHostTestingLogCapture",
            ],
        },
        android: {
            srcs: [
                ":BluetoothAndroidTestingLogCapture",
            ],
            test_config: "test/a2dp/AndroidTest.xml",
        }
    },
    data: [
        "test/a2dp/raw_data/*",
    ],
    srcs: [
        "a2dp/a2dp_aac.cc",
        "a2dp/a2dp_aac_decoder.cc",
        "a2dp/a2dp_aac_encoder.cc",
        "a2dp/a2dp_codec_config.cc",
        "a2dp/a2dp_sbc.cc",
        "a2dp/a2dp_sbc_decoder.cc",
        "a2dp/a2dp_sbc_encoder.cc",
        "a2dp/a2dp_sbc_up_sample.cc",
        "a2dp/a2dp_vendor.cc",
        "a2dp/a2dp_vendor_aptx.cc",
        "a2dp/a2dp_vendor_aptx_hd.cc",
        "a2dp/a2dp_vendor_aptx_encoder.cc",
        "a2dp/a2dp_vendor_aptx_hd_encoder.cc",
        "a2dp/a2dp_vendor_ldac.cc",
        "a2dp/a2dp_vendor_ldac_decoder.cc",
        "a2dp/a2dp_vendor_ldac_encoder.cc",
        "a2dp/a2dp_vendor_opus.cc",
        "a2dp/a2dp_vendor_opus_encoder.cc",
        "a2dp/a2dp_vendor_opus_decoder.cc",
        "test/a2dp/a2dp_aac_unittest.cc",
        "test/a2dp/mock_bta_av_codec.cc",
        "test/a2dp/test_util.cc",
        "test/a2dp/wav_reader.cc",
        "test/a2dp/wav_reader_unittest.cc",
        ":TestMockBta",
        ":TestMockStackA2dpApi",
    ],
    shared_libs: [
        "libcrypto",
        "libcutils",
        "libprotobuf-cpp-lite",
    ],
    static_libs: [
        "libbt-common",
        "libbt-protos-lite",
        "libbt-sbc-decoder",
        "libbt-sbc-encoder",
        "libFraunhoferAAC",
        "libgmock",
        "liblog",
        "libopus",
        "libosi",
        "libosi-AllocationTestHarness",
    ],
    whole_static_libs: [
        "libaptx_enc",
        "libaptxhd_enc",
        "libldacBT_abr",
        "libldacBT_enc",
    ],
    sanitize: {
        address: true,
        cfi: true,
        misc_undefined: ["bounds"],
    },
}

cc_test {
    name: "net_test_stack_a2dp_native",
    defaults: [
+39 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2022 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.
-->
<configuration description="Runs net_test_stack_a2dp_codecs_native.">
  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
  <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
        <option name="cleanup" value="true" />
        <option name="push" value="net_test_stack_a2dp_codecs_native->/data/local/tmp/net_test_stack_a2dp_codecs_native" />
        <option name="append-bitness" value="true" />
  </target_preparer>
  <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
        <option name="cleanup" value="true" />
        <option name="push" value="pcm0844s.wav->/data/local/tmp/test/a2dp/raw_data/pcm0844s.wav" />
        <option name="push" value="pcm1644s.wav->/data/local/tmp/test/a2dp/raw_data/pcm1644s.wav" />
  </target_preparer>
  <test class="com.android.tradefed.testtype.GTest" >
    <option name="native-test-device-path" value="/data/local/tmp" />
    <option name="module-name" value="net_test_stack_a2dp_codecs_native" />
    <option name="run-test-as" value="0" />
  </test>

  <!-- Only run tests in MTS if the Bluetooth Mainline module is installed. -->
  <object type="module_controller"
          class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
      <option name="mainline-module-package-name" value="com.google.android.bluetooth" />
  </object>
</configuration>
+240 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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.
 */

#include "stack/include/a2dp_aac.h"

#include <base/logging.h>
#include <gtest/gtest.h>
#include <stdio.h>

#include <cstdint>
#include <fstream>
#include <future>
#include <iomanip>
#include <map>
#include <string>

#include "common/init_flags.h"
#include "common/testing/log_capture.h"
#include "common/time_util.h"
#include "os/log.h"
#include "osi/include/allocator.h"
#include "osi/test/AllocationTestHarness.h"
#include "stack/include/bt_hdr.h"
#include "test_util.h"
#include "wav_reader.h"

extern void allocation_tracker_uninit(void);
namespace {
constexpr uint32_t kAacReadSize = 1024 * 2 * 2;
constexpr uint32_t kA2dpTickUs = 23 * 1000;
constexpr char kDecodedDataCallbackIsInvoked[] =
    "A2DP decoded data callback is invoked.";
constexpr char kEnqueueCallbackIsInvoked[] =
    "A2DP source enqueue callback is invoked.";
constexpr char kWavFile[] = "test/a2dp/raw_data/pcm1644s.wav";
constexpr uint8_t kCodecInfoAacCapability[AVDT_CODEC_SIZE] = {
    8,           // Length (A2DP_AAC_INFO_LEN)
    0,           // Media Type: AVDT_MEDIA_TYPE_AUDIO
    2,           // Media Codec Type: A2DP_MEDIA_CT_AAC
    0x80,        // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC
    0x01,        // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
    0x04,        // Channels: A2DP_AAC_CHANNEL_MODE_STEREO
    0x00 | 0x4,  // Variable Bit Rate:
                 // A2DP_AAC_VARIABLE_BIT_RATE_DISABLED
                 // Bit Rate: 320000 = 0x4e200
    0xe2,        // Bit Rate: 320000 = 0x4e200
    0x00,        // Bit Rate: 320000 = 0x4e200
    7,           // Unused
    8,           // Unused
    9            // Unused
};
uint8_t* Data(BT_HDR* packet) { return packet->data + packet->offset; }
}  // namespace

namespace bluetooth {
namespace testing {

static BT_HDR* packet = nullptr;
static WavReader wav_reader = WavReader(GetWavFilePath(kWavFile).c_str());

class A2dpAacTest : public AllocationTestHarness {
 protected:
  void SetUp() override {
    AllocationTestHarness::SetUp();
    common::InitFlags::SetAllForTesting();
    // Disable our allocation tracker to allow ASAN full range
    allocation_tracker_uninit();
    SetCodecConfig();
    encoder_iface_ = const_cast<tA2DP_ENCODER_INTERFACE*>(
        A2DP_GetEncoderInterfaceAac(kCodecInfoAacCapability));
    ASSERT_NE(encoder_iface_, nullptr);
    decoder_iface_ = const_cast<tA2DP_DECODER_INTERFACE*>(
        A2DP_GetDecoderInterfaceAac(kCodecInfoAacCapability));
    ASSERT_NE(decoder_iface_, nullptr);
  }

  void TearDown() override {
    if (a2dp_codecs_ != nullptr) {
      delete a2dp_codecs_;
    }
    if (encoder_iface_ != nullptr) {
      encoder_iface_->encoder_cleanup();
    }
    if (decoder_iface_ != nullptr) {
      decoder_iface_->decoder_cleanup();
    }
    AllocationTestHarness::TearDown();
  }

  void SetCodecConfig() {
    uint8_t codec_info_result[AVDT_CODEC_SIZE];
    btav_a2dp_codec_index_t peer_codec_index;
    a2dp_codecs_ = new A2dpCodecs(std::vector<btav_a2dp_codec_config_t>());

    ASSERT_TRUE(a2dp_codecs_->init());

    // Create the codec capability - AAC Sink
    memset(codec_info_result, 0, sizeof(codec_info_result));
    peer_codec_index = A2DP_SinkCodecIndex(kCodecInfoAacCapability);
    ASSERT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
    codec_config_ = a2dp_codecs_->findSinkCodecConfig(kCodecInfoAacCapability);
    ASSERT_NE(codec_config_, nullptr);
    ASSERT_TRUE(a2dp_codecs_->setSinkCodecConfig(kCodecInfoAacCapability, true,
                                                 codec_info_result, true));
    ASSERT_EQ(a2dp_codecs_->getCurrentCodecConfig(), codec_config_);
    // Compare the result codec with the local test codec info
    for (size_t i = 0; i < kCodecInfoAacCapability[0] + 1; i++) {
      ASSERT_EQ(codec_info_result[i], kCodecInfoAacCapability[i]);
    }
    ASSERT_EQ(codec_config_->getAudioBitsPerSample(), 16);
  }

  void InitializeEncoder(a2dp_source_read_callback_t read_cb,
                         a2dp_source_enqueue_callback_t enqueue_cb) {
    tA2DP_ENCODER_INIT_PEER_PARAMS peer_params = {true, true, 1000};
    encoder_iface_->encoder_init(&peer_params, codec_config_, read_cb,
                                 enqueue_cb);
  }

  void InitializeDecoder(decoded_data_callback_t data_cb) {
    decoder_iface_->decoder_init(data_cb);
  }

  BT_HDR* AllocateL2capPacket(const std::vector<uint8_t> data) const {
    auto packet = AllocatePacket(data.size());
    std::copy(data.cbegin(), data.cend(), Data(packet));
    return packet;
  }

  BT_HDR* AllocatePacket(size_t packet_length) const {
    BT_HDR* packet =
        static_cast<BT_HDR*>(osi_calloc(sizeof(BT_HDR) + packet_length));
    packet->len = packet_length;
    return packet;
  }
  A2dpCodecConfig* codec_config_;
  A2dpCodecs* a2dp_codecs_;
  tA2DP_ENCODER_INTERFACE* encoder_iface_;
  tA2DP_DECODER_INTERFACE* decoder_iface_;
  std::unique_ptr<LogCapture> log_capture_;
};

TEST_F(A2dpAacTest, a2dp_source_read_underflow) {
  log_capture_ = std::make_unique<LogCapture>();
  auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
    // underflow
    return 0;
  };
  auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
    return false;
  };
  InitializeEncoder(read_cb, enqueue_cb);
  uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
  encoder_iface_->send_frames(timestamp_us);
  usleep(kA2dpTickUs);
  timestamp_us = bluetooth::common::time_gettimeofday_us();
  encoder_iface_->send_frames(timestamp_us);
  std::promise<void> promise;
  log_capture_->WaitUntilLogContains(&promise,
                                     "a2dp_aac_encode_frames: underflow");
}

TEST_F(A2dpAacTest, a2dp_enqueue_cb_is_invoked) {
  log_capture_ = std::make_unique<LogCapture>();
  auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
    ASSERT(kAacReadSize == len);
    return len;
  };
  auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
    LOG_DEBUG("%s", kEnqueueCallbackIsInvoked);
    osi_free(p_buf);
    return false;
  };
  InitializeEncoder(read_cb, enqueue_cb);
  uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
  encoder_iface_->send_frames(timestamp_us);
  usleep(kA2dpTickUs);
  timestamp_us = bluetooth::common::time_gettimeofday_us();
  encoder_iface_->send_frames(timestamp_us);
  std::promise<void> promise;
  log_capture_->WaitUntilLogContains(&promise, kEnqueueCallbackIsInvoked);
}

TEST_F(A2dpAacTest, decoded_data_cb_not_invoked_when_empty_packet) {
  auto data_cb = +[](uint8_t* p_buf, uint32_t len) { FAIL(); };
  InitializeDecoder(data_cb);
  std::vector<uint8_t> data;
  BT_HDR* packet = AllocateL2capPacket(data);
  decoder_iface_->decode_packet(packet);
  osi_free(packet);
}

TEST_F(A2dpAacTest, decoded_data_cb_invoked) {
  log_capture_ = std::make_unique<LogCapture>();
  auto data_cb = +[](uint8_t* p_buf, uint32_t len) {
    LOG_DEBUG("%s", kDecodedDataCallbackIsInvoked);
  };
  InitializeDecoder(data_cb);

  auto read_cb = +[](uint8_t* p_buf, uint32_t len) -> uint32_t {
    static uint32_t counter = 0;
    memcpy(p_buf, wav_reader.GetSamples() + counter, len);
    counter += len;
    return len;
  };
  auto enqueue_cb = +[](BT_HDR* p_buf, size_t frames_n, uint32_t len) -> bool {
    packet = p_buf;
    LOG_DEBUG("%s", kEnqueueCallbackIsInvoked);
    return false;
  };
  InitializeEncoder(read_cb, enqueue_cb);

  uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
  encoder_iface_->send_frames(timestamp_us);
  usleep(kA2dpTickUs);
  timestamp_us = bluetooth::common::time_gettimeofday_us();
  encoder_iface_->send_frames(timestamp_us);

  std::promise<void> promise;
  log_capture_->WaitUntilLogContains(&promise, kEnqueueCallbackIsInvoked);
  decoder_iface_->decode_packet(packet);
  osi_free(packet);
  ASSERT_TRUE(log_capture_->Find(kDecodedDataCallbackIsInvoked));
}

}  // namespace testing
}  // namespace bluetooth
+26 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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.
 */

#include <map>
#include <string>

#include "service/common/bluetooth/a2dp_codec_config.h"

std::map<std::string, int> mock_function_count_map;

bluetooth::A2dpCodecConfig* bta_av_get_a2dp_current_codec(void) {
  return nullptr;
}
+576 KiB

File added.

No diff preview for this file type.

Loading