Loading include/private/media/AudioTrackShared.h +3 −0 Original line number Diff line number Diff line Loading @@ -182,6 +182,7 @@ private: // This is set by AudioTrack.setBufferSizeInFrames(). // A write will not fill the buffer above this limit. volatile uint32_t mBufferSizeInFrames; // effective size of the buffer volatile uint32_t mStartThresholdInFrames; // min frames in buffer to start streaming public: Loading Loading @@ -216,6 +217,8 @@ public: }; size_t frameCount() const { return mFrameCount; } uint32_t getStartThresholdInFrames() const; uint32_t setStartThresholdInFrames(uint32_t startThresholdInFrames); protected: // These refer to shared memory, and are virtual addresses with respect to the current process. Loading media/libaudioclient/AudioTrack.cpp +56 −0 Original line number Diff line number Diff line Loading @@ -1283,6 +1283,46 @@ ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames) return finalBufferSize; } ssize_t AudioTrack::getStartThresholdInFrames() const { AutoMutex lock(mLock); if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) { return NO_INIT; } return (ssize_t) mProxy->getStartThresholdInFrames(); } ssize_t AudioTrack::setStartThresholdInFrames(size_t startThresholdInFrames) { if (startThresholdInFrames > INT32_MAX || startThresholdInFrames == 0) { // contractually we could simply return the current threshold in frames // to indicate the request was ignored, but we return an error here. return BAD_VALUE; } AutoMutex lock(mLock); // We do not permit calling setStartThresholdInFrames() between the AudioTrack // default ctor AudioTrack() and set(...) but rather fail such an attempt. // (To do so would require a cached mOrigStartThresholdInFrames and we may // not have proper validation for the actual set value). if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) { return NO_INIT; } const uint32_t original = mProxy->getStartThresholdInFrames(); const uint32_t final = mProxy->setStartThresholdInFrames(startThresholdInFrames); if (original != final) { android::mediametrics::LogItem(mMetricsId) .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETSTARTTHRESHOLD) .set(AMEDIAMETRICS_PROP_STARTTHRESHOLDFRAMES, (int32_t)final) .record(); if (original > final) { // restart track if it was disabled by audioflinger due to previous underrun // and we reduced the number of frames for the threshold. restartIfDisabled(); } } return final; } status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount) { if (mSharedBuffer == 0 || isOffloadedOrDirect()) { Loading Loading @@ -2602,6 +2642,10 @@ status_t AudioTrack::restoreTrack_l(const char *from) staticPosition = mStaticProxy->getPosition().unsignedValue(); } // save the old startThreshold and framecount const uint32_t originalStartThresholdInFrames = mProxy->getStartThresholdInFrames(); const uint32_t originalFrameCount = mProxy->frameCount(); // See b/74409267. Connecting to a BT A2DP device supporting multiple codecs // causes a lot of churn on the service side, and it can reject starting // playback of a previously created track. May also apply to other cases. Loading Loading @@ -2662,6 +2706,18 @@ retry: return status; }); // restore the original start threshold if different than frameCount. if (originalStartThresholdInFrames != originalFrameCount) { // Note: mProxy->setStartThresholdInFrames() call is in the Proxy // and does not trigger a restart. // (Also CBLK_DISABLED is not set, buffers are empty after track recreation). // Any start would be triggered on the mState == ACTIVE check below. const uint32_t currentThreshold = mProxy->setStartThresholdInFrames(originalStartThresholdInFrames); ALOGD_IF(originalStartThresholdInFrames != currentThreshold, "%s(%d) startThresholdInFrames changing from %u to %u", __func__, mPortId, originalStartThresholdInFrames, currentThreshold); } if (mState == STATE_ACTIVE) { mAudioTrack->start(&result); } Loading media/libaudioclient/AudioTrackShared.cpp +38 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #define LOG_TAG "AudioTrackShared" //#define LOG_NDEBUG 0 #include <atomic> #include <android-base/macros.h> #include <private/media/AudioTrackShared.h> #include <utils/Log.h> Loading @@ -33,6 +34,21 @@ size_t clampToSize(T x) { return sizeof(T) > sizeof(size_t) && x > (T) SIZE_MAX ? SIZE_MAX : x < 0 ? 0 : (size_t) x; } // compile-time safe atomics. TODO: update all methods to use it template <typename T> T android_atomic_load(const volatile T* addr) { static_assert(sizeof(T) == sizeof(std::atomic<T>)); // no extra sync data required. static_assert(std::atomic<T>::is_always_lock_free); // no hash lock somewhere. return atomic_load((std::atomic<T>*)addr); // memory_order_seq_cst } template <typename T> void android_atomic_store(const volatile T* addr, T value) { static_assert(sizeof(T) == sizeof(std::atomic<T>)); // no extra sync data required. static_assert(std::atomic<T>::is_always_lock_free); // no hash lock somewhere. atomic_store((std::atomic<T>*)addr, value); // memory_order_seq_cst } // incrementSequence is used to determine the next sequence value // for the loop and position sequence counters. It should return // a value between "other" + 1 and "other" + INT32_MAX, the choice of Loading @@ -51,6 +67,7 @@ audio_track_cblk_t::audio_track_cblk_t() : mServer(0), mFutex(0), mMinimum(0) , mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0) , mBufferSizeInFrames(0) , mStartThresholdInFrames(0) // filled in by the server. , mFlags(0) { memset(&u, 0, sizeof(u)); Loading @@ -66,6 +83,26 @@ Proxy::Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t { } uint32_t Proxy::getStartThresholdInFrames() const { const uint32_t startThresholdInFrames = android_atomic_load(&mCblk->mStartThresholdInFrames); if (startThresholdInFrames == 0 || startThresholdInFrames > mFrameCount) { ALOGD("%s: startThresholdInFrames %u not between 1 and frameCount %zu, " "setting to frameCount", __func__, startThresholdInFrames, mFrameCount); return mFrameCount; } return startThresholdInFrames; } uint32_t Proxy::setStartThresholdInFrames(uint32_t startThresholdInFrames) { const uint32_t actual = std::min((size_t)startThresholdInFrames, frameCount()); android_atomic_store(&mCblk->mStartThresholdInFrames, actual); return actual; } // --------------------------------------------------------------------------- ClientProxy::ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, Loading Loading @@ -663,6 +700,7 @@ ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCo , mTimestampMutator(&cblk->mExtendedTimestampQueue) { cblk->mBufferSizeInFrames = frameCount; cblk->mStartThresholdInFrames = frameCount; } __attribute__((no_sanitize("integer"))) Loading media/libaudioclient/include/media/AudioTrack.h +13 −0 Original line number Diff line number Diff line Loading @@ -429,6 +429,19 @@ public: */ ssize_t setBufferSizeInFrames(size_t size); /* Returns the start threshold on the buffer for audio streaming * or a negative value if the AudioTrack is not initialized. */ ssize_t getStartThresholdInFrames() const; /* Sets the start threshold in frames on the buffer for audio streaming. * * May be clamped internally. Returns the actual value set, or a negative * value if the AudioTrack is not initialized or if the input * is zero or greater than INT_MAX. */ ssize_t setStartThresholdInFrames(size_t startThresholdInFrames); /* Return the static buffer specified in constructor or set(), or 0 for streaming mode */ sp<IMemory> sharedBuffer() const { return mSharedBuffer; } Loading media/libmediametrics/include/MediaMetricsConstants.h +2 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,7 @@ #define AMEDIAMETRICS_PROP_SESSIONID "sessionId" // int32 #define AMEDIAMETRICS_PROP_SHARINGMODE "sharingMode" // string value, "exclusive", shared" #define AMEDIAMETRICS_PROP_SOURCE "source" // string (AudioAttributes) #define AMEDIAMETRICS_PROP_STARTTHRESHOLDFRAMES "startThresholdFrames" // int32 (AudioTrack) #define AMEDIAMETRICS_PROP_STARTUPMS "startupMs" // double value // State is "ACTIVE" or "STOPPED" for AudioRecord #define AMEDIAMETRICS_PROP_STATE "state" // string Loading Loading @@ -187,6 +188,7 @@ #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETLOGSESSIONID "setLogSessionId" // AudioTrack, Record #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYBACKPARAM "setPlaybackParam" // AudioTrack #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYERIID "setPlayerIId" // AudioTrack #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETSTARTTHRESHOLD "setStartThreshold" // AudioTrack #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME "setVoiceVolume" // AudioFlinger #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOLUME "setVolume" // AudioTrack #define AMEDIAMETRICS_PROP_EVENT_VALUE_START "start" // AudioTrack, AudioRecord Loading Loading
include/private/media/AudioTrackShared.h +3 −0 Original line number Diff line number Diff line Loading @@ -182,6 +182,7 @@ private: // This is set by AudioTrack.setBufferSizeInFrames(). // A write will not fill the buffer above this limit. volatile uint32_t mBufferSizeInFrames; // effective size of the buffer volatile uint32_t mStartThresholdInFrames; // min frames in buffer to start streaming public: Loading Loading @@ -216,6 +217,8 @@ public: }; size_t frameCount() const { return mFrameCount; } uint32_t getStartThresholdInFrames() const; uint32_t setStartThresholdInFrames(uint32_t startThresholdInFrames); protected: // These refer to shared memory, and are virtual addresses with respect to the current process. Loading
media/libaudioclient/AudioTrack.cpp +56 −0 Original line number Diff line number Diff line Loading @@ -1283,6 +1283,46 @@ ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames) return finalBufferSize; } ssize_t AudioTrack::getStartThresholdInFrames() const { AutoMutex lock(mLock); if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) { return NO_INIT; } return (ssize_t) mProxy->getStartThresholdInFrames(); } ssize_t AudioTrack::setStartThresholdInFrames(size_t startThresholdInFrames) { if (startThresholdInFrames > INT32_MAX || startThresholdInFrames == 0) { // contractually we could simply return the current threshold in frames // to indicate the request was ignored, but we return an error here. return BAD_VALUE; } AutoMutex lock(mLock); // We do not permit calling setStartThresholdInFrames() between the AudioTrack // default ctor AudioTrack() and set(...) but rather fail such an attempt. // (To do so would require a cached mOrigStartThresholdInFrames and we may // not have proper validation for the actual set value). if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) { return NO_INIT; } const uint32_t original = mProxy->getStartThresholdInFrames(); const uint32_t final = mProxy->setStartThresholdInFrames(startThresholdInFrames); if (original != final) { android::mediametrics::LogItem(mMetricsId) .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_SETSTARTTHRESHOLD) .set(AMEDIAMETRICS_PROP_STARTTHRESHOLDFRAMES, (int32_t)final) .record(); if (original > final) { // restart track if it was disabled by audioflinger due to previous underrun // and we reduced the number of frames for the threshold. restartIfDisabled(); } } return final; } status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount) { if (mSharedBuffer == 0 || isOffloadedOrDirect()) { Loading Loading @@ -2602,6 +2642,10 @@ status_t AudioTrack::restoreTrack_l(const char *from) staticPosition = mStaticProxy->getPosition().unsignedValue(); } // save the old startThreshold and framecount const uint32_t originalStartThresholdInFrames = mProxy->getStartThresholdInFrames(); const uint32_t originalFrameCount = mProxy->frameCount(); // See b/74409267. Connecting to a BT A2DP device supporting multiple codecs // causes a lot of churn on the service side, and it can reject starting // playback of a previously created track. May also apply to other cases. Loading Loading @@ -2662,6 +2706,18 @@ retry: return status; }); // restore the original start threshold if different than frameCount. if (originalStartThresholdInFrames != originalFrameCount) { // Note: mProxy->setStartThresholdInFrames() call is in the Proxy // and does not trigger a restart. // (Also CBLK_DISABLED is not set, buffers are empty after track recreation). // Any start would be triggered on the mState == ACTIVE check below. const uint32_t currentThreshold = mProxy->setStartThresholdInFrames(originalStartThresholdInFrames); ALOGD_IF(originalStartThresholdInFrames != currentThreshold, "%s(%d) startThresholdInFrames changing from %u to %u", __func__, mPortId, originalStartThresholdInFrames, currentThreshold); } if (mState == STATE_ACTIVE) { mAudioTrack->start(&result); } Loading
media/libaudioclient/AudioTrackShared.cpp +38 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #define LOG_TAG "AudioTrackShared" //#define LOG_NDEBUG 0 #include <atomic> #include <android-base/macros.h> #include <private/media/AudioTrackShared.h> #include <utils/Log.h> Loading @@ -33,6 +34,21 @@ size_t clampToSize(T x) { return sizeof(T) > sizeof(size_t) && x > (T) SIZE_MAX ? SIZE_MAX : x < 0 ? 0 : (size_t) x; } // compile-time safe atomics. TODO: update all methods to use it template <typename T> T android_atomic_load(const volatile T* addr) { static_assert(sizeof(T) == sizeof(std::atomic<T>)); // no extra sync data required. static_assert(std::atomic<T>::is_always_lock_free); // no hash lock somewhere. return atomic_load((std::atomic<T>*)addr); // memory_order_seq_cst } template <typename T> void android_atomic_store(const volatile T* addr, T value) { static_assert(sizeof(T) == sizeof(std::atomic<T>)); // no extra sync data required. static_assert(std::atomic<T>::is_always_lock_free); // no hash lock somewhere. atomic_store((std::atomic<T>*)addr, value); // memory_order_seq_cst } // incrementSequence is used to determine the next sequence value // for the loop and position sequence counters. It should return // a value between "other" + 1 and "other" + INT32_MAX, the choice of Loading @@ -51,6 +67,7 @@ audio_track_cblk_t::audio_track_cblk_t() : mServer(0), mFutex(0), mMinimum(0) , mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0) , mBufferSizeInFrames(0) , mStartThresholdInFrames(0) // filled in by the server. , mFlags(0) { memset(&u, 0, sizeof(u)); Loading @@ -66,6 +83,26 @@ Proxy::Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t { } uint32_t Proxy::getStartThresholdInFrames() const { const uint32_t startThresholdInFrames = android_atomic_load(&mCblk->mStartThresholdInFrames); if (startThresholdInFrames == 0 || startThresholdInFrames > mFrameCount) { ALOGD("%s: startThresholdInFrames %u not between 1 and frameCount %zu, " "setting to frameCount", __func__, startThresholdInFrames, mFrameCount); return mFrameCount; } return startThresholdInFrames; } uint32_t Proxy::setStartThresholdInFrames(uint32_t startThresholdInFrames) { const uint32_t actual = std::min((size_t)startThresholdInFrames, frameCount()); android_atomic_store(&mCblk->mStartThresholdInFrames, actual); return actual; } // --------------------------------------------------------------------------- ClientProxy::ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, Loading Loading @@ -663,6 +700,7 @@ ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCo , mTimestampMutator(&cblk->mExtendedTimestampQueue) { cblk->mBufferSizeInFrames = frameCount; cblk->mStartThresholdInFrames = frameCount; } __attribute__((no_sanitize("integer"))) Loading
media/libaudioclient/include/media/AudioTrack.h +13 −0 Original line number Diff line number Diff line Loading @@ -429,6 +429,19 @@ public: */ ssize_t setBufferSizeInFrames(size_t size); /* Returns the start threshold on the buffer for audio streaming * or a negative value if the AudioTrack is not initialized. */ ssize_t getStartThresholdInFrames() const; /* Sets the start threshold in frames on the buffer for audio streaming. * * May be clamped internally. Returns the actual value set, or a negative * value if the AudioTrack is not initialized or if the input * is zero or greater than INT_MAX. */ ssize_t setStartThresholdInFrames(size_t startThresholdInFrames); /* Return the static buffer specified in constructor or set(), or 0 for streaming mode */ sp<IMemory> sharedBuffer() const { return mSharedBuffer; } Loading
media/libmediametrics/include/MediaMetricsConstants.h +2 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,7 @@ #define AMEDIAMETRICS_PROP_SESSIONID "sessionId" // int32 #define AMEDIAMETRICS_PROP_SHARINGMODE "sharingMode" // string value, "exclusive", shared" #define AMEDIAMETRICS_PROP_SOURCE "source" // string (AudioAttributes) #define AMEDIAMETRICS_PROP_STARTTHRESHOLDFRAMES "startThresholdFrames" // int32 (AudioTrack) #define AMEDIAMETRICS_PROP_STARTUPMS "startupMs" // double value // State is "ACTIVE" or "STOPPED" for AudioRecord #define AMEDIAMETRICS_PROP_STATE "state" // string Loading Loading @@ -187,6 +188,7 @@ #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETLOGSESSIONID "setLogSessionId" // AudioTrack, Record #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYBACKPARAM "setPlaybackParam" // AudioTrack #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETPLAYERIID "setPlayerIId" // AudioTrack #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETSTARTTHRESHOLD "setStartThreshold" // AudioTrack #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME "setVoiceVolume" // AudioFlinger #define AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOLUME "setVolume" // AudioTrack #define AMEDIAMETRICS_PROP_EVENT_VALUE_START "start" // AudioTrack, AudioRecord Loading