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

Commit 99985d98 authored by Marco Nelissen's avatar Marco Nelissen Committed by Android Git Automerger
Browse files

am e74da38e: Merge "Make SoundPool use MediaCodec"

* commit 'e74da38e':
  Make SoundPool use MediaCodec
parents f7049289 e74da38e
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