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

Commit 148bb94a authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 7227300 from 66689d7e to sc-v2-release

Change-Id: Ieff82edd7c3879828a6ed582143edae72ca5cdcb
parents a08e5d51 66689d7e
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -212,6 +212,15 @@ static inline bool isOutputDevice(const std::string& device) {
    return isOutputDevice(stringToAudioDevice(device));
}

static inline bool isTelephonyDevice(AudioDevice device) {
    return device == AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX ||
           device == AudioDevice::AUDIO_DEVICE_IN_TELEPHONY_RX;
}

static inline bool isTelephonyDevice(const std::string& device) {
    return isTelephonyDevice(stringToAudioDevice(device));
}

static inline bool maybeVendorExtension(const std::string& s) {
    // Only checks whether the string starts with the "vendor prefix".
    static const std::string vendorPrefix = "VX_";
@@ -260,6 +269,24 @@ static inline bool isUnknownAudioUsage(const std::string& usage) {
    return stringToAudioUsage(usage) == AudioUsage::UNKNOWN;
}

static inline bool isLinearPcm(AudioFormat format) {
    switch (format) {
        case AudioFormat::AUDIO_FORMAT_PCM_16_BIT:
        case AudioFormat::AUDIO_FORMAT_PCM_8_BIT:
        case AudioFormat::AUDIO_FORMAT_PCM_32_BIT:
        case AudioFormat::AUDIO_FORMAT_PCM_8_24_BIT:
        case AudioFormat::AUDIO_FORMAT_PCM_FLOAT:
        case AudioFormat::AUDIO_FORMAT_PCM_24_BIT_PACKED:
            return true;
        default:
            return false;
    }
}

static inline bool isLinearPcm(const std::string& format) {
    return isLinearPcm(stringToAudioFormat(format));
}

}  // namespace android::audio::policy::configuration::V7_0

#endif  // ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0__ENUMS_H
+7 −37
Original line number Diff line number Diff line
@@ -77,7 +77,6 @@ TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) {
                  .tags = {},
                  .channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO)}}};
#endif
        EventFlag* efGroup;
        for (auto microphone : microphones) {
#if MAJOR_VERSION <= 6
            if (microphone.deviceAddress.device != AudioDevice::IN_BUILTIN_MIC) {
@@ -96,44 +95,15 @@ TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) {
                                                            config, flags, initMetadata, cb);
                    },
                    config, &res, &suggestedConfig));
            StreamReader reader(stream.get(), stream->getBufferSize());
            ASSERT_TRUE(reader.start());
            reader.pause();  // This ensures that at least one read has happened.
            EXPECT_FALSE(reader.hasError());

            hidl_vec<MicrophoneInfo> activeMicrophones;
            Result readRes;
            typedef MessageQueue<IStreamIn::ReadParameters, kSynchronizedReadWrite> CommandMQ;
            typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
            std::unique_ptr<CommandMQ> commandMQ;
            std::unique_ptr<DataMQ> dataMQ;
            size_t frameSize = stream->getFrameSize();
            size_t frameCount = stream->getBufferSize() / frameSize;
            ASSERT_OK(stream->prepareForReading(
                    frameSize, frameCount, [&](auto r, auto& c, auto& d, auto&, auto) {
                        readRes = r;
                        if (readRes == Result::OK) {
                            commandMQ.reset(new CommandMQ(c));
                            dataMQ.reset(new DataMQ(d));
                            if (dataMQ->isValid() && dataMQ->getEventFlagWord()) {
                                EventFlag::createEventFlag(dataMQ->getEventFlagWord(), &efGroup);
                            }
                        }
                    }));
            ASSERT_OK(readRes);
            IStreamIn::ReadParameters params;
            params.command = IStreamIn::ReadCommand::READ;
            ASSERT_TRUE(commandMQ != nullptr);
            ASSERT_TRUE(commandMQ->isValid());
            ASSERT_TRUE(commandMQ->write(&params));
            efGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
            uint32_t efState = 0;
            efGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
            if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
            ASSERT_OK(stream->getActiveMicrophones(returnIn(res, activeMicrophones)));
            ASSERT_OK(res);
                ASSERT_NE(0U, activeMicrophones.size());
            }
            helper.close(true /*clear*/, &res);
            ASSERT_OK(res);
            if (efGroup) {
                EventFlag::deleteEventFlag(&efGroup);
            }
            EXPECT_NE(0U, activeMicrophones.size());
        }
    }
}
+304 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
 * limitations under the License.
 */

