| 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 | #define LOG_TAG "StreamHalHidl" | 
 | 18 | //#define LOG_NDEBUG 0 | 
 | 19 |  | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 20 | #include <android/hidl/manager/1.0/IServiceManager.h> | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 21 | #include <hwbinder/IPCThreadState.h> | 
| Mikhail Naganov | ac917ac | 2018-11-28 14:03:52 -0800 | [diff] [blame] | 22 | #include <media/AudioParameter.h> | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 23 | #include <mediautils/SchedulingPolicyService.h> | 
 | 24 | #include <utils/Log.h> | 
 | 25 |  | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 26 | #include PATH(android/hardware/audio/FILE_VERSION/IStreamOutCallback.h) | 
 | 27 | #include <HidlUtils.h> | 
 | 28 | #include <util/CoreUtils.h> | 
 | 29 |  | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 30 | #include "DeviceHalHidl.h" | 
 | 31 | #include "EffectHalHidl.h" | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 32 | #include "ParameterUtils.h" | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 33 | #include "StreamHalHidl.h" | 
 | 34 |  | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 35 | using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils; | 
 | 36 | using ::android::hardware::audio::CPP_VERSION::implementation::CoreUtils; | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 37 | using ::android::hardware::MQDescriptorSync; | 
 | 38 | using ::android::hardware::Return; | 
 | 39 | using ::android::hardware::Void; | 
| Kevin Rocard | df9b420 | 2018-05-10 19:56:08 -0700 | [diff] [blame] | 40 |  | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 41 | namespace android { | 
| Kevin Rocard | 070e751 | 2018-05-22 09:29:13 -0700 | [diff] [blame] | 42 | namespace CPP_VERSION { | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 43 |  | 
| Mikhail Naganov | 595caa3 | 2018-12-13 11:08:28 -0800 | [diff] [blame] | 44 | using EffectHalHidl = ::android::effect::CPP_VERSION::EffectHalHidl; | 
| Mikhail Naganov | 9ccaa16 | 2018-12-12 10:27:29 -0800 | [diff] [blame] | 45 | using ReadCommand = ::android::hardware::audio::CPP_VERSION::IStreamIn::ReadCommand; | 
 | 46 |  | 
 | 47 | using namespace ::android::hardware::audio::common::CPP_VERSION; | 
 | 48 | using namespace ::android::hardware::audio::CPP_VERSION; | 
 | 49 |  | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 50 | StreamHalHidl::StreamHalHidl(IStream *stream) | 
 | 51 |         : ConversionHelperHidl("Stream"), | 
 | 52 |           mStream(stream), | 
 | 53 |           mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT), | 
 | 54 |           mCachedBufferSize(0){ | 
 | 55 |  | 
 | 56 |     // Instrument audio signal power logging. | 
 | 57 |     // Note: This assumes channel mask, format, and sample rate do not change after creation. | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 58 |     audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER; | 
 | 59 |     if (/* mStreamPowerLog.isUserDebugOrEngBuild() && */ | 
| Mikhail Naganov | 560637e | 2021-03-31 22:40:13 +0000 | [diff] [blame] | 60 |         StreamHalHidl::getAudioProperties(&config) == NO_ERROR) { | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 61 |         mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format); | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 62 |     } | 
 | 63 | } | 
 | 64 |  | 
| Andy Hung | acb5b98 | 2021-01-20 10:12:00 -0800 | [diff] [blame] | 65 | StreamHalHidl::~StreamHalHidl() { | 
 | 66 |     // The last step is to flush all binder commands so that the deletion | 
 | 67 |     // of IStreamIn / IStreamOut (mStream) is issued with less delay. See b/35394629. | 
 | 68 |     hardware::IPCThreadState::self()->flushCommands(); | 
 | 69 | } | 
 | 70 |  | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 71 | status_t StreamHalHidl::getBufferSize(size_t *size) { | 
 | 72 |     if (!mStream) return NO_INIT; | 
 | 73 |     status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size); | 
 | 74 |     if (status == OK) { | 
 | 75 |         mCachedBufferSize = *size; | 
 | 76 |     } | 
 | 77 |     return status; | 
 | 78 | } | 
 | 79 |  | 
| Mikhail Naganov | 560637e | 2021-03-31 22:40:13 +0000 | [diff] [blame] | 80 | status_t StreamHalHidl::getAudioProperties(audio_config_base_t *configBase) { | 
 | 81 |     *configBase = AUDIO_CONFIG_BASE_INITIALIZER; | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 82 |     if (!mStream) return NO_INIT; | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 83 | #if MAJOR_VERSION <= 6 | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 84 |     Return<void> ret = mStream->getAudioProperties( | 
| Kevin Rocard | b9cfbf1 | 2018-02-23 19:11:06 -0800 | [diff] [blame] | 85 |             [&](uint32_t sr, auto m, auto f) { | 
| Mikhail Naganov | 560637e | 2021-03-31 22:40:13 +0000 | [diff] [blame] | 86 |                 configBase->sample_rate = sr; | 
 | 87 |                 configBase->channel_mask = static_cast<audio_channel_mask_t>(m); | 
 | 88 |                 configBase->format = static_cast<audio_format_t>(f); | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 89 |             }); | 
 | 90 |     return processReturn("getAudioProperties", ret); | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 91 | #else | 
 | 92 |     Result retval; | 
 | 93 |     status_t conversionStatus = BAD_VALUE; | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 94 |     Return<void> ret = mStream->getAudioProperties( | 
 | 95 |             [&](Result r, const AudioConfigBase& config) { | 
 | 96 |                 retval = r; | 
 | 97 |                 if (retval == Result::OK) { | 
| Mikhail Naganov | 560637e | 2021-03-31 22:40:13 +0000 | [diff] [blame] | 98 |                     conversionStatus = HidlUtils::audioConfigBaseToHal(config, configBase); | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 99 |                 } | 
 | 100 |             }); | 
 | 101 |     if (status_t status = processReturn("getAudioProperties", ret, retval); status == NO_ERROR) { | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 102 |         return conversionStatus; | 
 | 103 |     } else { | 
 | 104 |         return status; | 
 | 105 |     } | 
 | 106 | #endif | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 107 | } | 
 | 108 |  | 
 | 109 | status_t StreamHalHidl::setParameters(const String8& kvPairs) { | 
 | 110 |     if (!mStream) return NO_INIT; | 
 | 111 |     hidl_vec<ParameterValue> hidlParams; | 
 | 112 |     status_t status = parametersFromHal(kvPairs, &hidlParams); | 
 | 113 |     if (status != OK) return status; | 
| Kevin Rocard | b9cfbf1 | 2018-02-23 19:11:06 -0800 | [diff] [blame] | 114 |     return processReturn("setParameters", | 
| Dean Wheatley | 7b417a2 | 2019-01-31 20:39:42 +1100 | [diff] [blame] | 115 |                          utils::setParameters(mStream, {} /* context */, hidlParams)); | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 116 | } | 
 | 117 |  | 
 | 118 | status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) { | 
 | 119 |     values->clear(); | 
 | 120 |     if (!mStream) return NO_INIT; | 
 | 121 |     hidl_vec<hidl_string> hidlKeys; | 
 | 122 |     status_t status = keysFromHal(keys, &hidlKeys); | 
 | 123 |     if (status != OK) return status; | 
 | 124 |     Result retval; | 
| Kevin Rocard | b9cfbf1 | 2018-02-23 19:11:06 -0800 | [diff] [blame] | 125 |     Return<void> ret = utils::getParameters( | 
 | 126 |             mStream, | 
 | 127 |             {} /* context */, | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 128 |             hidlKeys, | 
 | 129 |             [&](Result r, const hidl_vec<ParameterValue>& parameters) { | 
 | 130 |                 retval = r; | 
 | 131 |                 if (retval == Result::OK) { | 
 | 132 |                     parametersToHal(parameters, values); | 
 | 133 |                 } | 
 | 134 |             }); | 
 | 135 |     return processReturn("getParameters", ret, retval); | 
 | 136 | } | 
 | 137 |  | 
 | 138 | status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) { | 
 | 139 |     if (!mStream) return NO_INIT; | 
 | 140 |     return processReturn("addEffect", mStream->addEffect( | 
 | 141 |                     static_cast<EffectHalHidl*>(effect.get())->effectId())); | 
 | 142 | } | 
 | 143 |  | 
 | 144 | status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) { | 
 | 145 |     if (!mStream) return NO_INIT; | 
 | 146 |     return processReturn("removeEffect", mStream->removeEffect( | 
 | 147 |                     static_cast<EffectHalHidl*>(effect.get())->effectId())); | 
 | 148 | } | 
 | 149 |  | 
 | 150 | status_t StreamHalHidl::standby() { | 
 | 151 |     if (!mStream) return NO_INIT; | 
 | 152 |     return processReturn("standby", mStream->standby()); | 
 | 153 | } | 
 | 154 |  | 
