| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -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 |  | 
 | 17 | #include <string.h> | 
 | 18 |  | 
 | 19 | #define LOG_TAG "HalHidl" | 
 | 20 | #include <media/AudioParameter.h> | 
 | 21 | #include <utils/Log.h> | 
 | 22 |  | 
 | 23 | #include "ConversionHelperHidl.h" | 
 | 24 |  | 
| jiabin | 9ff780e | 2018-03-19 18:19:52 -0700 | [diff] [blame^] | 25 | using ::android::hardware::audio::V4_0::AudioMicrophoneChannelMapping; | 
 | 26 | using ::android::hardware::audio::V4_0::AudioMicrophoneDirectionality; | 
 | 27 | using ::android::hardware::audio::V4_0::AudioMicrophoneLocation; | 
 | 28 | using ::android::hardware::audio::V4_0::DeviceAddress; | 
 | 29 | using ::android::hardware::audio::V4_0::MicrophoneInfo; | 
| Kevin Rocard | 51e076a | 2018-02-28 14:36:53 -0800 | [diff] [blame] | 30 | using ::android::hardware::audio::V4_0::Result; | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 31 |  | 
 | 32 | namespace android { | 
| Kevin Rocard | 51e076a | 2018-02-28 14:36:53 -0800 | [diff] [blame] | 33 | namespace V4_0 { | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 34 |  | 
 | 35 | // static | 
 | 36 | status_t ConversionHelperHidl::keysFromHal(const String8& keys, hidl_vec<hidl_string> *hidlKeys) { | 
 | 37 |     AudioParameter halKeys(keys); | 
 | 38 |     if (halKeys.size() == 0) return BAD_VALUE; | 
 | 39 |     hidlKeys->resize(halKeys.size()); | 
 | 40 |     //FIXME:  keyStreamSupportedChannels and keyStreamSupportedSamplingRates come with a | 
 | 41 |     // "keyFormat=<value>" pair. We need to transform it into a single key string so that it is | 
 | 42 |     // carried over to the legacy HAL via HIDL. | 
 | 43 |     String8 value; | 
 | 44 |     bool keepFormatValue = halKeys.size() == 2 && | 
 | 45 |          (halKeys.get(String8(AudioParameter::keyStreamSupportedChannels), value) == NO_ERROR || | 
 | 46 |          halKeys.get(String8(AudioParameter::keyStreamSupportedSamplingRates), value) == NO_ERROR); | 
 | 47 |  | 
 | 48 |     for (size_t i = 0; i < halKeys.size(); ++i) { | 
 | 49 |         String8 key; | 
 | 50 |         status_t status = halKeys.getAt(i, key); | 
 | 51 |         if (status != OK) return status; | 
 | 52 |         if (keepFormatValue && key == AudioParameter::keyFormat) { | 
 | 53 |             AudioParameter formatParam; | 
 | 54 |             halKeys.getAt(i, key, value); | 
 | 55 |             formatParam.add(key, value); | 
 | 56 |             key = formatParam.toString(); | 
 | 57 |         } | 
 | 58 |         (*hidlKeys)[i] = key.string(); | 
 | 59 |     } | 
 | 60 |     return OK; | 
 | 61 | } | 
 | 62 |  | 
 | 63 | // static | 
 | 64 | status_t ConversionHelperHidl::parametersFromHal( | 
 | 65 |         const String8& kvPairs, hidl_vec<ParameterValue> *hidlParams) { | 
 | 66 |     AudioParameter params(kvPairs); | 
 | 67 |     if (params.size() == 0) return BAD_VALUE; | 
 | 68 |     hidlParams->resize(params.size()); | 
 | 69 |     for (size_t i = 0; i < params.size(); ++i) { | 
 | 70 |         String8 key, value; | 
 | 71 |         status_t status = params.getAt(i, key, value); | 
 | 72 |         if (status != OK) return status; | 
 | 73 |         (*hidlParams)[i].key = key.string(); | 
 | 74 |         (*hidlParams)[i].value = value.string(); | 
 | 75 |     } | 
 | 76 |     return OK; | 
 | 77 | } | 
 | 78 |  | 
 | 79 | // static | 
 | 80 | void ConversionHelperHidl::parametersToHal( | 
 | 81 |         const hidl_vec<ParameterValue>& parameters, String8 *values) { | 
 | 82 |     AudioParameter params; | 
 | 83 |     for (size_t i = 0; i < parameters.size(); ++i) { | 
 | 84 |         params.add(String8(parameters[i].key.c_str()), String8(parameters[i].value.c_str())); | 
 | 85 |     } | 
 | 86 |     values->setTo(params.toString()); | 
 | 87 | } | 
 | 88 |  | 
 | 89 | ConversionHelperHidl::ConversionHelperHidl(const char* className) | 
 | 90 |         : mClassName(className) { | 
 | 91 | } | 
 | 92 |  | 
 | 93 | // static | 
 | 94 | status_t ConversionHelperHidl::analyzeResult(const Result& result) { | 
 | 95 |     switch (result) { | 
 | 96 |         case Result::OK: return OK; | 
 | 97 |         case Result::INVALID_ARGUMENTS: return BAD_VALUE; | 
 | 98 |         case Result::INVALID_STATE: return NOT_ENOUGH_DATA; | 
 | 99 |         case Result::NOT_INITIALIZED: return NO_INIT; | 
 | 100 |         case Result::NOT_SUPPORTED: return INVALID_OPERATION; | 
 | 101 |         default: return NO_INIT; | 
 | 102 |     } | 
 | 103 | } | 
 | 104 |  | 
 | 105 | void ConversionHelperHidl::emitError(const char* funcName, const char* description) { | 
 | 106 |     ALOGE("%s %p %s: %s (from rpc)", mClassName, this, funcName, description); | 
 | 107 | } | 
 | 108 |  | 
| jiabin | 9ff780e | 2018-03-19 18:19:52 -0700 | [diff] [blame^] | 109 | // TODO: Use the same implementation in the hal when it moves to a util library. | 
 | 110 | std::string deviceAddressToHal(const DeviceAddress& address) { | 
 | 111 |     // HAL assumes that the address is NUL-terminated. | 
 | 112 |     char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; | 
 | 113 |     memset(halAddress, 0, sizeof(halAddress)); | 
 | 114 |     audio_devices_t halDevice = static_cast<audio_devices_t>(address.device); | 
 | 115 |     const bool isInput = (halDevice & AUDIO_DEVICE_BIT_IN) != 0; | 
 | 116 |     if (isInput) halDevice &= ~AUDIO_DEVICE_BIT_IN; | 
 | 117 |     if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) || | 
 | 118 |         (isInput && (halDevice & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) { | 
 | 119 |         snprintf(halAddress, sizeof(halAddress), "%02X:%02X:%02X:%02X:%02X:%02X", | 
 | 120 |                  address.address.mac[0], address.address.mac[1], address.address.mac[2], | 
 | 121 |                  address.address.mac[3], address.address.mac[4], address.address.mac[5]); | 
 | 122 |     } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_IP) != 0) || | 
 | 123 |                (isInput && (halDevice & AUDIO_DEVICE_IN_IP) != 0)) { | 
 | 124 |         snprintf(halAddress, sizeof(halAddress), "%d.%d.%d.%d", address.address.ipv4[0], | 
 | 125 |                  address.address.ipv4[1], address.address.ipv4[2], address.address.ipv4[3]); | 
 | 126 |     } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_USB) != 0) || | 
 | 127 |                (isInput && (halDevice & AUDIO_DEVICE_IN_ALL_USB) != 0)) { | 
 | 128 |         snprintf(halAddress, sizeof(halAddress), "card=%d;device=%d", address.address.alsa.card, | 
 | 129 |                  address.address.alsa.device); | 
 | 130 |     } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_BUS) != 0) || | 
 | 131 |                (isInput && (halDevice & AUDIO_DEVICE_IN_BUS) != 0)) { | 
 | 132 |         snprintf(halAddress, sizeof(halAddress), "%s", address.busAddress.c_str()); | 
 | 133 |     } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 || | 
 | 134 |                (isInput && (halDevice & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) { | 
 | 135 |         snprintf(halAddress, sizeof(halAddress), "%s", address.rSubmixAddress.c_str()); | 
 | 136 |     } else { | 
 | 137 |         snprintf(halAddress, sizeof(halAddress), "%s", address.busAddress.c_str()); | 
 | 138 |     } | 
 | 139 |     return halAddress; | 
 | 140 | } | 
 | 141 |  | 
 | 142 | //local conversion helpers | 
 | 143 |  | 
 | 144 | audio_microphone_channel_mapping_t  channelMappingToHal(AudioMicrophoneChannelMapping mapping) { | 
 | 145 |     switch (mapping) { | 
 | 146 |         case AudioMicrophoneChannelMapping::UNUSED: | 
 | 147 |             return AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED; | 
 | 148 |         case AudioMicrophoneChannelMapping::DIRECT: | 
 | 149 |             return AUDIO_MICROPHONE_CHANNEL_MAPPING_DIRECT; | 
 | 150 |         case AudioMicrophoneChannelMapping::PROCESSED: | 
 | 151 |             return AUDIO_MICROPHONE_CHANNEL_MAPPING_PROCESSED; | 
 | 152 |         default: | 
 | 153 |             LOG_ALWAYS_FATAL("Unknown channelMappingToHal conversion %d", mapping); | 
 | 154 |     } | 
 | 155 | } | 
 | 156 |  | 
 | 157 | audio_microphone_location_t locationToHal(AudioMicrophoneLocation location) { | 
 | 158 |     switch (location) { | 
 | 159 |         case AudioMicrophoneLocation::UNKNOWN: | 
 | 160 |             return AUDIO_MICROPHONE_LOCATION_UNKNOWN; | 
 | 161 |         case AudioMicrophoneLocation::MAINBODY: | 
 | 162 |             return AUDIO_MICROPHONE_LOCATION_MAINBODY; | 
 | 163 |         case AudioMicrophoneLocation::MAINBODY_MOVABLE: | 
 | 164 |             return AUDIO_MICROPHONE_LOCATION_MAINBODY_MOVABLE; | 
 | 165 |         case AudioMicrophoneLocation::PERIPHERAL: | 
 | 166 |             return AUDIO_MICROPHONE_LOCATION_PERIPHERAL; | 
 | 167 |         default: | 
 | 168 |             LOG_ALWAYS_FATAL("Unknown locationToHal conversion %d", location); | 
 | 169 |     } | 
 | 170 | } | 
 | 171 | audio_microphone_directionality_t directionalityToHal(AudioMicrophoneDirectionality dir) { | 
 | 172 |     switch (dir) { | 
 | 173 |         case AudioMicrophoneDirectionality::UNKNOWN: | 
 | 174 |             return AUDIO_MICROPHONE_DIRECTIONALITY_UNKNOWN; | 
 | 175 |         case AudioMicrophoneDirectionality::OMNI: | 
 | 176 |             return AUDIO_MICROPHONE_DIRECTIONALITY_OMNI; | 
 | 177 |         case AudioMicrophoneDirectionality::BI_DIRECTIONAL: | 
 | 178 |             return AUDIO_MICROPHONE_DIRECTIONALITY_BI_DIRECTIONAL; | 
 | 179 |         case AudioMicrophoneDirectionality::CARDIOID: | 
 | 180 |             return AUDIO_MICROPHONE_DIRECTIONALITY_CARDIOID; | 
 | 181 |         case AudioMicrophoneDirectionality::HYPER_CARDIOID: | 
 | 182 |             return AUDIO_MICROPHONE_DIRECTIONALITY_HYPER_CARDIOID; | 
 | 183 |         case AudioMicrophoneDirectionality::SUPER_CARDIOID: | 
 | 184 |             return AUDIO_MICROPHONE_DIRECTIONALITY_SUPER_CARDIOID; | 
 | 185 |         default: | 
 | 186 |             LOG_ALWAYS_FATAL("Unknown directionalityToHal conversion %d", dir); | 
 | 187 |     } | 
 | 188 | } | 
 | 189 |  | 
 | 190 | // static | 
 | 191 | void ConversionHelperHidl::microphoneInfoToHal(const MicrophoneInfo& src, | 
 | 192 |                                                      audio_microphone_characteristic_t *pDst) { | 
 | 193 |     if (pDst != NULL) { | 
 | 194 |         snprintf(pDst->device_id, sizeof(pDst->device_id), | 
 | 195 |                  "%s", src.deviceId.c_str()); | 
 | 196 |         pDst->device = static_cast<audio_devices_t>(src.deviceAddress.device); | 
 | 197 |         snprintf(pDst->address, sizeof(pDst->address), | 
 | 198 |                  "%s", deviceAddressToHal(src.deviceAddress).c_str()); | 
 | 199 |         if (src.channelMapping.size() > AUDIO_CHANNEL_COUNT_MAX) { | 
 | 200 |             ALOGW("microphoneInfoToStruct found %zu channelMapping elements. Max expected is %d", | 
 | 201 |                   src.channelMapping.size(), AUDIO_CHANNEL_COUNT_MAX); | 
 | 202 |         } | 
 | 203 |         size_t ch; | 
 | 204 |         for (ch = 0; ch < src.channelMapping.size() && ch < AUDIO_CHANNEL_COUNT_MAX; ch++) { | 
 | 205 |             pDst->channel_mapping[ch] = channelMappingToHal(src.channelMapping[ch]); | 
 | 206 |         } | 
 | 207 |         for (; ch < AUDIO_CHANNEL_COUNT_MAX; ch++) { | 
 | 208 |             pDst->channel_mapping[ch] = AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED; | 
 | 209 |         } | 
 | 210 |         pDst->location = locationToHal(src.location); | 
 | 211 |         pDst->group = (audio_microphone_group_t)src.group; | 
 | 212 |         pDst->index_in_the_group = (unsigned int)src.indexInTheGroup; | 
 | 213 |         pDst->sensitivity = src.sensitivity; | 
 | 214 |         pDst->max_spl = src.maxSpl; | 
 | 215 |         pDst->min_spl = src.minSpl; | 
 | 216 |         pDst->directionality = directionalityToHal(src.directionality); | 
 | 217 |         pDst->num_frequency_responses = (unsigned int)src.frequencyResponse.size(); | 
 | 218 |         if (pDst->num_frequency_responses > AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES) { | 
 | 219 |             ALOGW("microphoneInfoToStruct found %d frequency responses. Max expected is %d", | 
 | 220 |                   pDst->num_frequency_responses, AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES); | 
 | 221 |             pDst->num_frequency_responses = AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES; | 
 | 222 |         } | 
 | 223 |         for (size_t k = 0; k < pDst->num_frequency_responses; k++) { | 
 | 224 |             pDst->frequency_responses[0][k] = src.frequencyResponse[k].frequency; | 
 | 225 |             pDst->frequency_responses[1][k] = src.frequencyResponse[k].level; | 
 | 226 |         } | 
 | 227 |         pDst->geometric_location.x = src.position.x; | 
 | 228 |         pDst->geometric_location.y = src.position.y; | 
 | 229 |         pDst->geometric_location.z = src.position.z; | 
 | 230 |         pDst->orientation.x = src.orientation.x; | 
 | 231 |         pDst->orientation.y = src.orientation.y; | 
 | 232 |         pDst->orientation.z = src.orientation.z; | 
 | 233 |     } | 
 | 234 | } | 
 | 235 |  | 
| Kevin Rocard | 51e076a | 2018-02-28 14:36:53 -0800 | [diff] [blame] | 236 | }  // namespace V4_0 | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 237 | }  // namespace android |