#include <android-base/chrono_utils.h>

#include "Generators.h"

// pull in all the <= 6.0 tests
@@ -487,3 +489,305 @@ TEST_P(SingleConfigInputStreamTest, UpdateInvalidSinkMetadata) {
                << ::testing::PrintToString(metadata);
    }
}

static const std::vector<DeviceConfigParameter>& getOutputDevicePcmOnlyConfigParameters() {
    static const std::vector<DeviceConfigParameter> parameters = [] {
        auto allParams = getOutputDeviceConfigParameters();
        std::vector<DeviceConfigParameter> pcmParams;
        std::copy_if(allParams.begin(), allParams.end(), std::back_inserter(pcmParams), [](auto cfg) {
            const auto& flags = std::get<PARAM_FLAGS>(cfg);
            return xsd::isLinearPcm(std::get<PARAM_CONFIG>(cfg).base.format)
                   // MMAP NOIRQ and HW A/V Sync profiles use special writing protocols.
                   &&
                   std::find_if(flags.begin(), flags.end(),
                                [](const auto& flag) {
                                    return flag == toString(xsd::AudioInOutFlag::
                                                                    AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) ||
                                           flag == toString(xsd::AudioInOutFlag::
                                                                    AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
                                }) == flags.end() &&
                   !getCachedPolicyConfig()
                            .getAttachedSinkDeviceForMixPort(
                                    std::get<PARAM_DEVICE_NAME>(std::get<PARAM_DEVICE>(cfg)),
                                    std::get<PARAM_PORT_NAME>(cfg))
                            .empty();
        });
        return pcmParams;
    }();
    return parameters;
}

class PcmOnlyConfigOutputStreamTest : public OutputStreamTest {
  public:
    void TearDown() override {
        releasePatchIfNeeded();
        OutputStreamTest::TearDown();
    }

    bool canQueryPresentationPosition() const {
        auto maybeSinkAddress =
                getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName());
        // Returning 'true' when no sink is found so the test can fail later with a more clear
        // problem description.
        return !maybeSinkAddress.has_value() ||
               !xsd::isTelephonyDevice(maybeSinkAddress.value().deviceType);
    }

    void createPatchIfNeeded() {
        auto maybeSinkAddress =
                getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName());
        ASSERT_TRUE(maybeSinkAddress.has_value())
                << "No sink device found for mix port " << getMixPortName() << " (module "
                << getDeviceName() << ")";
        if (areAudioPatchesSupported()) {
            AudioPortConfig source;
            source.base.format.value(getConfig().base.format);
            source.base.sampleRateHz.value(getConfig().base.sampleRateHz);
            source.base.channelMask.value(getConfig().base.channelMask);
            source.ext.mix({});
            source.ext.mix().ioHandle = helper.getIoHandle();
            source.ext.mix().useCase.stream({});
            AudioPortConfig sink;
            sink.ext.device(maybeSinkAddress.value());
            EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{source},
                                                    hidl_vec<AudioPortConfig>{sink},
                                                    returnIn(res, mPatchHandle)));
            mHasPatch = res == Result::OK;
        } else {
            EXPECT_OK(stream->setDevices({maybeSinkAddress.value()}));
        }
    }

    void releasePatchIfNeeded() {
        if (areAudioPatchesSupported()) {
            if (mHasPatch) {
                EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle));
                mHasPatch = false;
            }
        } else {
            EXPECT_OK(stream->setDevices({address}));
        }
    }

    const std::string& getMixPortName() const { return std::get<PARAM_PORT_NAME>(GetParam()); }

    void waitForPresentationPositionAdvance(StreamWriter& writer, uint64_t* firstPosition = nullptr,
                                            uint64_t* lastPosition = nullptr) {
        static constexpr int kWriteDurationUs = 50 * 1000;
        static constexpr std::chrono::milliseconds kPositionChangeTimeout{10000};
        uint64_t framesInitial;
        TimeSpec ts;
        // Starting / resuming of streams is asynchronous at HAL level.
        // Sometimes HAL doesn't have enough information until the audio data actually gets
        // consumed by the hardware.
        do {
            ASSERT_OK(stream->getPresentationPosition(returnIn(res, framesInitial, ts)));
            ASSERT_RESULT(okOrInvalidState, res);
        } while (res != Result::OK);
        uint64_t frames = framesInitial;
        bool timedOut = false;
        for (android::base::Timer elapsed;
             frames <= framesInitial && !writer.hasError() &&
             !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
            usleep(kWriteDurationUs);
            ASSERT_OK(stream->getPresentationPosition(returnIn(res, frames, ts)));
            ASSERT_RESULT(Result::OK, res);
        }
        EXPECT_FALSE(timedOut);
        EXPECT_FALSE(writer.hasError());
        EXPECT_GT(frames, framesInitial);
        if (firstPosition) *firstPosition = framesInitial;
        if (lastPosition) *lastPosition = frames;
    }

  private:
    AudioPatchHandle mPatchHandle = {};
    bool mHasPatch = false;
};

