From 570576b51b8123ab05b36707ec752cf966292ca5 Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Thu, 29 Jan 2015 18:20:20 -0800 Subject: [PATCH 1/2] soundpool: reuse channel for same sample if available Reuse channel for same sample if the channel completed current playback and is not reallocated to another sample, i.e. not stolen by other sample. authored-by: Ashish Jain Change-Id: Ibe7ee318c7dc11f3c4fd3a2f57d861318b10973b Signed-off-by: Glenn Kasten --- media/jni/soundpool/SoundPool.cpp | 81 +++++++++++++++++++------------ media/jni/soundpool/SoundPool.h | 4 +- 2 files changed, 52 insertions(+), 33 deletions(-) diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index a73209bf19795..8957b3cb13626 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -256,7 +256,7 @@ int SoundPool::play(int sampleID, float leftVolume, float rightVolume, dump(); // allocate a channel - channel = allocateChannel_l(priority); + channel = allocateChannel_l(priority, sampleID); // no channel allocated - return 0 if (!channel) { @@ -271,13 +271,25 @@ int SoundPool::play(int sampleID, float leftVolume, float rightVolume, return channelID; } -SoundChannel* SoundPool::allocateChannel_l(int priority) +SoundChannel* SoundPool::allocateChannel_l(int priority, int sampleID) { List::iterator iter; SoundChannel* channel = NULL; - // allocate a channel + // check if channel for given sampleID still available if (!mChannels.empty()) { + for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) { + if (sampleID == (*iter)->getPrevSampleID() && (*iter)->state() == SoundChannel::IDLE) { + channel = *iter; + mChannels.erase(iter); + ALOGV("Allocated recycled channel for same sampleID"); + break; + } + } + } + + // allocate any channel + if (!channel && !mChannels.empty()) { iter = mChannels.begin(); if (priority >= (*iter)->priority()) { channel = *iter; @@ -648,6 +660,7 @@ error: void SoundChannel::init(SoundPool* soundPool) { mSoundPool = soundPool; + mPrevSampleID = -1; } // call with sound pool lock held @@ -656,7 +669,7 @@ void SoundChannel::play(const sp& sample, int nextChannelID, float leftV { sp oldTrack; sp newTrack; - status_t status; + status_t status = NO_ERROR; { // scope for the lock Mutex::Autolock lock(&mLock); @@ -701,38 +714,41 @@ void SoundChannel::play(const sp& sample, int nextChannelID, float leftV } #endif - // mToggle toggles each time a track is started on a given channel. - // The toggle is concatenated with the SoundChannel address and passed to AudioTrack - // as callback user data. This enables the detection of callbacks received from the old - // audio track while the new one is being started and avoids processing them with - // wrong audio audio buffer size (mAudioBufferSize) - unsigned long toggle = mToggle ^ 1; - void *userData = (void *)((unsigned long)this | toggle); - audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(numChannels); + if (!mAudioTrack.get() || mPrevSampleID != sample->sampleID()) { + // mToggle toggles each time a track is started on a given channel. + // The toggle is concatenated with the SoundChannel address and passed to AudioTrack + // as callback user data. This enables the detection of callbacks received from the old + // audio track while the new one is being started and avoids processing them with + // wrong audio audio buffer size (mAudioBufferSize) + unsigned long toggle = mToggle ^ 1; + void *userData = (void *)((unsigned long)this | toggle); + audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(numChannels); - // do not create a new audio track if current track is compatible with sample parameters -#ifdef USE_SHARED_MEM_BUFFER - newTrack = new AudioTrack(streamType, sampleRate, sample->format(), - channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData); -#else - uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount; - newTrack = new AudioTrack(streamType, sampleRate, sample->format(), - channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData, - bufferFrames); -#endif - oldTrack = mAudioTrack; - status = newTrack->initCheck(); - if (status != NO_ERROR) { - ALOGE("Error creating AudioTrack"); - goto exit; + // do not create a new audio track if current track is compatible with sample parameters + #ifdef USE_SHARED_MEM_BUFFER + newTrack = new AudioTrack(streamType, sampleRate, sample->format(), + channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData); + #else + uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount; + newTrack = new AudioTrack(streamType, sampleRate, sample->format(), + channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData, + bufferFrames); + #endif + oldTrack = mAudioTrack; + status = newTrack->initCheck(); + if (status != NO_ERROR) { + ALOGE("Error creating AudioTrack"); + goto exit; + } + // From now on, AudioTrack callbacks received with previous toggle value will be ignored. + mToggle = toggle; + mAudioTrack = newTrack; + } else { + newTrack = mAudioTrack; + ALOGV("reusing track %p for sample %d", mAudioTrack.get(), sample->sampleID()); } - ALOGV("setVolume %p", newTrack.get()); newTrack->setVolume(leftVolume, rightVolume); newTrack->setLoop(0, frameCount, loop); - - // From now on, AudioTrack callbacks received with previous toggle value will be ignored. - mToggle = toggle; - mAudioTrack = newTrack; mPos = 0; mSample = sample; mChannelID = nextChannelID; @@ -875,6 +891,7 @@ bool SoundChannel::doStop_l() setVolume_l(0, 0); ALOGV("stop"); mAudioTrack->stop(); + mPrevSampleID = mSample->sampleID(); mSample.clear(); mState = IDLE; mPriority = IDLE_PRIORITY; diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h index 9d9cbdf701afe..f520406e8753d 100644 --- a/media/jni/soundpool/SoundPool.h +++ b/media/jni/soundpool/SoundPool.h @@ -136,6 +136,7 @@ public: void nextEvent(); int nextChannelID() { return mNextEvent.channelID(); } void dump(); + int getPrevSampleID(void) { return mPrevSampleID; } private: static void callback(int event, void* user, void *info); @@ -152,6 +153,7 @@ private: int mAudioBufferSize; unsigned long mToggle; bool mAutoPaused; + int mPrevSampleID; }; // application object for managing a pool of sounds @@ -193,7 +195,7 @@ private: sp findSample(int sampleID) { return mSamples.valueFor(sampleID); } SoundChannel* findChannel (int channelID); SoundChannel* findNextChannel (int channelID); - SoundChannel* allocateChannel_l(int priority); + SoundChannel* allocateChannel_l(int priority, int sampleID); void moveToFront_l(SoundChannel* channel); void notify(SoundPoolEvent event); void dump(); From a7d57a6f0068b1e2a0f07ca427cfba198b12a9b9 Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Tue, 3 Mar 2015 22:00:32 +0530 Subject: [PATCH 2/2] soundpool: update sample rate when reusing audiotrack User might update playback rate while calling Play on a sample. Update sample rate if reusing existing audio track. Change-Id: I7007c335fa405baf663a322408b92b9df53efdb0 Signed-off-by: Glenn Kasten --- media/jni/soundpool/SoundPool.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index 8957b3cb13626..dfe2844222a15 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -743,8 +743,10 @@ void SoundChannel::play(const sp& sample, int nextChannelID, float leftV // From now on, AudioTrack callbacks received with previous toggle value will be ignored. mToggle = toggle; mAudioTrack = newTrack; + ALOGV("using new track %p for sample %d", newTrack.get(), sample->sampleID()); } else { newTrack = mAudioTrack; + newTrack->setSampleRate(sampleRate); ALOGV("reusing track %p for sample %d", mAudioTrack.get(), sample->sampleID()); } newTrack->setVolume(leftVolume, rightVolume);