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

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

Snap for 6110375 from 60e7d69f to rvc-release

Change-Id: I6f60c077d6bed8605ce5d1069833ef0fa09dfeb0
parents f8d6a2a8 60e7d69f
Loading
Loading
Loading
Loading
+200 −168
Original line number Diff line number Diff line
@@ -131,6 +131,25 @@ static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
    return !strncmp(s.c_str(), comp, N - 1);
}

static inline bool startsWith(const std::string& s, const std::string& comp) {
    return !strncmp(s.c_str(), comp.c_str(), comp.size() - 1);
}

/**
 * Defers a function to run in the destructor.
 *
 * This helper class is used to log results on exit of a method.
 */
class Defer {
public:
    template <typename U>
    Defer(U &&f) : mThunk(std::forward<U>(f)) {}
    ~Defer() { mThunk(); }

private:
    const std::function<void()> mThunk;
};

/**
 * Media Metrics BaseItem
 *
@@ -616,9 +635,167 @@ private:
 *
 * The Item is designed for the service as it has getters.
 */
class Item : public mediametrics::BaseItem {
class Item final : public mediametrics::BaseItem {
public:

    class Prop {
    public:
        using Elem = std::variant<
                std::monostate,               // kTypeNone
                int32_t,                      // kTypeInt32
                int64_t,                      // kTypeInt64
                double,                       // kTypeDouble
                std::string,                  // kTypeCString
                std::pair<int64_t, int64_t>   // kTypeRate
                >;

        Prop() = default;
        Prop(const Prop& other) {
           *this = other;
        }
        Prop& operator=(const Prop& other) {
            mName = other.mName;
            mElem = other.mElem;
            return *this;
        }
        Prop(Prop&& other) {
            *this = std::move(other);
        }
        Prop& operator=(Prop&& other) {
            mName = std::move(other.mName);
            mElem = std::move(other.mElem);
            return *this;
        }

        bool operator==(const Prop& other) const {
            return mName == other.mName && mElem == other.mElem;
        }
        bool operator!=(const Prop& other) const {
            return !(*this == other);
        }

        void clear() {
            mName.clear();
            mElem = std::monostate{};
        }
        void clearValue() {
            mElem = std::monostate{};
        }

        const char *getName() const {
            return mName.c_str();
        }

        void swap(Prop& other) {
            std::swap(mName, other.mName);
            std::swap(mElem, other.mElem);
        }

        void setName(const char *name) {
            mName = name;
        }

        bool isNamed(const char *name) const {
            return mName == name;
        }

        template <typename T> void visit(T f) const {
            std::visit(f, mElem);
        }

        template <typename T> bool get(T *value) const {
            auto pval = std::get_if<T>(&mElem);
            if (pval != nullptr) {
                *value = *pval;
                return true;
            }
            return false;
        }

        const Elem& get() const {
            return mElem;
        }

        template <typename T> void set(const T& value) {
            mElem = value;
        }

        template <typename T> void add(const T& value) {
            auto pval = std::get_if<T>(&mElem);
            if (pval != nullptr) {
                *pval += value;
            } else {
                mElem = value;
            }
        }

        template <> void add(const std::pair<int64_t, int64_t>& value) {
            auto pval = std::get_if<std::pair<int64_t, int64_t>>(&mElem);
            if (pval != nullptr) {
                pval->first += value.first;
                pval->second += value.second;
            } else {
                mElem = value;
            }
        }

        status_t writeToParcel(Parcel *parcel) const {
            return std::visit([this, parcel](auto &value) {
                    return BaseItem::writeToParcel(mName.c_str(), value, parcel);}, mElem);
        }

        void toStringBuffer(char *buffer, size_t length) const {
            return std::visit([this, buffer, length](auto &value) {
                BaseItem::toStringBuffer(mName.c_str(), value, buffer, length);}, mElem);
        }

        size_t getByteStringSize() const {
            return std::visit([this](auto &value) {
                return BaseItem::sizeOfByteString(mName.c_str(), value);}, mElem);
        }

        status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const {
            return std::visit([this, bufferpptr, bufferptrmax](auto &value) {
                return BaseItem::writeToByteString(mName.c_str(), value, bufferpptr, bufferptrmax);
            }, mElem);
        }