TEST_P(PcmOnlyConfigOutputStreamTest, Write) {
    doc::test("Check that output streams opened for PCM output accepts audio data");
    StreamWriter writer(stream.get(), stream->getBufferSize());
    ASSERT_TRUE(writer.start());
    EXPECT_TRUE(writer.waitForAtLeastOneCycle());
}

TEST_P(PcmOnlyConfigOutputStreamTest, PresentationPositionAdvancesWithWrites) {
    doc::test("Check that the presentation position advances with writes");
    if (!canQueryPresentationPosition()) {
        GTEST_SKIP() << "Presentation position retrieval is not possible";
    }

    ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
    StreamWriter writer(stream.get(), stream->getBufferSize());
    ASSERT_TRUE(writer.start());
    ASSERT_TRUE(writer.waitForAtLeastOneCycle());
    ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer));

    writer.stop();
    releasePatchIfNeeded();
}

TEST_P(PcmOnlyConfigOutputStreamTest, PresentationPositionPreservedOnStandby) {
    doc::test("Check that the presentation position does not reset on standby");
    if (!canQueryPresentationPosition()) {
        GTEST_SKIP() << "Presentation position retrieval is not possible";
    }

    ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
    StreamWriter writer(stream.get(), stream->getBufferSize());
    ASSERT_TRUE(writer.start());
    ASSERT_TRUE(writer.waitForAtLeastOneCycle());

    uint64_t framesInitial;
    ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer, nullptr, &framesInitial));
    writer.pause();
    ASSERT_OK(stream->standby());
    writer.resume();

    uint64_t frames;
    ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer, &frames));
    EXPECT_GT(frames, framesInitial);

    writer.stop();
    releasePatchIfNeeded();
}

INSTANTIATE_TEST_CASE_P(PcmOnlyConfigOutputStream, PcmOnlyConfigOutputStreamTest,
                        ::testing::ValuesIn(getOutputDevicePcmOnlyConfigParameters()),
                        &DeviceConfigParameterToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PcmOnlyConfigOutputStreamTest);

static const std::vector<DeviceConfigParameter>& getInputDevicePcmOnlyConfigParameters() {
    static const std::vector<DeviceConfigParameter> parameters = [] {
        auto allParams = getInputDeviceConfigParameters();
        std::vector<DeviceConfigParameter> pcmParams;
        std::copy_if(
                allParams.begin(), allParams.end(), std::back_inserter(pcmParams), [](auto cfg) {
                    const auto& flags = std::get<PARAM_FLAGS>(cfg);
                    return xsd::isLinearPcm(std::get<PARAM_CONFIG>(cfg).base.format)
                           // MMAP NOIRQ profiles use different reading protocol.
                           &&
                           std::find(flags.begin(), flags.end(),
                                     toString(xsd::AudioInOutFlag::AUDIO_INPUT_FLAG_MMAP_NOIRQ)) ==
                                   flags.end() &&
                           !getCachedPolicyConfig()
                                    .getAttachedSourceDeviceForMixPort(
                                            std::get<PARAM_DEVICE_NAME>(
                                                    std::get<PARAM_DEVICE>(cfg)),
                                            std::get<PARAM_PORT_NAME>(cfg))
                                    .empty();
                });
        return pcmParams;
    }();
    return parameters;
}