| Andy Hung | 61589a4 | 2021-06-16 09:37:53 -0700 | [diff] [blame^] | 155 | status_t StreamHalHidl::dump(int fd, const Vector<String16>& args) { | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 156 |     if (!mStream) return NO_INIT; | 
 | 157 |     native_handle_t* hidlHandle = native_handle_create(1, 0); | 
 | 158 |     hidlHandle->data[0] = fd; | 
| Andy Hung | 61589a4 | 2021-06-16 09:37:53 -0700 | [diff] [blame^] | 159 |     hidl_vec<hidl_string> hidlArgs; | 
 | 160 |     argsFromHal(args, &hidlArgs); | 
 | 161 |     Return<void> ret = mStream->debug(hidlHandle, hidlArgs); | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 162 |     native_handle_delete(hidlHandle); | 
 | 163 |     mStreamPowerLog.dump(fd); | 
 | 164 |     return processReturn("dump", ret); | 
 | 165 | } | 
 | 166 |  | 
 | 167 | status_t StreamHalHidl::start() { | 
 | 168 |     if (!mStream) return NO_INIT; | 
 | 169 |     return processReturn("start", mStream->start()); | 
 | 170 | } | 
 | 171 |  | 
 | 172 | status_t StreamHalHidl::stop() { | 
 | 173 |     if (!mStream) return NO_INIT; | 
 | 174 |     return processReturn("stop", mStream->stop()); | 
 | 175 | } | 
 | 176 |  | 
 | 177 | status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames, | 
 | 178 |                                   struct audio_mmap_buffer_info *info) { | 
 | 179 |     Result retval; | 
 | 180 |     Return<void> ret = mStream->createMmapBuffer( | 
 | 181 |             minSizeFrames, | 
 | 182 |             [&](Result r, const MmapBufferInfo& hidlInfo) { | 
 | 183 |                 retval = r; | 
 | 184 |                 if (retval == Result::OK) { | 
 | 185 |                     const native_handle *handle = hidlInfo.sharedMemory.handle(); | 
 | 186 |                     if (handle->numFds > 0) { | 
 | 187 |                         info->shared_memory_fd = handle->data[0]; | 
| Kevin Rocard | 3d48dce | 2018-11-08 17:16:57 -0800 | [diff] [blame] | 188 | #if MAJOR_VERSION >= 4 | 
| Kevin Rocard | 734334f | 2018-07-12 19:37:41 -0700 | [diff] [blame] | 189 |                         info->flags = audio_mmap_buffer_flag(hidlInfo.flags); | 
 | 190 | #endif | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 191 |                         info->buffer_size_frames = hidlInfo.bufferSizeFrames; | 
| Kevin Rocard | 734334f | 2018-07-12 19:37:41 -0700 | [diff] [blame] | 192 |                         // Negative buffer size frame was a hack in O and P to | 
 | 193 |                         // indicate that the buffer is shareable to applications | 
 | 194 |                         if (info->buffer_size_frames < 0) { | 
 | 195 |                             info->buffer_size_frames *= -1; | 
 | 196 |                             info->flags = audio_mmap_buffer_flag( | 
 | 197 |                                     info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE); | 
 | 198 |                         } | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 199 |                         info->burst_size_frames = hidlInfo.burstSizeFrames; | 
 | 200 |                         // info->shared_memory_address is not needed in HIDL context | 
 | 201 |                         info->shared_memory_address = NULL; | 
 | 202 |                     } else { | 
 | 203 |                         retval = Result::NOT_INITIALIZED; | 
 | 204 |                     } | 
 | 205 |                 } | 
 | 206 |             }); | 
 | 207 |     return processReturn("createMmapBuffer", ret, retval); | 
 | 208 | } | 
 | 209 |  | 
 | 210 | status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) { | 
 | 211 |     Result retval; | 
 | 212 |     Return<void> ret = mStream->getMmapPosition( | 
 | 213 |             [&](Result r, const MmapPosition& hidlPosition) { | 
 | 214 |                 retval = r; | 
 | 215 |                 if (retval == Result::OK) { | 
 | 216 |                     position->time_nanoseconds = hidlPosition.timeNanoseconds; | 
 | 217 |                     position->position_frames = hidlPosition.positionFrames; | 
 | 218 |                 } | 
 | 219 |             }); | 
 | 220 |     return processReturn("getMmapPosition", ret, retval); | 
 | 221 | } | 
 | 222 |  | 
 | 223 | status_t StreamHalHidl::setHalThreadPriority(int priority) { | 
 | 224 |     mHalThreadPriority = priority; | 
 | 225 |     return OK; | 
 | 226 | } | 
 | 227 |  | 
 | 228 | status_t StreamHalHidl::getCachedBufferSize(size_t *size) { | 
 | 229 |     if (mCachedBufferSize != 0) { | 
 | 230 |         *size = mCachedBufferSize; | 
 | 231 |         return OK; | 
 | 232 |     } | 
 | 233 |     return getBufferSize(size); | 
 | 234 | } | 
 | 235 |  | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 236 | status_t StreamHalHidl::getHalPid(pid_t *pid) { | 
 | 237 |     using ::android::hidl::base::V1_0::DebugInfo; | 
 | 238 |     using ::android::hidl::manager::V1_0::IServiceManager; | 
 | 239 |  | 
 | 240 |     DebugInfo debugInfo; | 
 | 241 |     auto ret = mStream->getDebugInfo([&] (const auto &info) { | 
 | 242 |         debugInfo = info; | 
 | 243 |     }); | 
 | 244 |     if (!ret.isOk()) { | 
 | 245 |         return INVALID_OPERATION; | 
 | 246 |     } | 
 | 247 |     if (debugInfo.pid != (int)IServiceManager::PidConstant::NO_PID) { | 
 | 248 |         *pid = debugInfo.pid; | 
 | 249 |         return NO_ERROR; | 
 | 250 |     } | 
 | 251 |     return NAME_NOT_FOUND; | 
 | 252 | } | 
 | 253 |  | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 254 | bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) { | 
 | 255 |     if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) { | 
 | 256 |         return true; | 
 | 257 |     } | 
 | 258 |     int err = requestPriority( | 
 | 259 |             threadPid, threadId, | 
 | 260 |             mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/); | 
 | 261 |     ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d", | 
 | 262 |             mHalThreadPriority, threadPid, threadId, err); | 
 | 263 |     // Audio will still work, but latency will be higher and sometimes unacceptable. | 
 | 264 |     return err == 0; | 
 | 265 | } | 
 | 266 |  | 
 | 267 | namespace { | 
 | 268 |  | 
 | 269 | /* Notes on callback ownership. | 
 | 270 |  | 
 | 271 | This is how (Hw)Binder ownership model looks like. The server implementation | 
 | 272 | is owned by Binder framework (via sp<>). Proxies are owned by clients. | 
 | 273 | When the last proxy disappears, Binder framework releases the server impl. | 
 | 274 |  | 
 | 275 | Thus, it is not needed to keep any references to StreamOutCallback (this is | 
 | 276 | the server impl) -- it will live as long as HAL server holds a strong ref to | 
 | 277 | IStreamOutCallback proxy. We clear that reference by calling 'clearCallback' | 
 | 278 | from the destructor of StreamOutHalHidl. | 
 | 279 |  | 
 | 280 | The callback only keeps a weak reference to the stream. The stream is owned | 
 | 281 | by AudioFlinger. | 
 | 282 |  | 
 | 283 | */ | 
 | 284 |  | 
 | 285 | struct StreamOutCallback : public IStreamOutCallback { | 
 | 286 |     StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {} | 
 | 287 |  | 
 | 288 |     // IStreamOutCallback implementation | 
 | 289 |     Return<void> onWriteReady()  override { | 
 | 290 |         sp<StreamOutHalHidl> stream = mStream.promote(); | 
 | 291 |         if (stream != 0) { | 
 | 292 |             stream->onWriteReady(); | 
 | 293 |         } | 
 | 294 |         return Void(); | 
 | 295 |     } | 
 | 296 |  | 
 | 297 |     Return<void> onDrainReady()  override { | 
 | 298 |         sp<StreamOutHalHidl> stream = mStream.promote(); | 
 | 299 |         if (stream != 0) { | 
 | 300 |             stream->onDrainReady(); | 
 | 301 |         } | 
 | 302 |         return Void(); | 
 | 303 |     } | 
 | 304 |  | 
 | 305 |     Return<void> onError()  override { | 
 | 306 |         sp<StreamOutHalHidl> stream = mStream.promote(); | 
 | 307 |         if (stream != 0) { | 
 | 308 |             stream->onError(); | 
 | 309 |         } | 
 | 310 |         return Void(); | 
 | 311 |     } | 
 | 312 |  | 
 | 313 |   private: | 
| Andy Hung | 638f45b | 2021-01-18 20:02:56 -0800 | [diff] [blame] | 314 |     const wp<StreamOutHalHidl> mStream; | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 315 | }; | 
 | 316 |  | 
 | 317 | }  // namespace | 
 | 318 |  | 
 | 319 | StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream) | 
 | 320 |         : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) { | 
 | 321 | } | 
 | 322 |  | 
 | 323 | StreamOutHalHidl::~StreamOutHalHidl() { | 
 | 324 |     if (mStream != 0) { | 
| Andy Hung | 638f45b | 2021-01-18 20:02:56 -0800 | [diff] [blame] | 325 |         if (mCallback.load().unsafe_get()) { | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 326 |             processReturn("clearCallback", mStream->clearCallback()); | 
 | 327 |         } | 
| jiabin | f6eb4c3 | 2020-02-25 14:06:25 -0800 | [diff] [blame] | 328 | #if MAJOR_VERSION >= 6 | 
| Andy Hung | 638f45b | 2021-01-18 20:02:56 -0800 | [diff] [blame] | 329 |         if (mEventCallback.load().unsafe_get() != nullptr) { | 
| jiabin | f6eb4c3 | 2020-02-25 14:06:25 -0800 | [diff] [blame] | 330 |             processReturn("setEventCallback", | 
 | 331 |                     mStream->setEventCallback(nullptr)); | 
 | 332 |         } | 
 | 333 | #endif | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 334 |         processReturn("close", mStream->close()); | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 335 |     } | 
| Andy Hung | 638f45b | 2021-01-18 20:02:56 -0800 | [diff] [blame] | 336 |     mCallback = nullptr; | 
 | 337 |     mEventCallback = nullptr; | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 338 |     if (mEfGroup) { | 
 | 339 |         EventFlag::deleteEventFlag(&mEfGroup); | 
 | 340 |     } | 
 | 341 | } | 
 | 342 |  | 
 | 343 | status_t StreamOutHalHidl::getFrameSize(size_t *size) { | 
 | 344 |     if (mStream == 0) return NO_INIT; | 
 | 345 |     return processReturn("getFrameSize", mStream->getFrameSize(), size); | 
 | 346 | } | 
 | 347 |  | 
 | 348 | status_t StreamOutHalHidl::getLatency(uint32_t *latency) { | 
 | 349 |     if (mStream == 0) return NO_INIT; | 
 | 350 |     if (mWriterClient == gettid() && mCommandMQ) { | 
 | 351 |         return callWriterThread( | 
 | 352 |                 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0, | 
 | 353 |                 [&](const WriteStatus& writeStatus) { | 
 | 354 |                     *latency = writeStatus.reply.latencyMs; | 
 | 355 |                 }); | 
 | 356 |     } else { | 
 | 357 |         return processReturn("getLatency", mStream->getLatency(), latency); | 
 | 358 |     } | 
 | 359 | } | 
 | 360 |  | 
 | 361 | status_t StreamOutHalHidl::setVolume(float left, float right) { | 
 | 362 |     if (mStream == 0) return NO_INIT; | 
 | 363 |     return processReturn("setVolume", mStream->setVolume(left, right)); | 
 | 364 | } | 
 | 365 |  | 
| Mikhail Naganov | ac917ac | 2018-11-28 14:03:52 -0800 | [diff] [blame] | 366 | #if MAJOR_VERSION == 2 | 
 | 367 | status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) { | 
 | 368 |     if (mStream == 0) return NO_INIT; | 
 | 369 |     std::vector<ParameterValue> parameters; | 
 | 370 |     String8 halParameters; | 
 | 371 |     parameters.push_back({AudioParameter::keyPresentationId, std::to_string(presentationId)}); | 
 | 372 |     parameters.push_back({AudioParameter::keyProgramId, std::to_string(programId)}); | 
 | 373 |     parametersToHal(hidl_vec<ParameterValue>(parameters), &halParameters); | 
 | 374 |     return setParameters(halParameters); | 
 | 375 | } | 
