Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b11a5896 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge changes from topic 'fix broadcast radio HIDL build'

* changes:
  fix build for HIDL broadcast radio HAL.
  Revert "Revert "broadcast radio: initial support for HIDL HAL""
parents 1c92a2ab 475d5837
Loading
Loading
Loading
Loading
+22 −3
Original line number Diff line number Diff line
@@ -18,8 +18,7 @@ include $(CLEAR_VARS)


LOCAL_SRC_FILES:= \
    RadioService.cpp \
    RadioHalLegacy.cpp
    RadioService.cpp

LOCAL_SHARED_LIBRARIES:= \
    liblog \
@@ -31,6 +30,26 @@ LOCAL_SHARED_LIBRARIES:= \
    libradio \
    libradio_metadata

ifeq ($(ENABLE_TREBLE),true)
# Treble configuration
LOCAL_CFLAGS += -DENABLE_TREBLE
LOCAL_SRC_FILES += \
    HidlUtils.cpp \
    RadioHalHidl.cpp

LOCAL_SHARED_LIBRARIES += \
    libhwbinder \
    libhidlbase \
    libhidltransport \
    libbase \
    android.hardware.broadcastradio@1.0
else
# libhardware configuration
LOCAL_SRC_FILES +=               \
    RadioHalLegacy.cpp
endif


LOCAL_CFLAGS += -Wall -Wextra -Werror

LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+179 −0
Original line number Diff line number Diff line
/*
 * 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 "HidlUtils"
//#define LOG_NDEBUG 0

#include <utils/Log.h>
#include <utils/misc.h>
#include <system/radio_metadata.h>

#include "HidlUtils.h"

namespace android {

using android::hardware::broadcastradio::V1_0::MetadataType;
using android::hardware::broadcastradio::V1_0::Band;
using android::hardware::broadcastradio::V1_0::Deemphasis;
using android::hardware::broadcastradio::V1_0::Rds;

//static
int HidlUtils::convertHalResult(Result result)
{
    switch (result) {
        case Result::OK:
            return 0;
        case Result::INVALID_ARGUMENTS:
            return -EINVAL;
        case Result::INVALID_STATE:
            return -ENOSYS;
        case Result::TIMEOUT:
            return -ETIMEDOUT;
        case Result::NOT_INITIALIZED:
        default:
            return -ENODEV;
    }
}


//static
void HidlUtils::convertBandConfigToHal(BandConfig *halConfig,
                                       const radio_hal_band_config_t *config)
{
    halConfig->type = static_cast<Band>(config->type);
    halConfig->antennaConnected = config->antenna_connected;
    halConfig->lowerLimit = config->lower_limit;
    halConfig->upperLimit = config->upper_limit;
    halConfig->spacings.setToExternal(const_cast<unsigned int *>(&config->spacings[0]),
                                       config->num_spacings * sizeof(uint32_t));
    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
    halConfig->spacings.resize(config->num_spacings);

    if (halConfig->type == Band::FM) {
        halConfig->ext.fm.deemphasis = static_cast<Deemphasis>(config->fm.deemphasis);
        halConfig->ext.fm.stereo = config->fm.stereo;
        halConfig->ext.fm.rds = static_cast<Rds>(config->fm.rds);
        halConfig->ext.fm.ta = config->fm.ta;
        halConfig->ext.fm.af = config->fm.af;
        halConfig->ext.fm.ea = config->fm.ea;
    } else {
        halConfig->ext.am.stereo = config->am.stereo;
    }
}

//static
void HidlUtils::convertPropertiesFromHal(radio_hal_properties_t *properties,
                                         const Properties *halProperties)
{
    properties->class_id = static_cast<radio_class_t>(halProperties->classId);
    strlcpy(properties->implementor, halProperties->implementor.c_str(), RADIO_STRING_LEN_MAX);
    strlcpy(properties->product, halProperties->product.c_str(), RADIO_STRING_LEN_MAX);
    strlcpy(properties->version, halProperties->version.c_str(), RADIO_STRING_LEN_MAX);
    strlcpy(properties->serial, halProperties->serial.c_str(), RADIO_STRING_LEN_MAX);
    properties->num_tuners = halProperties->numTuners;
    properties->num_audio_sources = halProperties->numAudioSources;
    properties->supports_capture = halProperties->supportsCapture;
    properties->num_bands = halProperties->bands.size();

    for (size_t i = 0; i < halProperties->bands.size(); i++) {
        convertBandConfigFromHal(&properties->bands[i], &halProperties->bands[i]);
    }
}

//static
void HidlUtils::convertBandConfigFromHal(radio_hal_band_config_t *config,
                                         const BandConfig *halConfig)
{
    config->type = static_cast<radio_band_t>(halConfig->type);
    config->antenna_connected = halConfig->antennaConnected;
    config->lower_limit = halConfig->lowerLimit;
    config->upper_limit = halConfig->upperLimit;
    config->num_spacings = halConfig->spacings.size();
    if (config->num_spacings > RADIO_NUM_SPACINGS_MAX) {
        config->num_spacings = RADIO_NUM_SPACINGS_MAX;
    }
    memcpy(config->spacings, halConfig->spacings.data(),
           sizeof(uint32_t) * config->num_spacings);

    if (halConfig->type == Band::FM) {
        config->fm.deemphasis = static_cast<radio_deemphasis_t>(halConfig->ext.fm.deemphasis);
        config->fm.stereo = halConfig->ext.fm.stereo;
        config->fm.rds = static_cast<radio_rds_t>(halConfig->ext.fm.rds);
        config->fm.ta = halConfig->ext.fm.ta;
        config->fm.af = halConfig->ext.fm.af;
        config->fm.ea = halConfig->ext.fm.ea;
    } else {
        config->am.stereo = halConfig->ext.am.stereo;
    }
}


//static
void HidlUtils::convertProgramInfoFromHal(radio_program_info_t *info,
                                          const ProgramInfo *halInfo,
                                          bool withMetadata)
{
    info->channel = halInfo->channel;
    info->sub_channel = halInfo->subChannel;
    info->tuned = halInfo->tuned;
    info->stereo = halInfo->stereo;
    info->digital = halInfo->digital;
    info->signal_strength = halInfo->signalStrength;
    if (withMetadata && halInfo->metadata.size() != 0) {
        convertMetaDataFromHal(&info->metadata, halInfo->metadata,
                               halInfo->channel, halInfo->subChannel);
    }
}

//static
void HidlUtils::convertMetaDataFromHal(radio_metadata_t **metadata,
                                       const hidl_vec<MetaData>& halMetadata,
                                       uint32_t channel,
                                       uint32_t subChannel)
{

    radio_metadata_allocate(metadata, channel, subChannel);
    for (size_t i = 0; i < halMetadata.size(); i++) {
        radio_metadata_key_t key = static_cast<radio_metadata_key_t>(halMetadata[i].key);
        radio_metadata_type_t type = static_cast<radio_metadata_key_t>(halMetadata[i].type);
        radio_metadata_clock_t clock;

        switch (type) {
        case RADIO_METADATA_TYPE_INT:
            radio_metadata_add_int(metadata, key, halMetadata[i].intValue);
            break;
        case RADIO_METADATA_TYPE_TEXT:
            radio_metadata_add_text(metadata, key, halMetadata[i].stringValue.c_str());
            break;
        case RADIO_METADATA_TYPE_RAW:
            radio_metadata_add_raw(metadata, key,
                                   halMetadata[i].rawValue.data(),
                                   halMetadata[i].rawValue.size());
            break;
        case RADIO_METADATA_TYPE_CLOCK:
            clock.utc_seconds_since_epoch =
                    halMetadata[i].clockValue.utcSecondsSinceEpoch;
            clock.timezone_offset_in_minutes =
                    halMetadata[i].clockValue.timezoneOffsetInMinutes;
            radio_metadata_add_clock(metadata, key, &clock);
            break;
        default:
            ALOGW("%s invalid metadata type %u",__FUNCTION__, halMetadata[i].type);
            break;
        }
    }
}

}  // namespace android
+51 −0
Original line number Diff line number Diff line
/*
 * 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.
 */
