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