blob: 006e432b270978618c66b1bb989f8cdb9c160991 [file] [log] [blame]
/*
* Copyright 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.
*/
#define LOG_NDEBUG 0
#define LOG_TAG "AAudioTest"
#include <cstring>
#include <sstream>
#include <utility>
#include <aaudio/AAudio.h>
#include <android/log.h>
#include <android-base/properties.h>
#include <gtest/gtest.h>
#include <system/audio.h> /* FCC_LIMIT */
#include "utils.h"
/**
* See https://source.android.com/devices/tech/perf/low-ram
* for more details.
*
* @return true if running on low memory device
*/
static bool isLowRamDevice() {
return android::base::GetBoolProperty("ro.config.low_ram", false);
}
// Creates a builder, the caller takes ownership
static void create_stream_builder(AAudioStreamBuilder** aaudioBuilder) {
aaudio_result_t result = AAudio_createStreamBuilder(aaudioBuilder);
ASSERT_EQ(AAUDIO_OK, result);
ASSERT_NE(nullptr, *aaudioBuilder);
}
enum class Expect { FAIL, SUCCEED, NOT_CRASH };
// Tries to open an audio stream using a primed Builder.
// Takes ownership of the Builder.
static void try_opening_audio_stream(AAudioStreamBuilder *aaudioBuilder, Expect expect) {
// Create an AAudioStream using the Builder.
AAudioStream *aaudioStream = nullptr;
int64_t beforeTimeNanos = getNanoseconds();
aaudio_result_t result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
if (expect == Expect::FAIL) {
ASSERT_NE(AAUDIO_OK, result);
ASSERT_EQ(nullptr, aaudioStream);
} else if (expect == Expect::SUCCEED) {
ASSERT_EQ(AAUDIO_OK, result);
ASSERT_NE(nullptr, aaudioStream);
} else { // NOT_CRASH
ASSERT_TRUE(((result < 0) && (aaudioStream == nullptr))
|| ((result == AAUDIO_OK) && (aaudioStream != nullptr)));
}
// The stream should be open within one second.
static const int64_t kNanosPerSecond = 1e9;
ASSERT_LT(getNanoseconds() - beforeTimeNanos, kNanosPerSecond)
<< "It took more than one second to open stream";
// Cleanup
ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
if (aaudioStream != nullptr) {
beforeTimeNanos = getNanoseconds();
ASSERT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
// The stream should be closed within one second.
ASSERT_LT(getNanoseconds() - beforeTimeNanos, kNanosPerSecond)
<< "It took more than one second to close stream";
}
}
// Test creating a default stream with specific devices
static void runtest_aaudio_devices(int32_t deviceId, Expect expect) {
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
AAudioStreamBuilder_setDeviceId(aaudioBuilder, deviceId);
try_opening_audio_stream(aaudioBuilder, expect);
}
TEST(test_aaudio, aaudio_stream_device_unspecified) {
runtest_aaudio_devices(AAUDIO_UNSPECIFIED, Expect::NOT_CRASH);
}
/* FIXME - why can we open this device? What is an illegal deviceId?
TEST(test_aaudio, aaudio_stream_device_absurd) {
runtest_aaudio_devices(19736459, true);
}
*/
/* FIXME review
TEST(test_aaudio, aaudio_stream_device_reasonable) {
runtest_aaudio_devices(1, false);
}
*/
/* FIXME - why can we open this device? What is an illegal deviceId?
TEST(test_aaudio, aaudio_stream_device_negative) {
runtest_aaudio_devices(-765, true);
}
*/
// Test creating a default stream with everything unspecified.
TEST(test_aaudio, aaudio_stream_unspecified) {
if (!deviceSupportsFeature(FEATURE_PLAYBACK)) return;
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
// Create an AAudioStream using the Builder.
AAudioStream *aaudioStream = nullptr;
ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
ASSERT_NE(nullptr, aaudioStream);
// Cleanup
EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
}
class AAudioStreamBuilderSamplingRateTest : public ::testing::TestWithParam<int32_t> {
public:
static std::string getTestName(const ::testing::TestParamInfo<int32_t>& info) {
return info.param >= 0 ? std::to_string(info.param) : "_" + std::to_string(-info.param);
}
protected:
static bool isValidSamplingRate(int32_t sr) {
return sr == AAUDIO_UNSPECIFIED || (sr >= 8000 && sr <= 1000000);
}
};
TEST_P(AAudioStreamBuilderSamplingRateTest, openStream) {
if (!deviceSupportsFeature(FEATURE_PLAYBACK)) return;
const int32_t sampleRate = GetParam();
const bool isSampleRateValid = isValidSamplingRate(sampleRate);
// Opening a stream with a high sample rates can fail because the required buffer size
// is bigger than the heap size. This is a limitation in AudioFlinger. b/112528380
if (isSampleRateValid && isLowRamDevice() && (sampleRate > 192000)) {
return; // skip this test
}
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
AAudioStreamBuilder_setSampleRate(aaudioBuilder, sampleRate);
try_opening_audio_stream(
aaudioBuilder, isSampleRateValid ? Expect::SUCCEED : Expect::FAIL);
}
INSTANTIATE_TEST_CASE_P(SR, AAudioStreamBuilderSamplingRateTest,
::testing::Values(
// Commonly used values
AAUDIO_UNSPECIFIED, 8000, 11025, 16000, 22050, 44100, 48000, 88200, 96000,
176400, 192000, 384000,
// Odd values
AAUDIO_UNSPECIFIED - 1, AAUDIO_UNSPECIFIED + 1, 1234, 10000000),
&AAudioStreamBuilderSamplingRateTest::getTestName);
class AAudioStreamBuilderChannelCountTest : public ::testing::TestWithParam<int32_t> {
public:
static std::string getTestName(const ::testing::TestParamInfo<int32_t>& info) {
return info.param >= 0 ? std::to_string(info.param) : "_" + std::to_string(-info.param);
}
protected:
static bool isValidChannelCount(int32_t cc) {
return cc == AAUDIO_UNSPECIFIED || (cc >= 1 && cc <= FCC_LIMIT);
}
};
TEST_P(AAudioStreamBuilderChannelCountTest, openStream) {
if (!deviceSupportsFeature(FEATURE_PLAYBACK)) return;
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
AAudioStreamBuilder_setChannelCount(aaudioBuilder, GetParam());
try_opening_audio_stream(
aaudioBuilder, isValidChannelCount(GetParam()) ? Expect::SUCCEED : Expect::FAIL);
}
INSTANTIATE_TEST_CASE_P(CC, AAudioStreamBuilderChannelCountTest,
::testing::Values(
// Reasonable values that should work OK.
AAUDIO_UNSPECIFIED, 1, 2, 3, 4, 5, 6, 7, 8, FCC_LIMIT,
// These values should fail.
AAUDIO_UNSPECIFIED - 1, (FCC_LIMIT + 1), 1000, 1000000),
&AAudioStreamBuilderChannelCountTest::getTestName);
class AAudioStreamBuilderFormatTest : public ::testing::TestWithParam<aaudio_format_t> {
public:
static std::string getTestName(const ::testing::TestParamInfo<aaudio_format_t>& info) {
return info.param >= 0 ? std::to_string(info.param) : "_" + std::to_string(-info.param);
}
protected:
static bool isValidFormat(aaudio_format_t f) {
switch (f) {
case AAUDIO_FORMAT_UNSPECIFIED:
case AAUDIO_FORMAT_PCM_I16:
case AAUDIO_FORMAT_PCM_FLOAT:
return true;
}
return false;
}
};
TEST_P(AAudioStreamBuilderFormatTest, openStream) {
if (!deviceSupportsFeature(FEATURE_PLAYBACK)) return;
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
AAudioStreamBuilder_setFormat(aaudioBuilder, GetParam());
try_opening_audio_stream(
aaudioBuilder, isValidFormat(GetParam()) ? Expect::SUCCEED : Expect::FAIL);
}
INSTANTIATE_TEST_CASE_P(F, AAudioStreamBuilderFormatTest,
::testing::Values(
// Reasonable values
AAUDIO_FORMAT_UNSPECIFIED, AAUDIO_FORMAT_PCM_I16, AAUDIO_FORMAT_PCM_FLOAT,
// Odd values
AAUDIO_FORMAT_INVALID, AAUDIO_FORMAT_INVALID - 1, 100, 1000000, 10000000),
&AAudioStreamBuilderFormatTest::getTestName);
class AAudioStreamBuilderSharingModeTest : public ::testing::TestWithParam<aaudio_sharing_mode_t> {
public:
static std::string getTestName(const ::testing::TestParamInfo<aaudio_sharing_mode_t>& info) {
return info.param >= 0 ? std::to_string(info.param) : "_" + std::to_string(-info.param);
}
protected:
static bool isValidSharingMode(aaudio_sharing_mode_t f) {
return f == AAUDIO_SHARING_MODE_SHARED || f == AAUDIO_SHARING_MODE_EXCLUSIVE;
}
};
TEST_P(AAudioStreamBuilderSharingModeTest, openStream) {
if (!deviceSupportsFeature(FEATURE_PLAYBACK)) return;
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
AAudioStreamBuilder_setSharingMode(aaudioBuilder, GetParam());
try_opening_audio_stream(
aaudioBuilder, isValidSharingMode(GetParam()) ? Expect::SUCCEED : Expect::FAIL);
}
INSTANTIATE_TEST_CASE_P(SM, AAudioStreamBuilderSharingModeTest,
::testing::Values(
// Reasonable values
AAUDIO_SHARING_MODE_SHARED, AAUDIO_SHARING_MODE_EXCLUSIVE,
// Odd values
-1, 100, 1000000, 10000000),
&AAudioStreamBuilderSharingModeTest::getTestName);
class AAudioStreamBuilderDirectionTest : public ::testing::TestWithParam<aaudio_direction_t> {
public:
static std::string getTestName(const ::testing::TestParamInfo<aaudio_direction_t>& info) {
return info.param >= 0 ? std::to_string(info.param) : "_" + std::to_string(-info.param);
}
protected:
static bool isValidDirection(aaudio_direction_t f) {
return f == AAUDIO_DIRECTION_OUTPUT || f == AAUDIO_DIRECTION_INPUT;
}
};
TEST_P(AAudioStreamBuilderDirectionTest, openStream) {
if (GetParam() == AAUDIO_DIRECTION_OUTPUT
&& !deviceSupportsFeature(FEATURE_PLAYBACK)) return;
if (GetParam() == AAUDIO_DIRECTION_INPUT
&& !deviceSupportsFeature(FEATURE_RECORDING)) return;
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
AAudioStreamBuilder_setDirection(aaudioBuilder, GetParam());
try_opening_audio_stream(
aaudioBuilder, isValidDirection(GetParam()) ? Expect::SUCCEED : Expect::FAIL);
}
INSTANTIATE_TEST_CASE_P(SD, AAudioStreamBuilderDirectionTest,
::testing::Values(
// Reasonable values
AAUDIO_DIRECTION_OUTPUT, AAUDIO_DIRECTION_INPUT,
// Odd values
-1, 100, 1000000, 10000000),
&AAudioStreamBuilderDirectionTest::getTestName);
class AAudioStreamBuilderBufferCapacityTest : public ::testing::TestWithParam<int32_t> {
public:
static std::string getTestName(const ::testing::TestParamInfo<int32_t>& info) {
return info.param >= 0 ? std::to_string(info.param) : "_" + std::to_string(-info.param);
}
protected:
// There is no hard defined limit, the actual maximum capacity depends
// on the implementation.
static bool isValidCapacity(int32_t bc) {
return bc == AAUDIO_UNSPECIFIED || bc >= 0;
}
};
TEST_P(AAudioStreamBuilderBufferCapacityTest, openStream) {
if (!deviceSupportsFeature(FEATURE_PLAYBACK)) return;
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
AAudioStreamBuilder_setBufferCapacityInFrames(aaudioBuilder, GetParam());
try_opening_audio_stream(
aaudioBuilder, isValidCapacity(GetParam()) ? Expect::SUCCEED : Expect::FAIL);
}
INSTANTIATE_TEST_CASE_P(BC, AAudioStreamBuilderBufferCapacityTest,
::testing::Values(
// Reasonable values that should not fail
AAUDIO_UNSPECIFIED, 8 * 192, 2 * 1024,
// Odd values
AAUDIO_UNSPECIFIED - 1),
&AAudioStreamBuilderBufferCapacityTest::getTestName);
class AAudioStreamBuilderPerfModeTest : public ::testing::TestWithParam<aaudio_performance_mode_t> {
public:
static std::string getTestName(const ::testing::TestParamInfo<aaudio_performance_mode_t>& info) {
return info.param >= 0 ? std::to_string(info.param) : "_" + std::to_string(-info.param);
}
protected:
static bool isValidPerfMode(aaudio_performance_mode_t pm) {
switch (pm) {
case AAUDIO_PERFORMANCE_MODE_NONE:
case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
return true;
}
return false;
}
};
TEST_P(AAudioStreamBuilderPerfModeTest, openStream) {
if (!deviceSupportsFeature(FEATURE_PLAYBACK)) return;
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, GetParam());
try_opening_audio_stream(
aaudioBuilder, isValidPerfMode(GetParam()) ? Expect::SUCCEED : Expect::FAIL);
}
INSTANTIATE_TEST_CASE_P(PM, AAudioStreamBuilderPerfModeTest,
::testing::Values(
// Reasonable values
AAUDIO_PERFORMANCE_MODE_NONE,
AAUDIO_PERFORMANCE_MODE_POWER_SAVING,
AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
// Odd values
AAUDIO_UNSPECIFIED - 1, AAUDIO_UNSPECIFIED, 100, 1000000, 10000000),
&AAudioStreamBuilderPerfModeTest::getTestName);
class AAudioStreamBuilderChannelMaskTest : public ::testing::TestWithParam<aaudio_channel_mask_t> {
public:
static std::string getTestName(const ::testing::TestParamInfo<aaudio_channel_mask_t>& info) {
std::stringstream ss;
ss << "0x" << std::hex << info.param;
return ss.str();
}
protected:
static bool isValidChannelMask(aaudio_channel_mask_t channelMask, bool isInput) {
if (channelMask == AAUDIO_UNSPECIFIED) {
return true;
}
if (__builtin_popcount(channelMask) > FCC_LIMIT) {
return false;
}
if (isInput) {
switch (channelMask) {
case AAUDIO_CHANNEL_MONO:
case AAUDIO_CHANNEL_STEREO:
case AAUDIO_CHANNEL_FRONT_BACK:
case AAUDIO_CHANNEL_2POINT0POINT2:
case AAUDIO_CHANNEL_2POINT1POINT2:
case AAUDIO_CHANNEL_3POINT0POINT2:
case AAUDIO_CHANNEL_3POINT1POINT2:
case AAUDIO_CHANNEL_5POINT1:
return true;
}
return false;
} else {
switch (channelMask) {
case AAUDIO_CHANNEL_MONO:
case AAUDIO_CHANNEL_STEREO:
case AAUDIO_CHANNEL_2POINT1:
case AAUDIO_CHANNEL_TRI:
case AAUDIO_CHANNEL_TRI_BACK:
case AAUDIO_CHANNEL_3POINT1:
case AAUDIO_CHANNEL_2POINT0POINT2:
case AAUDIO_CHANNEL_2POINT1POINT2:
case AAUDIO_CHANNEL_3POINT0POINT2:
case AAUDIO_CHANNEL_3POINT1POINT2:
case AAUDIO_CHANNEL_QUAD:
case AAUDIO_CHANNEL_QUAD_SIDE:
case AAUDIO_CHANNEL_SURROUND:
case AAUDIO_CHANNEL_PENTA:
case AAUDIO_CHANNEL_5POINT1:
case AAUDIO_CHANNEL_5POINT1_SIDE:
case AAUDIO_CHANNEL_5POINT1POINT2:
case AAUDIO_CHANNEL_5POINT1POINT4:
case AAUDIO_CHANNEL_6POINT1:
case AAUDIO_CHANNEL_7POINT1:
case AAUDIO_CHANNEL_7POINT1POINT2:
case AAUDIO_CHANNEL_7POINT1POINT4:
case AAUDIO_CHANNEL_9POINT1POINT4:
case AAUDIO_CHANNEL_9POINT1POINT6:
return true;
}
return false;
}
}
void testChannelMask(aaudio_channel_mask_t channelMask, aaudio_direction_t direction);
};
void AAudioStreamBuilderChannelMaskTest::testChannelMask(aaudio_channel_mask_t channelMask,
aaudio_direction_t direction) {
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
AAudioStreamBuilder_setDirection(aaudioBuilder, direction);
AAudioStreamBuilder_setChannelMask(aaudioBuilder, channelMask);
const Expect expect =
isValidChannelMask(channelMask, direction) ? Expect::SUCCEED : Expect::FAIL;
AAudioStream *aaudioStream = nullptr;
aaudio_result_t result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
if (expect == Expect::FAIL) {
ASSERT_NE(AAUDIO_OK, result);
ASSERT_EQ(nullptr, aaudioStream);
} else if (expect == Expect::SUCCEED) {
ASSERT_EQ(AAUDIO_OK, result);
ASSERT_NE(nullptr, aaudioStream);
ASSERT_NE(0, AAudioStream_getChannelCount(aaudioStream));
ASSERT_NE(AAUDIO_UNSPECIFIED, AAudioStream_getChannelMask(aaudioStream));
ASSERT_NE(AAUDIO_CHANNEL_INVALID, AAudioStream_getChannelMask(aaudioStream));
} else { // NOT_CRASH
ASSERT_TRUE(((result < 0) && (aaudioStream == nullptr))
|| ((result == AAUDIO_OK) && (aaudioStream != nullptr)));
}
// Cleanup
ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
if (aaudioStream != nullptr) {
ASSERT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
}
}
TEST_P(AAudioStreamBuilderChannelMaskTest, openInputStream) {
if (!deviceSupportsFeature(FEATURE_RECORDING)) {
return;
}
testChannelMask(GetParam(), AAUDIO_DIRECTION_INPUT);
}
TEST_P(AAudioStreamBuilderChannelMaskTest, openOutputStream) {
if (!deviceSupportsFeature(FEATURE_PLAYBACK)) {
return;
}
testChannelMask(GetParam(), AAUDIO_DIRECTION_OUTPUT);
}
INSTANTIATE_TEST_CASE_P(
CM, AAudioStreamBuilderChannelMaskTest,
::testing::Values(
// UNSPECIFIED is valid channel mask
AAUDIO_UNSPECIFIED,
AAUDIO_CHANNEL_INVALID,
// Channel mask listed in audio.h
// AAUDIO_CHANNEL_FRONT_LEFT,
AAUDIO_CHANNEL_FRONT_RIGHT,
AAUDIO_CHANNEL_FRONT_CENTER,
AAUDIO_CHANNEL_LOW_FREQUENCY,
AAUDIO_CHANNEL_BACK_LEFT,
AAUDIO_CHANNEL_BACK_RIGHT,
AAUDIO_CHANNEL_FRONT_LEFT_OF_CENTER,
AAUDIO_CHANNEL_FRONT_RIGHT_OF_CENTER,
AAUDIO_CHANNEL_BACK_CENTER,
AAUDIO_CHANNEL_SIDE_LEFT,
AAUDIO_CHANNEL_SIDE_RIGHT,
AAUDIO_CHANNEL_TOP_CENTER,
AAUDIO_CHANNEL_TOP_FRONT_LEFT,
AAUDIO_CHANNEL_TOP_FRONT_CENTER,
AAUDIO_CHANNEL_TOP_FRONT_RIGHT,
AAUDIO_CHANNEL_TOP_BACK_LEFT,
AAUDIO_CHANNEL_TOP_BACK_CENTER,
AAUDIO_CHANNEL_TOP_BACK_RIGHT,
AAUDIO_CHANNEL_TOP_SIDE_LEFT,
AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
AAUDIO_CHANNEL_BOTTOM_FRONT_LEFT,
AAUDIO_CHANNEL_BOTTOM_FRONT_CENTER,
AAUDIO_CHANNEL_BOTTOM_FRONT_RIGHT,
AAUDIO_CHANNEL_LOW_FREQUENCY_2,
AAUDIO_CHANNEL_FRONT_WIDE_LEFT,
AAUDIO_CHANNEL_FRONT_WIDE_RIGHT,
AAUDIO_CHANNEL_MONO,
AAUDIO_CHANNEL_STEREO,
AAUDIO_CHANNEL_2POINT1,
AAUDIO_CHANNEL_TRI,
AAUDIO_CHANNEL_TRI_BACK,
AAUDIO_CHANNEL_3POINT1,
AAUDIO_CHANNEL_2POINT0POINT2,
AAUDIO_CHANNEL_2POINT1POINT2,
AAUDIO_CHANNEL_3POINT0POINT2,
AAUDIO_CHANNEL_3POINT1POINT2,
AAUDIO_CHANNEL_QUAD,
AAUDIO_CHANNEL_QUAD_SIDE,
AAUDIO_CHANNEL_SURROUND,
AAUDIO_CHANNEL_PENTA,
AAUDIO_CHANNEL_5POINT1,
AAUDIO_CHANNEL_5POINT1_SIDE,
AAUDIO_CHANNEL_6POINT1,
AAUDIO_CHANNEL_7POINT1,
AAUDIO_CHANNEL_5POINT1POINT2,
AAUDIO_CHANNEL_5POINT1POINT4,
AAUDIO_CHANNEL_7POINT1POINT2,
AAUDIO_CHANNEL_7POINT1POINT4,
AAUDIO_CHANNEL_9POINT1POINT4,
AAUDIO_CHANNEL_9POINT1POINT6,
AAUDIO_CHANNEL_FRONT_BACK,
// Odd value
0x20000000,
0x30000000,
0x40000005),
&AAudioStreamBuilderChannelMaskTest::getTestName);
using ChannelMaskAndCountParams = std::pair<aaudio_direction_t, aaudio_channel_mask_t>;
class AAudioStreamBuilderChannelMaskAndCountTest :
public ::testing::TestWithParam<ChannelMaskAndCountParams> {
public:
static std::string getTestName(
const ::testing::TestParamInfo<ChannelMaskAndCountParams>& info) {
std::stringstream ss;
ss << (info.param.first == AAUDIO_DIRECTION_INPUT ? "INPUT_0x" : "OUTPUT_0x")
<< std::hex << info.param.second;
return ss.str();
}
protected:
void testSetChannelMaskAndCount(aaudio_direction_t direction,
aaudio_channel_mask_t channelMask,
int32_t channelCount,
bool channelMaskFirst);
};
void AAudioStreamBuilderChannelMaskAndCountTest::testSetChannelMaskAndCount(
aaudio_direction_t direction, aaudio_channel_mask_t channelMask,
int32_t channelCount, bool setChannelMaskFirst) {
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
AAudioStreamBuilder_setDirection(aaudioBuilder, direction);
if (setChannelMaskFirst) {
AAudioStreamBuilder_setChannelMask(aaudioBuilder, channelMask);
AAudioStreamBuilder_setChannelCount(aaudioBuilder, channelCount);
} else {
AAudioStreamBuilder_setChannelCount(aaudioBuilder, channelCount);
AAudioStreamBuilder_setChannelMask(aaudioBuilder, channelMask);
}
AAudioStream *aaudioStream = nullptr;
aaudio_result_t result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
ASSERT_EQ(AAUDIO_OK, result);
ASSERT_NE(nullptr, aaudioStream);
if (setChannelMaskFirst) {
ASSERT_EQ(channelCount, AAudioStream_getChannelCount(aaudioStream));
ASSERT_EQ(AAUDIO_UNSPECIFIED, AAudioStream_getChannelMask(aaudioStream));
} else {
// If channel mask is unspecified, stereo will be returned.
ASSERT_EQ(channelMask == AAUDIO_UNSPECIFIED ? AAUDIO_CHANNEL_STEREO : channelMask,
AAudioStream_getChannelMask(aaudioStream));
ASSERT_EQ(channelMask == AAUDIO_UNSPECIFIED ? 2 : __builtin_popcount(channelMask),
AAudioStream_getChannelCount(aaudioStream));
}
ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
if (aaudioStream != nullptr) {
ASSERT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
}
}
TEST_P(AAudioStreamBuilderChannelMaskAndCountTest, channelMaskAndCount) {
const aaudio_direction_t direction = GetParam().first;
if ((direction == AAUDIO_DIRECTION_OUTPUT && !deviceSupportsFeature(FEATURE_PLAYBACK)) ||
(direction == AAUDIO_DIRECTION_INPUT && !deviceSupportsFeature(FEATURE_RECORDING))) {
return;
}
const aaudio_channel_mask_t channelMask = GetParam().second;
testSetChannelMaskAndCount(direction, channelMask,
2 /*channelCount*/, true /*setChannelMaskFirst*/);
testSetChannelMaskAndCount(direction, channelMask,
2 /*channelCount*/, false /*setChannelMaskFirst*/);
testSetChannelMaskAndCount(direction, AAUDIO_CHANNEL_5POINT1,
2 /*channelCount*/, true /*setChannelMaskFirst*/);
testSetChannelMaskAndCount(direction, AAUDIO_CHANNEL_5POINT1,
2 /*channelCount*/, false /*setChannelMaskFirst*/);
}
INSTANTIATE_TEST_CASE_P(CMC, AAudioStreamBuilderChannelMaskAndCountTest,
::testing::Values(
std::make_pair(AAUDIO_DIRECTION_OUTPUT, AAUDIO_CHANNEL_MONO),
std::make_pair(AAUDIO_DIRECTION_OUTPUT, AAUDIO_CHANNEL_5POINT1),
std::make_pair(AAUDIO_DIRECTION_OUTPUT, AAUDIO_UNSPECIFIED),
std::make_pair(AAUDIO_DIRECTION_INPUT, AAUDIO_CHANNEL_MONO),
std::make_pair(AAUDIO_DIRECTION_INPUT, AAUDIO_CHANNEL_5POINT1),
std::make_pair(AAUDIO_DIRECTION_INPUT, AAUDIO_UNSPECIFIED)),
&AAudioStreamBuilderChannelMaskAndCountTest::getTestName);
using CommonCombinationTestParams = std::tuple<aaudio_direction_t,
aaudio_sharing_mode_t,
aaudio_performance_mode_t,
int32_t /*sample rate*/,
aaudio_format_t,
aaudio_channel_mask_t>;
enum {
PARAM_DIRECTION = 0,
PARAM_SHARING_MODE,
PARAM_PERFORMANCE_MODE,
PARAM_SAMPLE_RATE,
PARAM_FORMAT,
PARAM_CHANNEL_MASK
};
class AAudioStreamBuilderCommonCombinationTest :
public ::testing::TestWithParam<CommonCombinationTestParams> {
public:
static std::string getTestName(
const ::testing::TestParamInfo<CommonCombinationTestParams>& info) {
std::stringstream ss;
ss << (std::get<PARAM_DIRECTION>(info.param) == AAUDIO_DIRECTION_INPUT ? "INPUT_"
: "OUTPUT_")
<< sharingModeToString(std::get<PARAM_SHARING_MODE>(info.param)) << "_"
<< performanceModeToString(std::get<PARAM_PERFORMANCE_MODE>(info.param)) << "_"
<< "sampleRate_" << std::get<PARAM_SAMPLE_RATE>(info.param) << "_"
<< "format_0x" << std::hex << std::get<PARAM_FORMAT>(info.param) << "_"
<< "channelMask_0x" << std::get<PARAM_CHANNEL_MASK>(info.param) << "";
return ss.str();
}
};
TEST_P(AAudioStreamBuilderCommonCombinationTest, openStream) {
if (!deviceSupportsFeature(FEATURE_PLAYBACK)) return;
AAudioStreamBuilder *aaudioBuilder = nullptr;
create_stream_builder(&aaudioBuilder);
const auto param = GetParam();
AAudioStreamBuilder_setDirection(aaudioBuilder, std::get<PARAM_DIRECTION>(param));
AAudioStreamBuilder_setSharingMode(aaudioBuilder, std::get<PARAM_SHARING_MODE>(param));
AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, std::get<PARAM_PERFORMANCE_MODE>(param));
AAudioStreamBuilder_setSampleRate(aaudioBuilder, std::get<PARAM_SAMPLE_RATE>(param));
AAudioStreamBuilder_setFormat(aaudioBuilder, std::get<PARAM_FORMAT>(param));
AAudioStreamBuilder_setChannelMask(aaudioBuilder, std::get<PARAM_CHANNEL_MASK>(param));
// All the test parameters all reasonable values with different combination. In that case,
// it is expected that the opening will be successful.
try_opening_audio_stream(aaudioBuilder, Expect::SUCCEED);
}
INSTANTIATE_TEST_CASE_P(CommonComb, AAudioStreamBuilderCommonCombinationTest,
::testing::Combine(
::testing::Values(AAUDIO_DIRECTION_OUTPUT, AAUDIO_DIRECTION_INPUT),
::testing::Values(AAUDIO_SHARING_MODE_SHARED, AAUDIO_SHARING_MODE_EXCLUSIVE),
::testing::Values(
AAUDIO_PERFORMANCE_MODE_NONE,
AAUDIO_PERFORMANCE_MODE_POWER_SAVING,
AAUDIO_PERFORMANCE_MODE_LOW_LATENCY),
::testing::Values(// Sample rate
AAUDIO_UNSPECIFIED, 8000, 16000, 44100, 48000, 96000, 192000),
::testing::Values(
AAUDIO_UNSPECIFIED,
AAUDIO_FORMAT_PCM_I16,
AAUDIO_FORMAT_PCM_FLOAT),
::testing::Values(AAUDIO_CHANNEL_MONO, AAUDIO_CHANNEL_STEREO)),
&AAudioStreamBuilderCommonCombinationTest::getTestName);