| Kevin Rocard | 1cf6b4d | 2018-11-20 18:05:44 -0800 | [diff] [blame] | 376 | #elif MAJOR_VERSION >= 4 | 
| Mikhail Naganov | ac917ac | 2018-11-28 14:03:52 -0800 | [diff] [blame] | 377 | status_t StreamOutHalHidl::selectPresentation(int presentationId, int programId) { | 
 | 378 |     if (mStream == 0) return NO_INIT; | 
 | 379 |     return processReturn("selectPresentation", | 
 | 380 |             mStream->selectPresentation(presentationId, programId)); | 
 | 381 | } | 
 | 382 | #endif | 
 | 383 |  | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 384 | status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) { | 
 | 385 |     if (mStream == 0) return NO_INIT; | 
 | 386 |     *written = 0; | 
 | 387 |  | 
 | 388 |     if (bytes == 0 && !mDataMQ) { | 
 | 389 |         // Can't determine the size for the MQ buffer. Wait for a non-empty write request. | 
| Andy Hung | 638f45b | 2021-01-18 20:02:56 -0800 | [diff] [blame] | 390 |         ALOGW_IF(mCallback.load().unsafe_get(), "First call to async write with 0 bytes"); | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 391 |         return OK; | 
 | 392 |     } | 
 | 393 |  | 
 | 394 |     status_t status; | 
 | 395 |     if (!mDataMQ) { | 
 | 396 |         // In case if playback starts close to the end of a compressed track, the bytes | 
 | 397 |         // that need to be written is less than the actual buffer size. Need to use | 
 | 398 |         // full buffer size for the MQ since otherwise after seeking back to the middle | 
 | 399 |         // data will be truncated. | 
 | 400 |         size_t bufferSize; | 
 | 401 |         if ((status = getCachedBufferSize(&bufferSize)) != OK) { | 
 | 402 |             return status; | 
 | 403 |         } | 
 | 404 |         if (bytes > bufferSize) bufferSize = bytes; | 
 | 405 |         if ((status = prepareForWriting(bufferSize)) != OK) { | 
 | 406 |             return status; | 
 | 407 |         } | 
 | 408 |     } | 
 | 409 |  | 
 | 410 |     status = callWriterThread( | 
 | 411 |             WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes, | 
 | 412 |             [&] (const WriteStatus& writeStatus) { | 
 | 413 |                 *written = writeStatus.reply.written; | 
 | 414 |                 // Diagnostics of the cause of b/35813113. | 
 | 415 |                 ALOGE_IF(*written > bytes, | 
 | 416 |                         "hal reports more bytes written than asked for: %lld > %lld", | 
 | 417 |                         (long long)*written, (long long)bytes); | 
 | 418 |             }); | 
 | 419 |     mStreamPowerLog.log(buffer, *written); | 
 | 420 |     return status; | 
 | 421 | } | 
 | 422 |  | 
 | 423 | status_t StreamOutHalHidl::callWriterThread( | 
 | 424 |         WriteCommand cmd, const char* cmdName, | 
 | 425 |         const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) { | 
 | 426 |     if (!mCommandMQ->write(&cmd)) { | 
 | 427 |         ALOGE("command message queue write failed for \"%s\"", cmdName); | 
 | 428 |         return -EAGAIN; | 
 | 429 |     } | 
 | 430 |     if (data != nullptr) { | 
 | 431 |         size_t availableToWrite = mDataMQ->availableToWrite(); | 
 | 432 |         if (dataSize > availableToWrite) { | 
 | 433 |             ALOGW("truncating write data from %lld to %lld due to insufficient data queue space", | 
 | 434 |                     (long long)dataSize, (long long)availableToWrite); | 
 | 435 |             dataSize = availableToWrite; | 
 | 436 |         } | 
 | 437 |         if (!mDataMQ->write(data, dataSize)) { | 
 | 438 |             ALOGE("data message queue write failed for \"%s\"", cmdName); | 
 | 439 |         } | 
 | 440 |     } | 
 | 441 |     mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)); | 
 | 442 |  | 
 | 443 |     // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422 | 
 | 444 |     uint32_t efState = 0; | 
 | 445 | retry: | 
 | 446 |     status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState); | 
 | 447 |     if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) { | 
 | 448 |         WriteStatus writeStatus; | 
 | 449 |         writeStatus.retval = Result::NOT_INITIALIZED; | 
 | 450 |         if (!mStatusMQ->read(&writeStatus)) { | 
 | 451 |             ALOGE("status message read failed for \"%s\"", cmdName); | 
 | 452 |         } | 
 | 453 |         if (writeStatus.retval == Result::OK) { | 
 | 454 |             ret = OK; | 
 | 455 |             callback(writeStatus); | 
 | 456 |         } else { | 
 | 457 |             ret = processReturn(cmdName, writeStatus.retval); | 
 | 458 |         } | 
 | 459 |         return ret; | 
 | 460 |     } | 
 | 461 |     if (ret == -EAGAIN || ret == -EINTR) { | 
 | 462 |         // Spurious wakeup. This normally retries no more than once. | 
 | 463 |         goto retry; | 
 | 464 |     } | 
 | 465 |     return ret; | 
 | 466 | } | 
 | 467 |  | 
 | 468 | status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) { | 
 | 469 |     std::unique_ptr<CommandMQ> tempCommandMQ; | 
 | 470 |     std::unique_ptr<DataMQ> tempDataMQ; | 
 | 471 |     std::unique_ptr<StatusMQ> tempStatusMQ; | 
 | 472 |     Result retval; | 
 | 473 |     pid_t halThreadPid, halThreadTid; | 
 | 474 |     Return<void> ret = mStream->prepareForWriting( | 
 | 475 |             1, bufferSize, | 
 | 476 |             [&](Result r, | 
 | 477 |                     const CommandMQ::Descriptor& commandMQ, | 
 | 478 |                     const DataMQ::Descriptor& dataMQ, | 
 | 479 |                     const StatusMQ::Descriptor& statusMQ, | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 480 |                     const auto& halThreadInfo) { | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 481 |                 retval = r; | 
 | 482 |                 if (retval == Result::OK) { | 
 | 483 |                     tempCommandMQ.reset(new CommandMQ(commandMQ)); | 
 | 484 |                     tempDataMQ.reset(new DataMQ(dataMQ)); | 
 | 485 |                     tempStatusMQ.reset(new StatusMQ(statusMQ)); | 
 | 486 |                     if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) { | 
 | 487 |                         EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup); | 
 | 488 |                     } | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 489 | #if MAJOR_VERSION <= 6 | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 490 |                     halThreadPid = halThreadInfo.pid; | 
 | 491 |                     halThreadTid = halThreadInfo.tid; | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 492 | #else | 
 | 493 |                     halThreadTid = halThreadInfo; | 
 | 494 | #endif | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 495 |                 } | 
 | 496 |             }); | 
 | 497 |     if (!ret.isOk() || retval != Result::OK) { | 
 | 498 |         return processReturn("prepareForWriting", ret, retval); | 
 | 499 |     } | 
 | 500 |     if (!tempCommandMQ || !tempCommandMQ->isValid() || | 
 | 501 |             !tempDataMQ || !tempDataMQ->isValid() || | 
 | 502 |             !tempStatusMQ || !tempStatusMQ->isValid() || | 
 | 503 |             !mEfGroup) { | 
 | 504 |         ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing"); | 
 | 505 |         ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(), | 
 | 506 |                 "Command message queue for writing is invalid"); | 
 | 507 |         ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing"); | 
 | 508 |         ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid"); | 
 | 509 |         ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing"); | 
 | 510 |         ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(), | 
 | 511 |                 "Status message queue for writing is invalid"); | 
 | 512 |         ALOGE_IF(!mEfGroup, "Event flag creation for writing failed"); | 
 | 513 |         return NO_INIT; | 
 | 514 |     } | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 515 | #if MAJOR_VERSION >= 7 | 
 | 516 |     if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) { | 
 | 517 |         return status; | 
 | 518 |     } | 
 | 519 | #endif | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 520 |     requestHalThreadPriority(halThreadPid, halThreadTid); | 
 | 521 |  | 
 | 522 |     mCommandMQ = std::move(tempCommandMQ); | 
 | 523 |     mDataMQ = std::move(tempDataMQ); | 
 | 524 |     mStatusMQ = std::move(tempStatusMQ); | 
 | 525 |     mWriterClient = gettid(); | 
 | 526 |     return OK; | 
 | 527 | } | 
 | 528 |  | 
 | 529 | status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) { | 
 | 530 |     if (mStream == 0) return NO_INIT; | 
 | 531 |     Result retval; | 
 | 532 |     Return<void> ret = mStream->getRenderPosition( | 
 | 533 |             [&](Result r, uint32_t d) { | 
 | 534 |                 retval = r; | 
 | 535 |                 if (retval == Result::OK) { | 
 | 536 |                     *dspFrames = d; | 
 | 537 |                 } | 
 | 538 |             }); | 
 | 539 |     return processReturn("getRenderPosition", ret, retval); | 
 | 540 | } | 
 | 541 |  | 
 | 542 | status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) { | 
 | 543 |     if (mStream == 0) return NO_INIT; | 
 | 544 |     Result retval; | 
 | 545 |     Return<void> ret = mStream->getNextWriteTimestamp( | 
 | 546 |             [&](Result r, int64_t t) { | 
 | 547 |                 retval = r; | 
 | 548 |                 if (retval == Result::OK) { | 
 | 549 |                     *timestamp = t; | 
 | 550 |                 } | 
 | 551 |             }); | 
 | 552 |     return processReturn("getRenderPosition", ret, retval); | 
 | 553 | } | 
 | 554 |  | 
 | 555 | status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) { | 
 | 556 |     if (mStream == 0) return NO_INIT; | 
 | 557 |     status_t status = processReturn( | 
 | 558 |             "setCallback", mStream->setCallback(new StreamOutCallback(this))); | 
 | 559 |     if (status == OK) { | 
 | 560 |         mCallback = callback; | 
 | 561 |     } | 
 | 562 |     return status; | 
 | 563 | } | 
 | 564 |  | 
 | 565 | status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) { | 
 | 566 |     if (mStream == 0) return NO_INIT; | 
 | 567 |     Return<void> ret = mStream->supportsPauseAndResume( | 
 | 568 |             [&](bool p, bool r) { | 
 | 569 |                 *supportsPause = p; | 
 | 570 |                 *supportsResume = r; | 
 | 571 |             }); | 
 | 572 |     return processReturn("supportsPauseAndResume", ret); | 
 | 573 | } | 
 | 574 |  | 
 | 575 | status_t StreamOutHalHidl::pause() { | 
 | 576 |     if (mStream == 0) return NO_INIT; | 
 | 577 |     return processReturn("pause", mStream->pause()); | 
 | 578 | } | 
 | 579 |  | 
 | 580 | status_t StreamOutHalHidl::resume() { | 
 | 581 |     if (mStream == 0) return NO_INIT; | 
 | 582 |     return processReturn("pause", mStream->resume()); | 
 | 583 | } | 
 | 584 |  | 
 | 585 | status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) { | 
 | 586 |     if (mStream == 0) return NO_INIT; | 
 | 587 |     return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain); | 
 | 588 | } | 
 | 589 |  | 
 | 590 | status_t StreamOutHalHidl::drain(bool earlyNotify) { | 
 | 591 |     if (mStream == 0) return NO_INIT; | 
 | 592 |     return processReturn( | 
 | 593 |             "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL)); | 
 | 594 | } | 
 | 595 |  | 
 | 596 | status_t StreamOutHalHidl::flush() { | 
 | 597 |     if (mStream == 0) return NO_INIT; | 
 | 598 |     return processReturn("pause", mStream->flush()); | 
 | 599 | } | 
 | 600 |  | 
 | 601 | status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) { | 
 | 602 |     if (mStream == 0) return NO_INIT; | 
 | 603 |     if (mWriterClient == gettid() && mCommandMQ) { | 
 | 604 |         return callWriterThread( | 
 | 605 |                 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0, | 
 | 606 |                 [&](const WriteStatus& writeStatus) { | 
 | 607 |                     *frames = writeStatus.reply.presentationPosition.frames; | 
 | 608 |                     timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec; | 
 | 609 |                     timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec; | 
 | 610 |                 }); | 
 | 611 |     } else { | 
 | 612 |         Result retval; | 
 | 613 |         Return<void> ret = mStream->getPresentationPosition( | 
 | 614 |                 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) { | 
 | 615 |                     retval = r; | 
 | 616 |                     if (retval == Result::OK) { | 
 | 617 |                         *frames = hidlFrames; | 
 | 618 |                         timestamp->tv_sec = hidlTimeStamp.tvSec; | 
 | 619 |                         timestamp->tv_nsec = hidlTimeStamp.tvNSec; | 
 | 620 |                     } | 
 | 621 |                 }); | 
 | 622 |         return processReturn("getPresentationPosition", ret, retval); | 
 | 623 |     } | 
 | 624 | } | 
 | 625 |  | 
