/* * Copyright (C) 2017 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 "BroadcastRadioHalUtils" //#define LOG_NDEBUG 0 #include <log/log.h> #include <system/radio_metadata.h> #include "Utils.h" namespace android { namespace hardware { namespace broadcastradio { namespace V1_1 { namespace implementation { using V1_0::Band; using V1_0::Deemphasis; using V1_0::Direction; using V1_0::MetadataKey; using V1_0::MetadataType; using V1_0::Rds; const char *Utils::sClassModuleNames[] = { RADIO_HARDWARE_MODULE_ID_FM, /* corresponds to RADIO_CLASS_AM_FM */ RADIO_HARDWARE_MODULE_ID_SAT, /* corresponds to RADIO_CLASS_SAT */ RADIO_HARDWARE_MODULE_ID_DT, /* corresponds to RADIO_CLASS_DT */ }; // make sure HIDL enum values are aligned with legacy values static_assert(RADIO_CLASS_AM_FM == static_cast<int>(Class::AM_FM), "AM/FM class mismatch with legacy"); static_assert(RADIO_CLASS_SAT == static_cast<int>(Class::SAT), "SAT class mismatch with legacy"); static_assert(RADIO_CLASS_DT == static_cast<int>(Class::DT), "DT class mismatch with legacy"); static_assert(RADIO_BAND_AM == static_cast<int>(Band::AM), "AM band mismatch with legacy"); static_assert(RADIO_BAND_FM == static_cast<int>(Band::FM), "FM band mismatch with legacy"); static_assert(RADIO_BAND_AM_HD == static_cast<int>(Band::AM_HD), "AM HD band mismatch with legacy"); static_assert(RADIO_BAND_FM_HD == static_cast<int>(Band::FM_HD), "FM HD band mismatch with legacy"); static_assert(RADIO_RDS_NONE == static_cast<int>(Rds::NONE), "RDS NONE mismatch with legacy"); static_assert(RADIO_RDS_WORLD == static_cast<int>(Rds::WORLD), "RDS WORLD mismatch with legacy"); static_assert(RADIO_RDS_US == static_cast<int>(Rds::US), "RDS US mismatch with legacy"); static_assert(RADIO_DEEMPHASIS_50 == static_cast<int>(Deemphasis::D50), "De-emphasis 50 mismatch with legacy"); static_assert(RADIO_DEEMPHASIS_75 == static_cast<int>(Deemphasis::D75), "De-emphasis 75 mismatch with legacy"); static_assert(RADIO_DIRECTION_UP == static_cast<int>(Direction::UP), "Direction Up mismatch with legacy"); static_assert(RADIO_DIRECTION_DOWN == static_cast<int>(Direction::DOWN), "Direction Up mismatch with legacy"); static_assert(RADIO_METADATA_TYPE_INVALID == static_cast<int>(MetadataType::INVALID), "Metadata type INVALID mismatch with legacy"); static_assert(RADIO_METADATA_TYPE_INT == static_cast<int>(MetadataType::INT), "Metadata type INT mismatch with legacy"); static_assert(RADIO_METADATA_TYPE_TEXT == static_cast<int>(MetadataType::TEXT), "Metadata type TEXT mismatch with legacy"); static_assert(RADIO_METADATA_TYPE_RAW == static_cast<int>(MetadataType::RAW), "Metadata type RAW mismatch with legacy"); static_assert(RADIO_METADATA_TYPE_CLOCK == static_cast<int>(MetadataType::CLOCK), "Metadata type CLOCK mismatch with legacy"); static_assert(RADIO_METADATA_KEY_INVALID == static_cast<int>(MetadataKey::INVALID), "Metadata key INVALID mismatch with legacy"); static_assert(RADIO_METADATA_KEY_RDS_PI == static_cast<int>(MetadataKey::RDS_PI), "Metadata key RDS_PI mismatch with legacy"); static_assert(RADIO_METADATA_KEY_RDS_PS == static_cast<int>(MetadataKey::RDS_PS), "Metadata key RDS_PS mismatch with legacy"); static_assert(RADIO_METADATA_KEY_RDS_PTY == static_cast<int>(MetadataKey::RDS_PTY), "Metadata key RDS_PTY mismatch with legacy"); static_assert(RADIO_METADATA_KEY_RBDS_PTY == static_cast<int>(MetadataKey::RBDS_PTY), "Metadata key RBDS_PTY mismatch with legacy"); static_assert(RADIO_METADATA_KEY_RDS_RT == static_cast<int>(MetadataKey::RDS_RT), "Metadata key RDS_RT mismatch with legacy"); static_assert(RADIO_METADATA_KEY_TITLE == static_cast<int>(MetadataKey::TITLE), "Metadata key TITLE mismatch with legacy"); static_assert(RADIO_METADATA_KEY_ARTIST == static_cast<int>(MetadataKey::ARTIST), "Metadata key ARTIST mismatch with legacy"); static_assert(RADIO_METADATA_KEY_ALBUM == static_cast<int>(MetadataKey::ALBUM), "Metadata key ALBUM mismatch with legacy"); static_assert(RADIO_METADATA_KEY_GENRE == static_cast<int>(MetadataKey::GENRE), "Metadata key GENRE mismatch with legacy"); static_assert(RADIO_METADATA_KEY_ICON == static_cast<int>(MetadataKey::ICON), "Metadata key ICON mismatch with legacy"); static_assert(RADIO_METADATA_KEY_ART == static_cast<int>(MetadataKey::ART), "Metadata key ART mismatch with legacy"); static_assert(RADIO_METADATA_KEY_CLOCK == static_cast<int>(MetadataKey::CLOCK), "Metadata key CLOCK mismatch with legacy"); //static const char * Utils::getClassString(Class ClassId) { int id = static_cast<int>(ClassId); if ((id < 0) || (id >= NELEM(sClassModuleNames))) { ALOGE("invalid class ID %d", id); return NULL; } return sClassModuleNames[id]; } //static Result Utils::convertHalResult(int rc) { switch (rc) { case 0: return Result::OK; case -EINVAL: return Result::INVALID_ARGUMENTS; case -ENOSYS: return Result::INVALID_STATE; case -ETIMEDOUT: return Result::TIMEOUT; case -ENODEV: default: return Result::NOT_INITIALIZED; } } //static void Utils::convertBandConfigFromHal( BandConfig *config, const radio_hal_band_config_t *halConfig) { config->type = static_cast<Band>(halConfig->type); config->antennaConnected = halConfig->antenna_connected; config->lowerLimit = halConfig->lower_limit; config->upperLimit = halConfig->upper_limit; config->spacings.setToExternal(const_cast<unsigned int *>(&halConfig->spacings[0]), halConfig->num_spacings * sizeof(uint32_t)); // FIXME: transfer buffer ownership. should have a method for that in hidl_vec config->spacings.resize(halConfig->num_spacings); if (config->type == Band::FM) { config->ext.fm.deemphasis = static_cast<Deemphasis>(halConfig->fm.deemphasis); config->ext.fm.stereo = halConfig->fm.stereo; config->ext.fm.rds = static_cast<Rds>(halConfig->fm.rds); config->ext.fm.ta = halConfig->fm.ta; config->ext.fm.af = halConfig->fm.af; config->ext.fm.ea = halConfig->fm.ea; } else { config->ext.am.stereo = halConfig->am.stereo; } } //static void Utils::convertPropertiesFromHal(Properties *properties, const radio_hal_properties_t *halProperties) { properties->classId = static_cast<Class>(halProperties->class_id); properties->implementor.setToExternal(halProperties->implementor, strlen(halProperties->implementor)); properties->product.setToExternal(halProperties->product, strlen(halProperties->product)); properties->version.setToExternal(halProperties->version, strlen(halProperties->version)); properties->serial.setToExternal(halProperties->serial, strlen(halProperties->serial)); properties->numTuners = halProperties->num_tuners; properties->numAudioSources = halProperties->num_audio_sources; properties->supportsCapture = halProperties->supports_capture; BandConfig *bands = new BandConfig[halProperties->num_bands]; for (size_t i = 0; i < halProperties->num_bands; i++) { convertBandConfigFromHal(&bands[i], &halProperties->bands[i]); } properties->bands.setToExternal(bands, halProperties->num_bands); // FIXME: transfer buffer ownership. should have a method for that in hidl_vec properties->bands.resize(halProperties->num_bands); delete[] bands; } //static void Utils::convertBandConfigToHal(radio_hal_band_config_t *halConfig, const BandConfig *config) { halConfig->type = static_cast<radio_band_t>(config->type); halConfig->antenna_connected = config->antennaConnected; halConfig->lower_limit = config->lowerLimit; halConfig->upper_limit = config->upperLimit; halConfig->num_spacings = config->spacings.size(); if (halConfig->num_spacings > RADIO_NUM_SPACINGS_MAX) { halConfig->num_spacings = RADIO_NUM_SPACINGS_MAX; } memcpy(halConfig->spacings, config->spacings.data(), sizeof(uint32_t) * halConfig->num_spacings); if (config->type == Band::FM) { halConfig->fm.deemphasis = static_cast<radio_deemphasis_t>(config->ext.fm.deemphasis); halConfig->fm.stereo = config->ext.fm.stereo; halConfig->fm.rds = static_cast<radio_rds_t>(config->ext.fm.rds); halConfig->fm.ta = config->ext.fm.ta; halConfig->fm.af = config->ext.fm.af; halConfig->fm.ea = config->ext.fm.ea; } else { halConfig->am.stereo = config->ext.am.stereo; } } //static void Utils::convertProgramInfoFromHal(ProgramInfo *info, radio_program_info_t *halInfo) { auto &info_1_1 = *info; auto &info_1_0 = info->base; info_1_0.channel = halInfo->channel; info_1_0.subChannel = halInfo->sub_channel; info_1_0.tuned = halInfo->tuned; info_1_0.stereo = halInfo->stereo; info_1_0.digital = halInfo->digital; info_1_0.signalStrength = halInfo->signal_strength; convertMetaDataFromHal(info_1_0.metadata, halInfo->metadata); // TODO(b/34348946): add support for HAL 1.1 fields info_1_1.flags = 0; } //static int Utils::convertMetaDataFromHal(hidl_vec<MetaData>& metadata, radio_metadata_t *halMetadata) { if (halMetadata == NULL) { ALOGE("Invalid argument: halMetadata is NULL"); return 0; } int count = radio_metadata_get_count(halMetadata); if (count <= 0) { return count; } MetaData *newMetadata = new MetaData[count]; int outCount = 0; for (int i = 0; i < count; i++) { radio_metadata_key_t key; radio_metadata_type_t type; void *value; size_t size; if (radio_metadata_get_at_index(halMetadata, i , &key, &type, &value, &size) != 0 || size == 0) { continue; } switch (type) { case RADIO_METADATA_TYPE_INT: { newMetadata[outCount].intValue = *(static_cast<int32_t *>(value)); } break; case RADIO_METADATA_TYPE_TEXT: { newMetadata[outCount].stringValue = static_cast<char *>(value); } break; case RADIO_METADATA_TYPE_RAW: { newMetadata[outCount].rawValue.setToExternal(static_cast<uint8_t *>(value), size); // FIXME: transfer buffer ownership. should have a method for that in hidl_vec newMetadata[outCount].rawValue.resize(size); } break; case RADIO_METADATA_TYPE_CLOCK: { radio_metadata_clock_t *clock = static_cast<radio_metadata_clock_t *>(value); newMetadata[outCount].clockValue.utcSecondsSinceEpoch = clock->utc_seconds_since_epoch; newMetadata[outCount].clockValue.timezoneOffsetInMinutes = clock->timezone_offset_in_minutes; } break; } newMetadata[outCount].type = static_cast<MetadataType>(type); newMetadata[outCount].key = static_cast<MetadataKey>(key); outCount++; } metadata.setToExternal(newMetadata, outCount); // FIXME: transfer buffer ownership. should have a method for that in hidl_vec metadata.resize(outCount); return outCount; } } // namespace implementation } // namespace V1_1 } // namespace broadcastradio } // namespace hardware } // namespace android