Loading include/media/audiohal/StreamHalInterface.h +4 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,10 @@ class StreamHalInterface : public virtual RefBase // Get current read/write position in the mmap buffer virtual status_t getMmapPosition(struct audio_mmap_position *position) = 0; // Set the priority of the thread that interacts with the HAL // (must match the priority of the audioflinger's thread that calls 'read' / 'write') virtual status_t setHalThreadPriority(int priority) = 0; protected: // Subclasses can not be constructed directly by clients. StreamHalInterface() {} Loading media/libaudiohal/Android.mk +4 −2 Original line number Diff line number Diff line Loading @@ -3,11 +3,13 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SHARED_LIBRARIES := \ libbase \ libcutils \ libeffects \ libfmq \ libhardware \ liblog \ libutils \ libeffects libutils ifeq ($(ENABLE_TREBLE), true) Loading media/libaudiohal/StreamHalHidl.cpp +199 −20 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include <time.h> #define LOG_TAG "StreamHalHidl" //#define LOG_NDEBUG 0 Loading @@ -28,18 +30,23 @@ using ::android::hardware::audio::common::V2_0::AudioChannelMask; using ::android::hardware::audio::common::V2_0::AudioFormat; using ::android::hardware::audio::V2_0::AudioDrain; using ::android::hardware::audio::V2_0::IStreamOutCallback; using ::android::hardware::audio::V2_0::MessageQueueFlagBits; using ::android::hardware::audio::V2_0::MmapBufferInfo; using ::android::hardware::audio::V2_0::MmapPosition; using ::android::hardware::audio::V2_0::ParameterValue; using ::android::hardware::audio::V2_0::Result; using ::android::hardware::audio::V2_0::ThreadPriority; using ::android::hardware::audio::V2_0::TimeSpec; using ::android::hardware::audio::V2_0::MmapBufferInfo; using ::android::hardware::audio::V2_0::MmapPosition; using ::android::hardware::MQDescriptorSync; using ::android::hardware::Return; using ::android::hardware::Void; namespace android { StreamHalHidl::StreamHalHidl(IStream *stream) : ConversionHelperHidl("Stream"), mStream(stream) { : ConversionHelperHidl("Stream"), mHalThreadPriority(static_cast<int>(ThreadPriority::NORMAL)), mStream(stream) { } StreamHalHidl::~StreamHalHidl() { Loading Loading @@ -176,6 +183,11 @@ status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) { return processReturn("getMmapPosition", ret, retval); } status_t StreamHalHidl::setHalThreadPriority(int priority) { mHalThreadPriority = priority; return OK; } namespace { /* Notes on callback ownership. Loading Loading @@ -229,14 +241,21 @@ struct StreamOutCallback : public IStreamOutCallback { } // namespace StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream) : StreamHalHidl(stream.get()), mStream(stream) { : StreamHalHidl(stream.get()), mStream(stream), mEfGroup(nullptr), mGetPresentationPositionNotSupported(false), mPPosFromWriteObtained(0) { } StreamOutHalHidl::~StreamOutHalHidl() { if (mCallback.unsafe_get() && mStream != 0) { if (mStream != 0) { if (mCallback.unsafe_get()) { processReturn("clearCallback", mStream->clearCallback()); } processReturn("close", mStream->close()); } mCallback.clear(); if (mEfGroup) { EventFlag::deleteEventFlag(&mEfGroup); } } status_t StreamOutHalHidl::getFrameSize(size_t *size) { Loading @@ -256,16 +275,89 @@ status_t StreamOutHalHidl::setVolume(float left, float right) { status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) { if (mStream == 0) return NO_INIT; hidl_vec<uint8_t> hidlData; hidlData.setToExternal(static_cast<uint8_t*>(const_cast<void*>(buffer)), bytes); *written = 0; if (bytes == 0 && !mDataMQ) { // Can't determine the size for the MQ buffer. Wait for a non-empty write request. ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes"); return OK; } status_t status; if (!mDataMQ && (status = prepareForWriting(bytes)) != OK) { return status; } const size_t availBytes = mDataMQ->availableToWrite(); if (bytes > availBytes) { bytes = availBytes; } if (!mDataMQ->write(static_cast<const uint8_t*>(buffer), bytes)) { ALOGW("data message queue write failed"); } mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)); // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422 uint32_t efState = 0; retry: status_t ret = mEfGroup->wait( static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState, NS_PER_SEC); if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) { WriteStatus writeStatus = { Result::NOT_INITIALIZED, 0, 0, { 0, 0 } }; mStatusMQ->read(&writeStatus); if (writeStatus.retval == Result::OK) { status = OK; *written = writeStatus.written; mPPosFromWriteFrames = writeStatus.frames; mPPosFromWriteTS.tv_sec = writeStatus.timeStamp.tvSec; mPPosFromWriteTS.tv_nsec = writeStatus.timeStamp.tvNSec; struct timespec timeNow; clock_gettime(CLOCK_MONOTONIC, &timeNow); mPPosFromWriteObtained = timeNow.tv_sec * 1000000 + timeNow.tv_nsec / 1000; } else { status = processReturn("write", writeStatus.retval); } return status; } if (ret == -EAGAIN) { // This normally retries no more than once. goto retry; } return ret; } status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) { std::unique_ptr<DataMQ> tempDataMQ; std::unique_ptr<StatusMQ> tempStatusMQ; Result retval; Return<void> ret = mStream->write( hidlData, [&](Result r, uint64_t w) { Return<void> ret = mStream->prepareForWriting( 1, bufferSize, ThreadPriority(mHalThreadPriority), [&](Result r, const MQDescriptorSync<uint8_t>& dataMQ, const MQDescriptorSync<WriteStatus>& statusMQ) { retval = r; *written = w; if (retval == Result::OK) { tempDataMQ.reset(new DataMQ(dataMQ)); tempStatusMQ.reset(new StatusMQ(statusMQ)); if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) { EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup); } } }); return processReturn("write", ret, retval); if (!ret.getStatus().isOk() || retval != Result::OK) { return processReturn("prepareForWriting", ret, retval); } if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid() || !mEfGroup) { ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing"); ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid"); ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing"); ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(), "Status message queue for writing is invalid"); ALOGE_IF(!mEfGroup, "Event flag creation for writing failed"); return NO_INIT; } mDataMQ = std::move(tempDataMQ); mStatusMQ = std::move(tempStatusMQ); return OK; } status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) { Loading Loading @@ -342,6 +434,18 @@ status_t StreamOutHalHidl::flush() { status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) { if (mStream == 0) return NO_INIT; if (mGetPresentationPositionNotSupported) return INVALID_OPERATION; struct timespec timeNow; clock_gettime(CLOCK_MONOTONIC, &timeNow); uint64_t timeStampNow = timeNow.tv_sec * 1000000 + timeNow.tv_nsec / 1000; if (timeStampNow - mPPosFromWriteObtained <= 1000) { // No more than 1 ms passed since the last write, use cached result to avoid binder calls. *frames = mPPosFromWriteFrames; timestamp->tv_sec = mPPosFromWriteTS.tv_sec; timestamp->tv_nsec = mPPosFromWriteTS.tv_nsec; return OK; } Result retval; Return<void> ret = mStream->getPresentationPosition( [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) { Loading @@ -352,6 +456,9 @@ status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct time timestamp->tv_nsec = hidlTimeStamp.tvNSec; } }); if (ret.getStatus().isOk() && retval == Result::NOT_SUPPORTED) { mGetPresentationPositionNotSupported = true; } return processReturn("getPresentationPosition", ret, retval); } Loading @@ -378,10 +485,16 @@ void StreamOutHalHidl::onError() { StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream) : StreamHalHidl(stream.get()), mStream(stream) { : StreamHalHidl(stream.get()), mStream(stream), mEfGroup(nullptr) { } StreamInHalHidl::~StreamInHalHidl() { if (mStream != 0) { processReturn("close", mStream->close()); } if (mEfGroup) { EventFlag::deleteEventFlag(&mEfGroup); } } status_t StreamInHalHidl::getFrameSize(size_t *size) { Loading @@ -396,17 +509,83 @@ status_t StreamInHalHidl::setGain(float gain) { status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) { if (mStream == 0) return NO_INIT; *read = 0; if (bytes == 0 && !mDataMQ) { // Can't determine the size for the MQ buffer. Wait for a non-empty read request. return OK; } status_t status; if (!mDataMQ) { if ((status = prepareForReading(bytes)) != OK) return status; // Trigger the first read. mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); } // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422 uint32_t efState = 0; retry: status_t ret = mEfGroup->wait( static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState, NS_PER_SEC); if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) { ReadStatus readStatus = { Result::NOT_INITIALIZED, 0 }; const size_t availToRead = mDataMQ->availableToRead(); if (bytes > availToRead) { bytes = availToRead; } mDataMQ->read(static_cast<uint8_t*>(buffer), bytes); mStatusMQ->read(&readStatus); mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); if (readStatus.retval == Result::OK) { ALOGW_IF(availToRead != readStatus.read, "HAL read report inconsistent: mq = %d, status = %d", (int32_t)availToRead, (int32_t)readStatus.read); *read = readStatus.read; } else { status = processReturn("read", readStatus.retval); } return status; } if (ret == -EAGAIN) { // This normally retries no more than once. goto retry; } return ret; } status_t StreamInHalHidl::prepareForReading(size_t bufferSize) { std::unique_ptr<DataMQ> tempDataMQ; std::unique_ptr<StatusMQ> tempStatusMQ; Result retval; Return<void> ret = mStream->read( bytes, [&](Result r, const hidl_vec<uint8_t>& hidlData) { Return<void> ret = mStream->prepareForReading( 1, bufferSize, ThreadPriority(mHalThreadPriority), [&](Result r, const MQDescriptorSync<uint8_t>& dataMQ, const MQDescriptorSync<ReadStatus>& statusMQ) { retval = r; *read = std::min(hidlData.size(), bytes); if (retval == Result::OK) { memcpy(buffer, &hidlData[0], *read); tempDataMQ.reset(new DataMQ(dataMQ)); tempStatusMQ.reset(new StatusMQ(statusMQ)); if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) { EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup); } } }); return processReturn("read", ret, retval); if (!ret.getStatus().isOk() || retval != Result::OK) { return processReturn("prepareForReading", ret, retval); } if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid() || !mEfGroup) { ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading"); ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid"); ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading"); ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(), "Status message queue for reading is invalid"); ALOGE_IF(!mEfGroup, "Event flag creation for reading failed"); return NO_INIT; } mDataMQ = std::move(tempDataMQ); mStatusMQ = std::move(tempStatusMQ); return OK; } status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) { Loading media/libaudiohal/StreamHalHidl.h +30 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include <android/hardware/audio/2.0/IStream.h> #include <android/hardware/audio/2.0/IStreamIn.h> #include <android/hardware/audio/2.0/IStreamOut.h> #include <fmq/EventFlag.h> #include <fmq/MessageQueue.h> #include <media/audiohal/StreamHalInterface.h> #include "ConversionHelperHidl.h" Loading @@ -27,7 +29,11 @@ using ::android::hardware::audio::V2_0::IStream; using ::android::hardware::audio::V2_0::IStreamIn; using ::android::hardware::audio::V2_0::IStreamOut; using ::android::hardware::EventFlag; using ::android::hardware::MessageQueue; using ::android::hardware::Return; using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus; using WriteStatus = ::android::hardware::audio::V2_0::IStreamOut::WriteStatus; namespace android { Loading Loading @@ -80,6 +86,10 @@ class StreamHalHidl : public virtual StreamHalInterface, public ConversionHelper // Get current read/write position in the mmap buffer virtual status_t getMmapPosition(struct audio_mmap_position *position); // Set the priority of the thread that interacts with the HAL // (must match the priority of the audioflinger's thread that calls 'read' / 'write') virtual status_t setHalThreadPriority(int priority); protected: // Subclasses can not be constructed directly by clients. explicit StreamHalHidl(IStream *stream); Loading @@ -87,6 +97,8 @@ class StreamHalHidl : public virtual StreamHalInterface, public ConversionHelper // The destructor automatically closes the stream. virtual ~StreamHalHidl(); int mHalThreadPriority; private: IStream *mStream; }; Loading Loading @@ -143,14 +155,25 @@ class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl { private: friend class DeviceHalHidl; typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ; typedef MessageQueue<WriteStatus, hardware::kSynchronizedReadWrite> StatusMQ; wp<StreamOutHalInterfaceCallback> mCallback; sp<IStreamOut> mStream; std::unique_ptr<DataMQ> mDataMQ; std::unique_ptr<StatusMQ> mStatusMQ; EventFlag* mEfGroup; bool mGetPresentationPositionNotSupported; uint64_t mPPosFromWriteObtained; uint64_t mPPosFromWriteFrames; struct timespec mPPosFromWriteTS; // Can not be constructed directly by clients. StreamOutHalHidl(const sp<IStreamOut>& stream); virtual ~StreamOutHalHidl(); status_t prepareForWriting(size_t bufferSize); }; class StreamInHalHidl : public StreamInHalInterface, public StreamHalHidl { Loading @@ -173,13 +196,20 @@ class StreamInHalHidl : public StreamInHalInterface, public StreamHalHidl { private: friend class DeviceHalHidl; typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ; typedef MessageQueue<ReadStatus, hardware::kSynchronizedReadWrite> StatusMQ; sp<IStreamIn> mStream; std::unique_ptr<DataMQ> mDataMQ; std::unique_ptr<StatusMQ> mStatusMQ; EventFlag* mEfGroup; // Can not be constructed directly by clients. StreamInHalHidl(const sp<IStreamIn>& stream); virtual ~StreamInHalHidl(); status_t prepareForReading(size_t bufferSize); }; } // namespace android Loading media/libaudiohal/StreamHalLocal.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -96,6 +96,12 @@ status_t StreamHalLocal::dump(int fd) { return mStream->dump(mStream, fd); } status_t StreamHalLocal::setHalThreadPriority(int) { // Don't need to do anything as local hal is executed by audioflinger directly // on the same thread. return OK; } StreamOutHalLocal::StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device) : StreamHalLocal(&stream->common, device), mStream(stream) { } Loading Loading
include/media/audiohal/StreamHalInterface.h +4 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,10 @@ class StreamHalInterface : public virtual RefBase // Get current read/write position in the mmap buffer virtual status_t getMmapPosition(struct audio_mmap_position *position) = 0; // Set the priority of the thread that interacts with the HAL // (must match the priority of the audioflinger's thread that calls 'read' / 'write') virtual status_t setHalThreadPriority(int priority) = 0; protected: // Subclasses can not be constructed directly by clients. StreamHalInterface() {} Loading
media/libaudiohal/Android.mk +4 −2 Original line number Diff line number Diff line Loading @@ -3,11 +3,13 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SHARED_LIBRARIES := \ libbase \ libcutils \ libeffects \ libfmq \ libhardware \ liblog \ libutils \ libeffects libutils ifeq ($(ENABLE_TREBLE), true) Loading
media/libaudiohal/StreamHalHidl.cpp +199 −20 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include <time.h> #define LOG_TAG "StreamHalHidl" //#define LOG_NDEBUG 0 Loading @@ -28,18 +30,23 @@ using ::android::hardware::audio::common::V2_0::AudioChannelMask; using ::android::hardware::audio::common::V2_0::AudioFormat; using ::android::hardware::audio::V2_0::AudioDrain; using ::android::hardware::audio::V2_0::IStreamOutCallback; using ::android::hardware::audio::V2_0::MessageQueueFlagBits; using ::android::hardware::audio::V2_0::MmapBufferInfo; using ::android::hardware::audio::V2_0::MmapPosition; using ::android::hardware::audio::V2_0::ParameterValue; using ::android::hardware::audio::V2_0::Result; using ::android::hardware::audio::V2_0::ThreadPriority; using ::android::hardware::audio::V2_0::TimeSpec; using ::android::hardware::audio::V2_0::MmapBufferInfo; using ::android::hardware::audio::V2_0::MmapPosition; using ::android::hardware::MQDescriptorSync; using ::android::hardware::Return; using ::android::hardware::Void; namespace android { StreamHalHidl::StreamHalHidl(IStream *stream) : ConversionHelperHidl("Stream"), mStream(stream) { : ConversionHelperHidl("Stream"), mHalThreadPriority(static_cast<int>(ThreadPriority::NORMAL)), mStream(stream) { } StreamHalHidl::~StreamHalHidl() { Loading Loading @@ -176,6 +183,11 @@ status_t StreamHalHidl::getMmapPosition(struct audio_mmap_position *position) { return processReturn("getMmapPosition", ret, retval); } status_t StreamHalHidl::setHalThreadPriority(int priority) { mHalThreadPriority = priority; return OK; } namespace { /* Notes on callback ownership. Loading Loading @@ -229,14 +241,21 @@ struct StreamOutCallback : public IStreamOutCallback { } // namespace StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream) : StreamHalHidl(stream.get()), mStream(stream) { : StreamHalHidl(stream.get()), mStream(stream), mEfGroup(nullptr), mGetPresentationPositionNotSupported(false), mPPosFromWriteObtained(0) { } StreamOutHalHidl::~StreamOutHalHidl() { if (mCallback.unsafe_get() && mStream != 0) { if (mStream != 0) { if (mCallback.unsafe_get()) { processReturn("clearCallback", mStream->clearCallback()); } processReturn("close", mStream->close()); } mCallback.clear(); if (mEfGroup) { EventFlag::deleteEventFlag(&mEfGroup); } } status_t StreamOutHalHidl::getFrameSize(size_t *size) { Loading @@ -256,16 +275,89 @@ status_t StreamOutHalHidl::setVolume(float left, float right) { status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) { if (mStream == 0) return NO_INIT; hidl_vec<uint8_t> hidlData; hidlData.setToExternal(static_cast<uint8_t*>(const_cast<void*>(buffer)), bytes); *written = 0; if (bytes == 0 && !mDataMQ) { // Can't determine the size for the MQ buffer. Wait for a non-empty write request. ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes"); return OK; } status_t status; if (!mDataMQ && (status = prepareForWriting(bytes)) != OK) { return status; } const size_t availBytes = mDataMQ->availableToWrite(); if (bytes > availBytes) { bytes = availBytes; } if (!mDataMQ->write(static_cast<const uint8_t*>(buffer), bytes)) { ALOGW("data message queue write failed"); } mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)); // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422 uint32_t efState = 0; retry: status_t ret = mEfGroup->wait( static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState, NS_PER_SEC); if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) { WriteStatus writeStatus = { Result::NOT_INITIALIZED, 0, 0, { 0, 0 } }; mStatusMQ->read(&writeStatus); if (writeStatus.retval == Result::OK) { status = OK; *written = writeStatus.written; mPPosFromWriteFrames = writeStatus.frames; mPPosFromWriteTS.tv_sec = writeStatus.timeStamp.tvSec; mPPosFromWriteTS.tv_nsec = writeStatus.timeStamp.tvNSec; struct timespec timeNow; clock_gettime(CLOCK_MONOTONIC, &timeNow); mPPosFromWriteObtained = timeNow.tv_sec * 1000000 + timeNow.tv_nsec / 1000; } else { status = processReturn("write", writeStatus.retval); } return status; } if (ret == -EAGAIN) { // This normally retries no more than once. goto retry; } return ret; } status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) { std::unique_ptr<DataMQ> tempDataMQ; std::unique_ptr<StatusMQ> tempStatusMQ; Result retval; Return<void> ret = mStream->write( hidlData, [&](Result r, uint64_t w) { Return<void> ret = mStream->prepareForWriting( 1, bufferSize, ThreadPriority(mHalThreadPriority), [&](Result r, const MQDescriptorSync<uint8_t>& dataMQ, const MQDescriptorSync<WriteStatus>& statusMQ) { retval = r; *written = w; if (retval == Result::OK) { tempDataMQ.reset(new DataMQ(dataMQ)); tempStatusMQ.reset(new StatusMQ(statusMQ)); if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) { EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup); } } }); return processReturn("write", ret, retval); if (!ret.getStatus().isOk() || retval != Result::OK) { return processReturn("prepareForWriting", ret, retval); } if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid() || !mEfGroup) { ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing"); ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid"); ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing"); ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(), "Status message queue for writing is invalid"); ALOGE_IF(!mEfGroup, "Event flag creation for writing failed"); return NO_INIT; } mDataMQ = std::move(tempDataMQ); mStatusMQ = std::move(tempStatusMQ); return OK; } status_t StreamOutHalHidl::getRenderPosition(uint32_t *dspFrames) { Loading Loading @@ -342,6 +434,18 @@ status_t StreamOutHalHidl::flush() { status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) { if (mStream == 0) return NO_INIT; if (mGetPresentationPositionNotSupported) return INVALID_OPERATION; struct timespec timeNow; clock_gettime(CLOCK_MONOTONIC, &timeNow); uint64_t timeStampNow = timeNow.tv_sec * 1000000 + timeNow.tv_nsec / 1000; if (timeStampNow - mPPosFromWriteObtained <= 1000) { // No more than 1 ms passed since the last write, use cached result to avoid binder calls. *frames = mPPosFromWriteFrames; timestamp->tv_sec = mPPosFromWriteTS.tv_sec; timestamp->tv_nsec = mPPosFromWriteTS.tv_nsec; return OK; } Result retval; Return<void> ret = mStream->getPresentationPosition( [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) { Loading @@ -352,6 +456,9 @@ status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct time timestamp->tv_nsec = hidlTimeStamp.tvNSec; } }); if (ret.getStatus().isOk() && retval == Result::NOT_SUPPORTED) { mGetPresentationPositionNotSupported = true; } return processReturn("getPresentationPosition", ret, retval); } Loading @@ -378,10 +485,16 @@ void StreamOutHalHidl::onError() { StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream) : StreamHalHidl(stream.get()), mStream(stream) { : StreamHalHidl(stream.get()), mStream(stream), mEfGroup(nullptr) { } StreamInHalHidl::~StreamInHalHidl() { if (mStream != 0) { processReturn("close", mStream->close()); } if (mEfGroup) { EventFlag::deleteEventFlag(&mEfGroup); } } status_t StreamInHalHidl::getFrameSize(size_t *size) { Loading @@ -396,17 +509,83 @@ status_t StreamInHalHidl::setGain(float gain) { status_t StreamInHalHidl::read(void *buffer, size_t bytes, size_t *read) { if (mStream == 0) return NO_INIT; *read = 0; if (bytes == 0 && !mDataMQ) { // Can't determine the size for the MQ buffer. Wait for a non-empty read request. return OK; } status_t status; if (!mDataMQ) { if ((status = prepareForReading(bytes)) != OK) return status; // Trigger the first read. mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); } // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422 uint32_t efState = 0; retry: status_t ret = mEfGroup->wait( static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState, NS_PER_SEC); if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) { ReadStatus readStatus = { Result::NOT_INITIALIZED, 0 }; const size_t availToRead = mDataMQ->availableToRead(); if (bytes > availToRead) { bytes = availToRead; } mDataMQ->read(static_cast<uint8_t*>(buffer), bytes); mStatusMQ->read(&readStatus); mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); if (readStatus.retval == Result::OK) { ALOGW_IF(availToRead != readStatus.read, "HAL read report inconsistent: mq = %d, status = %d", (int32_t)availToRead, (int32_t)readStatus.read); *read = readStatus.read; } else { status = processReturn("read", readStatus.retval); } return status; } if (ret == -EAGAIN) { // This normally retries no more than once. goto retry; } return ret; } status_t StreamInHalHidl::prepareForReading(size_t bufferSize) { std::unique_ptr<DataMQ> tempDataMQ; std::unique_ptr<StatusMQ> tempStatusMQ; Result retval; Return<void> ret = mStream->read( bytes, [&](Result r, const hidl_vec<uint8_t>& hidlData) { Return<void> ret = mStream->prepareForReading( 1, bufferSize, ThreadPriority(mHalThreadPriority), [&](Result r, const MQDescriptorSync<uint8_t>& dataMQ, const MQDescriptorSync<ReadStatus>& statusMQ) { retval = r; *read = std::min(hidlData.size(), bytes); if (retval == Result::OK) { memcpy(buffer, &hidlData[0], *read); tempDataMQ.reset(new DataMQ(dataMQ)); tempStatusMQ.reset(new StatusMQ(statusMQ)); if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) { EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup); } } }); return processReturn("read", ret, retval); if (!ret.getStatus().isOk() || retval != Result::OK) { return processReturn("prepareForReading", ret, retval); } if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid() || !mEfGroup) { ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading"); ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid"); ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading"); ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(), "Status message queue for reading is invalid"); ALOGE_IF(!mEfGroup, "Event flag creation for reading failed"); return NO_INIT; } mDataMQ = std::move(tempDataMQ); mStatusMQ = std::move(tempStatusMQ); return OK; } status_t StreamInHalHidl::getInputFramesLost(uint32_t *framesLost) { Loading
media/libaudiohal/StreamHalHidl.h +30 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include <android/hardware/audio/2.0/IStream.h> #include <android/hardware/audio/2.0/IStreamIn.h> #include <android/hardware/audio/2.0/IStreamOut.h> #include <fmq/EventFlag.h> #include <fmq/MessageQueue.h> #include <media/audiohal/StreamHalInterface.h> #include "ConversionHelperHidl.h" Loading @@ -27,7 +29,11 @@ using ::android::hardware::audio::V2_0::IStream; using ::android::hardware::audio::V2_0::IStreamIn; using ::android::hardware::audio::V2_0::IStreamOut; using ::android::hardware::EventFlag; using ::android::hardware::MessageQueue; using ::android::hardware::Return; using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus; using WriteStatus = ::android::hardware::audio::V2_0::IStreamOut::WriteStatus; namespace android { Loading Loading @@ -80,6 +86,10 @@ class StreamHalHidl : public virtual StreamHalInterface, public ConversionHelper // Get current read/write position in the mmap buffer virtual status_t getMmapPosition(struct audio_mmap_position *position); // Set the priority of the thread that interacts with the HAL // (must match the priority of the audioflinger's thread that calls 'read' / 'write') virtual status_t setHalThreadPriority(int priority); protected: // Subclasses can not be constructed directly by clients. explicit StreamHalHidl(IStream *stream); Loading @@ -87,6 +97,8 @@ class StreamHalHidl : public virtual StreamHalInterface, public ConversionHelper // The destructor automatically closes the stream. virtual ~StreamHalHidl(); int mHalThreadPriority; private: IStream *mStream; }; Loading Loading @@ -143,14 +155,25 @@ class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl { private: friend class DeviceHalHidl; typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ; typedef MessageQueue<WriteStatus, hardware::kSynchronizedReadWrite> StatusMQ; wp<StreamOutHalInterfaceCallback> mCallback; sp<IStreamOut> mStream; std::unique_ptr<DataMQ> mDataMQ; std::unique_ptr<StatusMQ> mStatusMQ; EventFlag* mEfGroup; bool mGetPresentationPositionNotSupported; uint64_t mPPosFromWriteObtained; uint64_t mPPosFromWriteFrames; struct timespec mPPosFromWriteTS; // Can not be constructed directly by clients. StreamOutHalHidl(const sp<IStreamOut>& stream); virtual ~StreamOutHalHidl(); status_t prepareForWriting(size_t bufferSize); }; class StreamInHalHidl : public StreamInHalInterface, public StreamHalHidl { Loading @@ -173,13 +196,20 @@ class StreamInHalHidl : public StreamInHalInterface, public StreamHalHidl { private: friend class DeviceHalHidl; typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ; typedef MessageQueue<ReadStatus, hardware::kSynchronizedReadWrite> StatusMQ; sp<IStreamIn> mStream; std::unique_ptr<DataMQ> mDataMQ; std::unique_ptr<StatusMQ> mStatusMQ; EventFlag* mEfGroup; // Can not be constructed directly by clients. StreamInHalHidl(const sp<IStreamIn>& stream); virtual ~StreamInHalHidl(); status_t prepareForReading(size_t bufferSize); }; } // namespace android Loading
media/libaudiohal/StreamHalLocal.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -96,6 +96,12 @@ status_t StreamHalLocal::dump(int fd) { return mStream->dump(mStream, fd); } status_t StreamHalLocal::setHalThreadPriority(int) { // Don't need to do anything as local hal is executed by audioflinger directly // on the same thread. return OK; } StreamOutHalLocal::StreamOutHalLocal(audio_stream_out_t *stream, sp<DeviceHalLocal> device) : StreamHalLocal(&stream->common, device), mStream(stream) { } Loading