The problem can occur if a sample is started at the same time as the last AudioTrack callback for a playing sample is called. At this time, allocateChannel() can be called concurrently with moveToFront() which can cause an entry in mChannels being used by moveToFront() to be erased temporarily by allocateChannel(). The fix consists in making sure that the SoundPool mutex is held whenever play(), stop() or done() are called. In addition, other potential weaknesses have been removed by making sure that the channel mutex is held while starting, stopping and processing the AudioTrack call back. To that purpose, a mechanism similar to the channel restart method is implemented to avoid stopping channels from the AudioTrack call back but do it from the restart thread instead. The sound effects SounPool management in AudioService has also been improved to make sure that the samples have been loaded when a playback request is received and also to immediately release the SoundPool when the effects are unloaded without waiting for the GC to occur. The SoundPool.java class was modified to allow the use of a looper attached to the thread in which the sample loaded listener is running and not to the thread in which the SoundPool is created. The maximum number of samples that can be loaded in a SoundPool lifetime as been increased from 255 to 65535. Change-Id: I368a3bdfda4239f807f857c3e97b70f6b31b0af3
67 lines
1.8 KiB
C++
67 lines
1.8 KiB
C++
/*
|
|
* Copyright (C) 2007 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 SOUNDPOOLTHREAD_H_
|
|
#define SOUNDPOOLTHREAD_H_
|
|
|
|
#include <utils/threads.h>
|
|
#include <utils/Vector.h>
|
|
#include <media/AudioTrack.h>
|
|
|
|
#include "SoundPool.h"
|
|
|
|
namespace android {
|
|
|
|
class SoundPoolMsg {
|
|
public:
|
|
enum MessageType { INVALID, KILL, LOAD_SAMPLE };
|
|
SoundPoolMsg() : mMessageType(INVALID), mData(0) {}
|
|
SoundPoolMsg(MessageType MessageType, int data) :
|
|
mMessageType(MessageType), mData(data) {}
|
|
uint16_t mMessageType;
|
|
uint16_t mData;
|
|
};
|
|
|
|
/*
|
|
* This class handles background requests from the SoundPool
|
|
*/
|
|
class SoundPoolThread {
|
|
public:
|
|
SoundPoolThread(SoundPool* SoundPool);
|
|
~SoundPoolThread();
|
|
void loadSample(int sampleID);
|
|
void quit();
|
|
void write(SoundPoolMsg msg);
|
|
|
|
private:
|
|
static const size_t maxMessages = 5;
|
|
|
|
static int beginThread(void* arg);
|
|
int run();
|
|
void doLoadSample(int sampleID);
|
|
const SoundPoolMsg read();
|
|
|
|
Mutex mLock;
|
|
Condition mCondition;
|
|
Vector<SoundPoolMsg> mMsgQueue;
|
|
SoundPool* mSoundPool;
|
|
bool mRunning;
|
|
};
|
|
|
|
} // end namespace android
|
|
|
|
#endif /*SOUNDPOOLTHREAD_H_*/
|