| /* |
| * Copyright 2020 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 <android-base/logging.h> |
| #include <android/hardware/tv/tuner/1.0/IDvr.h> |
| #include <android/hardware/tv/tuner/1.0/IDvrCallback.h> |
| #include <android/hardware/tv/tuner/1.0/ITuner.h> |
| #include <android/hardware/tv/tuner/1.0/types.h> |
| #include <fcntl.h> |
| #include <fmq/MessageQueue.h> |
| #include <gtest/gtest.h> |
| #include <hidl/HidlSupport.h> |
| #include <hidl/Status.h> |
| #include <utils/Condition.h> |
| #include <utils/Mutex.h> |
| #include <fstream> |
| #include <iostream> |
| #include <map> |
| |
| #include "FilterTests.h" |
| |
| using android::Condition; |
| using android::Mutex; |
| using android::sp; |
| using android::hardware::EventFlag; |
| using android::hardware::kSynchronizedReadWrite; |
| using android::hardware::MessageQueue; |
| using android::hardware::MQDescriptorSync; |
| using android::hardware::Return; |
| using android::hardware::Void; |
| using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; |
| using android::hardware::tv::tuner::V1_0::DvrSettings; |
| using android::hardware::tv::tuner::V1_0::DvrType; |
| using android::hardware::tv::tuner::V1_0::IDvr; |
| using android::hardware::tv::tuner::V1_0::IDvrCallback; |
| using android::hardware::tv::tuner::V1_0::ITuner; |
| using android::hardware::tv::tuner::V1_0::PlaybackSettings; |
| using android::hardware::tv::tuner::V1_0::PlaybackStatus; |
| using android::hardware::tv::tuner::V1_0::RecordSettings; |
| using android::hardware::tv::tuner::V1_0::RecordStatus; |
| using android::hardware::tv::tuner::V1_0::Result; |
| |
| using namespace std; |
| |
| #define WAIT_TIMEOUT 3000000000 |
| |
| class DvrCallback : public IDvrCallback { |
| public: |
| virtual Return<void> onRecordStatus(DemuxFilterStatus status) override { |
| ALOGD("[vts] record status %hhu", status); |
| switch (status) { |
| case DemuxFilterStatus::DATA_READY: |
| break; |
| case DemuxFilterStatus::LOW_WATER: |
| break; |
| case DemuxFilterStatus::HIGH_WATER: |
| case DemuxFilterStatus::OVERFLOW: |
| ALOGD("[vts] record overflow. Flushing."); |
| EXPECT_TRUE(mDvr) << "Dvr callback is not set with an IDvr"; |
| if (mDvr) { |
| Result result = mDvr->flush(); |
| ALOGD("[vts] Flushing result %d.", result); |
| } |
| break; |
| } |
| return Void(); |
| } |
| |
| virtual Return<void> onPlaybackStatus(PlaybackStatus status) override { |
| // android::Mutex::Autolock autoLock(mMsgLock); |
| ALOGD("[vts] playback status %d", status); |
| switch (status) { |
| case PlaybackStatus::SPACE_EMPTY: |
| case PlaybackStatus::SPACE_ALMOST_EMPTY: |
| ALOGD("[vts] keep playback inputing %d", status); |
| mKeepWritingPlaybackFMQ = true; |
| break; |
| case PlaybackStatus::SPACE_ALMOST_FULL: |
| case PlaybackStatus::SPACE_FULL: |
| ALOGD("[vts] stop playback inputing %d", status); |
| mKeepWritingPlaybackFMQ = false; |
| break; |
| } |
| return Void(); |
| } |
| |
| void stopPlaybackThread(); |
| void testRecordOutput(); |
| void stopRecordThread(); |
| |
| void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings, |
| MQDesc& playbackMQDescriptor); |
| void startRecordOutputThread(RecordSettings recordSettings, MQDesc& recordMQDescriptor); |
| static void* __threadLoopPlayback(void* user); |
| static void* __threadLoopRecord(void* threadArgs); |
| void playbackThreadLoop(); |
| void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ); |
| |
| bool readRecordFMQ(); |
| |
| void setDvr(sp<IDvr> dvr) { mDvr = dvr; } |
| |
| private: |
| struct RecordThreadArgs { |
| DvrCallback* user; |
| RecordSettings* recordSettings; |
| bool* keepReadingRecordFMQ; |
| }; |
| // uint16_t mDataLength = 0; |
| std::vector<uint8_t> mDataOutputBuffer; |
| |
| std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterMQ; |
| std::unique_ptr<FilterMQ> mPlaybackMQ; |
| std::unique_ptr<FilterMQ> mRecordMQ; |
| std::map<uint32_t, EventFlag*> mFilterMQEventFlag; |
| |
| android::Mutex mMsgLock; |
| android::Mutex mPlaybackThreadLock; |
| android::Mutex mRecordThreadLock; |
| android::Condition mMsgCondition; |
| |
| bool mKeepWritingPlaybackFMQ = true; |
| bool mKeepReadingRecordFMQ = true; |
| bool mPlaybackThreadRunning; |
| bool mRecordThreadRunning; |
| pthread_t mPlaybackThread; |
| pthread_t mRecordThread; |
| string mInputDataFile; |
| PlaybackSettings mPlaybackSettings; |
| |
| sp<IDvr> mDvr = nullptr; |
| |
| // int mPidFilterOutputCount = 0; |
| }; |
| |
| class DvrTests { |
| public: |
| void setService(sp<ITuner> tuner) { mService = tuner; } |
| void setDemux(sp<IDemux> demux) { mDemux = demux; } |
| |
| void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings) { |
| mDvrPlaybackCallback->startPlaybackInputThread(dataInputFile, settings, |
| mDvrPlaybackMQDescriptor); |
| }; |
| |
| void startRecordOutputThread(RecordSettings settings) { |
| mDvrRecordCallback->startRecordOutputThread(settings, mDvrRecordMQDescriptor); |
| }; |
| |
| void stopPlaybackThread() { mDvrPlaybackCallback->stopPlaybackThread(); } |
| void testRecordOutput() { mDvrRecordCallback->testRecordOutput(); } |
| void stopRecordThread() { mDvrRecordCallback->stopRecordThread(); } |
| |
| AssertionResult openDvrInDemux(DvrType type, uint32_t bufferSize); |
| AssertionResult configDvrPlayback(DvrSettings setting); |
| AssertionResult configDvrRecord(DvrSettings setting); |
| AssertionResult getDvrPlaybackMQDescriptor(); |
| AssertionResult getDvrRecordMQDescriptor(); |
| AssertionResult attachFilterToDvr(sp<IFilter> filter); |
| AssertionResult detachFilterToDvr(sp<IFilter> filter); |
| AssertionResult stopDvrPlayback(); |
| AssertionResult startDvrPlayback(); |
| AssertionResult stopDvrRecord(); |
| AssertionResult startDvrRecord(); |
| void closeDvrPlayback(); |
| void closeDvrRecord(); |
| |
| protected: |
| static AssertionResult failure() { return ::testing::AssertionFailure(); } |
| |
| static AssertionResult success() { return ::testing::AssertionSuccess(); } |
| |
| sp<ITuner> mService; |
| sp<IDvr> mDvrPlayback; |
| sp<IDvr> mDvrRecord; |
| sp<IDemux> mDemux; |
| sp<DvrCallback> mDvrPlaybackCallback; |
| sp<DvrCallback> mDvrRecordCallback; |
| MQDesc mDvrPlaybackMQDescriptor; |
| MQDesc mDvrRecordMQDescriptor; |
| }; |