普通文本  |  474行  |  20.69 KB

/*
 * 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.
 */

#include <gtest/gtest.h>

#include "client_interface.h"

namespace {

using ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
using ::android::hardware::bluetooth::audio::V2_0::AacParameters;
using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
using ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities;
using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
using ::android::hardware::bluetooth::audio::V2_0::CodecType;
using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
using ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
using ::android::hardware::bluetooth::audio::V2_0::SbcParameters;

using ::bluetooth::audio::AudioCapabilities;
using ::bluetooth::audio::AudioConfiguration;
using ::bluetooth::audio::BitsPerSample;
using ::bluetooth::audio::BluetoothAudioClientInterface;
using ::bluetooth::audio::BluetoothAudioStatus;
using ::bluetooth::audio::ChannelMode;
using ::bluetooth::audio::PcmParameters;
using ::bluetooth::audio::SampleRate;
using ::bluetooth::audio::SessionType;
using ::testing::Test;

constexpr SampleRate kSampleRates[9] = {
    SampleRate::RATE_UNKNOWN, SampleRate::RATE_44100, SampleRate::RATE_48000,
    SampleRate::RATE_88200,   SampleRate::RATE_96000, SampleRate::RATE_176400,
    SampleRate::RATE_192000,  SampleRate::RATE_16000, SampleRate::RATE_24000};
constexpr BitsPerSample kBitsPerSamples[4] = {
    BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16, BitsPerSample::BITS_24,
    BitsPerSample::BITS_32};
constexpr ChannelMode kChannelModes[3] = {
    ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
constexpr uint16_t kPeerMtus[5] = {660, 663, 883, 1005, 1500};

class TestTransport : public bluetooth::audio::IBluetoothTransportInstance {
 private:
  static constexpr uint64_t kRemoteDelayReportMs = 200;

 public:
  TestTransport(SessionType session_type)
      : bluetooth::audio::IBluetoothTransportInstance(session_type, {}){};
  bluetooth::audio::BluetoothAudioCtrlAck StartRequest() {
    return bluetooth::audio::BluetoothAudioCtrlAck::SUCCESS_FINISHED;
  }
  bluetooth::audio::BluetoothAudioCtrlAck SuspendRequest() {
    return bluetooth::audio::BluetoothAudioCtrlAck::SUCCESS_FINISHED;
  }
  void StopRequest() {}
  bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
                               uint64_t* total_bytes_readed,
                               timespec* data_position) {
    if (remote_delay_report_ns) {
      *remote_delay_report_ns = kRemoteDelayReportMs * 1000000;
    }
    if (total_bytes_readed) {
      *total_bytes_readed = 0;
    }
    if (data_position) {
      clock_gettime(CLOCK_MONOTONIC, data_position);
    }
    return true;
  }
  void MetadataChanged(const source_metadata_t& source_metadata __unused) {}
  void ResetPresentationPosition(){};
  void LogBytesRead(size_t bytes_readed __unused){};
};

class BluetoothAudioClientInterfaceTest : public Test {
 protected:
  TestTransport* test_transport_;
  BluetoothAudioClientInterface* clientif_;

  static constexpr int kClientIfReturnSuccess = 0;

  virtual void SetUp() override {}

  virtual void TearDown() override {
    clientif_ = nullptr;
    test_transport_ = nullptr;
  }

  bool IsSoftwarePcmParametersSupported(const PcmParameters& pcm_config) {
    const std::vector<AudioCapabilities>& capabilities =
        clientif_->GetAudioCapabilities();
    PcmParameters pcm_capabilities = capabilities[0].pcmCapabilities();
    bool is_pcm_config_valid =
        (pcm_config.sampleRate != SampleRate::RATE_UNKNOWN &&
         pcm_config.bitsPerSample != BitsPerSample::BITS_UNKNOWN &&
         pcm_config.channelMode != ChannelMode::UNKNOWN);
    bool is_pcm_config_supported =
        (pcm_config.sampleRate & pcm_capabilities.sampleRate &&
         pcm_config.bitsPerSample & pcm_capabilities.bitsPerSample &&
         pcm_config.channelMode & pcm_capabilities.channelMode);
    return (is_pcm_config_valid && is_pcm_config_supported);
  }

