1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker *
4*4d7e907cSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker *
8*4d7e907cSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker *
10*4d7e907cSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker */
16*4d7e907cSAndroid Build Coastguard Worker #define LOG_TAG "BroadcastRadioDefault.module"
17*4d7e907cSAndroid Build Coastguard Worker #define LOG_NDEBUG 0
18*4d7e907cSAndroid Build Coastguard Worker
19*4d7e907cSAndroid Build Coastguard Worker #include "BroadcastRadio.h"
20*4d7e907cSAndroid Build Coastguard Worker
21*4d7e907cSAndroid Build Coastguard Worker #include <log/log.h>
22*4d7e907cSAndroid Build Coastguard Worker
23*4d7e907cSAndroid Build Coastguard Worker #include "resources.h"
24*4d7e907cSAndroid Build Coastguard Worker
25*4d7e907cSAndroid Build Coastguard Worker namespace android {
26*4d7e907cSAndroid Build Coastguard Worker namespace hardware {
27*4d7e907cSAndroid Build Coastguard Worker namespace broadcastradio {
28*4d7e907cSAndroid Build Coastguard Worker namespace V1_1 {
29*4d7e907cSAndroid Build Coastguard Worker namespace implementation {
30*4d7e907cSAndroid Build Coastguard Worker
31*4d7e907cSAndroid Build Coastguard Worker using V1_0::Band;
32*4d7e907cSAndroid Build Coastguard Worker using V1_0::BandConfig;
33*4d7e907cSAndroid Build Coastguard Worker using V1_0::Class;
34*4d7e907cSAndroid Build Coastguard Worker using V1_0::Deemphasis;
35*4d7e907cSAndroid Build Coastguard Worker using V1_0::Rds;
36*4d7e907cSAndroid Build Coastguard Worker using V1_1::IdentifierType;
37*4d7e907cSAndroid Build Coastguard Worker using V1_1::ProgramSelector;
38*4d7e907cSAndroid Build Coastguard Worker using V1_1::ProgramType;
39*4d7e907cSAndroid Build Coastguard Worker using V1_1::Properties;
40*4d7e907cSAndroid Build Coastguard Worker using V1_1::VendorKeyValue;
41*4d7e907cSAndroid Build Coastguard Worker
42*4d7e907cSAndroid Build Coastguard Worker using std::lock_guard;
43*4d7e907cSAndroid Build Coastguard Worker using std::map;
44*4d7e907cSAndroid Build Coastguard Worker using std::mutex;
45*4d7e907cSAndroid Build Coastguard Worker using std::vector;
46*4d7e907cSAndroid Build Coastguard Worker
47*4d7e907cSAndroid Build Coastguard Worker // clang-format off
48*4d7e907cSAndroid Build Coastguard Worker static const map<Class, ModuleConfig> gModuleConfigs{
49*4d7e907cSAndroid Build Coastguard Worker {Class::AM_FM, ModuleConfig({
50*4d7e907cSAndroid Build Coastguard Worker "Digital radio mock",
51*4d7e907cSAndroid Build Coastguard Worker { // amFmBands
52*4d7e907cSAndroid Build Coastguard Worker AmFmBandConfig({
53*4d7e907cSAndroid Build Coastguard Worker Band::AM,
54*4d7e907cSAndroid Build Coastguard Worker 153, // lowerLimit
55*4d7e907cSAndroid Build Coastguard Worker 26100, // upperLimit
56*4d7e907cSAndroid Build Coastguard Worker {5, 9, 10}, // spacings
57*4d7e907cSAndroid Build Coastguard Worker }),
58*4d7e907cSAndroid Build Coastguard Worker AmFmBandConfig({
59*4d7e907cSAndroid Build Coastguard Worker Band::FM,
60*4d7e907cSAndroid Build Coastguard Worker 65800, // lowerLimit
61*4d7e907cSAndroid Build Coastguard Worker 108000, // upperLimit
62*4d7e907cSAndroid Build Coastguard Worker {10, 100, 200}, // spacings
63*4d7e907cSAndroid Build Coastguard Worker }),
64*4d7e907cSAndroid Build Coastguard Worker AmFmBandConfig({
65*4d7e907cSAndroid Build Coastguard Worker Band::AM_HD,
66*4d7e907cSAndroid Build Coastguard Worker 153, // lowerLimit
67*4d7e907cSAndroid Build Coastguard Worker 26100, // upperLimit
68*4d7e907cSAndroid Build Coastguard Worker {5, 9, 10}, // spacings
69*4d7e907cSAndroid Build Coastguard Worker }),
70*4d7e907cSAndroid Build Coastguard Worker AmFmBandConfig({
71*4d7e907cSAndroid Build Coastguard Worker Band::FM_HD,
72*4d7e907cSAndroid Build Coastguard Worker 87700, // lowerLimit
73*4d7e907cSAndroid Build Coastguard Worker 107900, // upperLimit
74*4d7e907cSAndroid Build Coastguard Worker {200}, // spacings
75*4d7e907cSAndroid Build Coastguard Worker }),
76*4d7e907cSAndroid Build Coastguard Worker },
77*4d7e907cSAndroid Build Coastguard Worker })},
78*4d7e907cSAndroid Build Coastguard Worker
79*4d7e907cSAndroid Build Coastguard Worker {Class::SAT, ModuleConfig({
80*4d7e907cSAndroid Build Coastguard Worker "Satellite radio mock",
81*4d7e907cSAndroid Build Coastguard Worker {}, // amFmBands
82*4d7e907cSAndroid Build Coastguard Worker })},
83*4d7e907cSAndroid Build Coastguard Worker };
84*4d7e907cSAndroid Build Coastguard Worker // clang-format on
85*4d7e907cSAndroid Build Coastguard Worker
BroadcastRadio(Class classId)86*4d7e907cSAndroid Build Coastguard Worker BroadcastRadio::BroadcastRadio(Class classId)
87*4d7e907cSAndroid Build Coastguard Worker : mClassId(classId), mConfig(gModuleConfigs.at(classId)) {}
88*4d7e907cSAndroid Build Coastguard Worker
isSupported(Class classId)89*4d7e907cSAndroid Build Coastguard Worker bool BroadcastRadio::isSupported(Class classId) {
90*4d7e907cSAndroid Build Coastguard Worker return gModuleConfigs.find(classId) != gModuleConfigs.end();
91*4d7e907cSAndroid Build Coastguard Worker }
92*4d7e907cSAndroid Build Coastguard Worker
getProperties(getProperties_cb _hidl_cb)93*4d7e907cSAndroid Build Coastguard Worker Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) {
94*4d7e907cSAndroid Build Coastguard Worker ALOGV("%s", __func__);
95*4d7e907cSAndroid Build Coastguard Worker return getProperties_1_1(
96*4d7e907cSAndroid Build Coastguard Worker [&](const Properties& properties) { _hidl_cb(Result::OK, properties.base); });
97*4d7e907cSAndroid Build Coastguard Worker }
98*4d7e907cSAndroid Build Coastguard Worker
getProperties_1_1(getProperties_1_1_cb _hidl_cb)99*4d7e907cSAndroid Build Coastguard Worker Return<void> BroadcastRadio::getProperties_1_1(getProperties_1_1_cb _hidl_cb) {
100*4d7e907cSAndroid Build Coastguard Worker ALOGV("%s", __func__);
101*4d7e907cSAndroid Build Coastguard Worker Properties prop11 = {};
102*4d7e907cSAndroid Build Coastguard Worker auto& prop10 = prop11.base;
103*4d7e907cSAndroid Build Coastguard Worker
104*4d7e907cSAndroid Build Coastguard Worker prop10.classId = mClassId;
105*4d7e907cSAndroid Build Coastguard Worker prop10.implementor = "Google";
106*4d7e907cSAndroid Build Coastguard Worker prop10.product = mConfig.productName;
107*4d7e907cSAndroid Build Coastguard Worker prop10.numTuners = 1;
108*4d7e907cSAndroid Build Coastguard Worker prop10.numAudioSources = 1;
109*4d7e907cSAndroid Build Coastguard Worker prop10.supportsCapture = false;
110*4d7e907cSAndroid Build Coastguard Worker prop11.supportsBackgroundScanning = true;
111*4d7e907cSAndroid Build Coastguard Worker prop11.supportedProgramTypes = hidl_vec<uint32_t>({
112*4d7e907cSAndroid Build Coastguard Worker static_cast<uint32_t>(ProgramType::AM), static_cast<uint32_t>(ProgramType::FM),
113*4d7e907cSAndroid Build Coastguard Worker static_cast<uint32_t>(ProgramType::AM_HD), static_cast<uint32_t>(ProgramType::FM_HD),
114*4d7e907cSAndroid Build Coastguard Worker });
115*4d7e907cSAndroid Build Coastguard Worker prop11.supportedIdentifierTypes = hidl_vec<uint32_t>({
116*4d7e907cSAndroid Build Coastguard Worker static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY),
117*4d7e907cSAndroid Build Coastguard Worker static_cast<uint32_t>(IdentifierType::RDS_PI),
118*4d7e907cSAndroid Build Coastguard Worker static_cast<uint32_t>(IdentifierType::HD_STATION_ID_EXT),
119*4d7e907cSAndroid Build Coastguard Worker static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL),
120*4d7e907cSAndroid Build Coastguard Worker });
121*4d7e907cSAndroid Build Coastguard Worker prop11.vendorInfo = hidl_vec<VendorKeyValue>({
122*4d7e907cSAndroid Build Coastguard Worker {"com.google.dummy", "dummy"},
123*4d7e907cSAndroid Build Coastguard Worker });
124*4d7e907cSAndroid Build Coastguard Worker
125*4d7e907cSAndroid Build Coastguard Worker prop10.bands = getAmFmBands();
126*4d7e907cSAndroid Build Coastguard Worker
127*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(prop11);
128*4d7e907cSAndroid Build Coastguard Worker return Void();
129*4d7e907cSAndroid Build Coastguard Worker }
130*4d7e907cSAndroid Build Coastguard Worker
openTuner(const BandConfig & config,bool audio __unused,const sp<V1_0::ITunerCallback> & callback,openTuner_cb _hidl_cb)131*4d7e907cSAndroid Build Coastguard Worker Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio __unused,
132*4d7e907cSAndroid Build Coastguard Worker const sp<V1_0::ITunerCallback>& callback,
133*4d7e907cSAndroid Build Coastguard Worker openTuner_cb _hidl_cb) {
134*4d7e907cSAndroid Build Coastguard Worker ALOGV("%s(%s)", __func__, toString(config.type).c_str());
135*4d7e907cSAndroid Build Coastguard Worker lock_guard<mutex> lk(mMut);
136*4d7e907cSAndroid Build Coastguard Worker
137*4d7e907cSAndroid Build Coastguard Worker auto oldTuner = mTuner.promote();
138*4d7e907cSAndroid Build Coastguard Worker if (oldTuner != nullptr) {
139*4d7e907cSAndroid Build Coastguard Worker ALOGI("Force-closing previously opened tuner");
140*4d7e907cSAndroid Build Coastguard Worker oldTuner->forceClose();
141*4d7e907cSAndroid Build Coastguard Worker mTuner = nullptr;
142*4d7e907cSAndroid Build Coastguard Worker }
143*4d7e907cSAndroid Build Coastguard Worker
144*4d7e907cSAndroid Build Coastguard Worker sp<Tuner> newTuner = new Tuner(this, mClassId, callback);
145*4d7e907cSAndroid Build Coastguard Worker mTuner = newTuner;
146*4d7e907cSAndroid Build Coastguard Worker if (mClassId == Class::AM_FM) {
147*4d7e907cSAndroid Build Coastguard Worker auto ret = newTuner->setConfiguration(config);
148*4d7e907cSAndroid Build Coastguard Worker if (ret != Result::OK) {
149*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(Result::INVALID_ARGUMENTS, {});
150*4d7e907cSAndroid Build Coastguard Worker return Void();
151*4d7e907cSAndroid Build Coastguard Worker }
152*4d7e907cSAndroid Build Coastguard Worker }
153*4d7e907cSAndroid Build Coastguard Worker
154*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(Result::OK, newTuner);
155*4d7e907cSAndroid Build Coastguard Worker return Void();
156*4d7e907cSAndroid Build Coastguard Worker }
157*4d7e907cSAndroid Build Coastguard Worker
getImage(int32_t id,getImage_cb _hidl_cb)158*4d7e907cSAndroid Build Coastguard Worker Return<void> BroadcastRadio::getImage(int32_t id, getImage_cb _hidl_cb) {
159*4d7e907cSAndroid Build Coastguard Worker ALOGV("%s(%x)", __func__, id);
160*4d7e907cSAndroid Build Coastguard Worker
161*4d7e907cSAndroid Build Coastguard Worker if (id == resources::demoPngId) {
162*4d7e907cSAndroid Build Coastguard Worker _hidl_cb(std::vector<uint8_t>(resources::demoPng, std::end(resources::demoPng)));
163*4d7e907cSAndroid Build Coastguard Worker return {};
164*4d7e907cSAndroid Build Coastguard Worker }
165*4d7e907cSAndroid Build Coastguard Worker
166*4d7e907cSAndroid Build Coastguard Worker ALOGI("Image %x doesn't exists", id);
167*4d7e907cSAndroid Build Coastguard Worker _hidl_cb({});
168*4d7e907cSAndroid Build Coastguard Worker return Void();
169*4d7e907cSAndroid Build Coastguard Worker }
170*4d7e907cSAndroid Build Coastguard Worker
getAmFmBands() const171*4d7e907cSAndroid Build Coastguard Worker std::vector<V1_0::BandConfig> BroadcastRadio::getAmFmBands() const {
172*4d7e907cSAndroid Build Coastguard Worker std::vector<V1_0::BandConfig> out;
173*4d7e907cSAndroid Build Coastguard Worker for (auto&& src : mConfig.amFmBands) {
174*4d7e907cSAndroid Build Coastguard Worker V1_0::BandConfig dst;
175*4d7e907cSAndroid Build Coastguard Worker
176*4d7e907cSAndroid Build Coastguard Worker dst.type = src.type;
177*4d7e907cSAndroid Build Coastguard Worker dst.antennaConnected = true;
178*4d7e907cSAndroid Build Coastguard Worker dst.lowerLimit = src.lowerLimit;
179*4d7e907cSAndroid Build Coastguard Worker dst.upperLimit = src.upperLimit;
180*4d7e907cSAndroid Build Coastguard Worker dst.spacings = src.spacings;
181*4d7e907cSAndroid Build Coastguard Worker
182*4d7e907cSAndroid Build Coastguard Worker if (utils::isAm(src.type)) {
183*4d7e907cSAndroid Build Coastguard Worker dst.ext.am.stereo = true;
184*4d7e907cSAndroid Build Coastguard Worker } else if (utils::isFm(src.type)) {
185*4d7e907cSAndroid Build Coastguard Worker dst.ext.fm.deemphasis = static_cast<Deemphasis>(Deemphasis::D50 | Deemphasis::D75);
186*4d7e907cSAndroid Build Coastguard Worker dst.ext.fm.stereo = true;
187*4d7e907cSAndroid Build Coastguard Worker dst.ext.fm.rds = static_cast<Rds>(Rds::WORLD | Rds::US);
188*4d7e907cSAndroid Build Coastguard Worker dst.ext.fm.ta = true;
189*4d7e907cSAndroid Build Coastguard Worker dst.ext.fm.af = true;
190*4d7e907cSAndroid Build Coastguard Worker dst.ext.fm.ea = true;
191*4d7e907cSAndroid Build Coastguard Worker }
192*4d7e907cSAndroid Build Coastguard Worker
193*4d7e907cSAndroid Build Coastguard Worker out.push_back(dst);
194*4d7e907cSAndroid Build Coastguard Worker }
195*4d7e907cSAndroid Build Coastguard Worker return out;
196*4d7e907cSAndroid Build Coastguard Worker }
197*4d7e907cSAndroid Build Coastguard Worker
198*4d7e907cSAndroid Build Coastguard Worker } // namespace implementation
199*4d7e907cSAndroid Build Coastguard Worker } // namespace V1_1
200*4d7e907cSAndroid Build Coastguard Worker } // namespace broadcastradio
201*4d7e907cSAndroid Build Coastguard Worker } // namespace hardware
202*4d7e907cSAndroid Build Coastguard Worker } // namespace android
203