Merge "Make SoundPool use MediaCodec"

This commit is contained in:
Marco Nelissen
2015-01-27 17:49:01 +00:00
committed by Gerrit Code Review
7 changed files with 1470 additions and 28 deletions

View File

@ -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() { }
}
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,232 @@
/*
* 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_*/

View File

@ -0,0 +1,114 @@
/*
* 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

View File

@ -0,0 +1,66 @@
/*
* 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_*/

View File

@ -23,7 +23,7 @@
#include <nativehelper/jni.h>
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <media/SoundPool.h>
#include "SoundPool.h"
using namespace android;
@ -45,20 +45,6 @@ struct audio_attributes_fields_t {
static audio_attributes_fields_t javaAudioAttrFields;
// ----------------------------------------------------------------------------
static jint
android_media_SoundPool_SoundPoolImpl_load_URL(JNIEnv *env, jobject thiz, jstring path, jint priority)
{
ALOGV("android_media_SoundPool_SoundPoolImpl_load_URL");
SoundPool *ap = MusterSoundPool(env, thiz);
if (path == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return 0;
}
const char* s = env->GetStringUTFChars(path, NULL);
int id = ap->load(s, priority);
env->ReleaseStringUTFChars(path, s);
return (jint) id;
}
static jint
android_media_SoundPool_SoundPoolImpl_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor,
@ -248,10 +234,6 @@ android_media_SoundPool_SoundPoolImpl_release(JNIEnv *env, jobject thiz)
// Dalvik VM type signatures
static JNINativeMethod gMethods[] = {
{ "_load",
"(Ljava/lang/String;I)I",
(void *)android_media_SoundPool_SoundPoolImpl_load_URL
},
{ "_load",
"(Ljava/io/FileDescriptor;JJI)I",
(void *)android_media_SoundPool_SoundPoolImpl_load_FD