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#define LOG_TAG "BroadcastRadioHalUtils" 17//#define LOG_NDEBUG 0 18 19#include <log/log.h> 20#include <utils/misc.h> 21#include <system/radio_metadata.h> 22 23#include "Utils.h" 24 25namespace android { 26namespace hardware { 27namespace broadcastradio { 28namespace V1_0 { 29namespace implementation { 30 31const char *Utils::sClassModuleNames[] = { 32 RADIO_HARDWARE_MODULE_ID_FM, /* corresponds to RADIO_CLASS_AM_FM */ 33 RADIO_HARDWARE_MODULE_ID_SAT, /* corresponds to RADIO_CLASS_SAT */ 34 RADIO_HARDWARE_MODULE_ID_DT, /* corresponds to RADIO_CLASS_DT */ 35}; 36 37// make sure HIDL enum values are aligned with legacy values 38static_assert(RADIO_CLASS_AM_FM == static_cast<int>(Class::AM_FM), 39 "AM/FM class mismatch with legacy"); 40static_assert(RADIO_CLASS_SAT == static_cast<int>(Class::SAT), 41 "SAT class mismatch with legacy"); 42static_assert(RADIO_CLASS_DT == static_cast<int>(Class::DT), 43 "DT class mismatch with legacy"); 44 45static_assert(RADIO_BAND_AM == static_cast<int>(Band::AM), 46 "AM band mismatch with legacy"); 47static_assert(RADIO_BAND_FM == static_cast<int>(Band::FM), 48 "FM band mismatch with legacy"); 49static_assert(RADIO_BAND_AM_HD == static_cast<int>(Band::AM_HD), 50 "AM HD band mismatch with legacy"); 51static_assert(RADIO_BAND_FM_HD == static_cast<int>(Band::FM_HD), 52 "FM HD band mismatch with legacy"); 53 54static_assert(RADIO_RDS_NONE == static_cast<int>(Rds::NONE), 55 "RDS NONE mismatch with legacy"); 56static_assert(RADIO_RDS_WORLD == static_cast<int>(Rds::WORLD), 57 "RDS WORLD mismatch with legacy"); 58static_assert(RADIO_RDS_US == static_cast<int>(Rds::US), 59 "RDS US mismatch with legacy"); 60 61static_assert(RADIO_DEEMPHASIS_50 == static_cast<int>(Deemphasis::D50), 62 "De-emphasis 50 mismatch with legacy"); 63static_assert(RADIO_DEEMPHASIS_75 == static_cast<int>(Deemphasis::D75), 64 "De-emphasis 75 mismatch with legacy"); 65 66static_assert(RADIO_DIRECTION_UP == static_cast<int>(Direction::UP), 67 "Direction Up mismatch with legacy"); 68static_assert(RADIO_DIRECTION_DOWN == static_cast<int>(Direction::DOWN), 69 "Direction Up mismatch with legacy"); 70 71static_assert(RADIO_METADATA_TYPE_INVALID == static_cast<int>(MetadataType::INVALID), 72 "Metadata type INVALID mismatch with legacy"); 73static_assert(RADIO_METADATA_TYPE_INT == static_cast<int>(MetadataType::INT), 74 "Metadata type INT mismatch with legacy"); 75static_assert(RADIO_METADATA_TYPE_TEXT == static_cast<int>(MetadataType::TEXT), 76 "Metadata type TEXT mismatch with legacy"); 77static_assert(RADIO_METADATA_TYPE_RAW == static_cast<int>(MetadataType::RAW), 78 "Metadata type RAW mismatch with legacy"); 79static_assert(RADIO_METADATA_TYPE_CLOCK == static_cast<int>(MetadataType::CLOCK), 80 "Metadata type CLOCK mismatch with legacy"); 81 82static_assert(RADIO_METADATA_KEY_INVALID == static_cast<int>(MetadataKey::INVALID), 83 "Metadata key INVALID mismatch with legacy"); 84static_assert(RADIO_METADATA_KEY_RDS_PI == static_cast<int>(MetadataKey::RDS_PI), 85 "Metadata key RDS_PI mismatch with legacy"); 86static_assert(RADIO_METADATA_KEY_RDS_PS == static_cast<int>(MetadataKey::RDS_PS), 87 "Metadata key RDS_PS mismatch with legacy"); 88static_assert(RADIO_METADATA_KEY_RDS_PTY == static_cast<int>(MetadataKey::RDS_PTY), 89 "Metadata key RDS_PTY mismatch with legacy"); 90static_assert(RADIO_METADATA_KEY_RBDS_PTY == static_cast<int>(MetadataKey::RBDS_PTY), 91 "Metadata key RBDS_PTY mismatch with legacy"); 92static_assert(RADIO_METADATA_KEY_RDS_RT == static_cast<int>(MetadataKey::RDS_RT), 93 "Metadata key RDS_RT mismatch with legacy"); 94static_assert(RADIO_METADATA_KEY_TITLE == static_cast<int>(MetadataKey::TITLE), 95 "Metadata key TITLE mismatch with legacy"); 96static_assert(RADIO_METADATA_KEY_ARTIST == static_cast<int>(MetadataKey::ARTIST), 97 "Metadata key ARTIST mismatch with legacy"); 98static_assert(RADIO_METADATA_KEY_ALBUM == static_cast<int>(MetadataKey::ALBUM), 99 "Metadata key ALBUM mismatch with legacy"); 100static_assert(RADIO_METADATA_KEY_GENRE == static_cast<int>(MetadataKey::GENRE), 101 "Metadata key GENRE mismatch with legacy"); 102static_assert(RADIO_METADATA_KEY_ICON == static_cast<int>(MetadataKey::ICON), 103 "Metadata key ICON mismatch with legacy"); 104static_assert(RADIO_METADATA_KEY_ART == static_cast<int>(MetadataKey::ART), 105 "Metadata key ART mismatch with legacy"); 106static_assert(RADIO_METADATA_KEY_CLOCK == static_cast<int>(MetadataKey::CLOCK), 107 "Metadata key CLOCK mismatch with legacy"); 108 109 110//static 111const char * Utils::getClassString(Class ClassId) 112{ 113 int id = static_cast<int>(ClassId); 114 115 if ((id < 0) || 116 (id >= NELEM(sClassModuleNames))) { 117 ALOGE("invalid class ID %d", id); 118 return NULL; 119 } 120 return sClassModuleNames[id]; 121} 122 123//static 124Result Utils::convertHalResult(int rc) 125{ 126 switch (rc) { 127 case 0: 128 return Result::OK; 129 case -EINVAL: 130 return Result::INVALID_ARGUMENTS; 131 case -ENOSYS: 132 return Result::INVALID_STATE; 133 case -ETIMEDOUT: 134 return Result::TIMEOUT; 135 case -ENODEV: 136 default: 137 return Result::NOT_INITIALIZED; 138 } 139} 140 141//static 142void Utils::convertBandConfigFromHal( 143 BandConfig *config, 144 const radio_hal_band_config_t *halConfig) 145{ 146 147 config->type = static_cast<Band>(halConfig->type); 148 config->antennaConnected = halConfig->antenna_connected; 149 config->lowerLimit = halConfig->lower_limit; 150 config->upperLimit = halConfig->upper_limit; 151 config->spacings.setToExternal(const_cast<unsigned int *>(&halConfig->spacings[0]), 152 halConfig->num_spacings * sizeof(uint32_t)); 153 // FIXME: transfer buffer ownership. should have a method for that in hidl_vec 154 config->spacings.resize(halConfig->num_spacings); 155 156 if (config->type == Band::FM) { 157 config->ext.fm.deemphasis = static_cast<Deemphasis>(halConfig->fm.deemphasis); 158 config->ext.fm.stereo = halConfig->fm.stereo; 159 config->ext.fm.rds = static_cast<Rds>(halConfig->fm.rds); 160 config->ext.fm.ta = halConfig->fm.ta; 161 config->ext.fm.af = halConfig->fm.af; 162 config->ext.fm.ea = halConfig->fm.ea; 163 } else { 164 config->ext.am.stereo = halConfig->am.stereo; 165 } 166} 167 168//static 169void Utils::convertPropertiesFromHal( 170 Properties *properties, 171 const radio_hal_properties_t *halProperties) 172{ 173 properties->classId = static_cast<Class>(halProperties->class_id); 174 properties->implementor.setToExternal(halProperties->implementor, strlen(halProperties->implementor)); 175 properties->product.setToExternal(halProperties->product, strlen(halProperties->product)); 176 properties->version.setToExternal(halProperties->version, strlen(halProperties->version)); 177 properties->serial.setToExternal(halProperties->serial, strlen(halProperties->serial)); 178 properties->numTuners = halProperties->num_tuners; 179 properties->numAudioSources = halProperties->num_audio_sources; 180 properties->supportsCapture = halProperties->supports_capture; 181 182 BandConfig *bands = 183 new BandConfig[halProperties->num_bands]; 184 for (size_t i = 0; i < halProperties->num_bands; i++) { 185 convertBandConfigFromHal(&bands[i], &halProperties->bands[i]); 186 } 187 properties->bands.setToExternal(bands, halProperties->num_bands); 188 // FIXME: transfer buffer ownership. should have a method for that in hidl_vec 189 properties->bands.resize(halProperties->num_bands); 190 delete[] bands; 191} 192 193//static 194void Utils::convertBandConfigToHal( 195 radio_hal_band_config_t *halConfig, 196 const BandConfig *config) 197{ 198 199 halConfig->type = static_cast<radio_band_t>(config->type); 200 halConfig->antenna_connected = config->antennaConnected; 201 halConfig->lower_limit = config->lowerLimit; 202 halConfig->upper_limit = config->upperLimit; 203 halConfig->num_spacings = config->spacings.size(); 204 if (halConfig->num_spacings > RADIO_NUM_SPACINGS_MAX) { 205 halConfig->num_spacings = RADIO_NUM_SPACINGS_MAX; 206 } 207 memcpy(halConfig->spacings, config->spacings.data(), 208 sizeof(uint32_t) * halConfig->num_spacings); 209 210 if (config->type == Band::FM) { 211 halConfig->fm.deemphasis = static_cast<radio_deemphasis_t>(config->ext.fm.deemphasis); 212 halConfig->fm.stereo = config->ext.fm.stereo; 213 halConfig->fm.rds = static_cast<radio_rds_t>(config->ext.fm.rds); 214 halConfig->fm.ta = config->ext.fm.ta; 215 halConfig->fm.af = config->ext.fm.af; 216 halConfig->fm.ea = config->ext.fm.ea; 217 } else { 218 halConfig->am.stereo = config->ext.am.stereo; 219 } 220} 221 222 223//static 224void Utils::convertProgramInfoFromHal(ProgramInfo *info, 225 radio_program_info_t *halInfo) 226{ 227 info->channel = halInfo->channel; 228 info->subChannel = halInfo->sub_channel; 229 info->tuned = halInfo->tuned; 230 info->stereo = halInfo->stereo; 231 info->digital = halInfo->digital; 232 info->signalStrength = halInfo->signal_strength; 233 convertMetaDataFromHal(info->metadata, halInfo->metadata); 234} 235 236//static 237int Utils::convertMetaDataFromHal(hidl_vec<MetaData>& metadata, 238 radio_metadata_t *halMetadata) 239{ 240 if (halMetadata == NULL) { 241 ALOGE("Invalid argument: halMetadata is NULL"); 242 return 0; 243 } 244 245 int count = radio_metadata_get_count(halMetadata); 246 if (count <= 0) { 247 return count; 248 } 249 MetaData *newMetadata = 250 new MetaData[count]; 251 int outCount = 0; 252 for (int i = 0; i < count; i++) { 253 radio_metadata_key_t key; 254 radio_metadata_type_t type; 255 void *value; 256 size_t size; 257 if (radio_metadata_get_at_index(halMetadata, i , &key, &type, &value, &size) != 0 || 258 size == 0) { 259 continue; 260 } 261 switch (type) { 262 case RADIO_METADATA_TYPE_INT: { 263 newMetadata[outCount].intValue = *(static_cast<int32_t *>(value)); 264 } break; 265 case RADIO_METADATA_TYPE_TEXT: { 266 newMetadata[outCount].stringValue = static_cast<char *>(value); 267 } break; 268 case RADIO_METADATA_TYPE_RAW: { 269 newMetadata[outCount].rawValue.setToExternal(static_cast<uint8_t *>(value), size); 270 // FIXME: transfer buffer ownership. should have a method for that in hidl_vec 271 newMetadata[outCount].rawValue.resize(size); 272 } break; 273 case RADIO_METADATA_TYPE_CLOCK: { 274 radio_metadata_clock_t *clock = static_cast<radio_metadata_clock_t *>(value); 275 newMetadata[outCount].clockValue.utcSecondsSinceEpoch = 276 clock->utc_seconds_since_epoch; 277 newMetadata[outCount].clockValue.timezoneOffsetInMinutes = 278 clock->timezone_offset_in_minutes; 279 } break; 280 } 281 newMetadata[outCount].type = static_cast<MetadataType>(type); 282 newMetadata[outCount].key = static_cast<MetadataKey>(key); 283 outCount++; 284 } 285 metadata.setToExternal(newMetadata, outCount); 286 // FIXME: transfer buffer ownership. should have a method for that in hidl_vec 287 metadata.resize(outCount); 288 return outCount; 289} 290 291} // namespace implementation 292} // namespace V1_0 293} // namespace broadcastradio 294} // namespace hardware 295} // namespace android 296