1/* 2 * Copyright (C) 2016 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 17#define LOG_TAG "RadioHalHidl" 18//#define LOG_NDEBUG 0 19 20#include <media/audiohal/hidl/HalDeathHandler.h> 21#include <utils/Log.h> 22#include <utils/misc.h> 23#include <system/RadioMetadataWrapper.h> 24#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h> 25 26#include "RadioHalHidl.h" 27#include "HidlUtils.h" 28 29namespace android { 30 31using android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory; 32using android::hardware::broadcastradio::V1_0::Class; 33using android::hardware::broadcastradio::V1_0::Direction; 34using android::hardware::broadcastradio::V1_0::Properties; 35 36 37/* static */ 38sp<RadioInterface> RadioInterface::connectModule(radio_class_t classId) 39{ 40 return new RadioHalHidl(classId); 41} 42 43int RadioHalHidl::getProperties(radio_hal_properties_t *properties) 44{ 45 ALOGV("%s IN", __FUNCTION__); 46 sp<IBroadcastRadio> module = getService(); 47 if (module == 0) { 48 return -ENODEV; 49 } 50 Properties halProperties; 51 Result halResult = Result::NOT_INITIALIZED; 52 Return<void> hidlReturn = 53 module->getProperties([&](Result result, const Properties& properties) { 54 halResult = result; 55 if (result == Result::OK) { 56 halProperties = properties; 57 } 58 }); 59 60 if (halResult == Result::OK) { 61 HidlUtils::convertPropertiesFromHal(properties, &halProperties); 62 } 63 return HidlUtils::convertHalResult(halResult); 64} 65 66int RadioHalHidl::openTuner(const radio_hal_band_config_t *config, 67 bool audio, 68 sp<TunerCallbackInterface> callback, 69 sp<TunerInterface>& tuner) 70{ 71 sp<IBroadcastRadio> module = getService(); 72 if (module == 0) { 73 return -ENODEV; 74 } 75 sp<Tuner> tunerImpl = new Tuner(callback, this); 76 77 BandConfig halConfig; 78 Result halResult = Result::NOT_INITIALIZED; 79 sp<ITuner> halTuner; 80 81 HidlUtils::convertBandConfigToHal(&halConfig, config); 82 Return<void> hidlReturn = 83 module->openTuner(halConfig, audio, tunerImpl, 84 [&](Result result, const sp<ITuner>& tuner) { 85 halResult = result; 86 if (result == Result::OK) { 87 halTuner = tuner; 88 } 89 }); 90 91 if (halResult == Result::OK) { 92 tunerImpl->setHalTuner(halTuner); 93 tuner = tunerImpl; 94 } 95 96 return HidlUtils::convertHalResult(halResult); 97} 98 99int RadioHalHidl::closeTuner(sp<TunerInterface>& tuner) 100{ 101 sp<Tuner> tunerImpl = static_cast<Tuner *>(tuner.get()); 102 sp<ITuner> clearTuner; 103 tunerImpl->setHalTuner(clearTuner); 104 return 0; 105} 106 107RadioHalHidl::RadioHalHidl(radio_class_t classId) 108 : mClassId(classId) 109{ 110} 111 112RadioHalHidl::~RadioHalHidl() 113{ 114} 115 116sp<IBroadcastRadio> RadioHalHidl::getService() 117{ 118 if (mHalModule == 0) { 119 sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService(); 120 if (factory != 0) { 121 factory->connectModule(static_cast<Class>(mClassId), 122 [&](Result retval, const ::android::sp<IBroadcastRadio>& result) { 123 if (retval == Result::OK) { 124 mHalModule = result; 125 } 126 }); 127 } 128 } 129 ALOGV("%s OUT module %p", __FUNCTION__, mHalModule.get()); 130 return mHalModule; 131} 132 133void RadioHalHidl::clearService() 134{ 135 ALOGV("%s IN module %p", __FUNCTION__, mHalModule.get()); 136 mHalModule.clear(); 137} 138 139 140int RadioHalHidl::Tuner::setConfiguration(const radio_hal_band_config_t *config) 141{ 142 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); 143 144 if (mHalTuner == 0) { 145 return -ENODEV; 146 } 147 BandConfig halConfig; 148 HidlUtils::convertBandConfigToHal(&halConfig, config); 149 150 Return<Result> hidlResult = mHalTuner->setConfiguration(halConfig); 151 return HidlUtils::convertHalResult(hidlResult); 152} 153 154int RadioHalHidl::Tuner::getConfiguration(radio_hal_band_config_t *config) 155{ 156 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); 157 if (mHalTuner == 0) { 158 return -ENODEV; 159 } 160 BandConfig halConfig; 161 Result halResult; 162 Return<void> hidlReturn = 163 mHalTuner->getConfiguration([&](Result result, const BandConfig& config) { 164 halResult = result; 165 if (result == Result::OK) { 166 halConfig = config; 167 } 168 }); 169 if (hidlReturn.isOk() && halResult == Result::OK) { 170 HidlUtils::convertBandConfigFromHal(config, &halConfig); 171 } 172 return HidlUtils::convertHalResult(halResult); 173} 174 175int RadioHalHidl::Tuner::scan(radio_direction_t direction, bool skip_sub_channel) 176{ 177 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); 178 if (mHalTuner == 0) { 179 return -ENODEV; 180 } 181 Return<Result> hidlResult = 182 mHalTuner->scan(static_cast<Direction>(direction), skip_sub_channel); 183 return HidlUtils::convertHalResult(hidlResult); 184} 185 186int RadioHalHidl::Tuner::step(radio_direction_t direction, bool skip_sub_channel) 187{ 188 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); 189 if (mHalTuner == 0) { 190 return -ENODEV; 191 } 192 Return<Result> hidlResult = 193 mHalTuner->step(static_cast<Direction>(direction), skip_sub_channel); 194 return HidlUtils::convertHalResult(hidlResult); 195} 196 197int RadioHalHidl::Tuner::tune(unsigned int channel, unsigned int sub_channel) 198{ 199 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); 200 if (mHalTuner == 0) { 201 return -ENODEV; 202 } 203 Return<Result> hidlResult = 204 mHalTuner->tune(channel, sub_channel); 205 return HidlUtils::convertHalResult(hidlResult); 206} 207 208int RadioHalHidl::Tuner::cancel() 209{ 210 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); 211 if (mHalTuner == 0) { 212 return -ENODEV; 213 } 214 Return<Result> hidlResult = mHalTuner->cancel(); 215 return HidlUtils::convertHalResult(hidlResult); 216} 217 218int RadioHalHidl::Tuner::getProgramInformation(radio_program_info_t *info) 219{ 220 ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); 221 if (mHalTuner == 0) { 222 return -ENODEV; 223 } 224 if (info == nullptr || info->metadata == nullptr) { 225 return BAD_VALUE; 226 } 227 ProgramInfo halInfo; 228 Result halResult; 229 Return<void> hidlReturn = mHalTuner->getProgramInformation( 230 [&](Result result, const ProgramInfo& info) { 231 halResult = result; 232 if (result == Result::OK) { 233 halInfo = info; 234 } 235 }); 236 if (hidlReturn.isOk() && halResult == Result::OK) { 237 HidlUtils::convertProgramInfoFromHal(info, &halInfo); 238 } 239 return HidlUtils::convertHalResult(halResult); 240} 241 242Return<void> RadioHalHidl::Tuner::hardwareFailure() 243{ 244 ALOGV("%s IN", __FUNCTION__); 245 handleHwFailure(); 246 return Return<void>(); 247} 248 249Return<void> RadioHalHidl::Tuner::configChange(Result result, const BandConfig& config) 250{ 251 ALOGV("%s IN", __FUNCTION__); 252 radio_hal_event_t event; 253 memset(&event, 0, sizeof(radio_hal_event_t)); 254 event.type = RADIO_EVENT_CONFIG; 255 event.status = HidlUtils::convertHalResult(result); 256 HidlUtils::convertBandConfigFromHal(&event.config, &config); 257 onCallback(&event); 258 return Return<void>(); 259} 260 261Return<void> RadioHalHidl::Tuner::tuneComplete(Result result, const ProgramInfo& info) 262{ 263 ALOGV("%s IN", __FUNCTION__); 264 radio_hal_event_t event = {}; 265 RadioMetadataWrapper metadataWrapper(&event.info.metadata); 266 267 event.type = RADIO_EVENT_TUNED; 268 event.status = HidlUtils::convertHalResult(result); 269 HidlUtils::convertProgramInfoFromHal(&event.info, &info); 270 onCallback(&event); 271 return Return<void>(); 272} 273 274Return<void> RadioHalHidl::Tuner::afSwitch(const ProgramInfo& info) 275{ 276 ALOGV("%s IN", __FUNCTION__); 277 radio_hal_event_t event = {}; 278 RadioMetadataWrapper metadataWrapper(&event.info.metadata); 279 280 event.type = RADIO_EVENT_AF_SWITCH; 281 HidlUtils::convertProgramInfoFromHal(&event.info, &info); 282 onCallback(&event); 283 return Return<void>(); 284} 285 286Return<void> RadioHalHidl::Tuner::antennaStateChange(bool connected) 287{ 288 ALOGV("%s IN", __FUNCTION__); 289 radio_hal_event_t event; 290 memset(&event, 0, sizeof(radio_hal_event_t)); 291 event.type = RADIO_EVENT_ANTENNA; 292 event.on = connected; 293 onCallback(&event); 294 return Return<void>(); 295} 296Return<void> RadioHalHidl::Tuner::trafficAnnouncement(bool active) 297{ 298 ALOGV("%s IN", __FUNCTION__); 299 radio_hal_event_t event; 300 memset(&event, 0, sizeof(radio_hal_event_t)); 301 event.type = RADIO_EVENT_TA; 302 event.on = active; 303 onCallback(&event); 304 return Return<void>(); 305} 306Return<void> RadioHalHidl::Tuner::emergencyAnnouncement(bool active) 307{ 308 ALOGV("%s IN", __FUNCTION__); 309 radio_hal_event_t event; 310 memset(&event, 0, sizeof(radio_hal_event_t)); 311 event.type = RADIO_EVENT_EA; 312 event.on = active; 313 onCallback(&event); 314 return Return<void>(); 315} 316Return<void> RadioHalHidl::Tuner::newMetadata(uint32_t channel, uint32_t subChannel, 317 const ::android::hardware::hidl_vec<MetaData>& metadata) 318{ 319 ALOGV("%s IN", __FUNCTION__); 320 radio_hal_event_t event = {}; 321 RadioMetadataWrapper metadataWrapper(&event.metadata); 322 323 event.type = RADIO_EVENT_METADATA; 324 HidlUtils::convertMetaDataFromHal(&event.metadata, metadata, channel, subChannel); 325 onCallback(&event); 326 return Return<void>(); 327} 328 329 330RadioHalHidl::Tuner::Tuner(sp<TunerCallbackInterface> callback, sp<RadioHalHidl> module) 331 : TunerInterface(), mHalTuner(NULL), mCallback(callback), mParentModule(module) 332{ 333 // Make sure the handler we are passing in only deals with const members, 334 // as it can be called on an arbitrary thread. 335 const auto& self = this; 336 HalDeathHandler::getInstance()->registerAtExitHandler( 337 this, [&self]() { self->sendHwFailureEvent(); }); 338} 339 340 341RadioHalHidl::Tuner::~Tuner() 342{ 343 HalDeathHandler::getInstance()->unregisterAtExitHandler(this); 344} 345 346void RadioHalHidl::Tuner::setHalTuner(sp<ITuner>& halTuner) { 347 if (mHalTuner != 0) { 348 mHalTuner->unlinkToDeath(HalDeathHandler::getInstance()); 349 } 350 mHalTuner = halTuner; 351 if (mHalTuner != 0) { 352 mHalTuner->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/); 353 } 354} 355 356void RadioHalHidl::Tuner::handleHwFailure() 357{ 358 ALOGV("%s IN", __FUNCTION__); 359 sp<RadioHalHidl> parentModule = mParentModule.promote(); 360 if (parentModule != 0) { 361 parentModule->clearService(); 362 } 363 sendHwFailureEvent(); 364 mHalTuner.clear(); 365} 366 367void RadioHalHidl::Tuner::sendHwFailureEvent() const 368{ 369 radio_hal_event_t event; 370 memset(&event, 0, sizeof(radio_hal_event_t)); 371 event.type = RADIO_EVENT_HW_FAILURE; 372 onCallback(&event); 373} 374 375void RadioHalHidl::Tuner::onCallback(radio_hal_event_t *halEvent) const 376{ 377 if (mCallback != 0) { 378 mCallback->onEvent(halEvent); 379 } 380} 381 382} // namespace android 383