Enable support for main type cap aware demux management

Adding 3 ITuner.aidl APIs:
 - int[] getDemuxIds();
 - IDemux openDemuxById(in int demuxId);
 - DemuxInfo getDemuxInfo(in int demuxId);

And adding DemuxInfo.aidl.

Bug: 239211919
Bug: 239227510
Test: atest VtsHalTvTunerTargetTest

Change-Id: Icd34cc974a6f6fa167d90b69b3ff0a119bf50ae8
This commit is contained in:
Kensuke Miyagi 2022-11-07 10:49:09 -08:00
parent bab42594b2
commit 73b18ac9ab
11 changed files with 276 additions and 19 deletions

View file

@ -0,0 +1,39 @@
/*
* Copyright 2021 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.
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.tv.tuner;
/* @hide */
@VintfStability
parcelable DemuxInfo {
int filterTypes = 0;
}

View file

@ -48,4 +48,7 @@ interface ITuner {
void setMaxNumberOfFrontends(in android.hardware.tv.tuner.FrontendType frontendType, in int maxNumber);
int getMaxNumberOfFrontends(in android.hardware.tv.tuner.FrontendType frontendType);
boolean isLnaSupported();
int[] getDemuxIds();
android.hardware.tv.tuner.IDemux openDemuxById(in int demuxId);
android.hardware.tv.tuner.DemuxInfo getDemuxInfo(in int demuxId);
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2021 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.
*/
package android.hardware.tv.tuner;
import android.hardware.tv.tuner.DemuxFilterMainType;
/**
* Information for the Demux.
* @hide
*/
@VintfStability
parcelable DemuxInfo {
/**
* Bitwise OR of DemuxFilterMainTypes
*/
int filterTypes = DemuxFilterMainType.UNDEFINED;
}

View file

@ -17,6 +17,7 @@
package android.hardware.tv.tuner;
import android.hardware.tv.tuner.DemuxCapabilities;
import android.hardware.tv.tuner.DemuxInfo;
import android.hardware.tv.tuner.FrontendInfo;
import android.hardware.tv.tuner.FrontendType;
import android.hardware.tv.tuner.IDemux;
@ -65,7 +66,7 @@ interface ITuner {
IDemux openDemux(out int[] demuxId);
/**
* Retrieve the Demux's Capabilities.
* Retrieve the system wide Demux's Capabilities
*
* @return the Demux's Capabilities.
*/
@ -158,4 +159,32 @@ interface ITuner {
* @return true if supported, otherwise false
*/
boolean isLnaSupported();
/**
* Get Demux IDs
*
* It is used by the client to get all available demuxes' IDs.
*
* @return an array of IDs for the available Demuxes.
*/
int[] getDemuxIds();
/**
* Create a new instance of Demux given a demuxId.
*
* It is used by the client to create a demux instance.
*
* @param demuxId the id of the demux to be opened.
*
* @return the newly created demux interface.
*/
IDemux openDemuxById(in int demuxId);
/**
* Retrieve the DemuxInfo of the specified Demux.
*
* @param demuxId the demux ID to query the DemuxInfo for.
* @return the DemuxInfo of the specified Demux by demuxId.
*/
DemuxInfo getDemuxInfo(in int demuxId);
}

View file

@ -31,8 +31,12 @@ namespace tuner {
#define WAIT_TIMEOUT 3000000000
Demux::Demux(int32_t demuxId, std::shared_ptr<Tuner> tuner) {
Demux::Demux(int32_t demuxId, uint32_t filterTypes) {
mDemuxId = demuxId;
mFilterTypes = filterTypes;
}
void Demux::setTunerService(std::shared_ptr<Tuner> tuner) {
mTuner = tuner;
}
@ -346,6 +350,22 @@ uint16_t Demux::getFilterTpid(int64_t filterId) {
return mFilters[filterId]->getTpid();
}
int32_t Demux::getDemuxId() {
return mDemuxId;
}
bool Demux::isInUse() {
return mInUse;
}
void Demux::setInUse(bool inUse) {
mInUse = inUse;
}
void Demux::getDemuxInfo(DemuxInfo* demuxInfo) {
*demuxInfo = {.filterTypes = mFilterTypes};
}
void Demux::startFrontendInputLoop() {
ALOGD("[Demux] start frontend on demux");
// Stop current Frontend thread loop first, in case the user starts a new

View file

@ -53,7 +53,7 @@ class Tuner;
class Demux : public BnDemux {
public:
Demux(int32_t demuxId, std::shared_ptr<Tuner> tuner);
Demux(int32_t demuxId, uint32_t filterTypes);
~Demux();
::ndk::ScopedAStatus setFrontendDataSource(int32_t in_frontendId) override;
@ -98,6 +98,12 @@ class Demux : public BnDemux {
void sendFrontendInputToRecord(vector<int8_t> data, uint16_t pid, uint64_t pts);
bool startRecordFilterDispatcher();
void getDemuxInfo(DemuxInfo* demuxInfo);
int32_t getDemuxId();
bool isInUse();
void setInUse(bool inUse);
void setTunerService(std::shared_ptr<Tuner> tuner);
private:
// Tuner service
std::shared_ptr<Tuner> mTuner;
@ -183,6 +189,9 @@ class Demux : public BnDemux {
vector<uint8_t> mPesOutput;
const bool DEBUG_DEMUX = false;
int32_t mFilterTypes;
bool mInUse = false;
};
} // namespace tuner

View file

@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "android.hardware.tv.tuner-service.example-Tuner"
#include <aidl/android/hardware/tv/tuner/DemuxFilterMainType.h>
#include <aidl/android/hardware/tv/tuner/Result.h>
#include <utils/Log.h>
@ -60,6 +61,16 @@ void Tuner::init() {
mMaxUsableFrontends[FrontendType::ISDBS3] = 1;
mMaxUsableFrontends[FrontendType::DTMB] = 1;
mDemuxes[0] =
ndk::SharedRefBase::make<Demux>(0, (static_cast<int32_t>(DemuxFilterMainType::TS) |
static_cast<int32_t>(DemuxFilterMainType::MMTP) |
static_cast<int32_t>(DemuxFilterMainType::TLV)));
mDemuxes[1] =
ndk::SharedRefBase::make<Demux>(1, (static_cast<int32_t>(DemuxFilterMainType::MMTP) |
static_cast<int32_t>(DemuxFilterMainType::TLV)));
mDemuxes[2] = ndk::SharedRefBase::make<Demux>(2, static_cast<int32_t>(DemuxFilterMainType::IP));
mDemuxes[3] = ndk::SharedRefBase::make<Demux>(3, static_cast<int32_t>(DemuxFilterMainType::TS));
mLnbs.resize(2);
mLnbs[0] = ndk::SharedRefBase::make<Lnb>(0);
mLnbs[1] = ndk::SharedRefBase::make<Lnb>(1);
@ -78,6 +89,28 @@ Tuner::~Tuner() {}
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus Tuner::getDemuxInfo(int32_t in_demuxId, DemuxInfo* _aidl_return) {
if (mDemuxes.find(in_demuxId) == mDemuxes.end()) {
return ::ndk::ScopedAStatus::fromServiceSpecificError(
static_cast<int32_t>(Result::INVALID_ARGUMENT));
} else {
mDemuxes[in_demuxId]->getDemuxInfo(_aidl_return);
return ::ndk::ScopedAStatus::ok();
}
}
::ndk::ScopedAStatus Tuner::getDemuxIds(std::vector<int32_t>* _aidl_return) {
ALOGV("%s", __FUNCTION__);
int numOfDemuxes = mDemuxes.size();
_aidl_return->resize(numOfDemuxes);
int i = 0;
for (auto e = mDemuxes.begin(); e != mDemuxes.end(); e++) {
(*_aidl_return)[i++] = e->first;
}
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus Tuner::openFrontendById(int32_t in_frontendId,
std::shared_ptr<IFrontend>* _aidl_return) {
ALOGV("%s", __FUNCTION__);
@ -94,17 +127,49 @@ Tuner::~Tuner() {}
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus Tuner::openDemuxById(int32_t in_demuxId,
std::shared_ptr<IDemux>* _aidl_return) {
ALOGV("%s", __FUNCTION__);
if (mDemuxes.find(in_demuxId) == mDemuxes.end()) {
ALOGW("[ WARN ] Demux with id %d isn't available", in_demuxId);
*_aidl_return = nullptr;
return ::ndk::ScopedAStatus::fromServiceSpecificError(
static_cast<int32_t>(Result::INVALID_ARGUMENT));
}
if (mDemuxes[in_demuxId]->isInUse()) {
return ::ndk::ScopedAStatus::fromServiceSpecificError(
static_cast<int32_t>(Result::UNAVAILABLE));
} else {
mDemuxes[in_demuxId]->setTunerService(this->ref<Tuner>());
mDemuxes[in_demuxId]->setInUse(true);
*_aidl_return = mDemuxes[in_demuxId];
return ::ndk::ScopedAStatus::ok();
}
}
::ndk::ScopedAStatus Tuner::openDemux(std::vector<int32_t>* out_demuxId,
std::shared_ptr<IDemux>* _aidl_return) {
ALOGV("%s", __FUNCTION__);
mLastUsedId += 1;
mDemuxes[mLastUsedId] = ndk::SharedRefBase::make<Demux>(mLastUsedId, this->ref<Tuner>());
bool found = false;
int32_t demuxId = 0;
for (auto e = mDemuxes.begin(); e != mDemuxes.end(); e++) {
if (!e->second->isInUse()) {
found = true;
demuxId = e->second->getDemuxId();
}
}
out_demuxId->push_back(mLastUsedId);
*_aidl_return = mDemuxes[mLastUsedId];
return ::ndk::ScopedAStatus::ok();
if (found) {
out_demuxId->push_back(demuxId);
return openDemuxById(demuxId, _aidl_return);
} else {
return ::ndk::ScopedAStatus::fromServiceSpecificError(
static_cast<int32_t>(Result::UNAVAILABLE));
}
}
::ndk::ScopedAStatus Tuner::getDemuxCaps(DemuxCapabilities* _aidl_return) {
@ -115,6 +180,18 @@ Tuner::~Tuner() {}
// Support time filter testing
_aidl_return->bTimeFilter = true;
// set filterCaps as the bitwize OR of all the demux' caps
std::vector<int32_t> demuxIds;
getDemuxIds(&demuxIds);
int32_t filterCaps = 0;
for (int i = 0; i < demuxIds.size(); i++) {
DemuxInfo demuxInfo;
getDemuxInfo(demuxIds[i], &demuxInfo);
filterCaps |= demuxInfo.filterTypes;
}
_aidl_return->filterCaps = filterCaps;
return ::ndk::ScopedAStatus::ok();
}
@ -250,13 +327,13 @@ void Tuner::removeDemux(int32_t demuxId) {
break;
}
}
mDemuxes.erase(demuxId);
mDemuxes[demuxId]->setInUse(false);
}
void Tuner::removeFrontend(int32_t frontendId) {
map<int32_t, int32_t>::iterator it = mFrontendToDemux.find(frontendId);
if (it != mFrontendToDemux.end()) {
mDemuxes.erase(it->second);
mDemuxes[it->second]->setInUse(false);
}
mFrontendToDemux.erase(frontendId);
}

View file

@ -46,7 +46,11 @@ class Tuner : public BnTuner {
std::shared_ptr<IFrontend>* _aidl_return) override;
::ndk::ScopedAStatus openDemux(std::vector<int32_t>* out_demuxId,
std::shared_ptr<IDemux>* _aidl_return) override;
::ndk::ScopedAStatus openDemuxById(int32_t in_demuxId,
std::shared_ptr<IDemux>* _aidl_return) override;
::ndk::ScopedAStatus getDemuxCaps(DemuxCapabilities* _aidl_return) override;
::ndk::ScopedAStatus getDemuxInfo(int32_t in_demuxId, DemuxInfo* _aidl_return) override;
::ndk::ScopedAStatus getDemuxIds(std::vector<int32_t>* _aidl_return) override;
::ndk::ScopedAStatus openDescrambler(std::shared_ptr<IDescrambler>* _aidl_return) override;
::ndk::ScopedAStatus getFrontendInfo(int32_t in_frontendId,
FrontendInfo* _aidl_return) override;
@ -77,12 +81,10 @@ class Tuner : public BnTuner {
// Static mFrontends array to maintain local frontends information
map<int32_t, std::shared_ptr<Frontend>> mFrontends;
map<int32_t, int32_t> mFrontendToDemux;
map<int32_t, std::shared_ptr<Demux>> mDemuxes;
map<int32_t, std::shared_ptr<Demux>> mDemuxes; // use demuxId as the key in
// this sample implementation
// To maintain how many Frontends we have
int mFrontendSize;
// The last used demux id. Initial value is -1.
// First used id will be 0.
int32_t mLastUsedId = -1;
vector<std::shared_ptr<Lnb>> mLnbs;
map<FrontendType, int32_t> mMaxUsableFrontends;
};

View file

@ -16,6 +16,12 @@
#include "DemuxTests.h"
AssertionResult DemuxTests::getDemuxIds(std::vector<int32_t>& demuxIds) {
ndk::ScopedAStatus status;
status = mService->getDemuxIds(&demuxIds);
return AssertionResult(status.isOk());
}
AssertionResult DemuxTests::openDemux(std::shared_ptr<IDemux>& demux, int32_t& demuxId) {
std::vector<int32_t> id;
auto status = mService->openDemux(&id, &mDemux);
@ -26,6 +32,14 @@ AssertionResult DemuxTests::openDemux(std::shared_ptr<IDemux>& demux, int32_t& d
return AssertionResult(status.isOk());
}
AssertionResult DemuxTests::openDemuxById(int32_t demuxId, std::shared_ptr<IDemux>& demux) {
auto status = mService->openDemuxById(demuxId, &mDemux);
if (status.isOk()) {
demux = mDemux;
}
return AssertionResult(status.isOk());
}
AssertionResult DemuxTests::setDemuxFrontendDataSource(int32_t frontendId) {
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
auto status = mDemux->setFrontendDataSource(frontendId);
@ -33,14 +47,15 @@ AssertionResult DemuxTests::setDemuxFrontendDataSource(int32_t frontendId) {
}
AssertionResult DemuxTests::getDemuxCaps(DemuxCapabilities& demuxCaps) {
if (!mDemux) {
ALOGW("[vts] Test with openDemux first.");
return failure();
}
auto status = mService->getDemuxCaps(&demuxCaps);
return AssertionResult(status.isOk());
}
AssertionResult DemuxTests::getDemuxInfo(int32_t demuxId, DemuxInfo& demuxInfo) {
auto status = mService->getDemuxInfo(demuxId, &demuxInfo);
return AssertionResult(status.isOk());
}
AssertionResult DemuxTests::getAvSyncId(std::shared_ptr<IFilter> filter, int32_t& avSyncHwId) {
EXPECT_TRUE(mDemux) << "Demux is not opened yet.";

View file

@ -17,6 +17,7 @@
#pragma once
#include <aidl/android/hardware/tv/tuner/DemuxCapabilities.h>
#include <aidl/android/hardware/tv/tuner/DemuxInfo.h>
#include <aidl/android/hardware/tv/tuner/IDemux.h>
#include <aidl/android/hardware/tv/tuner/IFilter.h>
#include <aidl/android/hardware/tv/tuner/ITuner.h>
@ -32,11 +33,14 @@ class DemuxTests {
public:
void setService(std::shared_ptr<ITuner> tuner) { mService = tuner; }
AssertionResult getDemuxIds(std::vector<int32_t>& demuxIds);
AssertionResult openDemux(std::shared_ptr<IDemux>& demux, int32_t& demuxId);
AssertionResult openDemuxById(int32_t demuxId, std::shared_ptr<IDemux>& demux);
AssertionResult setDemuxFrontendDataSource(int32_t frontendId);
AssertionResult getAvSyncId(std::shared_ptr<IFilter> filter, int32_t& avSyncHwId);
AssertionResult getAvSyncTime(int32_t avSyncId);
AssertionResult getDemuxCaps(DemuxCapabilities& demuxCaps);
AssertionResult getDemuxInfo(int32_t demuxId, DemuxInfo& demuxInfo);
AssertionResult closeDemux();
protected:

View file

@ -695,6 +695,34 @@ TEST_P(TunerDemuxAidlTest, openDemux) {
}
}
TEST_P(TunerDemuxAidlTest, openDemuxById) {
description("Open (with id) and close a Demux.");
std::vector<int32_t> demuxIds;
ASSERT_TRUE(mDemuxTests.getDemuxIds(demuxIds));
for (int i = 0; i < demuxIds.size(); i++) {
std::shared_ptr<IDemux> demux;
ASSERT_TRUE(mDemuxTests.openDemuxById(demuxIds[i], demux));
ASSERT_TRUE(mDemuxTests.closeDemux());
}
}
TEST_P(TunerDemuxAidlTest, getDemuxInfo) {
description("Check getDemuxInfo against demux caps");
std::vector<int32_t> demuxIds;
ASSERT_TRUE(mDemuxTests.getDemuxIds(demuxIds));
int32_t combinedFilterTypes = 0;
for (int i = 0; i < demuxIds.size(); i++) {
DemuxInfo demuxInfo;
ASSERT_TRUE(mDemuxTests.getDemuxInfo(demuxIds[i], demuxInfo));
combinedFilterTypes |= demuxInfo.filterTypes;
}
if (demuxIds.size() > 0) {
DemuxCapabilities demuxCaps;
ASSERT_TRUE(mDemuxTests.getDemuxCaps(demuxCaps));
ASSERT_TRUE(demuxCaps.filterCaps == combinedFilterTypes);
}
}
TEST_P(TunerDemuxAidlTest, getAvSyncTime) {
description("Get the A/V sync time from a PCR filter.");
if (!live.hasFrontendConnection) {