| Kevin Rocard | 070e751 | 2018-05-22 09:29:13 -0700 | [diff] [blame] | 626 | #if MAJOR_VERSION == 2 | 
| Mikhail Naganov | 9ccaa16 | 2018-12-12 10:27:29 -0800 | [diff] [blame] | 627 | status_t StreamOutHalHidl::updateSourceMetadata( | 
 | 628 |         const StreamOutHalInterface::SourceMetadata& /* sourceMetadata */) { | 
| Kevin Rocard | 070e751 | 2018-05-22 09:29:13 -0700 | [diff] [blame] | 629 |     // Audio HAL V2.0 does not support propagating source metadata | 
 | 630 |     return INVALID_OPERATION; | 
 | 631 | } | 
| Kevin Rocard | 3d48dce | 2018-11-08 17:16:57 -0800 | [diff] [blame] | 632 | #elif MAJOR_VERSION >= 4 | 
| Mikhail Naganov | 9ccaa16 | 2018-12-12 10:27:29 -0800 | [diff] [blame] | 633 | status_t StreamOutHalHidl::updateSourceMetadata( | 
 | 634 |         const StreamOutHalInterface::SourceMetadata& sourceMetadata) { | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 635 |     CPP_VERSION::SourceMetadata hidlMetadata; | 
 | 636 |     if (status_t status = CoreUtils::sourceMetadataFromHalV7( | 
 | 637 |                     sourceMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata); | 
 | 638 |             status != OK) { | 
 | 639 |         return status; | 
 | 640 |     } | 
 | 641 |     return processReturn("updateSourceMetadata", mStream->updateSourceMetadata(hidlMetadata)); | 
| Kevin Rocard | a8975a7 | 2018-03-27 10:16:52 -0700 | [diff] [blame] | 642 | } | 
| Kevin Rocard | 070e751 | 2018-05-22 09:29:13 -0700 | [diff] [blame] | 643 | #endif | 
| Kevin Rocard | a8975a7 | 2018-03-27 10:16:52 -0700 | [diff] [blame] | 644 |  | 
| jiabin | f6eb4c3 | 2020-02-25 14:06:25 -0800 | [diff] [blame] | 645 | #if MAJOR_VERSION < 6 | 
| Kuowei Li | d4adbdb | 2020-08-13 14:44:25 +0800 | [diff] [blame] | 646 | status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) { | 
 | 647 |     return INVALID_OPERATION; | 
 | 648 | } | 
 | 649 |  | 
 | 650 | status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) { | 
 | 651 |     return INVALID_OPERATION; | 
 | 652 | } | 
 | 653 |  | 
 | 654 | status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB __unused) { | 
 | 655 |     return INVALID_OPERATION; | 
 | 656 | } | 
 | 657 |  | 
 | 658 | status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB __unused) { | 
 | 659 |     return INVALID_OPERATION; | 
 | 660 | } | 
 | 661 |  | 
 | 662 | status_t StreamOutHalHidl::getPlaybackRateParameters( | 
 | 663 |         audio_playback_rate_t* playbackRate __unused) { | 
 | 664 |     return INVALID_OPERATION; | 
 | 665 | } | 
 | 666 |  | 
 | 667 | status_t StreamOutHalHidl::setPlaybackRateParameters( | 
 | 668 |         const audio_playback_rate_t& playbackRate __unused) { | 
 | 669 |     return INVALID_OPERATION; | 
 | 670 | } | 
 | 671 |  | 