        status_t readFromParcel(const Parcel& data);

        status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);

    private:
        std::string mName;
        Elem mElem;
    };

    // Iteration of props within item
    class iterator {
    public:
        iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
        iterator &operator++() {
            ++it;
            return *this;
        }
        bool operator!=(iterator &other) const {
            return it != other.it;
        }
        const Prop &operator*() const {
            return it->second;
        }

    private:
        std::map<std::string, Prop>::const_iterator it;
    };

    iterator begin() const {
        return iterator(mProps.cbegin());
    }

    iterator end() const {
        return iterator(mProps.cend());
    }

        enum {
            PROTO_V0 = 0,
            PROTO_FIRST = PROTO_V0,
@@ -632,15 +809,22 @@ public:
        : mKey(key) { }
    Item() = default;

    // We enable default copy and move constructors and make this class final
    // to prevent a derived class; this avoids possible data slicing.
    Item(const Item& other) = default;
    Item(Item&& other) = default;
    Item& operator=(const Item& other) = default;
    Item& operator=(Item&& other) = default;

    bool operator==(const Item& other) const {
        if (mPid != other.mPid
            || mUid != other.mUid
            || mPkgName != other.mPkgName
            || mPkgVersionCode != other.mPkgVersionCode
            || mKey != other.mKey
            || mTimestamp != other.mTimestamp
            || mProps != other.mProps) return false;
         return true;
        return mPid == other.mPid
            && mUid == other.mUid
            && mPkgName == other.mPkgName
            && mPkgVersionCode == other.mPkgVersionCode
            && mKey == other.mKey
            && mTimestamp == other.mTimestamp
            && mProps == other.mProps
            ;
    }
    bool operator!=(const Item& other) const {
        return !(*this == other);
@@ -770,6 +954,11 @@ public:
        return get(key, value);
    }

    const Prop::Elem* get(const char *key) const {
        const Prop *prop = findProp(key);
        return prop == nullptr ? nullptr : &prop->get();
    }

        // Deliver the item to MediaMetrics
        bool selfrecord();

@@ -820,164 +1009,6 @@ private:
    int32_t writeToParcel0(Parcel *) const;
    int32_t readFromParcel0(const Parcel&);

public:

    class Prop {
    public:
        using Elem = std::variant<
                std::monostate,               // kTypeNone
                int32_t,                      // kTypeInt32
                int64_t,                      // kTypeInt64
                double,                       // kTypeDouble
                std::string,                  // kTypeCString
                std::pair<int64_t, int64_t>   // kTypeRate
                >;

        Prop() = default;
        Prop(const Prop& other) {
           *this = other;
        }
        Prop& operator=(const Prop& other) {
            mName = other.mName;
            mElem = other.mElem;
            return *this;
        }
        Prop(Prop&& other) {
            *this = std::move(other);
        }
        Prop& operator=(Prop&& other) {
            mName = std::move(other.mName);
            mElem = std::move(other.mElem);
            return *this;
        }

        bool operator==(const Prop& other) const {
            return mName == other.mName && mElem == other.mElem;
        }
        bool operator!=(const Prop& other) const {
            return !(*this == other);
        }

        void clear() {
            mName.clear();
            mElem = std::monostate{};
        }
        void clearValue() {
            mElem = std::monostate{};
        }

        const char *getName() const {
            return mName.c_str();
        }

        void swap(Prop& other) {
            std::swap(mName, other.mName);
            std::swap(mElem, other.mElem);
        }

        void setName(const char *name) {
            mName = name;
        }

        bool isNamed(const char *name) const {
            return mName == name;
        }

        template <typename T> void visit(T f) const {
            std::visit(f, mElem);
        }

        template <typename T> bool get(T *value) const {
            auto pval = std::get_if<T>(&mElem);
            if (pval != nullptr) {
                *value = *pval;
                return true;
            }
            return false;
        }

        template <typename T> void set(const T& value) {
            mElem = value;
        }

        template <typename T> void add(const T& value) {
            auto pval = std::get_if<T>(&mElem);
            if (pval != nullptr) {
                *pval += value;
            } else {
                mElem = value;
            }
        }

