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

Commit def29f54 authored by Ram Mohan's avatar Ram Mohan
Browse files

Add dynamic policy routing tests

Bug: 258520033
Test: atest audiorouting_tests

Change-Id: I5a7977be600b5b053ae38b5ff139ac3bed8a703d
parent 93df3d56
Loading
Loading
Loading
Loading
+4 −2
Original line number Original line Diff line number Diff line
@@ -617,13 +617,15 @@ status_t getPortById(const audio_port_handle_t portId, audio_port_v7& port) {
}
}


status_t getPortByAttributes(audio_port_role_t role, audio_port_type_t type,
status_t getPortByAttributes(audio_port_role_t role, audio_port_type_t type,
                             audio_devices_t deviceType, audio_port_v7& port) {
                             audio_devices_t deviceType, const std::string& address,
                             audio_port_v7& port) {
    std::vector<struct audio_port_v7> ports;
    std::vector<struct audio_port_v7> ports;
    status_t status = listAudioPorts(ports);
    status_t status = listAudioPorts(ports);
    if (status != OK) return status;
    if (status != OK) return status;
    for (auto i = 0; i < ports.size(); i++) {
    for (auto i = 0; i < ports.size(); i++) {
        if (ports[i].role == role && ports[i].type == type &&
        if (ports[i].role == role && ports[i].type == type &&
            ports[i].ext.device.type == deviceType) {
            ports[i].ext.device.type == deviceType &&
            !strncmp(ports[i].ext.device.address, address.c_str(), AUDIO_DEVICE_MAX_ADDRESS_LEN)) {
            port = ports[i];
            port = ports[i];
            return OK;
            return OK;
        }
        }
+2 −1
Original line number Original line Diff line number Diff line
@@ -54,7 +54,8 @@ status_t parse_audio_policy_configuration_xml(std::vector<std::string>& attached
status_t listAudioPorts(std::vector<audio_port_v7>& portsVec);
status_t listAudioPorts(std::vector<audio_port_v7>& portsVec);
status_t listAudioPatches(std::vector<struct audio_patch>& patchesVec);
status_t listAudioPatches(std::vector<struct audio_patch>& patchesVec);
status_t getPortByAttributes(audio_port_role_t role, audio_port_type_t type,
status_t getPortByAttributes(audio_port_role_t role, audio_port_type_t type,
                             audio_devices_t deviceType, audio_port_v7& port);
                             audio_devices_t deviceType, const std::string& address,
                             audio_port_v7& port);
status_t getPatchForOutputMix(audio_io_handle_t audioIo, audio_patch& patch);
status_t getPatchForOutputMix(audio_io_handle_t audioIo, audio_patch& patch);
status_t getPatchForInputMix(audio_io_handle_t audioIo, audio_patch& patch);
status_t getPatchForInputMix(audio_io_handle_t audioIo, audio_patch& patch);
bool patchContainsOutputDevice(audio_port_handle_t deviceId, audio_patch patch);
bool patchContainsOutputDevice(audio_port_handle_t deviceId, audio_patch patch);
+166 −26
Original line number Original line Diff line number Diff line
@@ -46,10 +46,10 @@ TEST(AudioTrackTest, TestPerformanceMode) {
        attributes.usage = AUDIO_USAGE_MEDIA;
        attributes.usage = AUDIO_USAGE_MEDIA;
        attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
        attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
        attributes.flags = flags[i];
        attributes.flags = flags[i];
        sp<AudioPlayback> ap = sp<AudioPlayback>::make(
        sp<AudioPlayback> ap = sp<AudioPlayback>::make(0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT,
                0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
                                                       AUDIO_CHANNEL_OUT_STEREO,
                AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE, AudioTrack::TRANSFER_OBTAIN,
                                                       AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE,
                &attributes);
                                                       AudioTrack::TRANSFER_OBTAIN, &attributes);
        ASSERT_NE(nullptr, ap);
        ASSERT_NE(nullptr, ap);
        ASSERT_EQ(OK, ap->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
        ASSERT_EQ(OK, ap->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
                << "Unable to open Resource";
                << "Unable to open Resource";
@@ -77,46 +77,186 @@ TEST(AudioTrackTest, TestPerformanceMode) {
    }
    }
}
}


TEST(AudioTrackTest, TestRemoteSubmix) {
TEST(AudioTrackTest, DefaultRoutingTest) {
    std::vector<std::string> attachedDevices;
    audio_port_v7 port;
    std::vector<MixPort> mixPorts;
    if (OK != getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
    std::vector<Route> routes;
                                  AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port)) {
    EXPECT_EQ(OK, parse_audio_policy_configuration_xml(attachedDevices, mixPorts, routes));
        GTEST_SKIP() << "remote submix in device not connected";
    bool hasFlag = false;
    for (int j = 0; j < attachedDevices.size() && !hasFlag; j++) {
        if (attachedDevices[j].find("Remote Submix") != -1) hasFlag = true;
    }
    }
    if (!hasFlag) GTEST_SKIP() << " Device does not have Remote Submix port.";

    sp<AudioCapture> capture = new AudioCapture(AUDIO_SOURCE_REMOTE_SUBMIX, 48000,
    // create record instance
                                                AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO);
    sp<AudioCapture> capture = sp<AudioCapture>::make(
            AUDIO_SOURCE_REMOTE_SUBMIX, 48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO);
    ASSERT_NE(nullptr, capture);
    ASSERT_NE(nullptr, capture);
    ASSERT_EQ(OK, capture->create()) << "record creation failed";
    EXPECT_EQ(OK, capture->create()) << "record creation failed";
    sp<OnAudioDeviceUpdateNotifier> cbCapture = sp<OnAudioDeviceUpdateNotifier>::make();
    EXPECT_EQ(OK, capture->getAudioRecordHandle()->addAudioDeviceCallback(cbCapture));


    // create playback instance
    sp<AudioPlayback> playback = sp<AudioPlayback>::make(
    sp<AudioPlayback> playback = sp<AudioPlayback>::make(
            48000 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
            48000 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
            AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE);
            AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE);
    ASSERT_NE(nullptr, playback);
    ASSERT_NE(nullptr, playback);
    ASSERT_EQ(OK, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
    ASSERT_EQ(OK, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
            << "Unable to open Resource";
            << "Unable to open Resource";
    ASSERT_EQ(OK, playback->create()) << "track creation failed";
    EXPECT_EQ(OK, playback->create()) << "track creation failed";
    sp<OnAudioDeviceUpdateNotifier> cbPlayback = sp<OnAudioDeviceUpdateNotifier>::make();
    EXPECT_EQ(OK, playback->getAudioTrackHandle()->addAudioDeviceCallback(cbPlayback));

    // capture should be routed to submix in port
    EXPECT_EQ(OK, capture->start()) << "start recording failed";
    EXPECT_EQ(OK, cbCapture->waitForAudioDeviceCb());
    EXPECT_EQ(port.id, capture->getAudioRecordHandle()->getRoutedDeviceId())
            << "Capture NOT routed on expected port";

    // capture start should create submix out port
    status_t status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
                                          AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "0", port);
    EXPECT_EQ(OK, status) << "Could not find port";

    // playback should be routed to submix out as long as capture is active
    EXPECT_EQ(OK, playback->start()) << "audio track start failed";
    EXPECT_EQ(OK, cbPlayback->waitForAudioDeviceCb());
    EXPECT_EQ(port.id, playback->getAudioTrackHandle()->getRoutedDeviceId())
            << "Playback NOT routed on expected port";

    capture->stop();
    playback->stop();
}


class AudioRoutingTest : public ::testing::Test {
  public:
    void SetUp() override {
        audio_port_v7 port;
        audio_port_v7 port;
        if (OK != getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
                                      AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port)) {
            GTEST_SKIP() << "remote submix in device not connected";
        }
        uint32_t mixType = MIX_TYPE_PLAYERS;
        uint32_t mixFlag = MIX_ROUTE_FLAG_LOOP_BACK;
        audio_devices_t deviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
        AudioMixMatchCriterion criterion(AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT,
                                         RULE_MATCH_ATTRIBUTE_USAGE);
        std::vector<AudioMixMatchCriterion> criteria{criterion};
        audio_config_t config = AUDIO_CONFIG_INITIALIZER;
        config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
        config.format = AUDIO_FORMAT_PCM_16_BIT;
        config.sample_rate = 48000;
        AudioMix mix(criteria, mixType, config, mixFlag, String8{mAddress.c_str()}, 0);
        mix.mDeviceType = deviceType;
        mMixes.push(mix);
        if (OK == AudioSystem::registerPolicyMixes(mMixes, true)) {
            mPolicyMixRegistered = true;
        }
        ASSERT_TRUE(mPolicyMixRegistered) << "register policy mix failed";
    }

    void TearDown() override {
        if (mPolicyMixRegistered) {
            EXPECT_EQ(OK, AudioSystem::registerPolicyMixes(mMixes, false));
        }
    }

    bool mPolicyMixRegistered{false};
    std::string mAddress{"mix_1"};
    Vector<AudioMix> mMixes;
};

TEST_F(AudioRoutingTest, ConcurrentDynamicRoutingTest) {
    audio_port_v7 port, port_mix;
    // expect legacy submix in port to be connected
    status_t status = getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
    status_t status = getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
                                          AUDIO_DEVICE_IN_REMOTE_SUBMIX, port);
                                          AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port);
    EXPECT_EQ(OK, status) << "Could not find port";
    EXPECT_EQ(OK, status) << "Could not find port";


    EXPECT_EQ(OK, capture->start()) << "start recording failed";
    // as policy mix is registered, expect submix in port with mAddress to be connected
    EXPECT_EQ(port.id, capture->getAudioRecordHandle()->getRoutedDeviceId())
    status = getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
                                 AUDIO_DEVICE_IN_REMOTE_SUBMIX, mAddress, port_mix);
    EXPECT_EQ(OK, status) << "Could not find port";

    // create playback instance
    sp<AudioPlayback> playback = sp<AudioPlayback>::make(
            48000 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
            AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE, AudioTrack::TRANSFER_OBTAIN);
    ASSERT_NE(nullptr, playback);
    ASSERT_EQ(OK, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
            << "Unable to open Resource";
    EXPECT_EQ(OK, playback->create()) << "track creation failed";
    sp<OnAudioDeviceUpdateNotifier> cbPlayback = sp<OnAudioDeviceUpdateNotifier>::make();
    EXPECT_EQ(OK, playback->getAudioTrackHandle()->addAudioDeviceCallback(cbPlayback));

    // create capture instances on different ports
    sp<AudioCapture> captureA = sp<AudioCapture>::make(
            AUDIO_SOURCE_REMOTE_SUBMIX, 48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO);
    ASSERT_NE(nullptr, captureA);
    EXPECT_EQ(OK, captureA->create()) << "record creation failed";
    sp<OnAudioDeviceUpdateNotifier> cbCaptureA = sp<OnAudioDeviceUpdateNotifier>::make();
    EXPECT_EQ(OK, captureA->getAudioRecordHandle()->addAudioDeviceCallback(cbCaptureA));

    audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
    attr.source = AUDIO_SOURCE_REMOTE_SUBMIX;
    sprintf(attr.tags, "addr=%s", mAddress.c_str());
    sp<AudioCapture> captureB = sp<AudioCapture>::make(
            AUDIO_SOURCE_REMOTE_SUBMIX, 48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
            AUDIO_INPUT_FLAG_NONE, AUDIO_SESSION_ALLOCATE, AudioRecord::TRANSFER_CALLBACK, &attr);
    ASSERT_NE(nullptr, captureB);
    EXPECT_EQ(OK, captureB->create()) << "record creation failed";
    sp<OnAudioDeviceUpdateNotifier> cbCaptureB = sp<OnAudioDeviceUpdateNotifier>::make();
    EXPECT_EQ(OK, captureB->getAudioRecordHandle()->addAudioDeviceCallback(cbCaptureB));

    // launch
    EXPECT_EQ(OK, captureA->start()) << "start recording failed";
    EXPECT_EQ(OK, cbCaptureA->waitForAudioDeviceCb());
    EXPECT_EQ(port.id, captureA->getAudioRecordHandle()->getRoutedDeviceId())
            << "Capture NOT routed on expected port";
            << "Capture NOT routed on expected port";


    EXPECT_EQ(OK, captureB->start()) << "start recording failed";
    EXPECT_EQ(OK, cbCaptureB->waitForAudioDeviceCb());
    EXPECT_EQ(port_mix.id, captureB->getAudioRecordHandle()->getRoutedDeviceId())
            << "Capture NOT routed on expected port";

    // as record started, expect submix out ports to be connected
    status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
                                 AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "0", port);
    EXPECT_EQ(OK, status) << "unexpected submix out port found";

    status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
    status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
                                 AUDIO_DEVICE_OUT_REMOTE_SUBMIX, port);
                                 AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mAddress, port_mix);
    EXPECT_EQ(OK, status) << "Could not find port";
    EXPECT_EQ(OK, status) << "Could not find port";


    EXPECT_EQ(OK, playback->start()) << "audio track start failed";
    // check if playback routed to desired port
    EXPECT_EQ(OK, playback->onProcess());
    EXPECT_EQ(OK, playback->start());
    ASSERT_EQ(port.id, playback->getAudioTrackHandle()->getRoutedDeviceId())
    EXPECT_EQ(OK, cbPlayback->waitForAudioDeviceCb());
    EXPECT_EQ(port_mix.id, playback->getAudioTrackHandle()->getRoutedDeviceId())
            << "Playback NOT routed on expected port";
            << "Playback NOT routed on expected port";
    capture->stop();

    captureB->stop();

    // check if mAddress submix out is disconnected as capture session is stopped
    status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
                                 AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mAddress, port_mix);
    EXPECT_NE(OK, status) << "unexpected submix in port found";

    // check if legacy submix out is connected
    status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
                                 AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "0", port);
    EXPECT_EQ(OK, status) << "port not found";

    // unregister policy
    EXPECT_EQ(OK, AudioSystem::registerPolicyMixes(mMixes, false));
    mPolicyMixRegistered = false;

    // as policy mix is unregistered, expect submix in port with mAddress to be disconnected
    status = getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
                                 AUDIO_DEVICE_IN_REMOTE_SUBMIX, mAddress, port_mix);
    EXPECT_NE(OK, status) << "unexpected submix in port found";

    playback->onProcess();
    // as captureA is active, it should re route to legacy submix
    EXPECT_EQ(OK, cbPlayback->waitForAudioDeviceCb(port.id));
    EXPECT_EQ(port.id, playback->getAudioTrackHandle()->getRoutedDeviceId())
            << "Playback NOT routed on expected port";

    captureA->stop();
    playback->stop();
    playback->stop();
}
}