class PcmOnlyConfigInputStreamTest : public InputStreamTest {
  public:
    void TearDown() override {
        releasePatchIfNeeded();
        InputStreamTest::TearDown();
    }

    void createPatchIfNeeded() {
        auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
                getDeviceName(), getMixPortName());
        ASSERT_TRUE(maybeSourceAddress.has_value())
                << "No source device found for mix port " << getMixPortName() << " (module "
                << getDeviceName() << ")";
        if (areAudioPatchesSupported()) {
            AudioPortConfig source;
            source.ext.device(maybeSourceAddress.value());
            AudioPortConfig sink;
            sink.base.format.value(getConfig().base.format);
            sink.base.sampleRateHz.value(getConfig().base.sampleRateHz);
            sink.base.channelMask.value(getConfig().base.channelMask);
            sink.ext.mix({});
            sink.ext.mix().ioHandle = helper.getIoHandle();
            sink.ext.mix().useCase.source(toString(xsd::AudioSource::AUDIO_SOURCE_MIC));
            EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{source},
                                                    hidl_vec<AudioPortConfig>{sink},
                                                    returnIn(res, mPatchHandle)));
            mHasPatch = res == Result::OK;
        } else {
            EXPECT_OK(stream->setDevices({maybeSourceAddress.value()}));
        }
    }
    void releasePatchIfNeeded() {
        if (areAudioPatchesSupported()) {
            if (mHasPatch) {
                EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle));
                mHasPatch = false;
            }
        } else {
            EXPECT_OK(stream->setDevices({address}));
        }
    }
    const std::string& getMixPortName() const { return std::get<PARAM_PORT_NAME>(GetParam()); }

  private:
    AudioPatchHandle mPatchHandle = {};
    bool mHasPatch = false;
};

TEST_P(PcmOnlyConfigInputStreamTest, Read) {
    doc::test("Check that input streams opened for PCM input retrieve audio data");
    StreamReader reader(stream.get(), stream->getBufferSize());
    ASSERT_TRUE(reader.start());
    EXPECT_TRUE(reader.waitForAtLeastOneCycle());
}

TEST_P(PcmOnlyConfigInputStreamTest, CapturePositionAdvancesWithReads) {
    doc::test("Check that the capture position advances with reads");

    ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
    StreamReader reader(stream.get(), stream->getBufferSize());
    ASSERT_TRUE(reader.start());
    EXPECT_TRUE(reader.waitForAtLeastOneCycle());

    uint64_t framesInitial, ts;
    ASSERT_OK(stream->getCapturePosition(returnIn(res, framesInitial, ts)));
    ASSERT_RESULT(Result::OK, res);

    EXPECT_TRUE(reader.waitForAtLeastOneCycle());

    uint64_t frames;
    ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, ts)));
    ASSERT_RESULT(Result::OK, res);
    EXPECT_GT(frames, framesInitial);

    reader.stop();
    releasePatchIfNeeded();
}

TEST_P(PcmOnlyConfigInputStreamTest, CapturePositionPreservedOnStandby) {
    doc::test("Check that the capture position does not reset on standby");

    ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
    StreamReader reader(stream.get(), stream->getBufferSize());
    ASSERT_TRUE(reader.start());
    EXPECT_TRUE(reader.waitForAtLeastOneCycle());

    uint64_t framesInitial, ts;
    ASSERT_OK(stream->getCapturePosition(returnIn(res, framesInitial, ts)));
    ASSERT_RESULT(Result::OK, res);

    reader.pause();
    ASSERT_OK(stream->standby());
    reader.resume();
    EXPECT_FALSE(reader.hasError());

    uint64_t frames;
    ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, ts)));
    ASSERT_RESULT(Result::OK, res);
    EXPECT_GT(frames, framesInitial);

    reader.stop();
    releasePatchIfNeeded();
}

INSTANTIATE_TEST_CASE_P(PcmOnlyConfigInputStream, PcmOnlyConfigInputStreamTest,
                        ::testing::ValuesIn(getInputDevicePcmOnlyConfigParameters()),
                        &DeviceConfigParameterToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PcmOnlyConfigInputStreamTest);
