mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Merge "Add API to get the shared memory Audio/Video handle"
This commit is contained in:
@@ -51,4 +51,23 @@ interface IFilter extends @1.0::IFilter {
|
||||
* UNKNOWN_ERROR if failed for other reasons.
|
||||
*/
|
||||
configureIpCid(uint32_t ipCid) generates (Result result);
|
||||
|
||||
/**
|
||||
* Get the shared AV memory handle. Use IFilter.releaseAvHandle to release the handle.
|
||||
*
|
||||
* When media filters are opened, call this API to initialize the share memory handle if it's
|
||||
* needed.
|
||||
*
|
||||
* If DemuxFilterMediaEvent.avMemory contains file descriptor, share memory should be ignored.
|
||||
*
|
||||
* @return avMemory A handle associated to the shared memory for audio or video.
|
||||
* avMemory.data[0] is normally an fd for ION memory. When the avMemory->numFd is 0, the
|
||||
* share memory is not initialized and does not contain valid fd.
|
||||
* avMemory.data[avMemory.numFds] is an index used as a parameter of
|
||||
* C2DataIdInfo to build C2 buffer in Codec. No C2 buffer would be created if the index
|
||||
* does not exist.
|
||||
* @return avMemSize the size of the shared av memory. It should be ignored when the share
|
||||
* memory is not initialized.
|
||||
*/
|
||||
getAvSharedHandle() generates (Result result, handle avMemory, uint64_t avMemSize);
|
||||
};
|
||||
|
||||
@@ -163,8 +163,17 @@ Return<Result> Filter::flush() {
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
Return<Result> Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t avDataId) {
|
||||
Return<Result> Filter::releaseAvHandle(const hidl_handle& avMemory, uint64_t avDataId) {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
|
||||
if ((avMemory.getNativeHandle()->numFds > 0) &&
|
||||
(mSharedAvMemHandle.getNativeHandle()->numFds > 0) &&
|
||||
(sameFile(avMemory.getNativeHandle()->data[0],
|
||||
mSharedAvMemHandle.getNativeHandle()->data[0]))) {
|
||||
freeSharedAvHandle();
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
if (mDataId2Avfd.find(avDataId) == mDataId2Avfd.end()) {
|
||||
return Result::INVALID_ARGUMENT;
|
||||
}
|
||||
@@ -190,6 +199,35 @@ Return<Result> Filter::configureIpCid(uint32_t ipCid) {
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
Return<void> Filter::getAvSharedHandle(getAvSharedHandle_cb _hidl_cb) {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
|
||||
if (!mIsMediaFilter) {
|
||||
_hidl_cb(Result::INVALID_STATE, NULL, BUFFER_SIZE_16M);
|
||||
return Void();
|
||||
}
|
||||
|
||||
if (mSharedAvMemHandle.getNativeHandle() != nullptr) {
|
||||
_hidl_cb(Result::SUCCESS, mSharedAvMemHandle, BUFFER_SIZE_16M);
|
||||
return Void();
|
||||
}
|
||||
|
||||
int av_fd = createAvIonFd(BUFFER_SIZE_16M);
|
||||
if (av_fd == -1) {
|
||||
_hidl_cb(Result::UNKNOWN_ERROR, NULL, 0);
|
||||
}
|
||||
|
||||
native_handle_t* nativeHandle = createNativeHandle(av_fd);
|
||||
if (nativeHandle == NULL) {
|
||||
_hidl_cb(Result::UNKNOWN_ERROR, NULL, 0);
|
||||
}
|
||||
mSharedAvMemHandle.setTo(nativeHandle, /*shouldOwn=*/true);
|
||||
::close(av_fd);
|
||||
|
||||
_hidl_cb(Result::SUCCESS, mSharedAvMemHandle, BUFFER_SIZE_16M);
|
||||
return Void();
|
||||
}
|
||||
|
||||
bool Filter::createFilterMQ() {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
|
||||
@@ -313,10 +351,19 @@ void Filter::freeAvHandle() {
|
||||
}
|
||||
for (int i = 0; i < mFilterEvent.events.size(); i++) {
|
||||
::close(mFilterEvent.events[i].media().avMemory.getNativeHandle()->data[0]);
|
||||
native_handle_close(mFilterEvent.events[i].media().avMemory.getNativeHandle());
|
||||
native_handle_delete(const_cast<native_handle_t*>(
|
||||
mFilterEvent.events[i].media().avMemory.getNativeHandle()));
|
||||
}
|
||||
}
|
||||
|
||||
void Filter::freeSharedAvHandle() {
|
||||
if (!mIsMediaFilter) {
|
||||
return;
|
||||
}
|
||||
::close(mSharedAvMemHandle.getNativeHandle()->data[0]);
|
||||
native_handle_delete(const_cast<native_handle_t*>(mSharedAvMemHandle.getNativeHandle()));
|
||||
}
|
||||
|
||||
void Filter::maySendFilterStatusCallback() {
|
||||
if (!mIsUsingFMQ) {
|
||||
return;
|
||||
@@ -509,8 +556,8 @@ Result Filter::startMediaFilterHandler() {
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
Result result;
|
||||
if (mPts) {
|
||||
Result result;
|
||||
result = createMediaFilterEventWithIon(mFilterOutput);
|
||||
if (result == Result::SUCCESS) {
|
||||
mFilterOutput.clear();
|
||||
@@ -551,7 +598,10 @@ Result Filter::startMediaFilterHandler() {
|
||||
continue;
|
||||
}
|
||||
|
||||
createMediaFilterEventWithIon(mPesOutput);
|
||||
result = createMediaFilterEventWithIon(mPesOutput);
|
||||
if (result != Result::SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
mFilterOutput.clear();
|
||||
@@ -560,51 +610,14 @@ Result Filter::startMediaFilterHandler() {
|
||||
}
|
||||
|
||||
Result Filter::createMediaFilterEventWithIon(vector<uint8_t> output) {
|
||||
int av_fd = createAvIonFd(output.size());
|
||||
if (av_fd == -1) {
|
||||
return Result::UNKNOWN_ERROR;
|
||||
if (mUsingSharedAvMem) {
|
||||
if (mSharedAvMemHandle.getNativeHandle() == nullptr) {
|
||||
return Result::UNKNOWN_ERROR;
|
||||
}
|
||||
return createShareMemMediaEvents(output);
|
||||
}
|
||||
// copy the filtered data to the buffer
|
||||
uint8_t* avBuffer = getIonBuffer(av_fd, output.size());
|
||||
if (avBuffer == NULL) {
|
||||
return Result::UNKNOWN_ERROR;
|
||||
}
|
||||
memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t));
|
||||
|
||||
native_handle_t* nativeHandle = createNativeHandle(av_fd);
|
||||
if (nativeHandle == NULL) {
|
||||
return Result::UNKNOWN_ERROR;
|
||||
}
|
||||
hidl_handle handle;
|
||||
handle.setTo(nativeHandle, /*shouldOwn=*/true);
|
||||
|
||||
// Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
|
||||
uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
|
||||
mDataId2Avfd[dataId] = dup(av_fd);
|
||||
|
||||
// Create mediaEvent and send callback
|
||||
DemuxFilterMediaEvent mediaEvent;
|
||||
mediaEvent = {
|
||||
.avMemory = std::move(handle),
|
||||
.dataLength = static_cast<uint32_t>(output.size()),
|
||||
.avDataId = dataId,
|
||||
};
|
||||
if (mPts) {
|
||||
mediaEvent.pts = mPts;
|
||||
mPts = 0;
|
||||
}
|
||||
int size = mFilterEvent.events.size();
|
||||
mFilterEvent.events.resize(size + 1);
|
||||
mFilterEvent.events[size].media(mediaEvent);
|
||||
|
||||
// Clear and log
|
||||
output.clear();
|
||||
mAvBufferCopyCount = 0;
|
||||
::close(av_fd);
|
||||
if (DEBUG_FILTER) {
|
||||
ALOGD("[Filter] av data length %d", mediaEvent.dataLength);
|
||||
}
|
||||
return Result::SUCCESS;
|
||||
return createIndependentMediaEvents(output);
|
||||
}
|
||||
|
||||
Result Filter::startRecordFilterHandler() {
|
||||
@@ -713,15 +726,119 @@ uint8_t* Filter::getIonBuffer(int fd, int size) {
|
||||
}
|
||||
|
||||
native_handle_t* Filter::createNativeHandle(int fd) {
|
||||
// Create a native handle to pass the av fd via the callback event.
|
||||
native_handle_t* nativeHandle = native_handle_create(/*numFd*/ 1, 0);
|
||||
native_handle_t* nativeHandle;
|
||||
if (fd < 0) {
|
||||
nativeHandle = native_handle_create(/*numFd*/ 0, 0);
|
||||
} else {
|
||||
// Create a native handle to pass the av fd via the callback event.
|
||||
nativeHandle = native_handle_create(/*numFd*/ 1, 0);
|
||||
}
|
||||
if (nativeHandle == NULL) {
|
||||
ALOGE("[Filter] Failed to create native_handle %d", errno);
|
||||
return NULL;
|
||||
}
|
||||
nativeHandle->data[0] = dup(fd);
|
||||
if (nativeHandle->numFds > 0) {
|
||||
nativeHandle->data[0] = dup(fd);
|
||||
}
|
||||
return nativeHandle;
|
||||
}
|
||||
|
||||
Result Filter::createIndependentMediaEvents(vector<uint8_t> output) {
|
||||
int av_fd = createAvIonFd(output.size());
|
||||
if (av_fd == -1) {
|
||||
return Result::UNKNOWN_ERROR;
|
||||
}
|
||||
// copy the filtered data to the buffer
|
||||
uint8_t* avBuffer = getIonBuffer(av_fd, output.size());
|
||||
if (avBuffer == NULL) {
|
||||
return Result::UNKNOWN_ERROR;
|
||||
}
|
||||
memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t));
|
||||
|
||||
native_handle_t* nativeHandle = createNativeHandle(av_fd);
|
||||
if (nativeHandle == NULL) {
|
||||
return Result::UNKNOWN_ERROR;
|
||||
}
|
||||
hidl_handle handle;
|
||||
handle.setTo(nativeHandle, /*shouldOwn=*/true);
|
||||
|
||||
// Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
|
||||
uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
|
||||
mDataId2Avfd[dataId] = dup(av_fd);
|
||||
|
||||
// Create mediaEvent and send callback
|
||||
DemuxFilterMediaEvent mediaEvent;
|
||||
mediaEvent = {
|
||||
.avMemory = std::move(handle),
|
||||
.dataLength = static_cast<uint32_t>(output.size()),
|
||||
.avDataId = dataId,
|
||||
};
|
||||
if (mPts) {
|
||||
mediaEvent.pts = mPts;
|
||||
mPts = 0;
|
||||
}
|
||||
int size = mFilterEvent.events.size();
|
||||
mFilterEvent.events.resize(size + 1);
|
||||
mFilterEvent.events[size].media(mediaEvent);
|
||||
|
||||
// Clear and log
|
||||
output.clear();
|
||||
mAvBufferCopyCount = 0;
|
||||
::close(av_fd);
|
||||
if (DEBUG_FILTER) {
|
||||
ALOGD("[Filter] av data length %d", mediaEvent.dataLength);
|
||||
}
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
Result Filter::createShareMemMediaEvents(vector<uint8_t> output) {
|
||||
// copy the filtered data to the shared buffer
|
||||
uint8_t* sharedAvBuffer = getIonBuffer(mSharedAvMemHandle.getNativeHandle()->data[0],
|
||||
output.size() + mSharedAvMemOffset);
|
||||
if (sharedAvBuffer == NULL) {
|
||||
return Result::UNKNOWN_ERROR;
|
||||
}
|
||||
memcpy(sharedAvBuffer + mSharedAvMemOffset, output.data(), output.size() * sizeof(uint8_t));
|
||||
|
||||
// Create a memory handle with numFds == 0
|
||||
native_handle_t* nativeHandle = createNativeHandle(-1);
|
||||
if (nativeHandle == NULL) {
|
||||
return Result::UNKNOWN_ERROR;
|
||||
}
|
||||
hidl_handle handle;
|
||||
handle.setTo(nativeHandle, /*shouldOwn=*/true);
|
||||
|
||||
// Create mediaEvent and send callback
|
||||
DemuxFilterMediaEvent mediaEvent;
|
||||
mediaEvent = {
|
||||
.offset = static_cast<uint32_t>(mSharedAvMemOffset),
|
||||
.dataLength = static_cast<uint32_t>(output.size()),
|
||||
.avMemory = handle,
|
||||
};
|
||||
mSharedAvMemOffset += output.size();
|
||||
if (mPts) {
|
||||
mediaEvent.pts = mPts;
|
||||
mPts = 0;
|
||||
}
|
||||
int size = mFilterEvent.events.size();
|
||||
mFilterEvent.events.resize(size + 1);
|
||||
mFilterEvent.events[size].media(mediaEvent);
|
||||
|
||||
// Clear and log
|
||||
output.clear();
|
||||
if (DEBUG_FILTER) {
|
||||
ALOGD("[Filter] shared av data length %d", mediaEvent.dataLength);
|
||||
}
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
bool Filter::sameFile(int fd1, int fd2) {
|
||||
struct stat stat1, stat2;
|
||||
if (fstat(fd1, &stat1) < 0 || fstat(fd2, &stat2) < 0) {
|
||||
return false;
|
||||
}
|
||||
return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
|
||||
}
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
} // namespace tuner
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <ion/ion.h>
|
||||
#include <math.h>
|
||||
#include <sys/stat.h>
|
||||
#include <set>
|
||||
#include "Demux.h"
|
||||
#include "Dvr.h"
|
||||
@@ -43,6 +44,7 @@ using ::android::hardware::MessageQueue;
|
||||
using ::android::hardware::MQDescriptorSync;
|
||||
|
||||
using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
|
||||
const uint32_t BUFFER_SIZE_16M = 0x1000000;
|
||||
|
||||
class Demux;
|
||||
class Dvr;
|
||||
@@ -78,6 +80,8 @@ class Filter : public V1_1::IFilter {
|
||||
|
||||
virtual Return<Result> configureIpCid(uint32_t ipCid) override;
|
||||
|
||||
virtual Return<void> getAvSharedHandle(getAvSharedHandle_cb _hidl_cb) override;
|
||||
|
||||
/**
|
||||
* To create a FilterMQ and its Event Flag.
|
||||
*
|
||||
@@ -93,6 +97,7 @@ class Filter : public V1_1::IFilter {
|
||||
void attachFilterToRecord(const sp<Dvr> dvr);
|
||||
void detachFilterFromRecord();
|
||||
void freeAvHandle();
|
||||
void freeSharedAvHandle();
|
||||
bool isMediaFilter() { return mIsMediaFilter; };
|
||||
bool isPcrFilter() { return mIsPcrFilter; };
|
||||
bool isRecordFilter() { return mIsRecordFilter; };
|
||||
@@ -185,6 +190,9 @@ class Filter : public V1_1::IFilter {
|
||||
uint8_t* getIonBuffer(int fd, int size);
|
||||
native_handle_t* createNativeHandle(int fd);
|
||||
Result createMediaFilterEventWithIon(vector<uint8_t> output);
|
||||
Result createIndependentMediaEvents(vector<uint8_t> output);
|
||||
Result createShareMemMediaEvents(vector<uint8_t> output);
|
||||
bool sameFile(int fd1, int fd2);
|
||||
|
||||
/**
|
||||
* Lock to protect writes to the FMQs
|
||||
@@ -212,6 +220,11 @@ class Filter : public V1_1::IFilter {
|
||||
std::map<uint64_t, int> mDataId2Avfd;
|
||||
uint64_t mLastUsedDataId = 1;
|
||||
int mAvBufferCopyCount = 0;
|
||||
|
||||
// Shared A/V memory handle
|
||||
hidl_handle mSharedAvMemHandle;
|
||||
bool mUsingSharedAvMem = true;
|
||||
uint32_t mSharedAvMemOffset = 0;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
|
||||
@@ -16,22 +16,70 @@
|
||||
|
||||
#include "FilterTests.h"
|
||||
|
||||
bool FilterCallback::readFilterEventData() {
|
||||
bool result = false;
|
||||
ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId);
|
||||
void FilterCallback::testFilterDataOutput() {
|
||||
android::Mutex::Autolock autoLock(mMsgLock);
|
||||
while (mPidFilterOutputCount < 1) {
|
||||
if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
|
||||
EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
|
||||
return;
|
||||
}
|
||||
}
|
||||
mPidFilterOutputCount = 0;
|
||||
ALOGW("[vts] pass and stop");
|
||||
}
|
||||
|
||||
void FilterCallback::readFilterEventData() {
|
||||
ALOGW("[vts] reading filter event");
|
||||
// todo separate filter handlers
|
||||
for (int i = 0; i < mFilterEvent.events.size(); i++) {
|
||||
auto event = mFilterEvent.events[i];
|
||||
switch (event.getDiscriminator()) {
|
||||
case DemuxFilterEvent::Event::hidl_discriminator::media:
|
||||
ALOGD("[vts] Media filter event, avMemHandle numFds=%d.",
|
||||
event.media().avMemory.getNativeHandle()->numFds);
|
||||
dumpAvData(event.media());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < mFilterEventExt.events.size(); i++) {
|
||||
auto eventExt = mFilterEventExt.events[i];
|
||||
switch (eventExt.getDiscriminator()) {
|
||||
case DemuxFilterEventExt::Event::hidl_discriminator::tsRecord:
|
||||
ALOGW("[vts] Extended TS record filter event, pts=%" PRIu64 ".",
|
||||
ALOGD("[vts] Extended TS record filter event, pts=%" PRIu64 ".",
|
||||
eventExt.tsRecord().pts);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) {
|
||||
uint32_t length = event.dataLength;
|
||||
uint32_t offset = event.offset;
|
||||
// read data from buffer pointed by a handle
|
||||
hidl_handle handle = event.avMemory;
|
||||
if (handle.getNativeHandle()->numFds == 0) {
|
||||
if (mAvSharedHandle == NULL) {
|
||||
return false;
|
||||
}
|
||||
handle = mAvSharedHandle;
|
||||
}
|
||||
|
||||
int av_fd = handle.getNativeHandle()->data[0];
|
||||
uint8_t* buffer =
|
||||
static_cast<uint8_t*>(mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0));
|
||||
if (buffer == MAP_FAILED) {
|
||||
ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
|
||||
return false;
|
||||
}
|
||||
uint8_t output[length + 1];
|
||||
memcpy(output, buffer + offset, length);
|
||||
// print buffer and check with golden output.
|
||||
::close(av_fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, uint32_t bufferSize) {
|
||||
@@ -81,6 +129,33 @@ AssertionResult FilterTests::getNewlyOpenedFilterId_64bit(uint64_t& filterId) {
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult FilterTests::getSharedAvMemoryHandle(uint64_t filterId) {
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
|
||||
Result status = Result::UNKNOWN_ERROR;
|
||||
sp<android::hardware::tv::tuner::V1_1::IFilter> filter_v1_1 =
|
||||
android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilters[filterId]);
|
||||
if (filter_v1_1 != NULL) {
|
||||
filter_v1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
|
||||
status = r;
|
||||
if (status == Result::SUCCESS) {
|
||||
mFilterCallbacks[mFilterId]->setSharedHandle(avMemory);
|
||||
mFilterCallbacks[mFilterId]->setMemSize(avMemSize);
|
||||
mAvSharedHandle = avMemory;
|
||||
}
|
||||
});
|
||||
}
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult FilterTests::releaseShareAvHandle(uint64_t filterId) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
|
||||
EXPECT_TRUE(mAvSharedHandle) << "No shared av handle to release.";
|
||||
status = mFilters[filterId]->releaseAvHandle(mAvSharedHandle, 0 /*dataId*/);
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, uint64_t filterId) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
|
||||
@@ -46,6 +46,7 @@ using android::hardware::Return;
|
||||
using android::hardware::Void;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterType;
|
||||
@@ -93,7 +94,14 @@ class FilterCallback : public IFilterCallback {
|
||||
}
|
||||
|
||||
virtual Return<void> onFilterEvent(
|
||||
const android::hardware::tv::tuner::V1_0::DemuxFilterEvent& /*filterEvent*/) override {
|
||||
const android::hardware::tv::tuner::V1_0::DemuxFilterEvent& filterEvent) override {
|
||||
android::Mutex::Autolock autoLock(mMsgLock);
|
||||
// Temprarily we treat the first coming back filter data on the matching pid a success
|
||||
// once all of the MQ are cleared, means we got all the expected output
|
||||
mFilterEvent = filterEvent;
|
||||
readFilterEventData();
|
||||
mPidFilterOutputCount++;
|
||||
mMsgCondition.signal();
|
||||
return Void();
|
||||
}
|
||||
|
||||
@@ -104,8 +112,13 @@ class FilterCallback : public IFilterCallback {
|
||||
void setFilterId(uint32_t filterId) { mFilterId = filterId; }
|
||||
void setFilterInterface(sp<IFilter> filter) { mFilter = filter; }
|
||||
void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
|
||||
void setSharedHandle(hidl_handle sharedHandle) { mAvSharedHandle = sharedHandle; }
|
||||
void setMemSize(uint64_t size) { mAvSharedMemSize = size; }
|
||||
|
||||
bool readFilterEventData();
|
||||
void testFilterDataOutput();
|
||||
|
||||
void readFilterEventData();
|
||||
bool dumpAvData(DemuxFilterMediaEvent event);
|
||||
|
||||
private:
|
||||
uint32_t mFilterId;
|
||||
@@ -114,6 +127,9 @@ class FilterCallback : public IFilterCallback {
|
||||
DemuxFilterEvent mFilterEvent;
|
||||
DemuxFilterEventExt mFilterEventExt;
|
||||
|
||||
hidl_handle mAvSharedHandle = NULL;
|
||||
uint64_t mAvSharedMemSize = -1;
|
||||
|
||||
android::Mutex mMsgLock;
|
||||
android::Mutex mFilterOutputLock;
|
||||
android::Condition mMsgCondition;
|
||||
@@ -127,10 +143,12 @@ class FilterTests {
|
||||
void setDemux(sp<IDemux> demux) { mDemux = demux; }
|
||||
sp<IFilter> getFilterById(uint64_t filterId) { return mFilters[filterId]; }
|
||||
|
||||
std::map<uint64_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }
|
||||
map<uint64_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }
|
||||
|
||||
AssertionResult openFilterInDemux(DemuxFilterType type, uint32_t bufferSize);
|
||||
AssertionResult getNewlyOpenedFilterId_64bit(uint64_t& filterId);
|
||||
AssertionResult getSharedAvMemoryHandle(uint64_t filterId);
|
||||
AssertionResult releaseShareAvHandle(uint64_t filterId);
|
||||
AssertionResult configFilter(DemuxFilterSettings setting, uint64_t filterId);
|
||||
AssertionResult configIpFilterCid(uint32_t ipCid, uint64_t filterId);
|
||||
AssertionResult getFilterMQDescriptor(uint64_t filterId);
|
||||
@@ -193,12 +211,14 @@ class FilterTests {
|
||||
sp<ITuner> mService;
|
||||
sp<IFilter> mFilter;
|
||||
sp<IDemux> mDemux;
|
||||
std::map<uint64_t, sp<IFilter>> mFilters;
|
||||
std::map<uint64_t, sp<FilterCallback>> mFilterCallbacks;
|
||||
map<uint64_t, sp<IFilter>> mFilters;
|
||||
map<uint64_t, sp<FilterCallback>> mFilterCallbacks;
|
||||
|
||||
sp<FilterCallback> mFilterCallback;
|
||||
MQDesc mFilterMQDescriptor;
|
||||
vector<uint64_t> mUsedFilterIds;
|
||||
|
||||
hidl_handle mAvSharedHandle = NULL;
|
||||
|
||||
uint64_t mFilterId = -1;
|
||||
};
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
|
||||
namespace {
|
||||
|
||||
AssertionResult TunerBroadcastHidlTest::filterDataOutputTest() {
|
||||
return filterDataOutputTestBase(mFilterTests);
|
||||
}
|
||||
|
||||
void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf,
|
||||
FrontendConfig frontendConf) {
|
||||
uint32_t feId;
|
||||
@@ -46,6 +50,38 @@ void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf,
|
||||
ASSERT_TRUE(mFrontendTests.closeFrontend());
|
||||
}
|
||||
|
||||
void TunerBroadcastHidlTest::mediaFilterUsingSharedMemoryTest(FilterConfig filterConf,
|
||||
FrontendConfig frontendConf) {
|
||||
uint32_t feId;
|
||||
uint32_t demuxId;
|
||||
sp<IDemux> demux;
|
||||
uint64_t filterId;
|
||||
|
||||
mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
|
||||
ASSERT_TRUE(feId != INVALID_ID);
|
||||
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
|
||||
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
|
||||
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
|
||||
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
|
||||
mFrontendTests.setDemux(demux);
|
||||
mFilterTests.setDemux(demux);
|
||||
ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
|
||||
ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
|
||||
ASSERT_TRUE(mFilterTests.getSharedAvMemoryHandle(filterId));
|
||||
ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
|
||||
ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
|
||||
ASSERT_TRUE(mFilterTests.startFilter(filterId));
|
||||
// tune test
|
||||
ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
|
||||
ASSERT_TRUE(filterDataOutputTest());
|
||||
ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
|
||||
ASSERT_TRUE(mFilterTests.stopFilter(filterId));
|
||||
ASSERT_TRUE(mFilterTests.releaseShareAvHandle(filterId));
|
||||
ASSERT_TRUE(mFilterTests.closeFilter(filterId));
|
||||
ASSERT_TRUE(mDemuxTests.closeDemux());
|
||||
ASSERT_TRUE(mFrontendTests.closeFrontend());
|
||||
}
|
||||
|
||||
void TunerRecordHidlTest::recordSingleFilterTest(FilterConfig filterConf,
|
||||
FrontendConfig frontendConf, DvrConfig dvrConf) {
|
||||
uint32_t feId;
|
||||
@@ -116,6 +152,16 @@ TEST_P(TunerFrontendHidlTest, BlindScanFrontendWithEndFrequency) {
|
||||
mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND);
|
||||
}
|
||||
|
||||
TEST_P(TunerBroadcastHidlTest, MediaFilterWithSharedMemoryHandle) {
|
||||
description("Test the Media Filter with shared memory handle");
|
||||
mediaFilterUsingSharedMemoryTest(filterArray[TS_VIDEO0], frontendArray[DVBT]);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
PerInstance, TunerBroadcastHidlTest,
|
||||
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
|
||||
android::hardware::PrintInstanceNameToString);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
PerInstance, TunerFrontendHidlTest,
|
||||
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
|
||||
|
||||
@@ -26,6 +26,20 @@ void initConfiguration() {
|
||||
initDvrConfig();
|
||||
}
|
||||
|
||||
static AssertionResult success() {
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
AssertionResult filterDataOutputTestBase(FilterTests tests) {
|
||||
// Data Verify Module
|
||||
std::map<uint64_t, sp<FilterCallback>>::iterator it;
|
||||
std::map<uint64_t, sp<FilterCallback>> filterCallbacks = tests.getFilterCallbacks();
|
||||
for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) {
|
||||
it->second->testFilterDataOutput();
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
class TunerFilterHidlTest : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
virtual void SetUp() override {
|
||||
@@ -103,4 +117,34 @@ class TunerFrontendHidlTest : public testing::TestWithParam<std::string> {
|
||||
};
|
||||
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFrontendHidlTest);
|
||||
|
||||
class TunerBroadcastHidlTest : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
virtual void SetUp() override {
|
||||
mService = ITuner::getService(GetParam());
|
||||
ASSERT_NE(mService, nullptr);
|
||||
initConfiguration();
|
||||
|
||||
mFrontendTests.setService(mService);
|
||||
mDemuxTests.setService(mService);
|
||||
mFilterTests.setService(mService);
|
||||
}
|
||||
|
||||
protected:
|
||||
static void description(const std::string& description) {
|
||||
RecordProperty("description", description);
|
||||
}
|
||||
|
||||
sp<ITuner> mService;
|
||||
FrontendTests mFrontendTests;
|
||||
DemuxTests mDemuxTests;
|
||||
FilterTests mFilterTests;
|
||||
|
||||
AssertionResult filterDataOutputTest();
|
||||
|
||||
void mediaFilterUsingSharedMemoryTest(FilterConfig filterConf, FrontendConfig frontendConf);
|
||||
};
|
||||
|
||||
// TODO remove from the allow list once the cf tv target is enabled for testing
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerBroadcastHidlTest);
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user