        template <> void add(const std::pair<int64_t, int64_t>& value) {
            auto pval = std::get_if<std::pair<int64_t, int64_t>>(&mElem);
            if (pval != nullptr) {
                pval->first += value.first;
                pval->second += value.second;
            } else {
                mElem = value;
            }
        }

        status_t writeToParcel(Parcel *parcel) const {
            return std::visit([this, parcel](auto &value) {
                    return BaseItem::writeToParcel(mName.c_str(), value, parcel);}, mElem);
        }

        void toStringBuffer(char *buffer, size_t length) const {
            return std::visit([this, buffer, length](auto &value) {
                BaseItem::toStringBuffer(mName.c_str(), value, buffer, length);}, mElem);
        }

        size_t getByteStringSize() const {
            return std::visit([this](auto &value) {
                return BaseItem::sizeOfByteString(mName.c_str(), value);}, mElem);
        }

        status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const {
            return std::visit([this, bufferpptr, bufferptrmax](auto &value) {
                return BaseItem::writeToByteString(mName.c_str(), value, bufferpptr, bufferptrmax);
            }, mElem);
        }

        status_t readFromParcel(const Parcel& data);

        status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);

    private:
        std::string mName;
        Elem mElem;
    };

    // Iteration of props within item
    class iterator {
    public:
        iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
        iterator &operator++() {
            ++it;
            return *this;
        }
        bool operator!=(iterator &other) const {
            return it != other.it;
        }
        const Prop &operator*() const {
            return it->second;
        }

    private:
        std::map<std::string, Prop>::const_iterator it;
    };

    iterator begin() const {
        return iterator(mProps.cbegin());
    }

    iterator end() const {
        return iterator(mProps.cend());
    }

private:

    const Prop *findProp(const char *key) const {
        auto it = mProps.find(key);
        return it != mProps.end() ? &it->second : nullptr;
@@ -991,6 +1022,7 @@ private:
        return prop;
    }

    // Changes to member variables below require changes to clear().
    pid_t         mPid = -1;
    uid_t         mUid = -1;
    std::string   mPkgName;
+72 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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.
 */

#ifndef __AMRWBDEC_TEST_ENVIRONMENT_H__
#define __AMRWBDEC_TEST_ENVIRONMENT_H__

#include <gtest/gtest.h>

#include <getopt.h>

using namespace std;

class AmrwbDecTestEnvironment : public ::testing::Environment {
  public:
    AmrwbDecTestEnvironment() : res("/data/local/tmp/") {}

    // Parses the command line arguments
    int initFromOptions(int argc, char **argv);

    void setRes(const char *_res) { res = _res; }

    const string getRes() const { return res; }

  private:
    string res;
};

int AmrwbDecTestEnvironment::initFromOptions(int argc, char **argv) {
    static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};

    while (true) {
        int index = 0;
        int c = getopt_long(argc, argv, "P:", options, &index);
        if (c == -1) {
            break;
        }

        switch (c) {
            case 'P':
                setRes(optarg);
                break;
            default:
                break;
        }
    }

    if (optind < argc) {
        fprintf(stderr,
                "unrecognized option: %s\n\n"
                "usage: %s <gtest options> <test options>\n\n"
                "test options are:\n\n"
                "-P, --path: Resource files directory location\n",
                argv[optind ?: 1], argv[0]);
        return 2;
    }
    return 0;
}

#endif  // __AMRWBDEC_TEST_ENVIRONMENT_H__
+223 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "AmrwbDecoderTest"
#define OUTPUT_FILE "/data/local/tmp/amrwbDecode.out"

#include <utils/Log.h>

#include <audio_utils/sndfile.h>
#include <stdio.h>

#include "pvamrwbdecoder.h"
#include "pvamrwbdecoder_api.h"

#include "AmrwbDecTestEnvironment.h"

// Constants for AMR-WB.
constexpr int32_t kInputBufferSize = 64;
constexpr int32_t kSamplesPerFrame = 320;
constexpr int32_t kBitsPerSample = 16;
constexpr int32_t kSampleRate = 16000;
constexpr int32_t kChannels = 1;
constexpr int32_t kMaxSourceDataUnitSize = KAMRWB_NB_BITS_MAX * sizeof(int16_t);
constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
const int32_t kFrameSizes[16] = {17, 23, 32, 36, 40, 46, 50, 58, 60, -1, -1, -1, -1, -1, -1, -1};
constexpr int32_t kNumFrameReset = 150;