| jiabin | f6eb4c3 | 2020-02-25 14:06:25 -0800 | [diff] [blame] | 672 | status_t StreamOutHalHidl::setEventCallback( | 
 | 673 |         const sp<StreamOutHalInterfaceEventCallback>& callback __unused) { | 
 | 674 |     // Codec format callback is supported starting from audio HAL V6.0 | 
 | 675 |     return INVALID_OPERATION; | 
 | 676 | } | 
 | 677 | #else | 
 | 678 |  | 
| Kuowei Li | d4adbdb | 2020-08-13 14:44:25 +0800 | [diff] [blame] | 679 | status_t StreamOutHalHidl::getDualMonoMode(audio_dual_mono_mode_t* mode) { | 
 | 680 |     if (mStream == 0) return NO_INIT; | 
 | 681 |     Result retval; | 
 | 682 |     Return<void> ret = mStream->getDualMonoMode( | 
 | 683 |             [&](Result r, DualMonoMode hidlMode) { | 
 | 684 |                 retval = r; | 
 | 685 |                 if (retval == Result::OK) { | 
 | 686 |                     *mode = static_cast<audio_dual_mono_mode_t>(hidlMode); | 
 | 687 |                 } | 
 | 688 |             }); | 
 | 689 |     return processReturn("getDualMonoMode", ret, retval); | 
 | 690 | } | 
 | 691 |  | 
 | 692 | status_t StreamOutHalHidl::setDualMonoMode(audio_dual_mono_mode_t mode) { | 
 | 693 |     if (mStream == 0) return NO_INIT; | 
 | 694 |     return processReturn( | 
 | 695 |             "setDualMonoMode", mStream->setDualMonoMode(static_cast<DualMonoMode>(mode))); | 
 | 696 | } | 
 | 697 |  | 
 | 698 | status_t StreamOutHalHidl::getAudioDescriptionMixLevel(float* leveldB) { | 
 | 699 |     if (mStream == 0) return NO_INIT; | 
 | 700 |     Result retval; | 
 | 701 |     Return<void> ret = mStream->getAudioDescriptionMixLevel( | 
 | 702 |             [&](Result r, float hidlLeveldB) { | 
 | 703 |                 retval = r; | 
 | 704 |                 if (retval == Result::OK) { | 
 | 705 |                     *leveldB = hidlLeveldB; | 
 | 706 |                 } | 
 | 707 |             }); | 
 | 708 |     return processReturn("getAudioDescriptionMixLevel", ret, retval); | 
 | 709 | } | 
 | 710 |  | 
 | 711 | status_t StreamOutHalHidl::setAudioDescriptionMixLevel(float leveldB) { | 
 | 712 |     if (mStream == 0) return NO_INIT; | 
 | 713 |     return processReturn( | 
 | 714 |             "setAudioDescriptionMixLevel", mStream->setAudioDescriptionMixLevel(leveldB)); | 
 | 715 | } | 
 | 716 |  | 
 | 717 | status_t StreamOutHalHidl::getPlaybackRateParameters(audio_playback_rate_t* playbackRate) { | 
 | 718 |     if (mStream == 0) return NO_INIT; | 
 | 719 |     Result retval; | 
 | 720 |     Return<void> ret = mStream->getPlaybackRateParameters( | 
 | 721 |             [&](Result r, PlaybackRate hidlPlaybackRate) { | 
 | 722 |                 retval = r; | 
 | 723 |                 if (retval == Result::OK) { | 
 | 724 |                     playbackRate->mSpeed = hidlPlaybackRate.speed; | 
 | 725 |                     playbackRate->mPitch = hidlPlaybackRate.pitch; | 
 | 726 |                     playbackRate->mStretchMode = | 
 | 727 |                         static_cast<audio_timestretch_stretch_mode_t>( | 
 | 728 |                             hidlPlaybackRate.timestretchMode); | 
 | 729 |                     playbackRate->mFallbackMode = | 
 | 730 |                         static_cast<audio_timestretch_fallback_mode_t>( | 
 | 731 |                             hidlPlaybackRate.fallbackMode); | 
 | 732 |                 } | 
 | 733 |             }); | 
 | 734 |     return processReturn("getPlaybackRateParameters", ret, retval); | 
 | 735 | } | 
 | 736 |  | 
 | 737 | status_t StreamOutHalHidl::setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) { | 
 | 738 |     if (mStream == 0) return NO_INIT; | 
 | 739 |     return processReturn( | 
 | 740 |             "setPlaybackRateParameters", mStream->setPlaybackRateParameters( | 
 | 741 |                 PlaybackRate{playbackRate.mSpeed, playbackRate.mPitch, | 
 | 742 |                     static_cast<TimestretchMode>(playbackRate.mStretchMode), | 
 | 743 |                     static_cast<TimestretchFallbackMode>(playbackRate.mFallbackMode)})); | 
 | 744 | } | 
 | 745 |  | 
