blob: 07cb4d52bfd30370d480cedec862b7a145bb63a6 [file] [log] [blame]
/*
* 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 <utils/Log.h>
#include <utils/misc.h>
#include <system/radio_metadata.h>
#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
#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> RadioInterface::connectModule(radio_class_t classId)
{
return new RadioHalHidl(classId);
}
int RadioHalHidl::getProperties(radio_hal_properties_t *properties)
{
ALOGV("%s IN", __FUNCTION__);
sp<IBroadcastRadio> module = getService();
if (module == 0) {
return -ENODEV;
}
Properties halProperties;
Result halResult;
Return<void> hidlReturn =
module->getProperties([&](Result result, const Properties& properties) {
halResult = result;
if (result == Result::OK) {
halProperties = properties;
}
});
if (hidlReturn.getStatus().transactionError() == DEAD_OBJECT) {
clearService();
return -EPIPE;
}
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<TunerCallbackInterface> callback,
sp<TunerInterface>& tuner)
{
sp<IBroadcastRadio> module = getService();
if (module == 0) {
return -ENODEV;
}
sp<Tuner> tunerImpl = new Tuner(callback, this);
BandConfig halConfig;
Result halResult;
sp<ITuner> halTuner;
HidlUtils::convertBandConfigToHal(&halConfig, config);
Return<void> hidlReturn =
module->openTuner(halConfig, audio, tunerImpl,
[&](Result result, const sp<ITuner>& tuner) {
halResult = result;
if (result == Result::OK) {
halTuner = tuner;
}
});
if (hidlReturn.getStatus().transactionError() == DEAD_OBJECT) {
clearService();
return -EPIPE;
}
if (halResult == Result::OK) {
tunerImpl->setHalTuner(halTuner);
tuner = tunerImpl;
}
return HidlUtils::convertHalResult(halResult);
}
int RadioHalHidl::closeTuner(sp<TunerInterface>& tuner)
{
sp<Tuner> tunerImpl = static_cast<Tuner *>(tuner.get());
sp<ITuner> clearTuner;
tunerImpl->setHalTuner(clearTuner);
return 0;
}
RadioHalHidl::RadioHalHidl(radio_class_t classId)
: mClassId(classId)
{
}
RadioHalHidl::~RadioHalHidl()
{
}
sp<IBroadcastRadio> RadioHalHidl::getService()
{
if (mHalModule == 0) {
sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService("broadcastradio");
if (factory != 0) {
factory->connectModule(static_cast<Class>(mClassId),
[&](Result retval, const ::android::sp<IBroadcastRadio>& 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<Result> hidlResult = mHalTuner->setConfiguration(halConfig);
checkHidlStatus(hidlResult.getStatus());
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<void> hidlReturn =
mHalTuner->getConfiguration([&](Result result, const BandConfig& config) {
halResult = result;
if (result == Result::OK) {
halConfig = config;
}
});
status_t status = checkHidlStatus(hidlReturn.getStatus());
if (status == NO_ERROR && 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<Result> hidlResult =
mHalTuner->scan(static_cast<Direction>(direction), skip_sub_channel);
checkHidlStatus(hidlResult.getStatus());
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<Result> hidlResult =
mHalTuner->step(static_cast<Direction>(direction), skip_sub_channel);
checkHidlStatus(hidlResult.getStatus());
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<Result> hidlResult =
mHalTuner->tune(channel, sub_channel);
checkHidlStatus(hidlResult.getStatus());
return HidlUtils::convertHalResult(hidlResult);
}
int RadioHalHidl::Tuner::cancel()
{
ALOGV("%s IN mHalTuner %p", __FUNCTION__, mHalTuner.get());
if (mHalTuner == 0) {
return -ENODEV;
}
Return<Result> hidlResult = mHalTuner->cancel();
checkHidlStatus(hidlResult.getStatus());
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;
}
ProgramInfo halInfo;
Result halResult;
bool withMetaData = (info->metadata != NULL);
Return<void> hidlReturn = mHalTuner->getProgramInformation(
withMetaData, [&](Result result, const ProgramInfo& info) {
halResult = result;
if (result == Result::OK) {
halInfo = info;
}
});
status_t status = checkHidlStatus(hidlReturn.getStatus());
if (status == NO_ERROR && halResult == Result::OK) {
HidlUtils::convertProgramInfoFromHal(info, &halInfo, withMetaData);
}
return HidlUtils::convertHalResult(halResult);
}
Return<void> RadioHalHidl::Tuner::hardwareFailure()
{
ALOGV("%s IN", __FUNCTION__);
handleHwFailure();
return Return<void>();
}
Return<void> 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<void>();
}
Return<void> RadioHalHidl::Tuner::tuneComplete(Result result, const ProgramInfo& info)
{
ALOGV("%s IN", __FUNCTION__);
radio_hal_event_t event;
memset(&event, 0, sizeof(radio_hal_event_t));
event.type = RADIO_EVENT_TUNED;
event.status = HidlUtils::convertHalResult(result);
HidlUtils::convertProgramInfoFromHal(&event.info, &info, true);
onCallback(&event);
if (event.info.metadata != NULL) {
radio_metadata_deallocate(event.info.metadata);
}
return Return<void>();
}
Return<void> RadioHalHidl::Tuner::afSwitch(const ProgramInfo& info)
{
ALOGV("%s IN", __FUNCTION__);
radio_hal_event_t event;
memset(&event, 0, sizeof(radio_hal_event_t));
event.type = RADIO_EVENT_AF_SWITCH;
HidlUtils::convertProgramInfoFromHal(&event.info, &info, true);
onCallback(&event);
if (event.info.metadata != NULL) {
radio_metadata_deallocate(event.info.metadata);
}
return Return<void>();
}
Return<void> 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<void>();
}
Return<void> 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<void>();
}
Return<void> 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<void>();
}
Return<void> RadioHalHidl::Tuner::newMetadata(uint32_t channel, uint32_t subChannel,
const ::android::hardware::hidl_vec<MetaData>& metadata)
{
ALOGV("%s IN", __FUNCTION__);
radio_hal_event_t event;
memset(&event, 0, sizeof(radio_hal_event_t));
event.type = RADIO_EVENT_METADATA;
HidlUtils::convertMetaDataFromHal(&event.metadata, metadata, channel, subChannel);
onCallback(&event);
if (event.metadata != NULL) {
radio_metadata_deallocate(event.info.metadata);
}
return Return<void>();
}
RadioHalHidl::Tuner::Tuner(sp<TunerCallbackInterface> callback, sp<RadioHalHidl> module)
: TunerInterface(), mHalTuner(NULL), mCallback(callback), mParentModule(module)
{
}
RadioHalHidl::Tuner::~Tuner()
{
}
void RadioHalHidl::Tuner::handleHwFailure()
{
ALOGV("%s IN", __FUNCTION__);
sp<RadioHalHidl> parentModule = mParentModule.promote();
if (parentModule != 0) {
parentModule->clearService();
}
radio_hal_event_t event;
memset(&event, 0, sizeof(radio_hal_event_t));
event.type = RADIO_EVENT_HW_FAILURE;
onCallback(&event);
mHalTuner.clear();
}
status_t RadioHalHidl::Tuner::checkHidlStatus(Status hidlStatus)
{
status_t status = hidlStatus.transactionError();
if (status == DEAD_OBJECT) {
handleHwFailure();
}
return status;
}
void RadioHalHidl::Tuner::onCallback(radio_hal_event_t *halEvent)
{
if (mCallback != 0) {
mCallback->onEvent(halEvent);
}
}
} // namespace android