/*
* Copyright (C) 2017 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_TAG "BroadcastRadioDefault.module"
#define LOG_NDEBUG 0
#include "BroadcastRadio.h"
#include <log/log.h>
#include "resources.h"
namespace android {
namespace hardware {
namespace broadcastradio {
namespace V1_1 {
namespace implementation {
using V1_0::Band;
using V1_0::BandConfig;
using V1_0::Class;
using V1_0::Deemphasis;
using V1_0::Rds;
using V1_1::IdentifierType;
using V1_1::ProgramSelector;
using V1_1::ProgramType;
using V1_1::Properties;
using V1_1::VendorKeyValue;
using std::lock_guard;
using std::map;
using std::mutex;
using std::vector;
// clang-format off
static const map<Class, ModuleConfig> gModuleConfigs{
{Class::AM_FM, ModuleConfig({
"Digital radio mock",
{ // amFmBands
AmFmBandConfig({
Band::AM,
153, // lowerLimit
26100, // upperLimit
{5, 9, 10}, // spacings
}),
AmFmBandConfig({
Band::FM,
65800, // lowerLimit
108000, // upperLimit
{10, 100, 200}, // spacings
}),
AmFmBandConfig({
Band::AM_HD,
153, // lowerLimit
26100, // upperLimit
{5, 9, 10}, // spacings
}),
AmFmBandConfig({
Band::FM_HD,
87700, // lowerLimit
107900, // upperLimit
{200}, // spacings
}),
},
})},
{Class::SAT, ModuleConfig({
"Satellite radio mock",
{}, // amFmBands
})},
};
// clang-format on
BroadcastRadio::BroadcastRadio(Class classId)
: mClassId(classId), mConfig(gModuleConfigs.at(classId)) {}
bool BroadcastRadio::isSupported(Class classId) {
return gModuleConfigs.find(classId) != gModuleConfigs.end();
}
Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) {
ALOGV("%s", __func__);
return getProperties_1_1(
[&](const Properties& properties) { _hidl_cb(Result::OK, properties.base); });
}
Return<void> BroadcastRadio::getProperties_1_1(getProperties_1_1_cb _hidl_cb) {
ALOGV("%s", __func__);
Properties prop11 = {};
auto& prop10 = prop11.base;
prop10.classId = mClassId;
prop10.implementor = "Google";
prop10.product = mConfig.productName;
prop10.numTuners = 1;
prop10.numAudioSources = 1;
prop10.supportsCapture = false;
prop11.supportsBackgroundScanning = true;
prop11.supportedProgramTypes = hidl_vec<uint32_t>({
static_cast<uint32_t>(ProgramType::AM), static_cast<uint32_t>(ProgramType::FM),
static_cast<uint32_t>(ProgramType::AM_HD), static_cast<uint32_t>(ProgramType::FM_HD),
});
prop11.supportedIdentifierTypes = hidl_vec<uint32_t>({
static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY),
static_cast<uint32_t>(IdentifierType::RDS_PI),
static_cast<uint32_t>(IdentifierType::HD_STATION_ID_EXT),
static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL),
});
prop11.vendorInfo = hidl_vec<VendorKeyValue>({
{"com.google.dummy", "dummy"},
});
prop10.bands = getAmFmBands();
_hidl_cb(prop11);
return Void();
}
Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio __unused,
const sp<V1_0::ITunerCallback>& callback,
openTuner_cb _hidl_cb) {
ALOGV("%s(%s)", __func__, toString(config.type).c_str());
lock_guard<mutex> lk(mMut);
auto oldTuner = mTuner.promote();
if (oldTuner != nullptr) {
ALOGI("Force-closing previously opened tuner");
oldTuner->forceClose();
mTuner = nullptr;
}
sp<Tuner> newTuner = new Tuner(this, mClassId, callback);
mTuner = newTuner;
if (mClassId == Class::AM_FM) {
auto ret = newTuner->setConfiguration(config);
if (ret != Result::OK) {
_hidl_cb(Result::INVALID_ARGUMENTS, {});
return Void();
}
}
_hidl_cb(Result::OK, newTuner);
return Void();
}
Return<void> BroadcastRadio::getImage(int32_t id, getImage_cb _hidl_cb) {
ALOGV("%s(%x)", __func__, id);
if (id == resources::demoPngId) {
_hidl_cb(std::vector<uint8_t>(resources::demoPng, std::end(resources::demoPng)));
return {};
}
ALOGI("Image %x doesn't exists", id);
_hidl_cb({});
return Void();
}
std::vector<V1_0::BandConfig> BroadcastRadio::getAmFmBands() const {
std::vector<V1_0::BandConfig> out;
for (auto&& src : mConfig.amFmBands) {
V1_0::BandConfig dst;
dst.type = src.type;
dst.antennaConnected = true;
dst.lowerLimit = src.lowerLimit;
dst.upperLimit = src.upperLimit;
dst.spacings = src.spacings;
if (utils::isAm(src.type)) {
dst.ext.am.stereo = true;
} else if (utils::isFm(src.type)) {
dst.ext.fm.deemphasis = static_cast<Deemphasis>(Deemphasis::D50 | Deemphasis::D75);
dst.ext.fm.stereo = true;
dst.ext.fm.rds = static_cast<Rds>(Rds::WORLD | Rds::US);
dst.ext.fm.ta = true;
dst.ext.fm.af = true;
dst.ext.fm.ea = true;
}
out.push_back(dst);
}
return out;
}
} // namespace implementation
} // namespace V1_1
} // namespace broadcastradio
} // namespace hardware
} // namespace android