#ifndef ANDROID_HARDWARE_RADIO_HAL_HIDL_UTILS_H
#define ANDROID_HARDWARE_RADIO_HAL_HIDL_UTILS_H

#include <android/hardware/broadcastradio/1.0/types.h>
#include <hardware/radio.h>

namespace android {

using android::hardware::hidl_vec;
using android::hardware::broadcastradio::V1_0::Result;
using android::hardware::broadcastradio::V1_0::Properties;
using android::hardware::broadcastradio::V1_0::BandConfig;
using android::hardware::broadcastradio::V1_0::ProgramInfo;
using android::hardware::broadcastradio::V1_0::MetaData;

class HidlUtils {
public:
    static int convertHalResult(Result result);
    static void convertBandConfigFromHal(radio_hal_band_config_t *config,
                                         const BandConfig *halConfig);
    static void convertPropertiesFromHal(radio_hal_properties_t *properties,
                                         const Properties *halProperties);
    static void convertBandConfigToHal(BandConfig *halConfig,
                                       const radio_hal_band_config_t *config);
    static void convertProgramInfoFromHal(radio_program_info_t *info,
                                          const ProgramInfo *halInfo,
                                          bool withMetadata);
    static void convertMetaDataFromHal(radio_metadata_t **metadata,
                                       const hidl_vec<MetaData>& halMetadata,
                                       uint32_t channel,
                                       uint32_t subChannel);
};

}  // namespace android

#endif  // ANDROID_HARDWARE_RADIO_HAL_HIDL_UTILS_H
+388 −0
Original line number Diff line number Diff line
/*
 * 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
+108 −0

File added.

Preview size limit exceeded, changes collapsed.