Android13 SoundPool load流程分析

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);
    }
}
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值