/* * Copyright (C) 2016 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 "RadioHalHidl" //#define LOG_NDEBUG 0 #include #include #include #include #include #include "RadioHalHidl.h" #include "HidlUtils.h" namespace android { using android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory; using android::hardware::broadcastradio::V1_0::Class; using android::hardware::broadcastradio::V1_0::Direction; using android::hardware::broadcastradio::V1_0::Properties; /* static */ sp RadioInterface::connectModule(radio_class_t classId) { return new RadioHalHidl(classId); } int RadioHalHidl::getProperties(radio_hal_properties_t *properties) { ALOGV("%s IN", __FUNCTION__); sp module = getService(); if (module == 0) { return -ENODEV; } Properties halProperties; Result halResult = Result::NOT_INITIALIZED; Return hidlReturn = module->getProperties([&](Result result, const Properties& properties) { halResult = result; if (result == Result::OK) { halProperties = properties; } }); if (halResult == Result::OK) { HidlUtils::convertPropertiesFromHal(properties, &halProperties); } return HidlUtils::convertHalResult(halResult); } int RadioHalHidl::openTuner(const radio_hal_band_config_t *config, bool audio, sp callback, sp& tuner) { sp module = getService(); if (module == 0) { return -ENODEV; } sp tunerImpl = new Tuner(callback, this); BandConfig halConfig; Result halResult = Result::NOT_INITIALIZED; sp halTuner; HidlUtils::convertBandConfigToHal(&halConfig, config); Return hidlReturn = module->openTuner(halConfig, audio, tunerImpl, [&](Result result, const sp& tuner) { halResult = result; if (result == Result::OK) { halTuner = tuner; } }); if (halResult == Result::OK) { tunerImpl->setHalTuner(halTuner); tuner = tunerImpl; } return HidlUtils::convertHalResult(halResult); } int RadioHalHidl::closeTuner(sp& tuner) { sp tunerImpl = static_cast(tuner.get()); sp clearTuner; tunerImpl->setHalTuner(clearTuner); return 0; } RadioHalHidl::RadioHalHidl(radio_class_t classId) : mClassId(classId) { } RadioHalHidl::~RadioHalHidl() { } sp RadioHalHidl::getService() { if (mHalModule == 0) { sp factory = IBroadcastRadioFactory::getService(); if (factory != 0) { factory->connectModule(static_cast(mClassId), [&](Result retval, const ::android::sp& result) { if (retval == Result::OK) { mHalModule = result; } }); } } ALOGV("%s OUT module %p", __FUNCTION__, mHalModule.get()); return mHalModule; } void RadioHalHidl::clearService() { ALOGV("%s IN module %p", __FUNCTION__, mHalModule.get()); mHalModule.clear(); } int RadioHalHidl::Tuner::setConfiguration(const radio_hal_band_config_t *config) { ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); if (mHalTuner == 0) { return -ENODEV; } BandConfig halConfig; HidlUtils::convertBandConfigToHal(&halConfig, config); Return hidlResult = mHalTuner->setConfiguration(halConfig); return HidlUtils::convertHalResult(hidlResult); } int RadioHalHidl::Tuner::getConfiguration(radio_hal_band_config_t *config) { ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); if (mHalTuner == 0) { return -ENODEV; } BandConfig halConfig; Result halResult; Return hidlReturn = mHalTuner->getConfiguration([&](Result result, const BandConfig& config) { halResult = result; if (result == Result::OK) { halConfig = config; } }); if (hidlReturn.isOk() && halResult == Result::OK) { HidlUtils::convertBandConfigFromHal(config, &halConfig); } return HidlUtils::convertHalResult(halResult); } int RadioHalHidl::Tuner::scan(radio_direction_t direction, bool skip_sub_channel) { ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); if (mHalTuner == 0) { return -ENODEV; } Return hidlResult = mHalTuner->scan(static_cast(direction), skip_sub_channel); return HidlUtils::convertHalResult(hidlResult); } int RadioHalHidl::Tuner::step(radio_direction_t direction, bool skip_sub_channel) { ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); if (mHalTuner == 0) { return -ENODEV; } Return hidlResult = mHalTuner->step(static_cast(direction), skip_sub_channel); return HidlUtils::convertHalResult(hidlResult); } int RadioHalHidl::Tuner::tune(unsigned int channel, unsigned int sub_channel) { ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); if (mHalTuner == 0) { return -ENODEV; } Return hidlResult = mHalTuner->tune(channel, sub_channel); return HidlUtils::convertHalResult(hidlResult); } int RadioHalHidl::Tuner::cancel() { ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); if (mHalTuner == 0) { return -ENODEV; } Return hidlResult = mHalTuner->cancel(); return HidlUtils::convertHalResult(hidlResult); } int RadioHalHidl::Tuner::getProgramInformation(radio_program_info_t *info) { ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get()); if (mHalTuner == 0) { return -ENODEV; } if (info == nullptr || info->metadata == nullptr) { return BAD_VALUE; } ProgramInfo halInfo; Result halResult; Return hidlReturn = mHalTuner->getProgramInformation( [&](Result result, const ProgramInfo& info) { halResult = result; if (result == Result::OK) { halInfo = info; } }); if (hidlReturn.isOk() && halResult == Result::OK) { HidlUtils::convertProgramInfoFromHal(info, &halInfo); } return HidlUtils::convertHalResult(halResult); } Return RadioHalHidl::Tuner::hardwareFailure() { ALOGV("%s IN", __FUNCTION__); handleHwFailure(); return Return(); } Return RadioHalHidl::Tuner::configChange(Result result, const BandConfig& config) { ALOGV("%s IN", __FUNCTION__); radio_hal_event_t event; memset(&event, 0, sizeof(radio_hal_event_t)); event.type = RADIO_EVENT_CONFIG; event.status = HidlUtils::convertHalResult(result); HidlUtils::convertBandConfigFromHal(&event.config, &config); onCallback(&event); return Return(); } Return RadioHalHidl::Tuner::tuneComplete(Result result, const ProgramInfo& info) { ALOGV("%s IN", __FUNCTION__); radio_hal_event_t event = {}; RadioMetadataWrapper metadataWrapper(&event.info.metadata); event.type = RADIO_EVENT_TUNED; event.status = HidlUtils::convertHalResult(result); HidlUtils::convertProgramInfoFromHal(&event.info, &info); onCallback(&event); return Return(); } Return RadioHalHidl::Tuner::afSwitch(const ProgramInfo& info) { ALOGV("%s IN", __FUNCTION__); radio_hal_event_t event = {}; RadioMetadataWrapper metadataWrapper(&event.info.metadata); event.type = RADIO_EVENT_AF_SWITCH; HidlUtils::convertProgramInfoFromHal(&event.info, &info); onCallback(&event); return Return(); } Return RadioHalHidl::Tuner::antennaStateChange(bool connected) { ALOGV("%s IN", __FUNCTION__); radio_hal_event_t event; memset(&event, 0, sizeof(radio_hal_event_t)); event.type = RADIO_EVENT_ANTENNA; event.on = connected; onCallback(&event); return Return(); } Return RadioHalHidl::Tuner::trafficAnnouncement(bool active) { ALOGV("%s IN", __FUNCTION__); radio_hal_event_t event; memset(&event, 0, sizeof(radio_hal_event_t)); event.type = RADIO_EVENT_TA; event.on = active; onCallback(&event); return Return(); } Return RadioHalHidl::Tuner::emergencyAnnouncement(bool active) { ALOGV("%s IN", __FUNCTION__); radio_hal_event_t event; memset(&event, 0, sizeof(radio_hal_event_t)); event.type = RADIO_EVENT_EA; event.on = active; onCallback(&event); return Return(); } Return RadioHalHidl::Tuner::newMetadata(uint32_t channel, uint32_t subChannel, const ::android::hardware::hidl_vec& metadata) { ALOGV("%s IN", __FUNCTION__); radio_hal_event_t event = {}; RadioMetadataWrapper metadataWrapper(&event.metadata); event.type = RADIO_EVENT_METADATA; HidlUtils::convertMetaDataFromHal(&event.metadata, metadata, channel, subChannel); onCallback(&event); return Return(); } RadioHalHidl::Tuner::Tuner(sp callback, sp module) : TunerInterface(), mHalTuner(NULL), mCallback(callback), mParentModule(module) { // Make sure the handler we are passing in only deals with const members, // as it can be called on an arbitrary thread. const auto& self = this; HalDeathHandler::getInstance()->registerAtExitHandler( this, [&self]() { self->sendHwFailureEvent(); }); } RadioHalHidl::Tuner::~Tuner() { HalDeathHandler::getInstance()->unregisterAtExitHandler(this); } void RadioHalHidl::Tuner::setHalTuner(sp& halTuner) { if (mHalTuner != 0) { mHalTuner->unlinkToDeath(HalDeathHandler::getInstance()); } mHalTuner = halTuner; if (mHalTuner != 0) { mHalTuner->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/); } } void RadioHalHidl::Tuner::handleHwFailure() { ALOGV("%s IN", __FUNCTION__); sp parentModule = mParentModule.promote(); if (parentModule != 0) { parentModule->clearService(); } sendHwFailureEvent(); mHalTuner.clear(); } void RadioHalHidl::Tuner::sendHwFailureEvent() const { radio_hal_event_t event; memset(&event, 0, sizeof(radio_hal_event_t)); event.type = RADIO_EVENT_HW_FAILURE; onCallback(&event); } void RadioHalHidl::Tuner::onCallback(radio_hal_event_t *halEvent) const { if (mCallback != 0) { mCallback->onEvent(halEvent); } } } // namespace android