| jiabin | f6eb4c3 | 2020-02-25 14:06:25 -0800 | [diff] [blame] | 746 | #include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h) | 
 | 747 |  | 
 | 748 | namespace { | 
 | 749 |  | 
 | 750 | struct StreamOutEventCallback : public IStreamOutEventCallback { | 
 | 751 |     StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {} | 
 | 752 |  | 
 | 753 |     // IStreamOutEventCallback implementation | 
 | 754 |     Return<void> onCodecFormatChanged( | 
 | 755 |             const android::hardware::hidl_vec<uint8_t>& audioMetadata)  override { | 
 | 756 |         sp<StreamOutHalHidl> stream = mStream.promote(); | 
 | 757 |         if (stream != nullptr) { | 
 | 758 |             std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end()); | 
 | 759 |             stream->onCodecFormatChanged(metadataBs); | 
 | 760 |         } | 
 | 761 |         return Void(); | 
 | 762 |     } | 
 | 763 |  | 
 | 764 |   private: | 
 | 765 |     wp<StreamOutHalHidl> mStream; | 
 | 766 | }; | 
 | 767 |  | 
 | 768 | }  // namespace | 
 | 769 |  | 
 | 770 | status_t StreamOutHalHidl::setEventCallback( | 
 | 771 |         const sp<StreamOutHalInterfaceEventCallback>& callback) { | 
 | 772 |     if (mStream == nullptr) return NO_INIT; | 
 | 773 |     mEventCallback = callback; | 
 | 774 |     status_t status = processReturn( | 
 | 775 |             "setEventCallback", | 
 | 776 |             mStream->setEventCallback( | 
 | 777 |                     callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this))); | 
 | 778 |     return status; | 
 | 779 | } | 
 | 780 | #endif | 
 | 781 |  | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 782 | void StreamOutHalHidl::onWriteReady() { | 
| Andy Hung | 638f45b | 2021-01-18 20:02:56 -0800 | [diff] [blame] | 783 |     sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote(); | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 784 |     if (callback == 0) return; | 
 | 785 |     ALOGV("asyncCallback onWriteReady"); | 
 | 786 |     callback->onWriteReady(); | 
 | 787 | } | 
 | 788 |  | 
 | 789 | void StreamOutHalHidl::onDrainReady() { | 
| Andy Hung | 638f45b | 2021-01-18 20:02:56 -0800 | [diff] [blame] | 790 |     sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote(); | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 791 |     if (callback == 0) return; | 
 | 792 |     ALOGV("asyncCallback onDrainReady"); | 
 | 793 |     callback->onDrainReady(); | 
 | 794 | } | 
 | 795 |  | 
 | 796 | void StreamOutHalHidl::onError() { | 
| Andy Hung | 638f45b | 2021-01-18 20:02:56 -0800 | [diff] [blame] | 797 |     sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote(); | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 798 |     if (callback == 0) return; | 
 | 799 |     ALOGV("asyncCallback onError"); | 
 | 800 |     callback->onError(); | 
 | 801 | } | 
 | 802 |  | 
