/* * Copyright 2016 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. */ #ifndef AAUDIO_AUDIOSTREAM_H #define AAUDIO_AUDIOSTREAM_H #include #include #include #include #include #include #include #include #include #include #include #include "utility/AAudioUtilities.h" #include "utility/MonotonicCounter.h" // Cannot get android::media::VolumeShaper to compile! #define AAUDIO_USE_VOLUME_SHAPER 0 namespace aaudio { typedef void *(*aaudio_audio_thread_proc_t)(void *); typedef uint32_t aaudio_stream_id_t; class AudioStreamBuilder; constexpr pid_t CALLBACK_THREAD_NONE = 0; /** * AAudio audio stream. */ // By extending AudioDeviceCallback, we also inherit from RefBase. class AudioStream : public android::AudioSystem::AudioDeviceCallback { public: AudioStream(); virtual ~AudioStream(); protected: /** * Check the state to see if Pause is currently legal. * * @param result pointer to return code * @return true if OK to continue, if false then return result */ bool checkPauseStateTransition(aaudio_result_t *result); virtual bool isFlushSupported() const { // Only implement FLUSH for OUTPUT streams. return false; } virtual bool isPauseSupported() const { // Only implement PAUSE for OUTPUT streams. return false; } /* Asynchronous requests. * Use waitForStateChange() to wait for completion. */ virtual aaudio_result_t requestStart_l() REQUIRES(mStreamLock) = 0; virtual aaudio_result_t requestPause_l() REQUIRES(mStreamLock) { // Only implement this for OUTPUT streams. return AAUDIO_ERROR_UNIMPLEMENTED; } virtual aaudio_result_t requestFlush_l() REQUIRES(mStreamLock) { // Only implement this for OUTPUT streams. return AAUDIO_ERROR_UNIMPLEMENTED; } virtual aaudio_result_t requestStop_l() REQUIRES(mStreamLock) = 0; public: virtual aaudio_result_t getTimestamp(clockid_t clockId, int64_t *framePosition, int64_t *timeNanoseconds) = 0; /** * Update state machine.() * @return */ virtual aaudio_result_t updateStateMachine() = 0; // =========== End ABSTRACT methods =========================== virtual aaudio_result_t waitForStateChange(aaudio_stream_state_t currentState, aaudio_stream_state_t *nextState, int64_t timeoutNanoseconds); /** * Open the stream using the parameters in the builder. * Allocate the necessary resources. */ virtual aaudio_result_t open(const AudioStreamBuilder& builder); // log to MediaMetrics virtual void logOpenActual(); void logReleaseBufferState(); /* Note about naming for "release" and "close" related methods. * * These names are intended to match the public AAudio API. * The original AAudio API had an AAudioStream_close() function that * released the hardware and deleted the stream. That made it difficult * because apps want to release the HW ASAP but are not in a rush to delete * the stream object. So in R we added an AAudioStream_release() function * that just released the hardware. * The AAudioStream_close() method releases if needed and then closes. */ protected: /** * Free any hardware or system resources from the open() call. * It is safe to call release_l() multiple times. */ virtual aaudio_result_t release_l() REQUIRES(mStreamLock) { setState(AAUDIO_STREAM_STATE_CLOSING); return AAUDIO_OK; } /** * Free any resources not already freed by release_l(). * Assume release_l() already called. */ virtual void close_l() REQUIRES(mStreamLock); public: // This is only used to identify a stream in the logs without // revealing any pointers. aaudio_stream_id_t getId() { return mStreamId; } virtual aaudio_result_t setBufferSize(int32_t requestedFrames) = 0; aaudio_result_t createThread(int64_t periodNanoseconds, aaudio_audio_thread_proc_t threadProc, void *threadArg) EXCLUDES(mStreamLock) { std::lock_guard lock(mStreamLock); return createThread_l(periodNanoseconds, threadProc, threadArg); } aaudio_result_t joinThread(void **returnArg); virtual aaudio_result_t registerThread() { return AAUDIO_OK; } virtual aaudio_result_t unregisterThread() { return AAUDIO_OK; } /** * Internal function used to call the audio thread passed by the user. * It is unfortunately public because it needs to be called by a static 'C' function. */ void* wrapUserThread(); // ============== Queries =========================== aaudio_stream_state_t getState() const { return mState; } virtual int32_t getBufferSize() const { return AAUDIO_ERROR_UNIMPLEMENTED; } virtual int32_t getBufferCapacity() const { return mBufferCapacity; } virtual int32_t getFramesPerBurst() const { return mFramesPerBurst; } virtual int32_t getXRunCount() const { return AAUDIO_ERROR_UNIMPLEMENTED; } bool isActive() const { return mState == AAUDIO_STREAM_STATE_STARTING || mState == AAUDIO_STREAM_STATE_STARTED; } virtual bool isMMap() { return false; } aaudio_result_t getSampleRate() const { return mSampleRate; } audio_format_t getFormat() const { return mFormat; } aaudio_result_t getSamplesPerFrame() const { return mSamplesPerFrame; } virtual int32_t getPerformanceMode() const { return mPerformanceMode; } void setPerformanceMode(aaudio_performance_mode_t performanceMode) { mPerformanceMode = performanceMode; } int32_t getDeviceId() const { return mDeviceId; } aaudio_sharing_mode_t getSharingMode() const { return mSharingMode; } bool isSharingModeMatchRequired() const { return mSharingModeMatchRequired; } virtual aaudio_direction_t getDirection() const = 0; aaudio_usage_t getUsage() const { return mUsage; } aaudio_content_type_t getContentType() const { return mContentType; } aaudio_spatialization_behavior_t getSpatializationBehavior() const { return mSpatializationBehavior; } bool isContentSpatialized() const { return mIsContentSpatialized; } aaudio_input_preset_t getInputPreset() const { return mInputPreset; } aaudio_allowed_capture_policy_t getAllowedCapturePolicy() const { return mAllowedCapturePolicy; } int32_t getSessionId() const { return mSessionId; } bool isPrivacySensitive() const { return mIsPrivacySensitive; } bool getRequireMonoBlend() const { return mRequireMonoBlend; } float getAudioBalance() const { return mAudioBalance; } /** * This is only valid after setChannelMask() and setFormat() * have been called. */ int32_t getBytesPerFrame() const { return mSamplesPerFrame * getBytesPerSample(); } /** * This is only valid after setFormat() has been called. */ int32_t getBytesPerSample() const { return audio_bytes_per_sample(mFormat); } /** * This is only valid after setChannelMask() and setDeviceFormat() have been called. */ int32_t getBytesPerDeviceFrame() const { return getSamplesPerFrame() * audio_bytes_per_sample(getDeviceFormat()); } virtual int64_t getFramesWritten() = 0; virtual int64_t getFramesRead() = 0; AAudioStream_dataCallback getDataCallbackProc() const { return mDataCallbackProc; } AAudioStream_errorCallback getErrorCallbackProc() const { return mErrorCallbackProc; } aaudio_data_callback_result_t maybeCallDataCallback(void *audioData, int32_t numFrames); void maybeCallErrorCallback(aaudio_result_t result); void *getDataCallbackUserData() const { return mDataCallbackUserData; } void *getErrorCallbackUserData() const { return mErrorCallbackUserData; } int32_t getFramesPerDataCallback() const { return mFramesPerDataCallback; } aaudio_channel_mask_t getChannelMask() const { return mChannelMask; } void setChannelMask(aaudio_channel_mask_t channelMask) { mChannelMask = channelMask; mSamplesPerFrame = AAudioConvert_channelMaskToCount(channelMask); } /** * @return true if data callback has been specified */ bool isDataCallbackSet() const { return mDataCallbackProc != nullptr; } /** * @return true if data callback has been specified and stream is running */ bool isDataCallbackActive() const { return isDataCallbackSet() && isActive(); } /** * @return true if called from the same thread as the callback */ bool collidesWithCallback() const; // Implement AudioDeviceCallback void onAudioDeviceUpdate(audio_io_handle_t audioIo, audio_port_handle_t deviceId) override {}; // ============== I/O =========================== // A Stream will only implement read() or write() depending on its direction. virtual aaudio_result_t write(const void *buffer __unused, int32_t numFrames __unused, int64_t timeoutNanoseconds __unused) { return AAUDIO_ERROR_UNIMPLEMENTED; } virtual aaudio_result_t read(void *buffer __unused, int32_t numFrames __unused, int64_t timeoutNanoseconds __unused) { return AAUDIO_ERROR_UNIMPLEMENTED; } // This is used by the AudioManager to duck and mute the stream when changing audio focus. void setDuckAndMuteVolume(float duckAndMuteVolume); float getDuckAndMuteVolume() const { return mDuckAndMuteVolume; } // Implement this in the output subclasses. virtual android::status_t doSetVolume() { return android::NO_ERROR; } #if AAUDIO_USE_VOLUME_SHAPER virtual ::android::binder::Status applyVolumeShaper( const ::android::media::VolumeShaper::Configuration& configuration __unused, const ::android::media::VolumeShaper::Operation& operation __unused); #endif /** * Register this stream's PlayerBase with the AudioManager if needed. * Only register output streams. * This should only be called for client streams and not for streams * that run in the service. */ void registerPlayerBase() { if (getDirection() == AAUDIO_DIRECTION_OUTPUT) { mPlayerBase->registerWithAudioManager(this); } } /** * Unregister this stream's PlayerBase with the AudioManager. * This will only unregister if already registered. */ void unregisterPlayerBase() { mPlayerBase->unregisterWithAudioManager(); } aaudio_result_t systemStart(); aaudio_result_t systemPause(); aaudio_result_t safeFlush(); /** * This is called when an app calls AAudioStream_requestStop(); * It prevents calls from a callback. */ aaudio_result_t systemStopFromApp(); /** * This is called internally when an app callback returns AAUDIO_CALLBACK_RESULT_STOP. */ aaudio_result_t systemStopInternal(); /** * Safely RELEASE a stream after taking mStreamLock and checking * to make sure we are not being called from a callback. * @return AAUDIO_OK or a negative error */ aaudio_result_t safeRelease(); /** * Safely RELEASE and CLOSE a stream after taking mStreamLock and checking * to make sure we are not being called from a callback. * @return AAUDIO_OK or a negative error */ aaudio_result_t safeReleaseClose(); aaudio_result_t safeReleaseCloseInternal(); protected: // PlayerBase allows the system to control the stream volume. class MyPlayerBase : public android::PlayerBase { public: MyPlayerBase() = default; virtual ~MyPlayerBase() = default; /** * Register for volume changes and remote control. */ void registerWithAudioManager(const android::sp& parent); /** * UnRegister. */ void unregisterWithAudioManager(); /** * Just calls unregisterWithAudioManager(). */ void destroy() override; // Just a stub. The ability to start audio through PlayerBase is being deprecated. android::status_t playerStart() override { return android::NO_ERROR; } // Just a stub. The ability to pause audio through PlayerBase is being deprecated. android::status_t playerPause() override { return android::NO_ERROR; } // Just a stub. The ability to stop audio through PlayerBase is being deprecated. android::status_t playerStop() override { return android::NO_ERROR; } android::status_t playerSetVolume() override; #if AAUDIO_USE_VOLUME_SHAPER ::android::binder::Status applyVolumeShaper(); #endif aaudio_result_t getResult() { return mResult; } // Returns the playerIId if registered, -1 otherwise. int32_t getPlayerIId() const { return mPIId; } private: // Use a weak pointer so the AudioStream can be deleted. std::mutex mParentLock; android::wp mParent GUARDED_BY(mParentLock); aaudio_result_t mResult = AAUDIO_OK; bool mRegistered = false; }; /** * This should not be called after the open() call. * TODO for multiple setters: assert(mState == AAUDIO_STREAM_STATE_UNINITIALIZED) */ void setSampleRate(int32_t sampleRate) { mSampleRate = sampleRate; } // This should not be called after the open() call. void setFramesPerBurst(int32_t framesPerBurst) { mFramesPerBurst = framesPerBurst; } // This should not be called after the open() call. void setBufferCapacity(int32_t bufferCapacity) { mBufferCapacity = bufferCapacity; } // This should not be called after the open() call. void setSharingMode(aaudio_sharing_mode_t sharingMode) { mSharingMode = sharingMode; } // This should not be called after the open() call. void setFormat(audio_format_t format) { mFormat = format; } // This should not be called after the open() call. void setDeviceFormat(audio_format_t format) { mDeviceFormat = format; } audio_format_t getDeviceFormat() const { return mDeviceFormat; } void setState(aaudio_stream_state_t state); void setDeviceId(int32_t deviceId) { mDeviceId = deviceId; } // This should not be called after the open() call. void setSessionId(int32_t sessionId) { mSessionId = sessionId; } aaudio_result_t createThread_l(int64_t periodNanoseconds, aaudio_audio_thread_proc_t threadProc, void *threadArg) REQUIRES(mStreamLock); aaudio_result_t joinThread_l(void **returnArg) REQUIRES(mStreamLock); std::atomic mCallbackEnabled{false}; float mDuckAndMuteVolume = 1.0f; protected: /** * Either convert the data from device format to app format and return a pointer * to the conversion buffer, * OR just pass back the original pointer. * * Note that this is only used for the INPUT path. * * @param audioData * @param numFrames * @return original pointer or the conversion buffer */ virtual const void * maybeConvertDeviceData(const void *audioData, int32_t /*numFrames*/) { return audioData; } void setPeriodNanoseconds(int64_t periodNanoseconds) { mPeriodNanoseconds.store(periodNanoseconds, std::memory_order_release); } int64_t getPeriodNanoseconds() { return mPeriodNanoseconds.load(std::memory_order_acquire); } /** * This should not be called after the open() call. */ void setUsage(aaudio_usage_t usage) { mUsage = usage; } /** * This should not be called after the open() call. */ void setContentType(aaudio_content_type_t contentType) { mContentType = contentType; } void setSpatializationBehavior(aaudio_spatialization_behavior_t spatializationBehavior) { mSpatializationBehavior = spatializationBehavior; } void setIsContentSpatialized(bool isContentSpatialized) { mIsContentSpatialized = isContentSpatialized; } /** * This should not be called after the open() call. */ void setInputPreset(aaudio_input_preset_t inputPreset) { mInputPreset = inputPreset; } /** * This should not be called after the open() call. */ void setAllowedCapturePolicy(aaudio_allowed_capture_policy_t policy) { mAllowedCapturePolicy = policy; } /** * This should not be called after the open() call. */ void setPrivacySensitive(bool privacySensitive) { mIsPrivacySensitive = privacySensitive; } /** * This should not be called after the open() call. */ void setRequireMonoBlend(bool requireMonoBlend) { mRequireMonoBlend = requireMonoBlend; } /** * This should not be called after the open() call. */ void setAudioBalance(float audioBalance) { mAudioBalance = audioBalance; } std::string mMetricsId; // set once during open() std::mutex mStreamLock; private: aaudio_result_t safeStop_l() REQUIRES(mStreamLock); /** * Release then close the stream. */ void releaseCloseFinal_l() REQUIRES(mStreamLock) { if (getState() != AAUDIO_STREAM_STATE_CLOSING) { // not already released? // Ignore result and keep closing. (void) release_l(); } close_l(); } const android::sp mPlayerBase; // These do not change after open(). int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED; aaudio_channel_mask_t mChannelMask = AAUDIO_UNSPECIFIED; int32_t mSampleRate = AAUDIO_UNSPECIFIED; int32_t mDeviceId = AAUDIO_UNSPECIFIED; aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED; bool mSharingModeMatchRequired = false; // must match sharing mode requested audio_format_t mFormat = AUDIO_FORMAT_DEFAULT; aaudio_stream_state_t mState = AAUDIO_STREAM_STATE_UNINITIALIZED; aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE; int32_t mFramesPerBurst = 0; int32_t mBufferCapacity = 0; aaudio_usage_t mUsage = AAUDIO_UNSPECIFIED; aaudio_content_type_t mContentType = AAUDIO_UNSPECIFIED; aaudio_spatialization_behavior_t mSpatializationBehavior = AAUDIO_UNSPECIFIED; bool mIsContentSpatialized = false; aaudio_input_preset_t mInputPreset = AAUDIO_UNSPECIFIED; aaudio_allowed_capture_policy_t mAllowedCapturePolicy = AAUDIO_ALLOW_CAPTURE_BY_ALL; bool mIsPrivacySensitive = false; bool mRequireMonoBlend = false; float mAudioBalance = 0; int32_t mSessionId = AAUDIO_UNSPECIFIED; // Sometimes the hardware is operating with a different format from the app. // Then we require conversion in AAudio. audio_format_t mDeviceFormat = AUDIO_FORMAT_INVALID; // callback ---------------------------------- AAudioStream_dataCallback mDataCallbackProc = nullptr; // external callback functions void *mDataCallbackUserData = nullptr; int32_t mFramesPerDataCallback = AAUDIO_UNSPECIFIED; // frames std::atomic mDataCallbackThread{CALLBACK_THREAD_NONE}; AAudioStream_errorCallback mErrorCallbackProc = nullptr; void *mErrorCallbackUserData = nullptr; std::atomic mErrorCallbackThread{CALLBACK_THREAD_NONE}; // background thread ---------------------------------- // Use mHasThread to prevent joining twice, which has undefined behavior. bool mHasThread GUARDED_BY(mStreamLock) = false; pthread_t mThread GUARDED_BY(mStreamLock) = {}; // These are set by the application thread and then read by the audio pthread. std::atomic mPeriodNanoseconds; // for tuning SCHED_FIFO threads // TODO make atomic? aaudio_audio_thread_proc_t mThreadProc = nullptr; void *mThreadArg = nullptr; aaudio_result_t mThreadRegistrationResult = AAUDIO_OK; const aaudio_stream_id_t mStreamId; }; } /* namespace aaudio */ #endif /* AAUDIO_AUDIOSTREAM_H */