Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e74da38e authored by Marco Nelissen's avatar Marco Nelissen Committed by Gerrit Code Review
Browse files

Merge "Make SoundPool use MediaCodec"

parents 3812e68e 372be897
Loading
Loading
Loading
Loading
+33 −7
Original line number Diff line number Diff line
@@ -543,11 +543,6 @@ public class SoundPool {

        public int load(String path, int priority)
        {
            // pass network streams to player
            if (path.startsWith("http:"))
                return _load(path, priority);

            // try local path
            int id = 0;
            try {
                File f = new File(path);
@@ -562,6 +557,7 @@ public class SoundPool {
            return id;
        }

        @Override
        public int load(Context context, int resId, int priority) {
            AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId);
            int id = 0;
@@ -576,6 +572,7 @@ public class SoundPool {
            return id;
        }

        @Override
        public int load(AssetFileDescriptor afd, int priority) {
            if (afd != null) {
                long len = afd.getLength();
@@ -588,16 +585,17 @@ public class SoundPool {
            }
        }

        @Override
        public int load(FileDescriptor fd, long offset, long length, int priority) {
            return _load(fd, offset, length, priority);
        }

        private native final int _load(String uri, int priority);

        private native final int _load(FileDescriptor fd, long offset, long length, int priority);

        @Override
        public native final boolean unload(int soundID);

        @Override
        public final int play(int soundID, float leftVolume, float rightVolume,
                int priority, int loop, float rate) {
            if (isRestricted()) {
@@ -620,16 +618,22 @@ public class SoundPool {
            }
        }

        @Override
        public native final void pause(int streamID);

        @Override
        public native final void resume(int streamID);

        @Override
        public native final void autoPause();

        @Override
        public native final void autoResume();

        @Override
        public native final void stop(int streamID);

        @Override
        public final void setVolume(int streamID, float leftVolume, float rightVolume) {
            if (isRestricted()) {
                return;
@@ -639,16 +643,21 @@ public class SoundPool {

        private native final void _setVolume(int streamID, float leftVolume, float rightVolume);

        @Override
        public void setVolume(int streamID, float volume) {
            setVolume(streamID, volume, volume);
        }

        @Override
        public native final void setPriority(int streamID, int priority);

        @Override
        public native final void setLoop(int streamID, int loop);

        @Override
        public native final void setRate(int streamID, float rate);

        @Override
        public void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener)
        {
            synchronized(mLock) {
@@ -729,52 +738,69 @@ public class SoundPool {
            return 0;
        }

        @Override
        public int load(Context context, int resId, int priority) {
            return 0;
        }

        @Override
        public int load(AssetFileDescriptor afd, int priority) {
            return 0;
        }

        @Override
        public int load(FileDescriptor fd, long offset, long length, int priority) {
            return 0;
        }

        @Override
        public final boolean unload(int soundID) {
            return true;
        }

        @Override
        public final int play(int soundID, float leftVolume, float rightVolume,
                int priority, int loop, float rate) {
            return 0;
        }

        @Override
        public final void pause(int streamID) { }

        @Override
        public final void resume(int streamID) { }

        @Override
        public final void autoPause() { }

        @Override
        public final void autoResume() { }

        @Override
        public final void stop(int streamID) { }

        @Override
        public final void setVolume(int streamID,
                float leftVolume, float rightVolume) { }

        @Override
        public void setVolume(int streamID, float volume) {
        }

        @Override
        public final void setPriority(int streamID, int priority) { }

        @Override
        public final void setLoop(int streamID, int loop) { }

        @Override
        public final void setRate(int streamID, float rate) { }

        @Override
        public void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener) {
        }

        @Override
        public final void release() { }
    }
}
+6 −2
Original line number Diff line number Diff line
@@ -2,7 +2,9 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    android_media_SoundPool_SoundPoolImpl.cpp
    android_media_SoundPool_SoundPoolImpl.cpp \
    SoundPool.cpp \
    SoundPoolThread.cpp

LOCAL_SHARED_LIBRARIES := \
    liblog \
@@ -10,7 +12,9 @@ LOCAL_SHARED_LIBRARIES := \
    libutils \
    libandroid_runtime \
    libnativehelper \
    libmedia
    libmedia \
    libmediandk \
    libbinder

LOCAL_MODULE:= libsoundpool

+1018 −0

File added.

Preview size limit exceeded, changes collapsed.

+232 −0
Original line number Diff line number Diff line
/*
 * 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 SOUNDPOOL_H_
#define SOUNDPOOL_H_

#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Vector.h>
#include <utils/KeyedVector.h>
#include <media/AudioTrack.h>
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryBase.h>

namespace android {

static const int IDLE_PRIORITY = -1;

// forward declarations
class SoundEvent;
class SoundPoolThread;
class SoundPool;

// for queued events
class SoundPoolEvent {
public:
    SoundPoolEvent(int msg, int arg1=0, int arg2=0) :
        mMsg(msg), mArg1(arg1), mArg2(arg2) {}
    int         mMsg;
    int         mArg1;
    int         mArg2;
    enum MessageType { INVALID, SAMPLE_LOADED };
};

// callback function prototype
typedef void SoundPoolCallback(SoundPoolEvent event, SoundPool* soundPool, void* user);

// tracks samples used by application
class Sample  : public RefBase {
public:
    enum sample_state { UNLOADED, LOADING, READY, UNLOADING };
    Sample(int sampleID, int fd, int64_t offset, int64_t length);
    ~Sample();
    int sampleID() { return mSampleID; }
    int numChannels() { return mNumChannels; }
    int sampleRate() { return mSampleRate; }
    audio_format_t format() { return mFormat; }
    size_t size() { return mSize; }
    int state() { return mState; }
    uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); }
    status_t doLoad();
    void startLoad() { mState = LOADING; }
    sp<IMemory> getIMemory() { return mData; }

private:
    void init();

    size_t              mSize;
    volatile int32_t    mRefCount;
    uint16_t            mSampleID;
    uint16_t            mSampleRate;
    uint8_t             mState : 3;
    uint8_t             mNumChannels : 2;
    audio_format_t      mFormat;
    int                 mFd;
    int64_t             mOffset;
    int64_t             mLength;
    sp<IMemory>         mData;
    sp<MemoryHeapBase>  mHeap;
};

// stores pending events for stolen channels
class SoundEvent
{
public:
    SoundEvent() : mChannelID(0), mLeftVolume(0), mRightVolume(0),
            mPriority(IDLE_PRIORITY), mLoop(0), mRate(0) {}
    void set(const sp<Sample>& sample, int channelID, float leftVolume,
            float rightVolume, int priority, int loop, float rate);
    sp<Sample>      sample() { return mSample; }
    int             channelID() { return mChannelID; }
    float           leftVolume() { return mLeftVolume; }
    float           rightVolume() { return mRightVolume; }
    int             priority() { return mPriority; }
    int             loop() { return mLoop; }
    float           rate() { return mRate; }
    void            clear() { mChannelID = 0; mSample.clear(); }

protected:
    sp<Sample>      mSample;
    int             mChannelID;
    float           mLeftVolume;
    float           mRightVolume;
    int             mPriority;
    int             mLoop;
    float           mRate;
};

// for channels aka AudioTracks
class SoundChannel : public SoundEvent {
public:
    enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
    SoundChannel() : mState(IDLE), mNumChannels(1),
            mPos(0), mToggle(0), mAutoPaused(false) {}
    ~SoundChannel();
    void init(SoundPool* soundPool);
    void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume,
            int priority, int loop, float rate);
    void setVolume_l(float leftVolume, float rightVolume);
    void setVolume(float leftVolume, float rightVolume);
    void stop_l();
    void stop();
    void pause();
    void autoPause();
    void resume();
    void autoResume();
    void setRate(float rate);
    int state() { return mState; }
    void setPriority(int priority) { mPriority = priority; }
    void setLoop(int loop);
    int numChannels() { return mNumChannels; }
    void clearNextEvent() { mNextEvent.clear(); }
    void nextEvent();
    int nextChannelID() { return mNextEvent.channelID(); }
    void dump();

private:
    static void callback(int event, void* user, void *info);
    void process(int event, void *info, unsigned long toggle);
    bool doStop_l();

    SoundPool*          mSoundPool;
    sp<AudioTrack>      mAudioTrack;
    SoundEvent          mNextEvent;
    Mutex               mLock;
    int                 mState;
    int                 mNumChannels;
    int                 mPos;
    int                 mAudioBufferSize;
    unsigned long       mToggle;
    bool                mAutoPaused;
};

// application object for managing a pool of sounds
class SoundPool {
    friend class SoundPoolThread;
    friend class SoundChannel;
public:
    SoundPool(int maxChannels, const audio_attributes_t* pAttributes);
    ~SoundPool();
    int load(int fd, int64_t offset, int64_t length, int priority);
    bool unload(int sampleID);
    int play(int sampleID, float leftVolume, float rightVolume, int priority,
            int loop, float rate);
    void pause(int channelID);
    void autoPause();
    void resume(int channelID);
    void autoResume();
    void stop(int channelID);
    void setVolume(int channelID, float leftVolume, float rightVolume);
    void setPriority(int channelID, int priority);
    void setLoop(int channelID, int loop);
    void setRate(int channelID, float rate);
    const audio_attributes_t* attributes() { return &mAttributes; }

    // called from SoundPoolThread
    void sampleLoaded(int sampleID);

    // called from AudioTrack thread
    void done_l(SoundChannel* channel);

    // callback function
    void setCallback(SoundPoolCallback* callback, void* user);
    void* getUserData() { return mUserData; }

private:
    SoundPool() {} // no default constructor
    bool startThreads();
    void doLoad(sp<Sample>& sample);
    sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); }
    SoundChannel* findChannel (int channelID);
    SoundChannel* findNextChannel (int channelID);
    SoundChannel* allocateChannel_l(int priority);
    void moveToFront_l(SoundChannel* channel);
    void notify(SoundPoolEvent event);
    void dump();

    // restart thread
    void addToRestartList(SoundChannel* channel);
    void addToStopList(SoundChannel* channel);
    static int beginThread(void* arg);
    int run();
    void quit();

    Mutex                   mLock;
    Mutex                   mRestartLock;
    Condition               mCondition;
    SoundPoolThread*        mDecodeThread;
    SoundChannel*           mChannelPool;
    List<SoundChannel*>     mChannels;
    List<SoundChannel*>     mRestart;
    List<SoundChannel*>     mStop;
    DefaultKeyedVector< int, sp<Sample> >   mSamples;
    int                     mMaxChannels;
    audio_attributes_t      mAttributes;
    int                     mAllocated;
    int                     mNextSampleID;
    int                     mNextChannelID;
    bool                    mQuit;

    // callback
    Mutex                   mCallbackLock;
    SoundPoolCallback*      mCallback;
    void*                   mUserData;
};

} // end namespace android

#endif /*SOUNDPOOL_H_*/
+114 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "SoundPoolThread"
#include "utils/Log.h"

#include "SoundPoolThread.h"

namespace android {

void SoundPoolThread::write(SoundPoolMsg msg) {
    Mutex::Autolock lock(&mLock);
    while (mMsgQueue.size() >= maxMessages) {
        mCondition.wait(mLock);
    }

    // if thread is quitting, don't add to queue
    if (mRunning) {
        mMsgQueue.push(msg);
        mCondition.signal();
    }
}

const SoundPoolMsg SoundPoolThread::read() {
    Mutex::Autolock lock(&mLock);
    while (mMsgQueue.size() == 0) {
        mCondition.wait(mLock);
    }
    SoundPoolMsg msg = mMsgQueue[0];
    mMsgQueue.removeAt(0);
    mCondition.signal();
    return msg;
}

void SoundPoolThread::quit() {
    Mutex::Autolock lock(&mLock);
    if (mRunning) {
        mRunning = false;
        mMsgQueue.clear();
        mMsgQueue.push(SoundPoolMsg(SoundPoolMsg::KILL, 0));
        mCondition.signal();
        mCondition.wait(mLock);
    }
    ALOGV("return from quit");
}

SoundPoolThread::SoundPoolThread(SoundPool* soundPool) :
    mSoundPool(soundPool)
{
    mMsgQueue.setCapacity(maxMessages);
    if (createThreadEtc(beginThread, this, "SoundPoolThread")) {
        mRunning = true;
    }
}

SoundPoolThread::~SoundPoolThread()
{
    quit();
}

int SoundPoolThread::beginThread(void* arg) {
    ALOGV("beginThread");
    SoundPoolThread* soundPoolThread = (SoundPoolThread*)arg;
    return soundPoolThread->run();
}

int SoundPoolThread::run() {
    ALOGV("run");
    for (;;) {
        SoundPoolMsg msg = read();
        ALOGV("Got message m=%d, mData=%d", msg.mMessageType, msg.mData);
        switch (msg.mMessageType) {
        case SoundPoolMsg::KILL:
            ALOGV("goodbye");
            return NO_ERROR;
        case SoundPoolMsg::LOAD_SAMPLE:
            doLoadSample(msg.mData);
            break;
        default:
            ALOGW("run: Unrecognized message %d\n",
                    msg.mMessageType);
            break;
        }
    }
}

void SoundPoolThread::loadSample(int sampleID) {
    write(SoundPoolMsg(SoundPoolMsg::LOAD_SAMPLE, sampleID));
}

void SoundPoolThread::doLoadSample(int sampleID) {
    sp <Sample> sample = mSoundPool->findSample(sampleID);
    status_t status = -1;
    if (sample != 0) {
        status = sample->doLoad();
    }
    mSoundPool->notify(SoundPoolEvent(SoundPoolEvent::SAMPLE_LOADED, sampleID, status));
}

} // end namespace android
Loading