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

Commit bbee2baf authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

Merge "Create unit test framework for audio_a2dp_hw am: 431414ef am:...

Merge "Create unit test framework for audio_a2dp_hw am: 431414ef am: 1c4428bc" into nyc-mr2-dev-plus-aosp
parents fd369e13 ad9e74e9
Loading
Loading
Loading
Loading
+30 −9
Original line number Diff line number Diff line
cc_defaults {
    name: "audio_a2dp_hw_defaults",
    defaults: ["fluoride_defaults"],
    include_dirs: [
        "packages/modules/Bluetooth/system",
        "packages/modules/Bluetooth/system/audio_a2dp_hw/include",
    ]
}

// Audio A2DP shared library for target
// ========================================================
cc_library_shared {
cc_library {
    name: "audio.a2dp.default",
    defaults: ["fluoride_defaults"],
    defaults: ["audio_a2dp_hw_defaults"],
    relative_install_path: "hw",
    srcs: [
        "audio_a2dp_hw.cc",
        "audio_a2dp_hw_utils.cc",
    ],
    include_dirs: [
        "packages/modules/Bluetooth/system",
        "src/audio_a2dp_hw.cc",
        "src/audio_a2dp_hw_utils.cc",
    ],
    shared_libs: [
        "liblog",
@@ -19,8 +25,23 @@ cc_library_shared {

cc_library_static {
    name: "libaudio-a2dp-hw-utils",
    defaults: ["fluoride_defaults"],
    defaults: ["audio_a2dp_hw_defaults"],
    srcs: [
        "audio_a2dp_hw_utils.cc",
        "src/audio_a2dp_hw_utils.cc",
    ],
}

// Audio A2DP library unit tests for target and host
// ========================================================
cc_test {
    name: "net_test_audio_a2dp_hw",
    test_suites: ["device-tests"],
    defaults: ["audio_a2dp_hw_defaults"],
    srcs: [
        "test/audio_a2dp_hw_test.cc",
    ],
    shared_libs: [
        "liblog",
    ],
    static_libs: ["audio.a2dp.default"],
}
+33 −3
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@

#include <stdint.h>

#include <hardware/bt_av.h>

/*****************************************************************************
 *  Constants & Macros
 *****************************************************************************/
@@ -41,9 +43,6 @@
// If one assumes the write buffer is always full during normal BT playback,
// then increasing this value increases our playback latency.
//
// FIXME: AUDIO_STREAM_OUTPUT_BUFFER_SZ should be controlled by the actual audio
// sample rate rather than being constant.
//
// FIXME: The BT HAL should consume data at a constant rate.
// AudioFlinger assumes that the HAL draws data at a constant rate, which is
// true for most audio devices; however, the BT engine reads data at a variable
@@ -115,6 +114,37 @@ typedef uint8_t tA2DP_BITS_PER_SAMPLE;
 *  Functions
 *****************************************************************************/

// Computes the Audio A2DP HAL output buffer size.
// |codec_sample_rate| is the sample rate of the output stream.
// |codec_bits_per_sample| is the number of bits per sample of the output
// stream.
// |codec_channel_mode| is the channel mode of the output stream.
//
// The buffer size is computed by using the following formula:
//
// AUDIO_STREAM_OUTPUT_BUFFER_SIZE =
//    (TIME_PERIOD_MS * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS *
//     SAMPLE_RATE_HZ * NUMBER_OF_CHANNELS * (BITS_PER_SAMPLE / 8)) / 1000
//
// AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is
// divided for AudioFlinger data delivery. The AudioFlinger mixer delivers
// data in chunks of
// (AUDIO_STREAM_OUTPUT_BUFFER_SIZE / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS) .
// If the number of periods is 2, the socket buffer represents "double
// buffering" of the AudioFlinger mixer buffer.
//
// Furthermore, the AudioFlinger expects the buffer size to be a multiple
// of 16 frames.
//
// NOTE: Currently, the computation uses the conservative 20ms time period.
//
// Returns the computed buffer size. If any of the input parameters is
// invalid, the return value is the default |AUDIO_STREAM_OUTPUT_BUFFER_SZ|.
extern size_t audio_a2dp_hw_stream_compute_buffer_size(
    btav_a2dp_codec_sample_rate_t codec_sample_rate,
    btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample,
    btav_a2dp_codec_channel_mode_t codec_channel_mode);

// Returns a string representation of |event|.
extern const char* audio_a2dp_hw_dump_ctrl_event(tA2DP_CTRL_CMD event);

+3 −13
Original line number Diff line number Diff line
@@ -40,7 +40,6 @@
#include <mutex>

#include <hardware/audio.h>
#include <hardware/bt_av.h>
#include <hardware/hardware.h>
#include <system/audio.h>

@@ -150,10 +149,6 @@ struct a2dp_stream_in {
 *****************************************************************************/

static size_t out_get_buffer_size(const struct audio_stream* stream);
static size_t audio_stream_compute_buffer_size(
    btav_a2dp_codec_sample_rate_t codec_sample_rate,
    btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample,
    btav_a2dp_codec_channel_mode_t codec_channel_mode);

/*****************************************************************************
 *  Externs
@@ -611,7 +606,7 @@ static int a2dp_read_output_audio_config(
    common->cfg.rate = stream_config.rate;
    common->cfg.channel_mask = stream_config.channel_mask;
    common->cfg.format = stream_config.format;
    common->buffer_sz = audio_stream_compute_buffer_size(
    common->buffer_sz = audio_a2dp_hw_stream_compute_buffer_size(
        codec_config->sample_rate, codec_config->bits_per_sample,
        codec_config->channel_mode);
  }
@@ -922,24 +917,19 @@ static size_t out_get_buffer_size(const struct audio_stream* stream) {
  // period_size is the AudioFlinger mixer buffer size.
  const size_t period_size =
      out->common.buffer_sz / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS;
  const size_t mixer_unit_size = 16 /* frames */ * 4 /* framesize */;

  DEBUG("socket buffer size: %zu  period size: %zu", out->common.buffer_sz,
        period_size);
  if (period_size % mixer_unit_size != 0) {
    ERROR("period size %zu not a multiple of %zu", period_size,
          mixer_unit_size);
  }

  return period_size;
}

static size_t audio_stream_compute_buffer_size(
size_t audio_a2dp_hw_stream_compute_buffer_size(
    btav_a2dp_codec_sample_rate_t codec_sample_rate,
    btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample,
    btav_a2dp_codec_channel_mode_t codec_channel_mode) {
  size_t buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ;  // Default value
  const uint32_t time_period_ms = 20;                // Conservative 20ms
  const uint64_t time_period_ms = 20;                // Conservative 20ms
  uint32_t sample_rate;
  uint32_t bits_per_sample;
  uint32_t number_of_channels;
+142 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright (C) 2017 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 <gtest/gtest.h>

#include "audio_a2dp_hw/include/audio_a2dp_hw.h"

namespace {
static uint32_t codec_sample_rate2value(
    btav_a2dp_codec_sample_rate_t codec_sample_rate) {
  switch (codec_sample_rate) {
    case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
      return 44100;
    case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
      return 48000;
    case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
      return 88200;
    case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
      return 96000;
    case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
      return 176400;
    case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
      return 192000;
    case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
      break;
  }
  return 0;
}

static uint32_t codec_bits_per_sample2value(
    btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample) {
  switch (codec_bits_per_sample) {
    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
      return 16;
    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
      return 24;
    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
      return 32;
    case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
      break;
  }
  return 0;
}

static uint32_t codec_channel_mode2value(
    btav_a2dp_codec_channel_mode_t codec_channel_mode) {
  switch (codec_channel_mode) {
    case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
      return 1;
    case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
      return 2;
    case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
      break;
  }
  return 0;
}

}  // namespace

class AudioA2dpHwTest : public ::testing::Test {
 protected:
  AudioA2dpHwTest() {}

 private:
};

TEST_F(AudioA2dpHwTest, test_compute_buffer_size) {
  const btav_a2dp_codec_sample_rate_t codec_sample_rate_array[] = {
      BTAV_A2DP_CODEC_SAMPLE_RATE_NONE,  BTAV_A2DP_CODEC_SAMPLE_RATE_44100,
      BTAV_A2DP_CODEC_SAMPLE_RATE_48000, BTAV_A2DP_CODEC_SAMPLE_RATE_88200,
      BTAV_A2DP_CODEC_SAMPLE_RATE_96000, BTAV_A2DP_CODEC_SAMPLE_RATE_176400,
      BTAV_A2DP_CODEC_SAMPLE_RATE_192000};

  const btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample_array[] = {
      BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE, BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16,
      BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24, BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32};

  const btav_a2dp_codec_channel_mode_t codec_channel_mode_array[] = {
      BTAV_A2DP_CODEC_CHANNEL_MODE_NONE, BTAV_A2DP_CODEC_CHANNEL_MODE_MONO,
      BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO};

  for (const auto codec_sample_rate : codec_sample_rate_array) {
    for (const auto codec_bits_per_sample : codec_bits_per_sample_array) {
      for (const auto codec_channel_mode : codec_channel_mode_array) {
        size_t buffer_size = audio_a2dp_hw_stream_compute_buffer_size(
            codec_sample_rate, codec_bits_per_sample, codec_channel_mode);

        // Check for invalid input
        if ((codec_sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) ||
            (codec_bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) ||
            (codec_channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE)) {
          EXPECT_EQ(buffer_size,
                    static_cast<size_t>(AUDIO_STREAM_OUTPUT_BUFFER_SZ));
          continue;
        }

        uint32_t sample_rate = codec_sample_rate2value(codec_sample_rate);
        EXPECT_TRUE(sample_rate != 0);

        uint32_t bits_per_sample =
            codec_bits_per_sample2value(codec_bits_per_sample);
        EXPECT_TRUE(bits_per_sample != 0);

        uint32_t number_of_channels =
            codec_channel_mode2value(codec_channel_mode);
        EXPECT_TRUE(number_of_channels != 0);

        const uint64_t time_period_ms = 20;  // TODO: Must be a parameter
        size_t expected_buffer_size =
            (time_period_ms * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * sample_rate *
             number_of_channels * (bits_per_sample / 8)) /
            1000;

        // Compute the divisor and adjust the buffer size
        const size_t divisor = (AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * 16 *
                                number_of_channels * bits_per_sample) /
                               8;
        const size_t remainder = expected_buffer_size % divisor;
        if (remainder != 0) {
          expected_buffer_size += divisor - remainder;
        }

        EXPECT_EQ(buffer_size, expected_buffer_size);
      }
    }
  }
}
Loading