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