constexpr int32_t kMaxCount = 10;

static AmrwbDecTestEnvironment *gEnv = nullptr;

class AmrwbDecoderTest : public ::testing::TestWithParam<string> {
  public:
    AmrwbDecoderTest() : mFpInput(nullptr) {}

    ~AmrwbDecoderTest() {
        if (mFpInput) {
            fclose(mFpInput);
            mFpInput = nullptr;
        }
    }

    FILE *mFpInput;
    int32_t DecodeFrames(int16_t *decoderCookie, void *decoderBuf, SNDFILE *outFileHandle,
                         int32_t frameCount = INT32_MAX);
    SNDFILE *openOutputFile(SF_INFO *sfInfo);
};

SNDFILE *AmrwbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
    memset(sfInfo, 0, sizeof(SF_INFO));
    sfInfo->channels = kChannels;
    sfInfo->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
    sfInfo->samplerate = kSampleRate;
    SNDFILE *outFileHandle = sf_open(OUTPUT_FILE, SFM_WRITE, sfInfo);
    return outFileHandle;
}

int32_t AmrwbDecoderTest::DecodeFrames(int16_t *decoderCookie, void *decoderBuf,
                                       SNDFILE *outFileHandle, int32_t frameCount) {
    uint8_t inputBuf[kInputBufferSize];
    int16_t inputSampleBuf[kMaxSourceDataUnitSize];
    int16_t outputBuf[kOutputBufferSize];

    while (frameCount > 0) {
        uint8_t modeByte;
        int32_t bytesRead = fread(&modeByte, 1, 1, mFpInput);
        if (bytesRead != 1) break;

        int16 mode = ((modeByte >> 3) & 0x0f);
        if (mode >= 9) {
            // Produce silence for comfort noise, speech lost and no data.
            int32_t outputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
            memset(outputBuf, 0, outputBufferSize);
        } else {
            // Read rest of the frame.
            int32_t frameSize = kFrameSizes[mode];
            // AMR-WB file format cannot have mode 10, 11, 12 and 13.
            if (frameSize < 0) {
                ALOGE("Illegal frame mode");
                return -1;
            }
            bytesRead = fread(inputBuf, 1, frameSize, mFpInput);
            if (bytesRead != frameSize) break;

            int16 frameMode = mode;
            int16 frameType;
            RX_State_wb rx_state;
            mime_unsorting(inputBuf, inputSampleBuf, &frameType, &frameMode, 1, &rx_state);

            int16_t numSamplesOutput;
            pvDecoder_AmrWb(frameMode, inputSampleBuf, outputBuf, &numSamplesOutput, decoderBuf,
                            frameType, decoderCookie);
            if (numSamplesOutput != kSamplesPerFrame) {
                ALOGE("Failed to decode the input file");
                return -1;
            }
            for (int count = 0; count < kSamplesPerFrame; ++count) {
                /* Delete the 2 LSBs (14-bit output) */
                outputBuf[count] &= 0xfffc;
            }
        }
        sf_writef_short(outFileHandle, outputBuf, kSamplesPerFrame / kChannels);
        frameCount--;
    }
    return 0;
}

TEST_F(AmrwbDecoderTest, MultiCreateAmrwbDecoderTest) {
    uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
    void *decoderBuf = malloc(memRequirements);
    ASSERT_NE(decoderBuf, nullptr)
            << "Failed to allocate decoder memory of size " << memRequirements;

    // Create AMR-WB decoder instance.
    void *amrHandle = nullptr;
    int16_t *decoderCookie;
    for (int count = 0; count < kMaxCount; count++) {
        pvDecoder_AmrWb_Init(&amrHandle, decoderBuf, &decoderCookie);
        ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
        ALOGV("Decoder created successfully");
    }
    if (decoderBuf) {
        free(decoderBuf);
        decoderBuf = nullptr;
    }
}

