| /* |
| * Copyright (C) 2023 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include <atomic> |
| #include <memory> |
| #include <mutex> |
| #include <string_view> |
| |
| #include <aidl/android/hardware/audio/common/AudioOffloadMetadata.h> |
| #include <aidl/android/hardware/audio/core/BpStreamCommon.h> |
| #include <aidl/android/hardware/audio/core/BpStreamIn.h> |
| #include <aidl/android/hardware/audio/core/BpStreamOut.h> |
| #include <aidl/android/hardware/audio/core/MmapBufferDescriptor.h> |
| #include <aidl/android/media/audio/IHalAdapterVendorExtension.h> |
| #include <fmq/AidlMessageQueue.h> |
| #include <media/audiohal/EffectHalInterface.h> |
| #include <media/audiohal/StreamHalInterface.h> |
| #include <media/AidlConversionUtil.h> |
| #include <media/AudioParameter.h> |
| |
| #include "ConversionHelperAidl.h" |
| #include "StreamPowerLog.h" |
| |
| using ::aidl::android::hardware::audio::common::AudioOffloadMetadata; |
| using ::aidl::android::hardware::audio::core::MmapBufferDescriptor; |
| |
| namespace android { |
| |
| class StreamContextAidl { |
| public: |
| typedef AidlMessageQueue<::aidl::android::hardware::audio::core::StreamDescriptor::Command, |
| ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> CommandMQ; |
| typedef AidlMessageQueue<::aidl::android::hardware::audio::core::StreamDescriptor::Reply, |
| ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> ReplyMQ; |
| typedef AidlMessageQueue<int8_t, |
| ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> DataMQ; |
| |
| StreamContextAidl( |
| ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor, |
| bool isAsynchronous) |
| : mFrameSizeBytes(descriptor.frameSizeBytes), |
| mCommandMQ(new CommandMQ(descriptor.command)), |
| mReplyMQ(new ReplyMQ(descriptor.reply)), |
| mBufferSizeFrames(descriptor.bufferSizeFrames), |
| mDataMQ(maybeCreateDataMQ(descriptor)), |
| mIsAsynchronous(isAsynchronous), |
| mIsMmapped(isMmapped(descriptor)), |
| mMmapBufferDescriptor(maybeGetMmapBuffer(descriptor)) {} |
| StreamContextAidl(StreamContextAidl&& other) : |
| mFrameSizeBytes(other.mFrameSizeBytes), |
| mCommandMQ(std::move(other.mCommandMQ)), |
| mReplyMQ(std::move(other.mReplyMQ)), |
| mBufferSizeFrames(other.mBufferSizeFrames), |
| mDataMQ(std::move(other.mDataMQ)), |
| mIsAsynchronous(other.mIsAsynchronous), |
| mIsMmapped(other.mIsMmapped), |
| mMmapBufferDescriptor(std::move(other.mMmapBufferDescriptor)) {} |
| StreamContextAidl& operator=(StreamContextAidl&& other) { |
| mFrameSizeBytes = other.mFrameSizeBytes; |
| mCommandMQ = std::move(other.mCommandMQ); |
| mReplyMQ = std::move(other.mReplyMQ); |
| mBufferSizeFrames = other.mBufferSizeFrames; |
| mDataMQ = std::move(other.mDataMQ); |
| mIsAsynchronous = other.mIsAsynchronous; |
| mIsMmapped = other.mIsMmapped; |
| mMmapBufferDescriptor = std::move(other.mMmapBufferDescriptor); |
| return *this; |
| } |
| bool isValid() const { |
| return mFrameSizeBytes != 0 && |
| mCommandMQ != nullptr && mCommandMQ->isValid() && |
| mReplyMQ != nullptr && mReplyMQ->isValid() && |
| (mDataMQ == nullptr || ( |
| mDataMQ->isValid() && |
| mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() >= |
| mFrameSizeBytes * mBufferSizeFrames)) && |
| (!mIsMmapped || mMmapBufferDescriptor.sharedMemory.fd.get() >= 0); |
| } |
| size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; } |
| size_t getBufferSizeFrames() const { return mBufferSizeFrames; } |
| CommandMQ* getCommandMQ() const { return mCommandMQ.get(); } |
| DataMQ* getDataMQ() const { return mDataMQ.get(); } |
| size_t getFrameSizeBytes() const { return mFrameSizeBytes; } |
| ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); } |
| bool isAsynchronous() const { return mIsAsynchronous; } |
| bool isMmapped() const { return mIsMmapped; } |
| const MmapBufferDescriptor& getMmapBufferDescriptor() const { return mMmapBufferDescriptor; } |
| |
| private: |
| static std::unique_ptr<DataMQ> maybeCreateDataMQ( |
| const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor) { |
| using Tag = ::aidl::android::hardware::audio::core::StreamDescriptor::AudioBuffer::Tag; |
| if (descriptor.audio.getTag() == Tag::fmq) { |
| return std::make_unique<DataMQ>(descriptor.audio.get<Tag::fmq>()); |
| } |
| return nullptr; |
| } |
| static bool isMmapped( |
| const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor) { |
| using Tag = ::aidl::android::hardware::audio::core::StreamDescriptor::AudioBuffer::Tag; |
| return descriptor.audio.getTag() == Tag::mmap; |
| } |
| static MmapBufferDescriptor maybeGetMmapBuffer( |
| ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor) { |
| using Tag = ::aidl::android::hardware::audio::core::StreamDescriptor::AudioBuffer::Tag; |
| if (descriptor.audio.getTag() == Tag::mmap) { |
| return std::move(descriptor.audio.get<Tag::mmap>()); |
| } |
| return {}; |
| } |
| |
| size_t mFrameSizeBytes; |
| std::unique_ptr<CommandMQ> mCommandMQ; |
| std::unique_ptr<ReplyMQ> mReplyMQ; |
| size_t mBufferSizeFrames; |
| std::unique_ptr<DataMQ> mDataMQ; |
| bool mIsAsynchronous; |
| bool mIsMmapped; |
| MmapBufferDescriptor mMmapBufferDescriptor; |
| }; |
| |
| class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelperAidl { |
| public: |
| // Return size of input/output buffer in bytes for this stream - eg. 4800. |
| status_t getBufferSize(size_t *size) override; |
| |
| // Return the base configuration of the stream: |
| // - channel mask; |
| // - format - e.g. AUDIO_FORMAT_PCM_16_BIT; |
| // - sampling rate in Hz - eg. 44100. |
| status_t getAudioProperties(audio_config_base_t *configBase) override; |
| |
| // Set audio stream parameters. |
| status_t setParameters(const String8& kvPairs) override; |
| |
| // Get audio stream parameters. |
| status_t getParameters(const String8& keys, String8 *values) override; |
| |
| // Return the frame size (number of bytes per sample) of a stream. |
| status_t getFrameSize(size_t *size) override; |
| |
| // Add or remove the effect on the stream. |
| status_t addEffect(sp<EffectHalInterface> effect) override; |
| status_t removeEffect(sp<EffectHalInterface> effect) override; |
| |
| // Put the audio hardware input/output into standby mode. |
| status_t standby() override; |
| |
| status_t dump(int fd, const Vector<String16>& args) override; |
| |
| // Start a stream operating in mmap mode. |
| status_t start() override; |
| |
| // Stop a stream operating in mmap mode. |
| status_t stop() override; |
| |
| // Retrieve information on the data buffer in mmap mode. |
| status_t createMmapBuffer(int32_t minSizeFrames, |
| struct audio_mmap_buffer_info *info) override; |
| |
| // Get current read/write position in the mmap buffer |
| status_t getMmapPosition(struct audio_mmap_position *position) override; |
| |
| // Set the priority of the thread that interacts with the HAL |
| // (must match the priority of the audioflinger's thread that calls 'read' / 'write') |
| status_t setHalThreadPriority(int priority) override; |
| |
| status_t legacyCreateAudioPatch(const struct audio_port_config& port, |
| std::optional<audio_source_t> source, |
| audio_devices_t type) override; |
| |
| status_t legacyReleaseAudioPatch() override; |
| |
| protected: |
| // For tests. |
| friend class sp<StreamHalAidl>; |
| |
| template<class T> |
| static std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> getStreamCommon( |
| const std::shared_ptr<T>& stream); |
| |
| // Subclasses can not be constructed directly by clients. |
| StreamHalAidl(std::string_view className, |
| bool isInput, |
| const audio_config& config, |
| int32_t nominalLatency, |
| StreamContextAidl&& context, |
| const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon>& stream, |
| const std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension>& vext); |
| |
| ~StreamHalAidl() override; |
| |
| status_t getLatency(uint32_t *latency); |
| |
| // Always returns non-negative values. |
| status_t getObservablePosition(int64_t *frames, int64_t *timestamp); |
| |
| // Always returns non-negative values. |
| status_t getHardwarePosition(int64_t *frames, int64_t *timestamp); |
| |
| // Always returns non-negative values. |
| status_t getXruns(int32_t *frames); |
| |
| status_t transfer(void *buffer, size_t bytes, size_t *transferred); |
| |
| status_t pause( |
| ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr); |
| |
| status_t resume( |
| ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr); |
| |
| status_t drain(bool earlyNotify, |
| ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr); |
| |
| status_t flush( |
| ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr); |
| |
| status_t exit(); |
| |
| const bool mIsInput; |
| const audio_config_base_t mConfig; |
| const StreamContextAidl mContext; |
| |
| private: |
| static audio_config_base_t configToBase(const audio_config& config) { |
| audio_config_base_t result = AUDIO_CONFIG_BASE_INITIALIZER; |
| result.sample_rate = config.sample_rate; |
| result.channel_mask = config.channel_mask; |
| result.format = config.format; |
| return result; |
| } |
| ::aidl::android::hardware::audio::core::StreamDescriptor::State getState() { |
| std::lock_guard l(mLock); |
| return mLastReply.state; |
| } |
| status_t sendCommand( |
| const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command, |
| ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr, |
| bool safeFromNonWorkerThread = false); |
| status_t updateCountersIfNeeded( |
| ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr); |
| |
| const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> mStream; |
| const std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension> mVendorExt; |
| std::mutex mLock; |
| ::aidl::android::hardware::audio::core::StreamDescriptor::Reply mLastReply GUARDED_BY(mLock); |
| // mStreamPowerLog is used for audio signal power logging. |
| StreamPowerLog mStreamPowerLog; |
| std::atomic<pid_t> mWorkerTid = -1; |
| }; |
| |
| class CallbackBroker; |
| |
| class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl { |
| public: |
| // Extract the output stream parameters and set by AIDL APIs. |
| status_t setParameters(const String8& kvPairs) override; |
| |
| // Return the audio hardware driver estimated latency in milliseconds. |
| status_t getLatency(uint32_t *latency) override; |
| |
| // Use this method in situations where audio mixing is done in the hardware. |
| status_t setVolume(float left, float right) override; |
| |
| // Selects the audio presentation (if available). |
| status_t selectPresentation(int presentationId, int programId) override; |
| |
| // Write audio buffer to driver. |
| status_t write(const void *buffer, size_t bytes, size_t *written) override; |
| |
| // Return the number of audio frames written by the audio dsp to DAC since |
| // the output has exited standby. |
| status_t getRenderPosition(uint32_t *dspFrames) override; |
| |
| // Get the local time at which the next write to the audio driver will be presented. |
| status_t getNextWriteTimestamp(int64_t *timestamp) override; |
| |
| // Set the callback for notifying completion of non-blocking write and drain. |
| status_t setCallback(wp<StreamOutHalInterfaceCallback> callback) override; |
| |
| // Returns whether pause and resume operations are supported. |
| status_t supportsPauseAndResume(bool *supportsPause, bool *supportsResume) override; |
| |
| // Notifies to the audio driver to resume playback following a pause. |
| status_t pause() override; |
| |
| // Notifies to the audio driver to resume playback following a pause. |
| status_t resume() override; |
| |
| // Returns whether drain operation is supported. |
| status_t supportsDrain(bool *supportsDrain) override; |
| |
| // Requests notification when data buffered by the driver/hardware has been played. |
| status_t drain(bool earlyNotify) override; |
| |
| // Notifies to the audio driver to flush the queued data. |
| status_t flush() override; |
| |
| // Return a recent count of the number of audio frames presented to an external observer. |
| status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp) override; |
| |
| // Called when the metadata of the stream's source has been changed. |
| status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) override; |
| |
| // Returns the Dual Mono mode presentation setting. |
| status_t getDualMonoMode(audio_dual_mono_mode_t* mode) override; |
| |
| // Sets the Dual Mono mode presentation on the output device. |
| status_t setDualMonoMode(audio_dual_mono_mode_t mode) override; |
| |
| // Returns the Audio Description Mix level in dB. |
| status_t getAudioDescriptionMixLevel(float* leveldB) override; |
| |
| // Sets the Audio Description Mix level in dB. |
| status_t setAudioDescriptionMixLevel(float leveldB) override; |
| |
| // Retrieves current playback rate parameters. |
| status_t getPlaybackRateParameters(audio_playback_rate_t* playbackRate) override; |
| |
| // Sets the playback rate parameters that control playback behavior. |
| status_t setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) override; |
| |
| status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override; |
| |
| status_t setLatencyMode(audio_latency_mode_t mode) override; |
| status_t getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) override; |
| status_t setLatencyModeCallback( |
| const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) override; |
| |
| status_t exit() override; |
| |
| private: |
| friend class sp<StreamOutHalAidl>; |
| |
| static ConversionResult<::aidl::android::hardware::audio::common::SourceMetadata> |
| legacy2aidl_SourceMetadata(const StreamOutHalInterface::SourceMetadata& legacy); |
| |
| const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut> mStream; |
| const wp<CallbackBroker> mCallbackBroker; |
| |
| AudioOffloadMetadata mOffloadMetadata; |
| |
| // Can not be constructed directly by clients. |
| StreamOutHalAidl( |
| const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency, |
| const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut>& stream, |
| const std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension>& vext, |
| const sp<CallbackBroker>& callbackBroker); |
| |
| ~StreamOutHalAidl() override; |
| |
| // Filter and update the offload metadata. The parameters which are related to the offload |
| // metadata will be removed after filtering. |
| status_t filterAndUpdateOffloadMetadata(AudioParameter ¶meters); |
| }; |
| |
| class MicrophoneInfoProvider; |
| |
| class StreamInHalAidl : public StreamInHalInterface, public StreamHalAidl { |
| public: |
| // Set the input gain for the audio driver. |
| status_t setGain(float gain) override; |
| |
| // Read audio buffer in from driver. |
| status_t read(void *buffer, size_t bytes, size_t *read) override; |
| |
| // Return the amount of input frames lost in the audio driver. |
| status_t getInputFramesLost(uint32_t *framesLost) override; |
| |
| // Return a recent count of the number of audio frames received and |
| // the clock time associated with that frame count. |
| status_t getCapturePosition(int64_t *frames, int64_t *time) override; |
| |
| // Get active microphones |
| status_t getActiveMicrophones(std::vector<media::MicrophoneInfoFw> *microphones) override; |
| |
| // Set microphone direction (for processing) |
| status_t setPreferredMicrophoneDirection( |
| audio_microphone_direction_t direction) override; |
| |
| // Set microphone zoom (for processing) |
| status_t setPreferredMicrophoneFieldDimension(float zoom) override; |
| |
| // Called when the metadata of the stream's sink has been changed. |
| status_t updateSinkMetadata(const SinkMetadata& sinkMetadata) override; |
| |
| private: |
| friend class sp<StreamInHalAidl>; |
| |
| static ConversionResult<::aidl::android::hardware::audio::common::SinkMetadata> |
| legacy2aidl_SinkMetadata(const StreamInHalInterface::SinkMetadata& legacy); |
| |
| const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamIn> mStream; |
| const wp<MicrophoneInfoProvider> mMicInfoProvider; |
| |
| // Can not be constructed directly by clients. |
| StreamInHalAidl( |
| const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency, |
| const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamIn>& stream, |
| const std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension>& vext, |
| const sp<MicrophoneInfoProvider>& micInfoProvider); |
| |
| ~StreamInHalAidl() override = default; |
| }; |
| |
| } // namespace android |