+12 −12
Original line number Diff line number Diff line
@@ -110,7 +110,7 @@ std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(bool one
                    if (isOffload) {
                        config.offloadInfo.info(generateOffloadInfo(config.base));
                    }
                    result.emplace_back(device, config, flags);
                    result.emplace_back(device, mixPort.getName(), config, flags);
                    if (oneProfilePerDevice) break;
                }
                if (oneProfilePerDevice) break;
@@ -160,7 +160,7 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters
                        if (isOffload) {
                            config.offloadInfo.info(generateOffloadInfo(validBase));
                        }
                        result.emplace_back(device, config, validFlags);
                        result.emplace_back(device, mixPort.getName(), config, validFlags);
                    }
                    {
                        AudioConfig config{.base = validBase};
@@ -168,7 +168,7 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters
                        if (isOffload) {
                            config.offloadInfo.info(generateOffloadInfo(validBase));
                        }
                        result.emplace_back(device, config, validFlags);
                        result.emplace_back(device, mixPort.getName(), config, validFlags);
                    }
                    if (generateInvalidFlags) {
                        AudioConfig config{.base = validBase};
@@ -176,32 +176,32 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters
                            config.offloadInfo.info(generateOffloadInfo(validBase));
                        }
                        std::vector<AudioInOutFlag> flags = {"random_string", ""};
                        result.emplace_back(device, config, flags);
                        result.emplace_back(device, mixPort.getName(), config, flags);
                    }
                    if (isOffload) {
                        {
                            AudioConfig config{.base = validBase};
                            config.offloadInfo.info(generateOffloadInfo(validBase));
                            config.offloadInfo.info().base.channelMask = "random_string";
                            result.emplace_back(device, config, validFlags);
                            result.emplace_back(device, mixPort.getName(), config, validFlags);
                        }
                        {
                            AudioConfig config{.base = validBase};
                            config.offloadInfo.info(generateOffloadInfo(validBase));
                            config.offloadInfo.info().base.format = "random_string";
                            result.emplace_back(device, config, validFlags);
                            result.emplace_back(device, mixPort.getName(), config, validFlags);
                        }
                        {
                            AudioConfig config{.base = validBase};
                            config.offloadInfo.info(generateOffloadInfo(validBase));
                            config.offloadInfo.info().streamType = "random_string";
                            result.emplace_back(device, config, validFlags);
                            result.emplace_back(device, mixPort.getName(), config, validFlags);
                        }
                        {
                            AudioConfig config{.base = validBase};
                            config.offloadInfo.info(generateOffloadInfo(validBase));
                            config.offloadInfo.info().usage = "random_string";
                            result.emplace_back(device, config, validFlags);
                            result.emplace_back(device, mixPort.getName(), config, validFlags);
                        }
                        hasOffloadConfig = true;
                    } else {
@@ -234,7 +234,7 @@ std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(bool oneP
                auto configs = combineAudioConfig(profile.getChannelMasks(),
                                                  profile.getSamplingRates(), profile.getFormat());
                for (const auto& config : configs) {
                    result.emplace_back(device, config, flags);
                    result.emplace_back(device, mixPort.getName(), config, flags);
                    if (oneProfilePerDevice) break;
                }
                if (oneProfilePerDevice) break;
@@ -285,17 +285,17 @@ const std::vector<DeviceConfigParameter>& getInputDeviceInvalidConfigParameters(
                    {
                        AudioConfig config{.base = validBase};
                        config.base.channelMask = "random_string";
                        result.emplace_back(device, config, validFlags);
                        result.emplace_back(device, mixPort.getName(), config, validFlags);
                    }
                    {
                        AudioConfig config{.base = validBase};
                        config.base.format = "random_string";
                        result.emplace_back(device, config, validFlags);
                        result.emplace_back(device, mixPort.getName(), config, validFlags);
                    }
                    if (generateInvalidFlags) {
                        AudioConfig config{.base = validBase};
                        std::vector<AudioInOutFlag> flags = {"random_string", ""};
                        result.emplace_back(device, config, flags);
                        result.emplace_back(device, mixPort.getName(), config, flags);
                    }
                    hasConfig = true;
                    break;
+215 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading