Eric Laurent | a174588 | 2016-11-21 10:41:22 -0800 | [diff] [blame^] | 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 <utils/Log.h> |
| 20 | #include <utils/misc.h> |
| 21 | #include <system/radio_metadata.h> |
| 22 | |
| 23 | #include "Utils.h" |
| 24 | |
| 25 | namespace android { |
| 26 | namespace hardware { |
| 27 | namespace broadcastradio { |
| 28 | namespace V1_0 { |
| 29 | namespace implementation { |
| 30 | |
| 31 | const 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 |
| 38 | static_assert(RADIO_CLASS_AM_FM == static_cast<int>(Class::AM_FM), |
| 39 | "AM/FM class mismatch with legacy"); |
| 40 | static_assert(RADIO_CLASS_SAT == static_cast<int>(Class::SAT), |
| 41 | "SAT class mismatch with legacy"); |
| 42 | static_assert(RADIO_CLASS_DT == static_cast<int>(Class::DT), |
| 43 | "DT class mismatch with legacy"); |
| 44 | |
| 45 | static_assert(RADIO_BAND_AM == static_cast<int>(Band::AM), |
| 46 | "AM band mismatch with legacy"); |
| 47 | static_assert(RADIO_BAND_FM == static_cast<int>(Band::FM), |
| 48 | "FM band mismatch with legacy"); |
| 49 | static_assert(RADIO_BAND_AM_HD == static_cast<int>(Band::AM_HD), |
| 50 | "AM HD band mismatch with legacy"); |
| 51 | static_assert(RADIO_BAND_FM_HD == static_cast<int>(Band::FM_HD), |
| 52 | "FM HD band mismatch with legacy"); |
| 53 | |
| 54 | static_assert(RADIO_RDS_NONE == static_cast<int>(Rds::NONE), |
| 55 | "RDS NONE mismatch with legacy"); |
| 56 | static_assert(RADIO_RDS_WORLD == static_cast<int>(Rds::WORLD), |
| 57 | "RDS WORLD mismatch with legacy"); |
| 58 | static_assert(RADIO_RDS_US == static_cast<int>(Rds::US), |
| 59 | "RDS US mismatch with legacy"); |
| 60 | |
| 61 | static_assert(RADIO_DEEMPHASIS_50 == static_cast<int>(Deemphasis::D50), |
| 62 | "De-emphasis 50 mismatch with legacy"); |
| 63 | static_assert(RADIO_DEEMPHASIS_75 == static_cast<int>(Deemphasis::D75), |
| 64 | "De-emphasis 75 mismatch with legacy"); |
| 65 | |
| 66 | static_assert(RADIO_DIRECTION_UP == static_cast<int>(Direction::UP), |
| 67 | "Direction Up mismatch with legacy"); |
| 68 | static_assert(RADIO_DIRECTION_DOWN == static_cast<int>(Direction::DOWN), |
| 69 | "Direction Up mismatch with legacy"); |
| 70 | |
| 71 | static_assert(RADIO_METADATA_TYPE_INVALID == static_cast<int>(MetadataType::INVALID), |
| 72 | "Metadata type INVALID mismatch with legacy"); |
| 73 | static_assert(RADIO_METADATA_TYPE_INT == static_cast<int>(MetadataType::INT), |
| 74 | "Metadata type INT mismatch with legacy"); |
| 75 | static_assert(RADIO_METADATA_TYPE_TEXT == static_cast<int>(MetadataType::TEXT), |
| 76 | "Metadata type TEXT mismatch with legacy"); |
| 77 | static_assert(RADIO_METADATA_TYPE_RAW == static_cast<int>(MetadataType::RAW), |
| 78 | "Metadata type RAW mismatch with legacy"); |
| 79 | static_assert(RADIO_METADATA_TYPE_CLOCK == static_cast<int>(MetadataType::CLOCK), |
| 80 | "Metadata type CLOCK mismatch with legacy"); |
| 81 | |
| 82 | static_assert(RADIO_METADATA_KEY_INVALID == static_cast<int>(MetadataKey::INVALID), |
| 83 | "Metadata key INVALID mismatch with legacy"); |
| 84 | static_assert(RADIO_METADATA_KEY_RDS_PI == static_cast<int>(MetadataKey::RDS_PI), |
| 85 | "Metadata key RDS_PI mismatch with legacy"); |
| 86 | static_assert(RADIO_METADATA_KEY_RDS_PS == static_cast<int>(MetadataKey::RDS_PS), |
| 87 | "Metadata key RDS_PS mismatch with legacy"); |
| 88 | static_assert(RADIO_METADATA_KEY_RDS_PTY == static_cast<int>(MetadataKey::RDS_PTY), |
| 89 | "Metadata key RDS_PTY mismatch with legacy"); |
| 90 | static_assert(RADIO_METADATA_KEY_RBDS_PTY == static_cast<int>(MetadataKey::RBDS_PTY), |
| 91 | "Metadata key RBDS_PTY mismatch with legacy"); |
| 92 | static_assert(RADIO_METADATA_KEY_RDS_RT == static_cast<int>(MetadataKey::RDS_RT), |
| 93 | "Metadata key RDS_RT mismatch with legacy"); |
| 94 | static_assert(RADIO_METADATA_KEY_TITLE == static_cast<int>(MetadataKey::TITLE), |
| 95 | "Metadata key TITLE mismatch with legacy"); |
| 96 | static_assert(RADIO_METADATA_KEY_ARTIST == static_cast<int>(MetadataKey::ARTIST), |
| 97 | "Metadata key ARTIST mismatch with legacy"); |
| 98 | static_assert(RADIO_METADATA_KEY_ALBUM == static_cast<int>(MetadataKey::ALBUM), |
| 99 | "Metadata key ALBUM mismatch with legacy"); |
| 100 | static_assert(RADIO_METADATA_KEY_GENRE == static_cast<int>(MetadataKey::GENRE), |
| 101 | "Metadata key GENRE mismatch with legacy"); |
| 102 | static_assert(RADIO_METADATA_KEY_ICON == static_cast<int>(MetadataKey::ICON), |
| 103 | "Metadata key ICON mismatch with legacy"); |
| 104 | static_assert(RADIO_METADATA_KEY_ART == static_cast<int>(MetadataKey::ART), |
| 105 | "Metadata key ART mismatch with legacy"); |
| 106 | static_assert(RADIO_METADATA_KEY_CLOCK == static_cast<int>(MetadataKey::CLOCK), |
| 107 | "Metadata key CLOCK mismatch with legacy"); |
| 108 | |
| 109 | |
| 110 | //static |
| 111 | const 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 |
| 124 | Result 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 |
| 142 | void 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 |
| 169 | void 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 |
| 194 | void 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 |
| 224 | void Utils::convertProgramInfoFromHal(ProgramInfo *info, |
| 225 | radio_program_info_t *halInfo, |
| 226 | bool withMetadata) |
| 227 | { |
| 228 | info->channel = halInfo->channel; |
| 229 | info->subChannel = halInfo->sub_channel; |
| 230 | info->tuned = halInfo->tuned; |
| 231 | info->stereo = halInfo->stereo; |
| 232 | info->digital = halInfo->digital; |
| 233 | info->signalStrength = halInfo->signal_strength; |
| 234 | if (withMetadata && halInfo->metadata != NULL) { |
| 235 | convertMetaDataFromHal(info->metadata, halInfo->metadata); |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | //static |
| 240 | int Utils::convertMetaDataFromHal(hidl_vec<MetaData>& metadata, |
| 241 | radio_metadata_t *halMetadata) |
| 242 | { |
| 243 | if (halMetadata == NULL) { |
| 244 | return 0; |
| 245 | } |
| 246 | |
| 247 | int count = radio_metadata_get_count(halMetadata); |
| 248 | if (count <= 0) { |
| 249 | return count; |
| 250 | } |
| 251 | MetaData *newMetadata = |
| 252 | new MetaData[count]; |
| 253 | int outCount = 0; |
| 254 | for (int i = 0; i < count; i++) { |
| 255 | radio_metadata_key_t key; |
| 256 | radio_metadata_type_t type; |
| 257 | void *value; |
| 258 | size_t size; |
| 259 | if (radio_metadata_get_at_index(halMetadata, i , &key, &type, &value, &size) != 0 || |
| 260 | size == 0) { |
| 261 | continue; |
| 262 | } |
| 263 | switch (type) { |
| 264 | case RADIO_METADATA_TYPE_INT: { |
| 265 | newMetadata[outCount].intValue = *(static_cast<int32_t *>(value)); |
| 266 | } break; |
| 267 | case RADIO_METADATA_TYPE_TEXT: { |
| 268 | newMetadata[outCount].stringValue = static_cast<char *>(value); |
| 269 | } break; |
| 270 | case RADIO_METADATA_TYPE_RAW: { |
| 271 | newMetadata[outCount].rawValue.setToExternal(static_cast<uint8_t *>(value), size); |
| 272 | // FIXME: transfer buffer ownership. should have a method for that in hidl_vec |
| 273 | newMetadata[outCount].rawValue.resize(size); |
| 274 | } break; |
| 275 | case RADIO_METADATA_TYPE_CLOCK: { |
| 276 | radio_metadata_clock_t *clock = static_cast<radio_metadata_clock_t *>(value); |
| 277 | newMetadata[outCount].clockValue.utcSecondsSinceEpoch = |
| 278 | clock->utc_seconds_since_epoch; |
| 279 | newMetadata[outCount].clockValue.timezoneOffsetInMinutes = |
| 280 | clock->timezone_offset_in_minutes; |
| 281 | } break; |
| 282 | } |
| 283 | newMetadata[outCount].type = static_cast<MetadataType>(type); |
| 284 | newMetadata[outCount].key = static_cast<MetadataKey>(key); |
| 285 | outCount++; |
| 286 | } |
| 287 | metadata.setToExternal(newMetadata, outCount); |
| 288 | // FIXME: transfer buffer ownership. should have a method for that in hidl_vec |
| 289 | metadata.resize(outCount); |
| 290 | return outCount; |
| 291 | } |
| 292 | |
| 293 | } // namespace implementation |
| 294 | } // namespace V1_0 |
| 295 | } // namespace broadcastradio |
| 296 | } // namespace hardware |
| 297 | } // namespace android |