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