| jiabin | f6eb4c3 | 2020-02-25 14:06:25 -0800 | [diff] [blame] | 803 | void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) { | 
| Andy Hung | 638f45b | 2021-01-18 20:02:56 -0800 | [diff] [blame] | 804 |     sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote(); | 
| jiabin | f6eb4c3 | 2020-02-25 14:06:25 -0800 | [diff] [blame] | 805 |     if (callback == nullptr) return; | 
 | 806 |     ALOGV("asyncCodecFormatCallback %s", __func__); | 
 | 807 |     callback->onCodecFormatChanged(metadataBs); | 
 | 808 | } | 
 | 809 |  | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 810 |  | 
 | 811 | StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream) | 
 | 812 |         : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) { | 
 | 813 | } | 
 | 814 |  | 
 | 815 | StreamInHalHidl::~StreamInHalHidl() { | 
 | 816 |     if (mStream != 0) { | 
 | 817 |         processReturn("close", mStream->close()); | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 818 |     } | 
 | 819 |     if (mEfGroup) { | 
 | 820 |         EventFlag::deleteEventFlag(&mEfGroup); | 
 | 821 |     } | 
 | 822 | } | 
 | 823 |  | 
 | 824 | status_t StreamInHalHidl::getFrameSize(size_t *size) { | 
 | 825 |     if (mStream == 0) return NO_INIT; | 
 | 826 |     return processReturn("getFrameSize", mStream->getFrameSize(), size); | 
 | 827 | } | 
 | 828 |  | 
 | 829 | status_t StreamInHalHidl::setGain(float gain) { | 
 | 830 |     if (mStream == 0) return NO_INIT; | 
 | 831 |     return processReturn("setGain", mStream->setGain(gain)); | 
 | 832 | } | 
 | 833 |  | 
 | 834 | status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) { | 
 | 835 |     if (mStream == 0) return NO_INIT; | 
 | 836 |     *read = 0; | 
 | 837 |  | 
 | 838 |     if (bytes == 0 && !mDataMQ) { | 
 | 839 |         // Can't determine the size for the MQ buffer. Wait for a non-empty read request. | 
 | 840 |         return OK; | 
 | 841 |     } | 
 | 842 |  | 
 | 843 |     status_t status; | 
 | 844 |     if (!mDataMQ && (status = prepareForReading(bytes)) != OK) { | 
 | 845 |         return status; | 
 | 846 |     } | 
 | 847 |  | 
 | 848 |     ReadParameters params; | 
 | 849 |     params.command = ReadCommand::READ; | 
 | 850 |     params.params.read = bytes; | 
 | 851 |     status = callReaderThread(params, "read", | 
 | 852 |             [&](const ReadStatus& readStatus) { | 
 | 853 |                 const size_t availToRead = mDataMQ->availableToRead(); | 
 | 854 |                 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) { | 
 | 855 |                     ALOGE("data message queue read failed for \"read\""); | 
 | 856 |                 } | 
 | 857 |                 ALOGW_IF(availToRead != readStatus.reply.read, | 
 | 858 |                         "HAL read report inconsistent: mq = %d, status = %d", | 
 | 859 |                         (int32_t)availToRead, (int32_t)readStatus.reply.read); | 
 | 860 |                 *read = readStatus.reply.read; | 
 | 861 |             }); | 
 | 862 |     mStreamPowerLog.log(buffer, *read); | 
 | 863 |     return status; | 
 | 864 | } | 
 | 865 |  | 
 | 866 | status_t StreamInHalHidl::callReaderThread( | 
 | 867 |         const ReadParameters& params, const char* cmdName, | 
 | 868 |         StreamInHalHidl::ReaderCallback callback) { | 
 | 869 |     if (!mCommandMQ->write(¶ms)) { | 
 | 870 |         ALOGW("command message queue write failed"); | 
 | 871 |         return -EAGAIN; | 
 | 872 |     } | 
 | 873 |     mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); | 
 | 874 |  | 
 | 875 |     // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422 | 
 | 876 |     uint32_t efState = 0; | 
 | 877 | retry: | 
 | 878 |     status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState); | 
 | 879 |     if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) { | 
 | 880 |         ReadStatus readStatus; | 
 | 881 |         readStatus.retval = Result::NOT_INITIALIZED; | 
 | 882 |         if (!mStatusMQ->read(&readStatus)) { | 
 | 883 |             ALOGE("status message read failed for \"%s\"", cmdName); | 
 | 884 |         } | 
 | 885 |          if (readStatus.retval == Result::OK) { | 
 | 886 |             ret = OK; | 
 | 887 |             callback(readStatus); | 
 | 888 |         } else { | 
 | 889 |             ret = processReturn(cmdName, readStatus.retval); | 
 | 890 |         } | 
 | 891 |         return ret; | 
 | 892 |     } | 
 | 893 |     if (ret == -EAGAIN || ret == -EINTR) { | 
 | 894 |         // Spurious wakeup. This normally retries no more than once. | 
 | 895 |         goto retry; | 
 | 896 |     } | 
 | 897 |     return ret; | 
 | 898 | } | 
 | 899 |  | 
 | 900 | status_t StreamInHalHidl::prepareForReading(size_t bufferSize) { | 
 | 901 |     std::unique_ptr<CommandMQ> tempCommandMQ; | 
 | 902 |     std::unique_ptr<DataMQ> tempDataMQ; | 
 | 903 |     std::unique_ptr<StatusMQ> tempStatusMQ; | 
 | 904 |     Result retval; | 
 | 905 |     pid_t halThreadPid, halThreadTid; | 
 | 906 |     Return<void> ret = mStream->prepareForReading( | 
 | 907 |             1, bufferSize, | 
 | 908 |             [&](Result r, | 
 | 909 |                     const CommandMQ::Descriptor& commandMQ, | 
 | 910 |                     const DataMQ::Descriptor& dataMQ, | 
 | 911 |                     const StatusMQ::Descriptor& statusMQ, | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 912 |                     const auto& halThreadInfo) { | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 913 |                 retval = r; | 
 | 914 |                 if (retval == Result::OK) { | 
 | 915 |                     tempCommandMQ.reset(new CommandMQ(commandMQ)); | 
 | 916 |                     tempDataMQ.reset(new DataMQ(dataMQ)); | 
 | 917 |                     tempStatusMQ.reset(new StatusMQ(statusMQ)); | 
 | 918 |                     if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) { | 
 | 919 |                         EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup); | 
 | 920 |                     } | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 921 | #if MAJOR_VERSION <= 6 | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 922 |                     halThreadPid = halThreadInfo.pid; | 
 | 923 |                     halThreadTid = halThreadInfo.tid; | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 924 | #else | 
 | 925 |                     halThreadTid = halThreadInfo; | 
 | 926 | #endif | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 927 |                 } | 
 | 928 |             }); | 
 | 929 |     if (!ret.isOk() || retval != Result::OK) { | 
 | 930 |         return processReturn("prepareForReading", ret, retval); | 
 | 931 |     } | 
 | 932 |     if (!tempCommandMQ || !tempCommandMQ->isValid() || | 
 | 933 |             !tempDataMQ || !tempDataMQ->isValid() || | 
 | 934 |             !tempStatusMQ || !tempStatusMQ->isValid() || | 
 | 935 |             !mEfGroup) { | 
 | 936 |         ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing"); | 
 | 937 |         ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(), | 
 | 938 |                 "Command message queue for writing is invalid"); | 
 | 939 |         ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading"); | 
 | 940 |         ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid"); | 
 | 941 |         ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading"); | 
 | 942 |         ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(), | 
 | 943 |                 "Status message queue for reading is invalid"); | 
 | 944 |         ALOGE_IF(!mEfGroup, "Event flag creation for reading failed"); | 
 | 945 |         return NO_INIT; | 
 | 946 |     } | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 947 | #if MAJOR_VERSION >= 7 | 
 | 948 |     if (status_t status = getHalPid(&halThreadPid); status != NO_ERROR) { | 
 | 949 |         return status; | 
 | 950 |     } | 
 | 951 | #endif | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 952 |     requestHalThreadPriority(halThreadPid, halThreadTid); | 
 | 953 |  | 
 | 954 |     mCommandMQ = std::move(tempCommandMQ); | 
 | 955 |     mDataMQ = std::move(tempDataMQ); | 
 | 956 |     mStatusMQ = std::move(tempStatusMQ); | 
 | 957 |     mReaderClient = gettid(); | 
 | 958 |     return OK; | 
 | 959 | } | 
 | 960 |  | 
 | 961 | status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) { | 
 | 962 |     if (mStream == 0) return NO_INIT; | 
 | 963 |     return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost); | 
 | 964 | } | 
 | 965 |  | 
 | 966 | status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) { | 
 | 967 |     if (mStream == 0) return NO_INIT; | 
 | 968 |     if (mReaderClient == gettid() && mCommandMQ) { | 
 | 969 |         ReadParameters params; | 
 | 970 |         params.command = ReadCommand::GET_CAPTURE_POSITION; | 
 | 971 |         return callReaderThread(params, "getCapturePosition", | 
 | 972 |                 [&](const ReadStatus& readStatus) { | 
 | 973 |                     *frames = readStatus.reply.capturePosition.frames; | 
 | 974 |                     *time = readStatus.reply.capturePosition.time; | 
 | 975 |                 }); | 
 | 976 |     } else { | 
 | 977 |         Result retval; | 
 | 978 |         Return<void> ret = mStream->getCapturePosition( | 
 | 979 |                 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) { | 
 | 980 |                     retval = r; | 
 | 981 |                     if (retval == Result::OK) { | 
 | 982 |                         *frames = hidlFrames; | 
 | 983 |                         *time = hidlTime; | 
 | 984 |                     } | 
 | 985 |                 }); | 
 | 986 |         return processReturn("getCapturePosition", ret, retval); | 
 | 987 |     } | 
 | 988 | } | 
 | 989 |  | 
