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 20 #include <android/hardware/audio/2.0/IStreamOutCallback.h> 21 #include <hwbinder/IPCThreadState.h> 22 #include <mediautils/SchedulingPolicyService.h> 23 #include <utils/Log.h> 24 25 #include "DeviceHalHidl.h" 26 #include "EffectHalHidl.h" 27 #include "StreamHalHidl.h" 28 29 using ::android::hardware::audio::common::V2_0::AudioChannelMask; 30 using ::android::hardware::audio::common::V2_0::AudioFormat; 31 using ::android::hardware::audio::common::V2_0::ThreadInfo; 32 using ::android::hardware::audio::V2_0::AudioDrain; 33 using ::android::hardware::audio::V2_0::IStreamOutCallback; 34 using ::android::hardware::audio::V2_0::MessageQueueFlagBits; 35 using ::android::hardware::audio::V2_0::MmapBufferInfo; 36 using ::android::hardware::audio::V2_0::MmapPosition; 37 using ::android::hardware::audio::V2_0::ParameterValue; 38 using ::android::hardware::audio::V2_0::Result; 39 using ::android::hardware::audio::V2_0::TimeSpec; 40 using ::android::hardware::MQDescriptorSync; 41 using ::android::hardware::Return; 42 using ::android::hardware::Void; 43 using ReadCommand = ::android::hardware::audio::V2_0::IStreamIn::ReadCommand; 44 45 namespace android { 46 47 StreamHalHidl::StreamHalHidl(IStream *stream) 48 : ConversionHelperHidl("Stream"), 49 mStream(stream), 50 mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT), 51 mCachedBufferSize(0){ 52 53 // Instrument audio signal power logging. 54 // Note: This assumes channel mask, format, and sample rate do not change after creation. 55 if (mStream != nullptr && mStreamPowerLog.isUserDebugOrEngBuild()) { 56 // Obtain audio properties (see StreamHalHidl::getAudioProperties() below). 57 Return<void> ret = mStream->getAudioProperties( 58 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) { 59 mStreamPowerLog.init(sr, 60 static_cast<audio_channel_mask_t>(m), 61 static_cast<audio_format_t>(f)); 62 }); 63 } 64 } 65 66 StreamHalHidl::~StreamHalHidl() { 67 mStream = nullptr; 68 } 69 70 status_t StreamHalHidl::getSampleRate(uint32_t *rate) { 71 if (!mStream) return NO_INIT; 72 return processReturn("getSampleRate", mStream->getSampleRate(), rate); 73 } 74 75 status_t StreamHalHidl::getBufferSize(size_t *size) { 76 if (!mStream) return NO_INIT; 77 status_t status = processReturn("getBufferSize", mStream->getBufferSize(), size); 78 if (status == OK) { 79 mCachedBufferSize = *size; 80 } 81 return status; 82 } 83 84 status_t StreamHalHidl::getChannelMask(audio_channel_mask_t *mask) { 85 if (!mStream) return NO_INIT; 86 return processReturn("getChannelMask", mStream->getChannelMask(), mask); 87 } 88 89 status_t StreamHalHidl::getFormat(audio_format_t *format) { 90 if (!mStream) return NO_INIT; 91 return processReturn("getFormat", mStream->getFormat(), format); 92 } 93 94 status_t StreamHalHidl::getAudioProperties( 95 uint32_t *sampleRate, audio_channel_mask_t *mask, audio_format_t *format) { 96 if (!mStream) return NO_INIT; 97 Return<void> ret = mStream->getAudioProperties( 98 [&](uint32_t sr, AudioChannelMask m, AudioFormat f) { 99 *sampleRate = sr; 100 *mask = static_cast<audio_channel_mask_t>(m); 101 *format = static_cast<audio_format_t>(f); 102 }); 103 return processReturn("getAudioProperties", ret); 104 } 105 106 status_t StreamHalHidl::setParameters(const String8& kvPairs) { 107 if (!mStream) return NO_INIT; 108 hidl_vec<ParameterValue> hidlParams; 109 status_t status = parametersFromHal(kvPairs, &hidlParams); 110 if (status != OK) return status; 111 return processReturn("setParameters", mStream->setParameters(hidlParams)); 112 } 113 114 status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) { 115 values->clear(); 116 if (!mStream) return NO_INIT; 117 hidl_vec<hidl_string> hidlKeys; 118 status_t status = keysFromHal(keys, &hidlKeys); 119 if (status != OK) return status; 120 Result retval; 121 Return<void> ret = mStream->getParameters( 122 hidlKeys, 123 [&](Result r, const hidl_vec<ParameterValue>& parameters) { 124 retval = r; 125 if (retval == Result::OK) { 126 parametersToHal(parameters, values); 127 } 128 }); 129 return processReturn("getParameters", ret, retval); 130 } 131 132 status_t StreamHalHidl::addEffect(sp<EffectHalInterface> effect) { 133 if (!mStream) return NO_INIT; 134 return processReturn("addEffect", mStream->addEffect( 135 static_cast<EffectHalHidl*>(effect.get())->effectId())); 136 } 137 138 status_t StreamHalHidl::removeEffect(sp<EffectHalInterface> effect) { 139 if (!mStream) return NO_INIT; 140 return processReturn("removeEffect", mStream->removeEffect( 141 static_cast<EffectHalHidl*>(effect.get())->effectId())); 142 } 143 144 status_t StreamHalHidl::standby() { 145 if (!mStream) return NO_INIT; 146 return processReturn("standby", mStream->standby()); 147 } 148 149 status_t StreamHalHidl::dump(int fd) { 150 if (!mStream) return NO_INIT; 151 native_handle_t* hidlHandle = native_handle_create(1, 0); 152 hidlHandle->data[0] = fd; 153 Return<void> ret = mStream->debugDump(hidlHandle); 154 native_handle_delete(hidlHandle); 155 mStreamPowerLog.dump(fd); 156 return processReturn("dump", ret); 157 } 158 159 status_t StreamHalHidl::start() { 160 if (!mStream) return NO_INIT; 161 return processReturn("start", mStream->start()); 162 } 163 164 status_t StreamHalHidl::stop() { 165 if (!mStream) return NO_INIT; 166 return processReturn("stop", mStream->stop()); 167 } 168 169 status_t StreamHalHidl::createMmapBuffer(int32_t minSizeFrames, 170 struct audio_mmap_buffer_info *info) { 171 Result retval; 172 Return<void> ret = mStream->createMmapBuffer( 173 minSizeFrames, 174 [&](Result r, const MmapBufferInfo& hidlInfo) { 175 retval = r; 176 if (retval == Result::OK) { 177 const native_handle *handle = hidlInfo.sharedMemory.handle(); 178 if (handle->numFds > 0) { 179 info->shared_memory_fd = handle->data[0]; 180 info->buffer_size_frames = hidlInfo.bufferSizeFrames; 181 info->burst_size_frames = hidlInfo.burstSizeFrames; 182 // info->shared_memory_address is not needed in HIDL context 183 info->shared_memory_address = NULL; 184 } else { 185 retval = Result::NOT_INITIALIZED; 186 } 187 } 188 }); 189 return processReturn("createMmapBuffer", ret, retval); 190 } 191 192 status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) { 193 Result retval; 194 Return<void> ret = mStream->getMmapPosition( 195 [&](Result r, const MmapPosition& hidlPosition) { 196 retval = r; 197 if (retval == Result::OK) { 198 position->time_nanoseconds = hidlPosition.timeNanoseconds; 199 position->position_frames = hidlPosition.positionFrames; 200 } 201 }); 202 return processReturn("getMmapPosition", ret, retval); 203 } 204 205 status_t StreamHalHidl::setHalThreadPriority(int priority) { 206 mHalThreadPriority = priority; 207 return OK; 208 } 209 210 status_t StreamHalHidl::getCachedBufferSize(size_t *size) { 211 if (mCachedBufferSize != 0) { 212 *size = mCachedBufferSize; 213 return OK; 214 } 215 return getBufferSize(size); 216 } 217 218 bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) { 219 if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) { 220 return true; 221 } 222 int err = requestPriority( 223 threadPid, threadId, 224 mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/); 225 ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d", 226 mHalThreadPriority, threadPid, threadId, err); 227 // Audio will still work, but latency will be higher and sometimes unacceptable. 228 return err == 0; 229 } 230 231 namespace { 232 233 /* Notes on callback ownership. 234 235 This is how (Hw)Binder ownership model looks like. The server implementation 236 is owned by Binder framework (via sp<>). Proxies are owned by clients. 237 When the last proxy disappears, Binder framework releases the server impl. 238 239 Thus, it is not needed to keep any references to StreamOutCallback (this is 240 the server impl) -- it will live as long as HAL server holds a strong ref to 241 IStreamOutCallback proxy. We clear that reference by calling 'clearCallback' 242 from the destructor of StreamOutHalHidl. 243 244 The callback only keeps a weak reference to the stream. The stream is owned 245 by AudioFlinger. 246 247 */ 248 249 struct StreamOutCallback : public IStreamOutCallback { 250 StreamOutCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {} 251 252 // IStreamOutCallback implementation 253 Return<void> onWriteReady() override { 254 sp<StreamOutHalHidl> stream = mStream.promote(); 255 if (stream != 0) { 256 stream->onWriteReady(); 257 } 258 return Void(); 259 } 260 261 Return<void> onDrainReady() override { 262 sp<StreamOutHalHidl> stream = mStream.promote(); 263 if (stream != 0) { 264 stream->onDrainReady(); 265 } 266 return Void(); 267 } 268 269 Return<void> onError() override { 270 sp<StreamOutHalHidl> stream = mStream.promote(); 271 if (stream != 0) { 272 stream->onError(); 273 } 274 return Void(); 275 } 276 277 private: 278 wp<StreamOutHalHidl> mStream; 279 }; 280 281 } // namespace 282 283 StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream) 284 : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) { 285 } 286 287 StreamOutHalHidl::~StreamOutHalHidl() { 288 if (mStream != 0) { 289 if (mCallback.unsafe_get()) { 290 processReturn("clearCallback", mStream->clearCallback()); 291 } 292 processReturn("close", mStream->close()); 293 mStream.clear(); 294 } 295 mCallback.clear(); 296 hardware::IPCThreadState::self()->flushCommands(); 297 if (mEfGroup) { 298 EventFlag::deleteEventFlag(&mEfGroup); 299 } 300 } 301 302 status_t StreamOutHalHidl::getFrameSize(size_t *size) { 303 if (mStream == 0) return NO_INIT; 304 return processReturn("getFrameSize", mStream->getFrameSize(), size); 305 } 306 307 status_t StreamOutHalHidl::getLatency(uint32_t *latency) { 308 if (mStream == 0) return NO_INIT; 309 if (mWriterClient == gettid() && mCommandMQ) { 310 return callWriterThread( 311 WriteCommand::GET_LATENCY, "getLatency", nullptr, 0, 312 [&](const WriteStatus& writeStatus) { 313 *latency = writeStatus.reply.latencyMs; 314 }); 315 } else { 316 return processReturn("getLatency", mStream->getLatency(), latency); 317 } 318 } 319 320 status_t StreamOutHalHidl::setVolume(float left, float right) { 321 if (mStream == 0) return NO_INIT; 322 return processReturn("setVolume", mStream->setVolume(left, right)); 323 } 324 325 status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) { 326 if (mStream == 0) return NO_INIT; 327 *written = 0; 328 329 if (bytes == 0 && !mDataMQ) { 330 // Can't determine the size for the MQ buffer. Wait for a non-empty write request. 331 ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes"); 332 return OK; 333 } 334 335 status_t status; 336 if (!mDataMQ) { 337 // In case if playback starts close to the end of a compressed track, the bytes 338 // that need to be written is less than the actual buffer size. Need to use 339 // full buffer size for the MQ since otherwise after seeking back to the middle 340 // data will be truncated. 341 size_t bufferSize; 342 if ((status = getCachedBufferSize(&bufferSize)) != OK) { 343 return status; 344 } 345 if (bytes > bufferSize) bufferSize = bytes; 346 if ((status = prepareForWriting(bufferSize)) != OK) { 347 return status; 348 } 349 } 350 351 status = callWriterThread( 352 WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes, 353 [&] (const WriteStatus& writeStatus) { 354 *written = writeStatus.reply.written; 355 // Diagnostics of the cause of b/35813113. 356 ALOGE_IF(*written > bytes, 357 "hal reports more bytes written than asked for: %lld > %lld", 358 (long long)*written, (long long)bytes); 359 }); 360 mStreamPowerLog.log(buffer, *written); 361 return status; 362 } 363 364 status_t StreamOutHalHidl::callWriterThread( 365 WriteCommand cmd, const char* cmdName, 366 const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) { 367 if (!mCommandMQ->write(&cmd)) { 368 ALOGE("command message queue write failed for \"%s\"", cmdName); 369 return -EAGAIN; 370 } 371 if (data != nullptr) { 372 size_t availableToWrite = mDataMQ->availableToWrite(); 373 if (dataSize > availableToWrite) { 374 ALOGW("truncating write data from %lld to %lld due to insufficient data queue space", 375 (long long)dataSize, (long long)availableToWrite); 376 dataSize = availableToWrite; 377 } 378 if (!mDataMQ->write(data, dataSize)) { 379 ALOGE("data message queue write failed for \"%s\"", cmdName); 380 } 381 } 382 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)); 383 384 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422 385 uint32_t efState = 0; 386 retry: 387 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState); 388 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) { 389 WriteStatus writeStatus; 390 writeStatus.retval = Result::NOT_INITIALIZED; 391 if (!mStatusMQ->read(&writeStatus)) { 392 ALOGE("status message read failed for \"%s\"", cmdName); 393 } 394 if (writeStatus.retval == Result::OK) { 395 ret = OK; 396 callback(writeStatus); 397 } else { 398 ret = processReturn(cmdName, writeStatus.retval); 399 } 400 return ret; 401 } 402 if (ret == -EAGAIN || ret == -EINTR) { 403 // Spurious wakeup. This normally retries no more than once. 404 goto retry; 405 } 406 return ret; 407 } 408 409 status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) { 410 std::unique_ptr<CommandMQ> tempCommandMQ; 411 std::unique_ptr<DataMQ> tempDataMQ; 412 std::unique_ptr<StatusMQ> tempStatusMQ; 413 Result retval; 414 pid_t halThreadPid, halThreadTid; 415 Return<void> ret = mStream->prepareForWriting( 416 1, bufferSize, 417 [&](Result r, 418 const CommandMQ::Descriptor& commandMQ, 419 const DataMQ::Descriptor& dataMQ, 420 const StatusMQ::Descriptor& statusMQ, 421 const ThreadInfo& halThreadInfo) { 422 retval = r; 423 if (retval == Result::OK) { 424 tempCommandMQ.reset(new CommandMQ(commandMQ)); 425 tempDataMQ.reset(new DataMQ(dataMQ)); 426 tempStatusMQ.reset(new StatusMQ(statusMQ)); 427 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) { 428 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup); 429 } 430 halThreadPid = halThreadInfo.pid; 431 halThreadTid = halThreadInfo.tid; 432 } 433 }); 434 if (!ret.isOk() || retval != Result::OK) { 435 return processReturn("prepareForWriting", ret, retval); 436 } 437 if (!tempCommandMQ || !tempCommandMQ->isValid() || 438 !tempDataMQ || !tempDataMQ->isValid() || 439 !tempStatusMQ || !tempStatusMQ->isValid() || 440 !mEfGroup) { 441 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing"); 442 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(), 443 "Command message queue for writing is invalid"); 444 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing"); 445 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid"); 446 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing"); 447 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(), 448 "Status message queue for writing is invalid"); 449 ALOGE_IF(!mEfGroup, "Event flag creation for writing failed"); 450 return NO_INIT; 451 } 452 requestHalThreadPriority(halThreadPid, halThreadTid); 453 454 mCommandMQ = std::move(tempCommandMQ); 455 mDataMQ = std::move(tempDataMQ); 456 mStatusMQ = std::move(tempStatusMQ); 457 mWriterClient = gettid(); 458 return OK; 459 } 460 461 status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) { 462 if (mStream == 0) return NO_INIT; 463 Result retval; 464 Return<void> ret = mStream->getRenderPosition( 465 [&](Result r, uint32_t d) { 466 retval = r; 467 if (retval == Result::OK) { 468 *dspFrames = d; 469 } 470 }); 471 return processReturn("getRenderPosition", ret, retval); 472 } 473 474 status_t StreamOutHalHidl::getNextWriteTimestamp(int64_t *timestamp) { 475 if (mStream == 0) return NO_INIT; 476 Result retval; 477 Return<void> ret = mStream->getNextWriteTimestamp( 478 [&](Result r, int64_t t) { 479 retval = r; 480 if (retval == Result::OK) { 481 *timestamp = t; 482 } 483 }); 484 return processReturn("getRenderPosition", ret, retval); 485 } 486 487 status_t StreamOutHalHidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) { 488 if (mStream == 0) return NO_INIT; 489 status_t status = processReturn( 490 "setCallback", mStream->setCallback(new StreamOutCallback(this))); 491 if (status == OK) { 492 mCallback = callback; 493 } 494 return status; 495 } 496 497 status_t StreamOutHalHidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) { 498 if (mStream == 0) return NO_INIT; 499 Return<void> ret = mStream->supportsPauseAndResume( 500 [&](bool p, bool r) { 501 *supportsPause = p; 502 *supportsResume = r; 503 }); 504 return processReturn("supportsPauseAndResume", ret); 505 } 506 507 status_t StreamOutHalHidl::pause() { 508 if (mStream == 0) return NO_INIT; 509 return processReturn("pause", mStream->pause()); 510 } 511 512 status_t StreamOutHalHidl::resume() { 513 if (mStream == 0) return NO_INIT; 514 return processReturn("pause", mStream->resume()); 515 } 516 517 status_t StreamOutHalHidl::supportsDrain(bool *supportsDrain) { 518 if (mStream == 0) return NO_INIT; 519 return processReturn("supportsDrain", mStream->supportsDrain(), supportsDrain); 520 } 521 522 status_t StreamOutHalHidl::drain(bool earlyNotify) { 523 if (mStream == 0) return NO_INIT; 524 return processReturn( 525 "drain", mStream->drain(earlyNotify ? AudioDrain::EARLY_NOTIFY : AudioDrain::ALL)); 526 } 527 528 status_t StreamOutHalHidl::flush() { 529 if (mStream == 0) return NO_INIT; 530 return processReturn("pause", mStream->flush()); 531 } 532 533 status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) { 534 if (mStream == 0) return NO_INIT; 535 if (mWriterClient == gettid() && mCommandMQ) { 536 return callWriterThread( 537 WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0, 538 [&](const WriteStatus& writeStatus) { 539 *frames = writeStatus.reply.presentationPosition.frames; 540 timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec; 541 timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec; 542 }); 543 } else { 544 Result retval; 545 Return<void> ret = mStream->getPresentationPosition( 546 [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) { 547 retval = r; 548 if (retval == Result::OK) { 549 *frames = hidlFrames; 550 timestamp->tv_sec = hidlTimeStamp.tvSec; 551 timestamp->tv_nsec = hidlTimeStamp.tvNSec; 552 } 553 }); 554 return processReturn("getPresentationPosition", ret, retval); 555 } 556 } 557 558 void StreamOutHalHidl::onWriteReady() { 559 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote(); 560 if (callback == 0) return; 561 ALOGV("asyncCallback onWriteReady"); 562 callback->onWriteReady(); 563 } 564 565 void StreamOutHalHidl::onDrainReady() { 566 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote(); 567 if (callback == 0) return; 568 ALOGV("asyncCallback onDrainReady"); 569 callback->onDrainReady(); 570 } 571 572 void StreamOutHalHidl::onError() { 573 sp<StreamOutHalInterfaceCallback> callback = mCallback.promote(); 574 if (callback == 0) return; 575 ALOGV("asyncCallback onError"); 576 callback->onError(); 577 } 578 579 580 StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream) 581 : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) { 582 } 583 584 StreamInHalHidl::~StreamInHalHidl() { 585 if (mStream != 0) { 586 processReturn("close", mStream->close()); 587 mStream.clear(); 588 hardware::IPCThreadState::self()->flushCommands(); 589 } 590 if (mEfGroup) { 591 EventFlag::deleteEventFlag(&mEfGroup); 592 } 593 } 594 595 status_t StreamInHalHidl::getFrameSize(size_t *size) { 596 if (mStream == 0) return NO_INIT; 597 return processReturn("getFrameSize", mStream->getFrameSize(), size); 598 } 599 600 status_t StreamInHalHidl::setGain(float gain) { 601 if (mStream == 0) return NO_INIT; 602 return processReturn("setGain", mStream->setGain(gain)); 603 } 604 605 status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) { 606 if (mStream == 0) return NO_INIT; 607 *read = 0; 608 609 if (bytes == 0 && !mDataMQ) { 610 // Can't determine the size for the MQ buffer. Wait for a non-empty read request. 611 return OK; 612 } 613 614 status_t status; 615 if (!mDataMQ && (status = prepareForReading(bytes)) != OK) { 616 return status; 617 } 618 619 ReadParameters params; 620 params.command = ReadCommand::READ; 621 params.params.read = bytes; 622 status = callReaderThread(params, "read", 623 [&](const ReadStatus& readStatus) { 624 const size_t availToRead = mDataMQ->availableToRead(); 625 if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) { 626 ALOGE("data message queue read failed for \"read\""); 627 } 628 ALOGW_IF(availToRead != readStatus.reply.read, 629 "HAL read report inconsistent: mq = %d, status = %d", 630 (int32_t)availToRead, (int32_t)readStatus.reply.read); 631 *read = readStatus.reply.read; 632 }); 633 mStreamPowerLog.log(buffer, *read); 634 return status; 635 } 636 637 status_t StreamInHalHidl::callReaderThread( 638 const ReadParameters& params, const char* cmdName, 639 StreamInHalHidl::ReaderCallback callback) { 640 if (!mCommandMQ->write(¶ms)) { 641 ALOGW("command message queue write failed"); 642 return -EAGAIN; 643 } 644 mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); 645 646 // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422 647 uint32_t efState = 0; 648 retry: 649 status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState); 650 if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) { 651 ReadStatus readStatus; 652 readStatus.retval = Result::NOT_INITIALIZED; 653 if (!mStatusMQ->read(&readStatus)) { 654 ALOGE("status message read failed for \"%s\"", cmdName); 655 } 656 if (readStatus.retval == Result::OK) { 657 ret = OK; 658 callback(readStatus); 659 } else { 660 ret = processReturn(cmdName, readStatus.retval); 661 } 662 return ret; 663 } 664 if (ret == -EAGAIN || ret == -EINTR) { 665 // Spurious wakeup. This normally retries no more than once. 666 goto retry; 667 } 668 return ret; 669 } 670 671 status_t StreamInHalHidl::prepareForReading(size_t bufferSize) { 672 std::unique_ptr<CommandMQ> tempCommandMQ; 673 std::unique_ptr<DataMQ> tempDataMQ; 674 std::unique_ptr<StatusMQ> tempStatusMQ; 675 Result retval; 676 pid_t halThreadPid, halThreadTid; 677 Return<void> ret = mStream->prepareForReading( 678 1, bufferSize, 679 [&](Result r, 680 const CommandMQ::Descriptor& commandMQ, 681 const DataMQ::Descriptor& dataMQ, 682 const StatusMQ::Descriptor& statusMQ, 683 const ThreadInfo& halThreadInfo) { 684 retval = r; 685 if (retval == Result::OK) { 686 tempCommandMQ.reset(new CommandMQ(commandMQ)); 687 tempDataMQ.reset(new DataMQ(dataMQ)); 688 tempStatusMQ.reset(new StatusMQ(statusMQ)); 689 if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) { 690 EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup); 691 } 692 halThreadPid = halThreadInfo.pid; 693 halThreadTid = halThreadInfo.tid; 694 } 695 }); 696 if (!ret.isOk() || retval != Result::OK) { 697 return processReturn("prepareForReading", ret, retval); 698 } 699 if (!tempCommandMQ || !tempCommandMQ->isValid() || 700 !tempDataMQ || !tempDataMQ->isValid() || 701 !tempStatusMQ || !tempStatusMQ->isValid() || 702 !mEfGroup) { 703 ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing"); 704 ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(), 705 "Command message queue for writing is invalid"); 706 ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading"); 707 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid"); 708 ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading"); 709 ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(), 710 "Status message queue for reading is invalid"); 711 ALOGE_IF(!mEfGroup, "Event flag creation for reading failed"); 712 return NO_INIT; 713 } 714 requestHalThreadPriority(halThreadPid, halThreadTid); 715 716 mCommandMQ = std::move(tempCommandMQ); 717 mDataMQ = std::move(tempDataMQ); 718 mStatusMQ = std::move(tempStatusMQ); 719 mReaderClient = gettid(); 720 return OK; 721 } 722 723 status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) { 724 if (mStream == 0) return NO_INIT; 725 return processReturn("getInputFramesLost", mStream->getInputFramesLost(), framesLost); 726 } 727 728 status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) { 729 if (mStream == 0) return NO_INIT; 730 if (mReaderClient == gettid() && mCommandMQ) { 731 ReadParameters params; 732 params.command = ReadCommand::GET_CAPTURE_POSITION; 733 return callReaderThread(params, "getCapturePosition", 734 [&](const ReadStatus& readStatus) { 735 *frames = readStatus.reply.capturePosition.frames; 736 *time = readStatus.reply.capturePosition.time; 737 }); 738 } else { 739 Result retval; 740 Return<void> ret = mStream->getCapturePosition( 741 [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) { 742 retval = r; 743 if (retval == Result::OK) { 744 *frames = hidlFrames; 745 *time = hidlTime; 746 } 747 }); 748 return processReturn("getCapturePosition", ret, retval); 749 } 750 } 751 752 } // namespace android 753