SoundPool的load方法用于加载音效文件,代码如下:
//frameworks/base/media/java/android/media/SoundPool.java
public class SoundPool extends PlayerBase {
public int load(String path, int priority) {
int id = 0;
try {
File f = new File(path);
ParcelFileDescriptor fd = ParcelFileDescriptor.open(f,
ParcelFileDescriptor.MODE_READ_ONLY); //ParcelFileDescriptor是Android中的一个类,用于处理文件描述符。它提供了一些方法来创建、转换和关闭文件描述符,以实现进程间的数据流传输和跨进程访问文件。
if (fd != null) {
id = _load(fd.getFileDescriptor(), 0, f.length(), priority);
fd.close();
}
} catch (java.io.IOException e) {
Log.e(TAG, "error loading " + path);
}
return id;
}
}
调用_load方法,_load方法是一个native方法,实现代码如下:
//frameworks/base/media/jni/soundpool/android_media_soundPool.cpp
static jint
android_media_SoundPool_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor,
jlong offset, jlong length, jint priority)
{
ALOGV("android_media_SoundPool_load_FD");
auto soundPool = getSoundPool(env, thiz);
if (soundPool == nullptr) return 0;
return (jint) soundPool->load(jniGetFDFromFileDescriptor(env, fileDescriptor),
int64_t(offset), int64_t(length), int(priority));
}
上面方法处理如下:
1、调用getSoundPool方法,获取SoundPool对象
2、调用SoundPool的load方法加载soundPool
下面分别进行分析:
getSoundPool
调用getSoundPool方法,获取SoundPool对象:
//frameworks/base/media/jni/soundpool/android_media_soundPool.cpp
inline auto getSoundPool(JNIEnv *env, jobject thiz) {
return getSoundPoolManager().get(env, thiz);
}
调用getSoundPoolManager方法:
//frameworks/base/media/jni/soundpool/android_media_soundPool.cpp
auto& getSoundPoolManager() {
static ObjectManager<std::shared_ptr<SoundPool>> soundPoolManager(fields.mNativeContext);
return soundPoolManager;
}
SoundPool load
调用SoundPool的load方法加载soundPool:
//frameworks/base/media/jni/SoundPool/SoundPool.cpp
soundpool::SoundManager mSoundManager;
int32_t SoundPool::load(int fd, int64_t offset, int64_t length, int32_t priority)
{
ALOGV("%s(fd=%d, offset=%lld, length=%lld, priority=%d)",
__func__, fd, (long long)offset, (long long)length, priority);
auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
return mSoundManager.load(fd, offset, length, priority);
}
调用SoundManager的load方法:
//frameworks/base/media/jni/SoundPool/SoundManager.cpp
std::unordered_map<int, std::shared_ptr<Sound>> mSounds GUARDED_BY(mSoundManagerLock);
const std::unique_ptr<SoundDecoder> mDecoder; // has its own lock
int32_t SoundManager::load(int fd, int64_t offset, int64_t length, int32_t priority)
{
ALOGV("%s(fd=%d, offset=%lld, length=%lld, priority=%d)",
__func__, fd, (long long)offset, (long long)length, priority);
int32_t soundID;
{
std::lock_guard lock(mSoundManagerLock);
// mNextSoundID is always positive and does not "integer overflow"
do {
mNextSoundID = mNextSoundID == INT32_MAX ? 1 : mNextSoundID + 1;
} while (findSound_l(mNextSoundID) != nullptr);
soundID = mNextSoundID;
auto sound = std::make_shared<Sound>(soundID, fd, offset, length); //创建Sound对象
mSounds.emplace(soundID, sound); //构造mSounds容器
}
// mDecoder->loadSound() must be called outside of mSoundManagerLock.
// mDecoder->loadSound() may block on mDecoder message queue space;
// the message queue emptying may block on SoundManager::findSound().
//
// It is theoretically possible that sound loads might decode out-of-order.
mDecoder->loadSound(soundID); //调用SoundDecoder的loadSound方法
return soundID;
}
上面方法主要处理如下:
1、创建Sound对象
2、调用SoundDecoder的loadSound方法
下面分别进行分析:
Sound
Sound的构造方法如下:
//frameworks/base/media/jni/SoundPool/Sound.cpp
Sound::Sound(int32_t soundID, int fd, int64_t offset, int64_t length)
: mSoundID(soundID)
, mFd(fcntl(fd, F_DUPFD_CLOEXEC, (int)0 /* arg */)) // dup(fd) + close on exec to prevent leaks.
, mOffset(offset)
, mLength(length)
{
ALOGV("%s(soundID=%d, fd=%d, offset=%lld, length=%lld)",
__func__, soundID, fd, (long long)offset, (long long)length);
ALOGW_IF(mFd == -1, "Unable to dup descriptor %d", fd);
}
SoundDecoder loadSound
调用SoundDecoder的loadSound方法:
//frameworks/base/media/jni/SoundPool/SoundDecoder.cpp
std::condition_variable mQueueSpaceAvailable GUARDED_BY(mLock);
std::condition_variable mQueueDataAvailable GUARDED_BY(mLock);
std::deque<int32_t> mSoundIDs GUARDED_BY(mLock);
bool mQuit GUARDED_BY(mLock) = false;
void SoundDecoder::loadSound(int32_t soundID)
{
ALOGV("%s(%d)", __func__, soundID);
size_t pendingSounds;
{
std::unique_lock lock(mLock);
while (mSoundIDs.size() == kMaxQueueSize) {
if (mQuit) return;
ALOGV("%s: waiting soundID: %d size: %zu", __func__, soundID, mSoundIDs.size());
mQueueSpaceAvailable.wait(lock);
}
if (mQuit) return;
mSoundIDs.push_back(soundID);
mQueueDataAvailable.notify_one();
ALOGV("%s: adding soundID: %d size: %zu", __func__, soundID, mSoundIDs.size());
pendingSounds = mSoundIDs.size();
}
// Launch threads as needed. The "as needed" is weakly consistent as we release mLock.
if (pendingSounds > mThreadPool->getActiveThreadCount()) {
const int32_t id = mThreadPool->launch([this](int32_t id) { run(id); });
(void)id; // avoid clang warning -Wunused-variable -Wused-but-marked-unused
ALOGV_IF(id != 0, "%s: launched thread %d", __func__, id);
}
}