  bool IsOffloadCodecConfigurationSupported(
      const CodecConfiguration& codec_config) {
    CodecCapabilities codec_capability = {};
    for (auto audio_capability : clientif_->GetAudioCapabilities()) {
      if (audio_capability.codecCapabilities().codecType ==
          codec_config.codecType) {
        codec_capability = audio_capability.codecCapabilities();
      }
    }
    if (codec_capability.codecType != codec_config.codecType) {
      // codec is unsupported
      return false;
    }
    bool is_codec_config_supported = false;
    switch (codec_config.codecType) {
      case CodecType::SBC: {
        SbcParameters sbc_config = codec_config.config.sbcConfig();
        SbcParameters sbc_capability =
            codec_capability.capabilities.sbcCapabilities();
        is_codec_config_supported =
            (sbc_config.sampleRate & sbc_capability.sampleRate &&
             sbc_config.channelMode & sbc_capability.channelMode &&
             sbc_config.blockLength & sbc_capability.blockLength &&
             sbc_config.numSubbands & sbc_capability.numSubbands &&
             sbc_config.allocMethod & sbc_capability.allocMethod &&
             sbc_config.bitsPerSample & sbc_capability.bitsPerSample &&
             (sbc_capability.minBitpool <= sbc_config.minBitpool &&
              sbc_config.minBitpool <= sbc_config.maxBitpool &&
              sbc_config.maxBitpool <= sbc_capability.maxBitpool));
        return is_codec_config_supported;
      }
      case CodecType::AAC: {
        AacParameters aac_config = codec_config.config.aacConfig();
        AacParameters aac_capability =
            codec_capability.capabilities.aacCapabilities();
        is_codec_config_supported =
            (aac_config.objectType & aac_capability.objectType &&
             aac_config.sampleRate & aac_capability.sampleRate &&
             aac_config.channelMode & aac_capability.channelMode &&
             (aac_config.variableBitRateEnabled ==
                  AacVariableBitRate::DISABLED ||
              aac_capability.variableBitRateEnabled ==
                  AacVariableBitRate::ENABLED) &&
             aac_config.bitsPerSample & aac_capability.bitsPerSample);
        return is_codec_config_supported;
      }
      case CodecType::LDAC: {
        LdacParameters ldac_config = codec_config.config.ldacConfig();
        LdacParameters ldac_capability =
            codec_capability.capabilities.ldacCapabilities();
        is_codec_config_supported =
            (ldac_config.sampleRate & ldac_capability.sampleRate &&
             ldac_config.channelMode & ldac_capability.channelMode &&
             ldac_config.bitsPerSample & ldac_capability.bitsPerSample);
        return is_codec_config_supported;
      }
      case CodecType::APTX:
        [[fallthrough]];
      case CodecType::APTX_HD: {
        AptxParameters aptx_config = codec_config.config.aptxConfig();
        AptxParameters aptx_capability =
            codec_capability.capabilities.aptxCapabilities();
        is_codec_config_supported =
            (aptx_config.sampleRate & aptx_capability.sampleRate &&
             aptx_config.channelMode & aptx_capability.channelMode &&
             aptx_config.bitsPerSample & aptx_capability.bitsPerSample);
        return is_codec_config_supported;
      }
      case CodecType::UNKNOWN:
        return false;
    }
  }
};

}  // namespace

TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpSoftwareSession) {
  test_transport_ =
      new TestTransport(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
  clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
  AudioConfiguration audio_config = {};
  PcmParameters pcm_config = {};
  for (auto sample_rate : kSampleRates) {
    pcm_config.sampleRate = sample_rate;
    for (auto bits_per_sample : kBitsPerSamples) {
      pcm_config.bitsPerSample = bits_per_sample;
      for (auto channel_mode : kChannelModes) {
        pcm_config.channelMode = channel_mode;
        audio_config.pcmConfig(pcm_config);
        clientif_->UpdateAudioConfig(audio_config);
        if (IsSoftwarePcmParametersSupported(pcm_config)) {
          EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
        } else {
          EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
        }
        EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
      }  // ChannelMode
    }    // BitsPerSampple
  }      // SampleRate
}

TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadSbcSession) {
  test_transport_ =
      new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
  clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
  AudioConfiguration audio_config = {};
  CodecConfiguration codec_config = {};
  SbcBlockLength block_lengths[4] = {
      SbcBlockLength::BLOCKS_4, SbcBlockLength::BLOCKS_8,
      SbcBlockLength::BLOCKS_12, SbcBlockLength::BLOCKS_16};
  SbcNumSubbands num_subbands[2] = {SbcNumSubbands::SUBBAND_4,
                                    SbcNumSubbands::SUBBAND_8};
  SbcAllocMethod alloc_methods[2] = {SbcAllocMethod::ALLOC_MD_S,
                                     SbcAllocMethod::ALLOC_MD_L};
  for (auto sample_rate : kSampleRates) {
    for (auto bits_per_sample : kBitsPerSamples) {
      for (auto channel_mode : kChannelModes) {
        for (auto peer_mtu : kPeerMtus) {
          for (auto block_length : block_lengths) {
            for (auto num_subband : num_subbands) {
              for (auto alloc_method : alloc_methods) {
                codec_config.codecType = CodecType::SBC;
                codec_config.peerMtu = peer_mtu;
                codec_config.isScmstEnabled = false;
                // A2DP_SBC_DEFAULT_BITRATE
                codec_config.encodedAudioBitrate = 328000;
                SbcParameters sbc = {
                    .sampleRate = sample_rate,
                    .channelMode = (channel_mode == ChannelMode::MONO
                                        ? SbcChannelMode::MONO
                                        : SbcChannelMode::JOINT_STEREO),
                    .blockLength = block_length,
                    .numSubbands = num_subband,
                    .allocMethod = alloc_method,
                    .bitsPerSample = bits_per_sample,
                    .minBitpool = 2,
                    .maxBitpool = 53};
                codec_config.config.sbcConfig(sbc);
                audio_config.codecConfig(codec_config);
                clientif_->UpdateAudioConfig(audio_config);
                if (IsOffloadCodecConfigurationSupported(codec_config)) {
                  EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
                } else {
                  EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
                }
                EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
              }  // SbcAllocMethod
            }    // SbcNumSubbands
          }      // SbcBlockLength
        }        // peerMtu
      }          // ChannelMode
    }            // BitsPerSampple
  }              // SampleRate
}

TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAacSession) {
  test_transport_ =
      new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
  clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
  AudioConfiguration audio_config = {};
  CodecConfiguration codec_config = {};
  AacObjectType object_types[4] = {
      AacObjectType::MPEG2_LC, AacObjectType::MPEG4_LC,
      AacObjectType::MPEG4_LTP, AacObjectType::MPEG4_SCALABLE};
  AacVariableBitRate variable_bitrates[2] = {AacVariableBitRate::DISABLED,
                                             AacVariableBitRate::ENABLED};
  for (auto sample_rate : kSampleRates) {
    for (auto bits_per_sample : kBitsPerSamples) {
      for (auto channel_mode : kChannelModes) {
        for (auto peer_mtu : kPeerMtus) {
          for (auto object_type : object_types) {
            for (auto variable_bitrate : variable_bitrates) {
              codec_config.codecType = CodecType::AAC;
              codec_config.peerMtu = peer_mtu;
              codec_config.isScmstEnabled = false;
              // A2DP_AAC_DEFAULT_BITRATE
              codec_config.encodedAudioBitrate = 320000;
              AacParameters aac = {.objectType = object_type,
                                   .sampleRate = sample_rate,
                                   .channelMode = channel_mode,
                                   .variableBitRateEnabled = variable_bitrate,
                                   .bitsPerSample = bits_per_sample};
              codec_config.config.aacConfig(aac);
              audio_config.codecConfig(codec_config);
              clientif_->UpdateAudioConfig(audio_config);
              if (IsOffloadCodecConfigurationSupported(codec_config)) {
                EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
              } else {
                EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
              }
              EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
            }  // AacVariableBitRate
          }    // AacObjectType
        }      // peerMtu
      }        // ChannelMode
    }          // BitsPerSampple
  }            // SampleRate
}

TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadLdacSession) {
  test_transport_ =
      new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
  clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
  AudioConfiguration audio_config = {};
  CodecConfiguration codec_config = {};
  LdacQualityIndex quality_indexes[4] = {
      LdacQualityIndex::QUALITY_HIGH, LdacQualityIndex::QUALITY_MID,
      LdacQualityIndex::QUALITY_LOW, LdacQualityIndex::QUALITY_ABR};
  for (auto sample_rate : kSampleRates) {
    for (auto bits_per_sample : kBitsPerSamples) {
      for (auto channel_mode : kChannelModes) {
        for (auto peer_mtu : kPeerMtus) {
          for (auto quality_index : quality_indexes) {
            codec_config.codecType = CodecType::LDAC;
            codec_config.peerMtu = peer_mtu;
            codec_config.isScmstEnabled = false;
            codec_config.encodedAudioBitrate = 990000;
            LdacParameters ldac = {
                .sampleRate = sample_rate,
                .channelMode = (channel_mode == ChannelMode::MONO
                                    ? LdacChannelMode::MONO
                                    : LdacChannelMode::STEREO),
                .qualityIndex = quality_index,
                .bitsPerSample = bits_per_sample};
            codec_config.config.ldacConfig(ldac);
            audio_config.codecConfig(codec_config);
            clientif_->UpdateAudioConfig(audio_config);
            if (IsOffloadCodecConfigurationSupported(codec_config)) {
              EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
            } else {
              EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
            }
            EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
          }  // LdacQualityIndex
        }    // peerMtu
      }      // ChannelMode
    }        // BitsPerSampple
  }          // SampleRate
}

TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAptxSession) {
  test_transport_ =
      new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
  clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
  AudioConfiguration audio_config = {};
  CodecConfiguration codec_config = {};
  for (auto sample_rate : kSampleRates) {
    for (auto bits_per_sample : kBitsPerSamples) {
      for (auto channel_mode : kChannelModes) {
        for (auto peer_mtu : kPeerMtus) {
          codec_config.codecType = CodecType::APTX;
          codec_config.peerMtu = peer_mtu;
          codec_config.isScmstEnabled = false;
          codec_config.encodedAudioBitrate = 352000;
          AptxParameters aptx = {.sampleRate = sample_rate,
                                 .channelMode = channel_mode,
                                 .bitsPerSample = bits_per_sample};
          codec_config.config.aptxConfig(aptx);
          audio_config.codecConfig(codec_config);
          clientif_->UpdateAudioConfig(audio_config);
          if (IsOffloadCodecConfigurationSupported(codec_config)) {
            EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
          } else {
            EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
          }
          EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
        }  // peerMtu
      }    // ChannelMode
    }      // BitsPerSampple
  }        // SampleRate
}

TEST_F(BluetoothAudioClientInterfaceTest, StartAndEndA2dpOffloadAptxHdSession) {
  test_transport_ =
      new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
  clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
  AudioConfiguration audio_config = {};
  CodecConfiguration codec_config = {};
  for (auto sample_rate : kSampleRates) {
    for (auto bits_per_sample : kBitsPerSamples) {
      for (auto channel_mode : kChannelModes) {
        for (auto peer_mtu : kPeerMtus) {
          codec_config.codecType = CodecType::APTX_HD;
          codec_config.peerMtu = peer_mtu;
          codec_config.isScmstEnabled = false;
          codec_config.encodedAudioBitrate = 576000;
          AptxParameters aptx = {.sampleRate = sample_rate,
                                 .channelMode = channel_mode,
                                 .bitsPerSample = bits_per_sample};
          codec_config.config.aptxConfig(aptx);
          audio_config.codecConfig(codec_config);
          clientif_->UpdateAudioConfig(audio_config);
          if (IsOffloadCodecConfigurationSupported(codec_config)) {
            EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
          } else {
            EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
          }
          EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
        }  // peerMtu
      }    // ChannelMode
    }      // BitsPerSampple
  }        // SampleRate
}

TEST_F(BluetoothAudioClientInterfaceTest,
       StartAndEndA2dpOffloadUnknownSession) {
  test_transport_ =
      new TestTransport(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
  clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
  AudioConfiguration audio_config = {};
  CodecConfiguration codec_config = {};
  codec_config.codecType = CodecType::UNKNOWN;
  codec_config.peerMtu = 1005;
  codec_config.isScmstEnabled = false;
  codec_config.encodedAudioBitrate = 328000;
  codec_config.config = {};
  audio_config.codecConfig(codec_config);
  clientif_->UpdateAudioConfig(audio_config);
  if (IsOffloadCodecConfigurationSupported(codec_config)) {
    EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
  } else {
    EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
  }
  EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
}

TEST_F(BluetoothAudioClientInterfaceTest,
       StartAndEndHearingAidSoftwareSession) {
  test_transport_ =
      new TestTransport(SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
  clientif_ = new BluetoothAudioClientInterface(test_transport_, nullptr);
  AudioConfiguration audio_config = {};
  PcmParameters pcm_config = {};
  for (auto sample_rate : kSampleRates) {
    pcm_config.sampleRate = sample_rate;
    for (auto bits_per_sample : kBitsPerSamples) {
      pcm_config.bitsPerSample = bits_per_sample;
      for (auto channel_mode : kChannelModes) {
        pcm_config.channelMode = channel_mode;
        audio_config.pcmConfig(pcm_config);
        clientif_->UpdateAudioConfig(audio_config);
        if (IsSoftwarePcmParametersSupported(pcm_config)) {
          EXPECT_EQ(clientif_->StartSession(), kClientIfReturnSuccess);
        } else {
          EXPECT_NE(clientif_->StartSession(), kClientIfReturnSuccess);
        }
        EXPECT_EQ(clientif_->EndSession(), kClientIfReturnSuccess);
      }  // ChannelMode
    }    // BitsPerSampple
  }      // SampleRate
}