| Kevin Rocard | 070e751 | 2018-05-22 09:29:13 -0700 | [diff] [blame] | 990 | #if MAJOR_VERSION == 2 | 
 | 991 | status_t StreamInHalHidl::getActiveMicrophones( | 
 | 992 |         std::vector<media::MicrophoneInfo> *microphones __unused) { | 
 | 993 |     if (mStream == 0) return NO_INIT; | 
 | 994 |     return INVALID_OPERATION; | 
 | 995 | } | 
 | 996 |  | 
| Mikhail Naganov | 9ccaa16 | 2018-12-12 10:27:29 -0800 | [diff] [blame] | 997 | status_t StreamInHalHidl::updateSinkMetadata( | 
 | 998 |         const StreamInHalInterface::SinkMetadata& /* sinkMetadata */) { | 
| Kevin Rocard | 070e751 | 2018-05-22 09:29:13 -0700 | [diff] [blame] | 999 |     // Audio HAL V2.0 does not support propagating sink metadata | 
 | 1000 |     return INVALID_OPERATION; | 
 | 1001 | } | 
 | 1002 |  | 
| Kevin Rocard | 3d48dce | 2018-11-08 17:16:57 -0800 | [diff] [blame] | 1003 | #elif MAJOR_VERSION >= 4 | 
| jiabin | 9ff780e | 2018-03-19 18:19:52 -0700 | [diff] [blame] | 1004 | status_t StreamInHalHidl::getActiveMicrophones( | 
 | 1005 |         std::vector<media::MicrophoneInfo> *microphonesInfo) { | 
 | 1006 |     if (!mStream) return NO_INIT; | 
 | 1007 |     Result retval; | 
 | 1008 |     Return<void> ret = mStream->getActiveMicrophones( | 
 | 1009 |             [&](Result r, hidl_vec<MicrophoneInfo> micArrayHal) { | 
 | 1010 |         retval = r; | 
 | 1011 |         for (size_t k = 0; k < micArrayHal.size(); k++) { | 
 | 1012 |             audio_microphone_characteristic_t dst; | 
 | 1013 |             // convert | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 1014 |             (void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst); | 
| jiabin | 9ff780e | 2018-03-19 18:19:52 -0700 | [diff] [blame] | 1015 |             media::MicrophoneInfo microphone = media::MicrophoneInfo(dst); | 
 | 1016 |             microphonesInfo->push_back(microphone); | 
 | 1017 |         } | 
 | 1018 |     }); | 
 | 1019 |     return processReturn("getActiveMicrophones", ret, retval); | 
 | 1020 | } | 
 | 1021 |  | 
| Mikhail Naganov | 9ccaa16 | 2018-12-12 10:27:29 -0800 | [diff] [blame] | 1022 | status_t StreamInHalHidl::updateSinkMetadata(const | 
 | 1023 |         StreamInHalInterface::SinkMetadata& sinkMetadata) { | 
| Mikhail Naganov | 247b5f9 | 2021-01-15 19:16:12 +0000 | [diff] [blame] | 1024 |     CPP_VERSION::SinkMetadata hidlMetadata; | 
 | 1025 |     if (status_t status = CoreUtils::sinkMetadataFromHalV7( | 
 | 1026 |                     sinkMetadata.tracks, true /*ignoreNonVendorTags*/, &hidlMetadata); | 
 | 1027 |             status != OK) { | 
 | 1028 |         return status; | 
 | 1029 |     } | 
 | 1030 |     return processReturn("updateSinkMetadata", mStream->updateSinkMetadata(hidlMetadata)); | 
| Kevin Rocard | a8975a7 | 2018-03-27 10:16:52 -0700 | [diff] [blame] | 1031 | } | 
| Kevin Rocard | 070e751 | 2018-05-22 09:29:13 -0700 | [diff] [blame] | 1032 | #endif | 
| Kevin Rocard | a8975a7 | 2018-03-27 10:16:52 -0700 | [diff] [blame] | 1033 |  | 
| Paul McLean | 03a6e6a | 2018-12-04 10:54:13 -0700 | [diff] [blame] | 1034 | #if MAJOR_VERSION < 5 | 
| Paul McLean | 1234008 | 2019-03-19 09:35:05 -0600 | [diff] [blame] | 1035 | status_t StreamInHalHidl::setPreferredMicrophoneDirection( | 
 | 1036 |             audio_microphone_direction_t direction __unused) { | 
| Paul McLean | 03a6e6a | 2018-12-04 10:54:13 -0700 | [diff] [blame] | 1037 |     if (mStream == 0) return NO_INIT; | 
 | 1038 |     return INVALID_OPERATION; | 
 | 1039 | } | 
 | 1040 |  | 
| Paul McLean | 1234008 | 2019-03-19 09:35:05 -0600 | [diff] [blame] | 1041 | status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom __unused) { | 
| Paul McLean | 03a6e6a | 2018-12-04 10:54:13 -0700 | [diff] [blame] | 1042 |     if (mStream == 0) return NO_INIT; | 
 | 1043 |     return INVALID_OPERATION; | 
 | 1044 | } | 
 | 1045 | #else | 
| Paul McLean | 1234008 | 2019-03-19 09:35:05 -0600 | [diff] [blame] | 1046 | status_t StreamInHalHidl::setPreferredMicrophoneDirection(audio_microphone_direction_t direction) { | 
| Paul McLean | 03a6e6a | 2018-12-04 10:54:13 -0700 | [diff] [blame] | 1047 |     if (!mStream) return NO_INIT; | 
| Paul McLean | 1234008 | 2019-03-19 09:35:05 -0600 | [diff] [blame] | 1048 |     return processReturn("setPreferredMicrophoneDirection", | 
 | 1049 |         mStream->setMicrophoneDirection(static_cast<MicrophoneDirection>(direction))); | 
| Paul McLean | 03a6e6a | 2018-12-04 10:54:13 -0700 | [diff] [blame] | 1050 | } | 
 | 1051 |  | 
| Paul McLean | 1234008 | 2019-03-19 09:35:05 -0600 | [diff] [blame] | 1052 | status_t StreamInHalHidl::setPreferredMicrophoneFieldDimension(float zoom) { | 
| Paul McLean | 03a6e6a | 2018-12-04 10:54:13 -0700 | [diff] [blame] | 1053 |     if (!mStream) return NO_INIT; | 
| Paul McLean | 1234008 | 2019-03-19 09:35:05 -0600 | [diff] [blame] | 1054 |     return processReturn("setPreferredMicrophoneFieldDimension", | 
| Paul McLean | 03a6e6a | 2018-12-04 10:54:13 -0700 | [diff] [blame] | 1055 |                 mStream->setMicrophoneFieldDimension(zoom)); | 
 | 1056 | } | 
 | 1057 | #endif | 
 | 1058 |  | 
| Kevin Rocard | 070e751 | 2018-05-22 09:29:13 -0700 | [diff] [blame] | 1059 | } // namespace CPP_VERSION | 
| Kevin Rocard | 4bcd67f | 2018-02-28 14:33:38 -0800 | [diff] [blame] | 1060 | } // namespace android |