Merge "SoundPool: Implement generic garbage collection"
This commit is contained in:
@@ -228,10 +228,9 @@ Stream* Stream::getPairStream() const
|
|||||||
return mStreamManager->getPairStream(this);
|
return mStreamManager->getPairStream(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream* Stream::playPairStream() {
|
Stream* Stream::playPairStream(std::vector<std::any>& garbage) {
|
||||||
Stream* pairStream = getPairStream();
|
Stream* pairStream = getPairStream();
|
||||||
LOG_ALWAYS_FATAL_IF(pairStream == nullptr, "No pair stream!");
|
LOG_ALWAYS_FATAL_IF(pairStream == nullptr, "No pair stream!");
|
||||||
sp<AudioTrack> releaseTracks[2];
|
|
||||||
{
|
{
|
||||||
ALOGV("%s: track streamID: %d", __func__, (int)getStreamID());
|
ALOGV("%s: track streamID: %d", __func__, (int)getStreamID());
|
||||||
// TODO: Do we really want to force a simultaneous synchronization between
|
// TODO: Do we really want to force a simultaneous synchronization between
|
||||||
@@ -260,7 +259,7 @@ Stream* Stream::playPairStream() {
|
|||||||
const int pairState = pairStream->mState;
|
const int pairState = pairStream->mState;
|
||||||
pairStream->play_l(pairStream->mSound, pairStream->mStreamID,
|
pairStream->play_l(pairStream->mSound, pairStream->mStreamID,
|
||||||
pairStream->mLeftVolume, pairStream->mRightVolume, pairStream->mPriority,
|
pairStream->mLeftVolume, pairStream->mRightVolume, pairStream->mPriority,
|
||||||
pairStream->mLoop, pairStream->mRate, releaseTracks);
|
pairStream->mLoop, pairStream->mRate, garbage);
|
||||||
if (pairStream->mState == IDLE) {
|
if (pairStream->mState == IDLE) {
|
||||||
return nullptr; // AudioTrack error
|
return nullptr; // AudioTrack error
|
||||||
}
|
}
|
||||||
@@ -269,17 +268,16 @@ Stream* Stream::playPairStream() {
|
|||||||
pairStream->mAudioTrack->pause();
|
pairStream->mAudioTrack->pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// release tracks outside of Stream lock
|
|
||||||
return pairStream;
|
return pairStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID,
|
void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID,
|
||||||
float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate,
|
float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate,
|
||||||
sp<AudioTrack> releaseTracks[2])
|
std::vector<std::any>& garbage)
|
||||||
{
|
{
|
||||||
// These tracks are released without the lock.
|
// oldTrack and newTrack are placeholders to be released by garbage without the lock.
|
||||||
sp<AudioTrack> &oldTrack = releaseTracks[0];
|
sp<AudioTrack> oldTrack;
|
||||||
sp<AudioTrack> &newTrack = releaseTracks[1];
|
sp<AudioTrack> newTrack;
|
||||||
status_t status = NO_ERROR;
|
status_t status = NO_ERROR;
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -383,8 +381,12 @@ exit:
|
|||||||
mState = IDLE;
|
mState = IDLE;
|
||||||
mSoundID = 0;
|
mSoundID = 0;
|
||||||
mSound.reset();
|
mSound.reset();
|
||||||
mAudioTrack.clear(); // actual release from releaseTracks[]
|
mAudioTrack.clear(); // actual release from garbage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// move tracks to garbage to be released later outside of lock.
|
||||||
|
if (newTrack) garbage.emplace_back(std::move(newTrack));
|
||||||
|
if (oldTrack) garbage.emplace_back(std::move(oldTrack));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
|
|
||||||
|
#include <any>
|
||||||
#include <android-base/thread_annotations.h>
|
#include <android-base/thread_annotations.h>
|
||||||
#include <audio_utils/clock.h>
|
#include <audio_utils/clock.h>
|
||||||
#include <media/AudioTrack.h>
|
#include <media/AudioTrack.h>
|
||||||
@@ -90,8 +91,9 @@ public:
|
|||||||
void mute(bool muting);
|
void mute(bool muting);
|
||||||
void dump() const NO_THREAD_SAFETY_ANALYSIS; // disable for ALOGV (see func for details).
|
void dump() const NO_THREAD_SAFETY_ANALYSIS; // disable for ALOGV (see func for details).
|
||||||
|
|
||||||
// returns the pair stream if successful, nullptr otherwise
|
// returns the pair stream if successful, nullptr otherwise.
|
||||||
Stream* playPairStream();
|
// garbage is used to release tracks and data outside of any lock.
|
||||||
|
Stream* playPairStream(std::vector<std::any>& garbage);
|
||||||
|
|
||||||
// These parameters are explicitly checked in the SoundPool class
|
// These parameters are explicitly checked in the SoundPool class
|
||||||
// so never deviate from the Java API specified values.
|
// so never deviate from the Java API specified values.
|
||||||
@@ -123,9 +125,10 @@ public:
|
|||||||
Stream* getPairStream() const;
|
Stream* getPairStream() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// garbage is used to release tracks and data outside of any lock.
|
||||||
void play_l(const std::shared_ptr<Sound>& sound, int streamID,
|
void play_l(const std::shared_ptr<Sound>& sound, int streamID,
|
||||||
float leftVolume, float rightVolume, int priority, int loop, float rate,
|
float leftVolume, float rightVolume, int priority, int loop, float rate,
|
||||||
sp<AudioTrack> releaseTracks[2]) REQUIRES(mLock);
|
std::vector<std::any>& garbage) REQUIRES(mLock);
|
||||||
void stop_l() REQUIRES(mLock);
|
void stop_l() REQUIRES(mLock);
|
||||||
void setVolume_l(float leftVolume, float rightVolume) REQUIRES(mLock);
|
void setVolume_l(float leftVolume, float rightVolume) REQUIRES(mLock);
|
||||||
|
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ int32_t StreamManager::queueForPlay(const std::shared_ptr<Sound> &sound,
|
|||||||
__func__, sound.get(), soundID, leftVolume, rightVolume, priority, loop, rate);
|
__func__, sound.get(), soundID, leftVolume, rightVolume, priority, loop, rate);
|
||||||
bool launchThread = false;
|
bool launchThread = false;
|
||||||
int32_t streamID = 0;
|
int32_t streamID = 0;
|
||||||
|
std::vector<std::any> garbage;
|
||||||
|
|
||||||
{ // for lock
|
{ // for lock
|
||||||
std::unique_lock lock(mStreamManagerLock);
|
std::unique_lock lock(mStreamManagerLock);
|
||||||
@@ -243,7 +244,7 @@ int32_t StreamManager::queueForPlay(const std::shared_ptr<Sound> &sound,
|
|||||||
removeFromQueues_l(newStream);
|
removeFromQueues_l(newStream);
|
||||||
mProcessingStreams.emplace(newStream);
|
mProcessingStreams.emplace(newStream);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
if (Stream* nextStream = newStream->playPairStream()) {
|
if (Stream* nextStream = newStream->playPairStream(garbage)) {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
ALOGV("%s: starting streamID:%d", __func__, nextStream->getStreamID());
|
ALOGV("%s: starting streamID:%d", __func__, nextStream->getStreamID());
|
||||||
addToActiveQueue_l(nextStream);
|
addToActiveQueue_l(nextStream);
|
||||||
@@ -266,6 +267,7 @@ int32_t StreamManager::queueForPlay(const std::shared_ptr<Sound> &sound,
|
|||||||
ALOGV_IF(id != 0, "%s: launched thread %d", __func__, id);
|
ALOGV_IF(id != 0, "%s: launched thread %d", __func__, id);
|
||||||
}
|
}
|
||||||
ALOGV("%s: returning %d", __func__, streamID);
|
ALOGV("%s: returning %d", __func__, streamID);
|
||||||
|
// garbage is cleared here outside mStreamManagerLock.
|
||||||
return streamID;
|
return streamID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,6 +361,7 @@ void StreamManager::run(int32_t id)
|
|||||||
{
|
{
|
||||||
ALOGV("%s(%d) entering", __func__, id);
|
ALOGV("%s(%d) entering", __func__, id);
|
||||||
int64_t waitTimeNs = 0; // on thread start, mRestartStreams can be non-empty.
|
int64_t waitTimeNs = 0; // on thread start, mRestartStreams can be non-empty.
|
||||||
|
std::vector<std::any> garbage; // used for garbage collection
|
||||||
std::unique_lock lock(mStreamManagerLock);
|
std::unique_lock lock(mStreamManagerLock);
|
||||||
while (!mQuit) {
|
while (!mQuit) {
|
||||||
if (waitTimeNs > 0) {
|
if (waitTimeNs > 0) {
|
||||||
@@ -388,7 +391,7 @@ void StreamManager::run(int32_t id)
|
|||||||
if (!mLockStreamManagerStop) lock.unlock();
|
if (!mLockStreamManagerStop) lock.unlock();
|
||||||
stream->stop();
|
stream->stop();
|
||||||
ALOGV("%s(%d) stopping streamID:%d", __func__, id, stream->getStreamID());
|
ALOGV("%s(%d) stopping streamID:%d", __func__, id, stream->getStreamID());
|
||||||
if (Stream* nextStream = stream->playPairStream()) {
|
if (Stream* nextStream = stream->playPairStream(garbage)) {
|
||||||
ALOGV("%s(%d) starting streamID:%d", __func__, id, nextStream->getStreamID());
|
ALOGV("%s(%d) starting streamID:%d", __func__, id, nextStream->getStreamID());
|
||||||
if (!mLockStreamManagerStop) lock.lock();
|
if (!mLockStreamManagerStop) lock.lock();
|
||||||
if (nextStream->getStopTimeNs() > 0) {
|
if (nextStream->getStopTimeNs() > 0) {
|
||||||
@@ -405,6 +408,12 @@ void StreamManager::run(int32_t id)
|
|||||||
}
|
}
|
||||||
mProcessingStreams.erase(stream);
|
mProcessingStreams.erase(stream);
|
||||||
sanityCheckQueue_l();
|
sanityCheckQueue_l();
|
||||||
|
if (!garbage.empty()) {
|
||||||
|
lock.unlock();
|
||||||
|
// garbage audio tracks (etc) are cleared here outside mStreamManagerLock.
|
||||||
|
garbage.clear();
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ALOGV("%s(%d) exiting", __func__, id);
|
ALOGV("%s(%d) exiting", __func__, id);
|
||||||
|
|||||||
Reference in New Issue
Block a user