TEST_P(AmrwbDecoderTest, DecodeTest) {
    uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
    void *decoderBuf = malloc(memRequirements);
    ASSERT_NE(decoderBuf, nullptr)
            << "Failed to allocate decoder memory of size " << memRequirements;

    void *amrHandle = nullptr;
    int16_t *decoderCookie;
    pvDecoder_AmrWb_Init(&amrHandle, decoderBuf, &decoderCookie);
    ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";

    string inputFile = gEnv->getRes() + GetParam();
    mFpInput = fopen(inputFile.c_str(), "rb");
    ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;

    // Open the output file.
    SF_INFO sfInfo;
    SNDFILE *outFileHandle = openOutputFile(&sfInfo);
    ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";

    int32_t decoderErr = DecodeFrames(decoderCookie, decoderBuf, outFileHandle);
    ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";

    sf_close(outFileHandle);
    if (decoderBuf) {
        free(decoderBuf);
        decoderBuf = nullptr;
    }
}

TEST_P(AmrwbDecoderTest, ResetDecoderTest) {
    uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
    void *decoderBuf = malloc(memRequirements);
    ASSERT_NE(decoderBuf, nullptr)
            << "Failed to allocate decoder memory of size " << memRequirements;

    void *amrHandle = nullptr;
    int16_t *decoderCookie;
    pvDecoder_AmrWb_Init(&amrHandle, decoderBuf, &decoderCookie);
    ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";

    string inputFile = gEnv->getRes() + GetParam();
    mFpInput = fopen(inputFile.c_str(), "rb");
    ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;

    // Open the output file.
    SF_INFO sfInfo;
    SNDFILE *outFileHandle = openOutputFile(&sfInfo);
    ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";

    // Decode 150 frames first
    int32_t decoderErr = DecodeFrames(decoderCookie, decoderBuf, outFileHandle, kNumFrameReset);
    ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";

    // Reset Decoder
    pvDecoder_AmrWb_Reset(decoderBuf, 1);

    // Start decoding again
    decoderErr = DecodeFrames(decoderCookie, decoderBuf, outFileHandle);
    ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";

    sf_close(outFileHandle);
    if (decoderBuf) {
        free(decoderBuf);
    }
}

INSTANTIATE_TEST_SUITE_P(AmrwbDecoderTestAll, AmrwbDecoderTest,
                         ::testing::Values(("bbb_amrwb_1ch_14kbps_16000hz.amrwb"),
                                           ("bbb_16000hz_1ch_9kbps_amrwb_30sec.amrwb")));

int main(int argc, char **argv) {
    gEnv = new AmrwbDecTestEnvironment();
    ::testing::AddGlobalTestEnvironment(gEnv);
    ::testing::InitGoogleTest(&argc, argv);
    int status = gEnv->initFromOptions(argc, argv);
    if (status == 0) {
        status = RUN_ALL_TESTS();
        ALOGV("Test result = %d\n", status);
    }
    return status;
}
+47 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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.
 */

cc_test {
    name: "AmrwbDecoderTest",
    gtest: true,

    srcs: [
        "AmrwbDecoderTest.cpp",
    ],

    static_libs: [
        "libstagefright_amrwbdec",
        "libsndfile",
        "libaudioutils",
    ],

    shared_libs: [
        "liblog",
    ],

    cflags: [
        "-Werror",
        "-Wall",
    ],

    sanitize: {
        cfi: true,
        misc_undefined: [
            "unsigned-integer-overflow",
            "signed-integer-overflow",
        ],
    },
}
+34 −0
Original line number Diff line number Diff line
## Media Testing ##
---
#### AMR-WB Decoder :
The Amr-Wb Decoder Test Suite validates the amrwb decoder available in libstagefright.

Run the following steps to build the test suite:
```
m AmrwbDecoderTest
```

The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/

The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/

To test 64-bit binary push binaries from nativetest64.
```
adb push ${OUT}/data/nativetest64/AmrwbDecoderTest/AmrwbDecoderTest /data/local/tmp/
```

To test 32-bit binary push binaries from nativetest.
```
adb push ${OUT}/data/nativetest/AmrwbDecoderTest/AmrwbDecoderTest /data/local/tmp/
```

The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b). Push these files into device for testing.
Download amr-wb folder and push all the files in this folder to /data/local/tmp/ on the device.
```
adb push amr-wb/. /data/local/tmp/
```

usage: AmrwbDecoderTest -P \<path_to_folder\>
```
adb shell /data/local/tmp/AmrwbDecoderTest -P /data/local/tmp/
```
Loading