diff --git a/audio/2.0/IStream.hal b/audio/2.0/IStream.hal index dc43346ed2..5c88a6938c 100644 --- a/audio/2.0/IStream.hal +++ b/audio/2.0/IStream.hal @@ -227,4 +227,56 @@ interface IStream { * @param fd dump file descriptor. */ debugDump(handle fd); + + /* + * Called by the framework to start a stream operating in mmap mode. + * createMmapBuffer() must be called before calling start(). + * Function only implemented by streams operating in mmap mode. + * + * @return retval OK in case the success. + * NOT_SUPPORTED on non mmap mode streams + * INVALID_STATE if called out of sequence + */ + start() generates (Result retval); + + /** + * Called by the framework to stop a stream operating in mmap mode. + * Function only implemented by streams operating in mmap mode. + * + * @return retval OK in case the succes. + * NOT_SUPPORTED on non mmap mode streams + * INVALID_STATE if called out of sequence + */ + stop() generates (Result retval) ; + + /* + * Called by the framework to retrieve information on the mmap buffer used for audio + * samples transfer. + * Function only implemented by streams operating in mmap mode. + * + * @param minSizeFrames minimum buffer size requested. The actual buffer + * size returned in struct MmapBufferInfo can be larger. + * @return retval OK in case the success. + * NOT_SUPPORTED on non mmap mode streams + * NOT_INITIALIZED in case of memory allocation error + * INVALID_ARGUMENTS if the requested buffer size is too large + * INVALID_STATE if called out of sequence + * @return info a MmapBufferInfo struct containing information on the MMMAP buffer created. + */ + createMmapBuffer(int32_t minSizeFrames) + generates (Result retval, MmapBufferInfo info); + + /* + * Called by the framework to read current read/write position in the mmap buffer + * with associated time stamp. + * Function only implemented by streams operating in mmap mode. + * + * @return retval OK in case the success. + * NOT_SUPPORTED on non mmap mode streams + * INVALID_STATE if called out of sequence + * @return position a MmapPosition struct containing current HW read/write position in frames + * with associated time stamp. + */ + getMmapPosition() + generates (Result retval, MmapPosition position); }; diff --git a/audio/2.0/default/Android.mk b/audio/2.0/default/Android.mk index 2b1aa4f20b..c3cfd69999 100644 --- a/audio/2.0/default/Android.mk +++ b/audio/2.0/default/Android.mk @@ -33,6 +33,7 @@ LOCAL_SHARED_LIBRARIES := \ libhidlbase \ libhidltransport \ libhwbinder \ + libcutils \ libutils \ libhardware \ liblog \ diff --git a/audio/2.0/default/Stream.cpp b/audio/2.0/default/Stream.cpp index 40f67f0723..f214eed976 100644 --- a/audio/2.0/default/Stream.cpp +++ b/audio/2.0/default/Stream.cpp @@ -43,9 +43,10 @@ Stream::~Stream() { mStream = nullptr; } +// static Result Stream::analyzeStatus(const char* funcName, int status, int ignoreError) { if (status != 0 && status != -ignoreError) { - ALOGW("Stream %p %s: %s", mStream, funcName, strerror(-status)); + ALOGW("Error from HAL stream in function %s: %s", funcName, strerror(-status)); } switch (status) { case 0: return Result::OK; @@ -229,6 +230,29 @@ Return Stream::debugDump(const hidl_handle& fd) { return Void(); } +Return Stream::start() { + return Result::NOT_SUPPORTED; +} + +Return Stream::stop() { + return Result::NOT_SUPPORTED; +} + +Return Stream::createMmapBuffer(int32_t minSizeFrames __unused, + createMmapBuffer_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + MmapBufferInfo info; + _hidl_cb(retval, info); + return Void(); +} + +Return Stream::getMmapPosition(getMmapPosition_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + MmapPosition position; + _hidl_cb(retval, position); + return Void(); +} + } // namespace implementation } // namespace V2_0 } // namespace audio diff --git a/audio/2.0/default/Stream.h b/audio/2.0/default/Stream.h index 0ebd723efb..819bbf7c9a 100644 --- a/audio/2.0/default/Stream.h +++ b/audio/2.0/default/Stream.h @@ -18,6 +18,7 @@ #define ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H #include +#include #include #include @@ -71,9 +72,13 @@ struct Stream : public IStream, public ParametersUtil { const hidl_vec& keys, getParameters_cb _hidl_cb) override; Return setParameters(const hidl_vec& parameters) override; Return debugDump(const hidl_handle& fd) override; + Return start() override; + Return stop() override; + Return createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; + Return getMmapPosition(getMmapPosition_cb _hidl_cb) override; // Utility methods for extending interfaces. - Result analyzeStatus(const char* funcName, int status, int ignoreError = OK); + static Result analyzeStatus(const char* funcName, int status, int ignoreError = OK); private: audio_stream_t *mStream; @@ -85,6 +90,80 @@ struct Stream : public IStream, public ParametersUtil { int halSetParameters(const char* keysAndValues) override; }; + +template +struct StreamMmap : public RefBase { + explicit StreamMmap(T* stream) : mStream(stream) {} + + Return start(); + Return stop(); + Return createMmapBuffer( + int32_t minSizeFrames, size_t frameSize, IStream::createMmapBuffer_cb _hidl_cb); + Return getMmapPosition(IStream::getMmapPosition_cb _hidl_cb); + + private: + StreamMmap() {} + + T *mStream; +}; + +template +Return StreamMmap::start() { + if (mStream->start == NULL) return Result::NOT_SUPPORTED; + int result = mStream->start(mStream); + return Stream::analyzeStatus("start", result); +} + +template +Return StreamMmap::stop() { + if (mStream->stop == NULL) return Result::NOT_SUPPORTED; + int result = mStream->stop(mStream); + return Stream::analyzeStatus("stop", result); +} + +template +Return StreamMmap::createMmapBuffer(int32_t minSizeFrames, size_t frameSize, + IStream::createMmapBuffer_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + MmapBufferInfo info; + + if (mStream->create_mmap_buffer != NULL) { + struct audio_mmap_buffer_info halInfo; + retval = Stream::analyzeStatus( + "create_mmap_buffer", + mStream->create_mmap_buffer(mStream, minSizeFrames, &halInfo)); + if (retval == Result::OK) { + native_handle_t* hidlHandle = native_handle_create(1, 0); + hidlHandle->data[0] = halInfo.shared_memory_fd; + info.sharedMemory = hidl_memory("audio_buffer", hidlHandle, + frameSize *halInfo.buffer_size_frames); + info.bufferSizeFrames = halInfo.buffer_size_frames; + info.burstSizeFrames = halInfo.burst_size_frames; + } + } + _hidl_cb(retval, info); + return Void(); +} + +template +Return StreamMmap::getMmapPosition(IStream::getMmapPosition_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + MmapPosition position; + + if (mStream->get_mmap_position != NULL) { + struct audio_mmap_position halPosition; + retval = Stream::analyzeStatus( + "get_mmap_position", + mStream->get_mmap_position(mStream, &halPosition)); + if (retval == Result::OK) { + position.timeNanoseconds = halPosition.time_nanoseconds; + position.positionFrames = halPosition.position_frames; + } + } + _hidl_cb(retval, position); + return Void(); +} + } // namespace implementation } // namespace V2_0 } // namespace audio diff --git a/audio/2.0/default/StreamIn.cpp b/audio/2.0/default/StreamIn.cpp index 1bc9dfb4ec..1441e74cac 100644 --- a/audio/2.0/default/StreamIn.cpp +++ b/audio/2.0/default/StreamIn.cpp @@ -28,7 +28,9 @@ namespace V2_0 { namespace implementation { StreamIn::StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream) - : mDevice(device), mStream(stream), mStreamCommon(new Stream(&stream->common)) { + : mDevice(device), mStream(stream), + mStreamCommon(new Stream(&stream->common)), + mStreamMmap(new StreamMmap(stream)) { } StreamIn::~StreamIn() { @@ -130,6 +132,22 @@ Return StreamIn::debugDump(const hidl_handle& fd) { return mStreamCommon->debugDump(fd); } +Return StreamIn::start() { + return mStreamMmap->start(); +} + +Return StreamIn::stop() { + return mStreamMmap->stop(); +} + +Return StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) { + return mStreamMmap->createMmapBuffer( + minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb); +} + +Return StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) { + return mStreamMmap->getMmapPosition(_hidl_cb); +} // Methods from ::android::hardware::audio::V2_0::IStreamIn follow. Return StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) { @@ -144,7 +162,7 @@ Return StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) { } Return StreamIn::setGain(float gain) { - return mStreamCommon->analyzeStatus("set_gain", mStream->set_gain(mStream, gain)); + return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain)); } Return StreamIn::read(uint64_t size, read_cb _hidl_cb) { @@ -157,7 +175,7 @@ Return StreamIn::read(uint64_t size, read_cb _hidl_cb) { data.resize(readResult); } else if (readResult < 0) { data.resize(0); - retval = mStreamCommon->analyzeStatus("read", readResult); + retval = Stream::analyzeStatus("read", readResult); } _hidl_cb(retval, data); return Void(); @@ -172,7 +190,7 @@ Return StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) { uint64_t frames = 0, time = 0; if (mStream->get_capture_position != NULL) { int64_t halFrames, halTime; - retval = mStreamCommon->analyzeStatus( + retval = Stream::analyzeStatus( "get_capture_position", mStream->get_capture_position(mStream, &halFrames, &halTime)); if (retval == Result::OK) { diff --git a/audio/2.0/default/StreamIn.h b/audio/2.0/default/StreamIn.h index f7c17b7ab2..65e94bbf4c 100644 --- a/audio/2.0/default/StreamIn.h +++ b/audio/2.0/default/StreamIn.h @@ -80,11 +80,17 @@ struct StreamIn : public IStreamIn { Return read(uint64_t size, read_cb _hidl_cb) override; Return getInputFramesLost() override; Return getCapturePosition(getCapturePosition_cb _hidl_cb) override; + Return start() override; + Return stop() override; + Return createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; + Return getMmapPosition(getMmapPosition_cb _hidl_cb) override; private: audio_hw_device_t *mDevice; audio_stream_in_t *mStream; sp mStreamCommon; + sp> mStreamMmap; + virtual ~StreamIn(); }; diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp index 805734b76f..3d20d11dfb 100644 --- a/audio/2.0/default/StreamOut.cpp +++ b/audio/2.0/default/StreamOut.cpp @@ -29,7 +29,9 @@ namespace V2_0 { namespace implementation { StreamOut::StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream) - : mDevice(device), mStream(stream), mStreamCommon(new Stream(&stream->common)) { + : mDevice(device), mStream(stream), + mStreamCommon(new Stream(&stream->common)), + mStreamMmap(new StreamMmap(stream)) { } StreamOut::~StreamOut() { @@ -133,7 +135,6 @@ Return StreamOut::debugDump(const hidl_handle& fd) { return mStreamCommon->debugDump(fd); } - // Methods from ::android::hardware::audio::V2_0::IStreamOut follow. Return StreamOut::getLatency() { return mStream->get_latency(mStream); @@ -142,7 +143,7 @@ Return StreamOut::getLatency() { Return StreamOut::setVolume(float left, float right) { Result retval(Result::NOT_SUPPORTED); if (mStream->set_volume != NULL) { - retval = mStreamCommon->analyzeStatus( + retval = Stream::analyzeStatus( "set_volume", mStream->set_volume(mStream, left, right)); } return retval; @@ -156,7 +157,7 @@ Return StreamOut::write(const hidl_vec& data, write_cb _hidl_cb) if (writeResult >= 0) { written = writeResult; } else { - retval = mStreamCommon->analyzeStatus("write", writeResult); + retval = Stream::analyzeStatus("write", writeResult); written = 0; } _hidl_cb(retval, written); @@ -165,7 +166,7 @@ Return StreamOut::write(const hidl_vec& data, write_cb _hidl_cb) Return StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) { uint32_t halDspFrames; - Result retval = mStreamCommon->analyzeStatus( + Result retval = Stream::analyzeStatus( "get_render_position", mStream->get_render_position(mStream, &halDspFrames)); _hidl_cb(retval, halDspFrames); return Void(); @@ -175,7 +176,7 @@ Return StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) Result retval(Result::NOT_SUPPORTED); int64_t timestampUs = 0; if (mStream->get_next_write_timestamp != NULL) { - retval = mStreamCommon->analyzeStatus( + retval = Stream::analyzeStatus( "get_next_write_timestamp", mStream->get_next_write_timestamp(mStream, ×tampUs)); } @@ -189,7 +190,7 @@ Return StreamOut::setCallback(const sp& callback) { if (result == 0) { mCallback = callback; } - return mStreamCommon->analyzeStatus("set_callback", result); + return Stream::analyzeStatus("set_callback", result); } Return StreamOut::clearCallback() { @@ -228,13 +229,13 @@ Return StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_c Return StreamOut::pause() { return mStream->pause != NULL ? - mStreamCommon->analyzeStatus("pause", mStream->pause(mStream)) : + Stream::analyzeStatus("pause", mStream->pause(mStream)) : Result::NOT_SUPPORTED; } Return StreamOut::resume() { return mStream->resume != NULL ? - mStreamCommon->analyzeStatus("resume", mStream->resume(mStream)) : + Stream::analyzeStatus("resume", mStream->resume(mStream)) : Result::NOT_SUPPORTED; } @@ -244,14 +245,14 @@ Return StreamOut::supportsDrain() { Return StreamOut::drain(AudioDrain type) { return mStream->drain != NULL ? - mStreamCommon->analyzeStatus( + Stream::analyzeStatus( "drain", mStream->drain(mStream, static_cast(type))) : Result::NOT_SUPPORTED; } Return StreamOut::flush() { return mStream->flush != NULL ? - mStreamCommon->analyzeStatus("flush", mStream->flush(mStream)) : + Stream::analyzeStatus("flush", mStream->flush(mStream)) : Result::NOT_SUPPORTED; } @@ -261,7 +262,7 @@ Return StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl TimeSpec timeStamp = { 0, 0 }; if (mStream->get_presentation_position != NULL) { struct timespec halTimeStamp; - retval = mStreamCommon->analyzeStatus( + retval = Stream::analyzeStatus( "get_presentation_position", mStream->get_presentation_position(mStream, &frames, &halTimeStamp), // Don't logspam on EINVAL--it's normal for get_presentation_position @@ -276,6 +277,23 @@ Return StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl return Void(); } +Return StreamOut::start() { + return mStreamMmap->start(); +} + +Return StreamOut::stop() { + return mStreamMmap->stop(); +} + +Return StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) { + return mStreamMmap->createMmapBuffer( + minSizeFrames, audio_stream_out_frame_size(mStream), _hidl_cb); +} + +Return StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) { + return mStreamMmap->getMmapPosition(_hidl_cb); +} + } // namespace implementation } // namespace V2_0 } // namespace audio diff --git a/audio/2.0/default/StreamOut.h b/audio/2.0/default/StreamOut.h index dc9a60499a..9b7f9f834b 100644 --- a/audio/2.0/default/StreamOut.h +++ b/audio/2.0/default/StreamOut.h @@ -91,11 +91,16 @@ struct StreamOut : public IStreamOut { Return drain(AudioDrain type) override; Return flush() override; Return getPresentationPosition(getPresentationPosition_cb _hidl_cb) override; + Return start() override; + Return stop() override; + Return createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; + Return getMmapPosition(getMmapPosition_cb _hidl_cb) override; private: audio_hw_device_t *mDevice; audio_stream_out_t *mStream; sp mStreamCommon; + sp> mStreamMmap; sp mCallback; virtual ~StreamOut(); diff --git a/audio/2.0/types.hal b/audio/2.0/types.hal index 7002f38640..37c39e4df0 100644 --- a/audio/2.0/types.hal +++ b/audio/2.0/types.hal @@ -70,3 +70,22 @@ struct DeviceAddress { string busAddress; // used for BUS string rSubmixAddress; // used for REMOTE_SUBMIX }; + +/* + * Mmap buffer descriptor returned by IStream.createMmapBuffer(). + * Used by streams opened in mmap mode. + */ +struct MmapBufferInfo { + memory sharedMemory; // mmap memory buffer + int32_t bufferSizeFrames; // total buffer size in frames + int32_t burstSizeFrames; // transfer size granularity in frames +}; + +/* + * Mmap buffer read/write position returned by IStream.getMmapPosition(). + * Used by streams opened in mmap mode. + */ +struct MmapPosition { + int64_t timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC + int32_t positionFrames; // increasing 32 bit frame count reset when IStream.stop() is called +};