diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
| commit | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch) | |
| tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /media/jni/soundpool | |
| parent | 076357b8567458d4b6dfdcf839ef751634cd2bfb (diff) | |
| download | frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.zip frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.gz frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.bz2 | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'media/jni/soundpool')
| -rw-r--r-- | media/jni/soundpool/Android.mk | 18 | ||||
| -rw-r--r-- | media/jni/soundpool/SoundPool.cpp | 764 | ||||
| -rw-r--r-- | media/jni/soundpool/SoundPool.h | 224 | ||||
| -rw-r--r-- | media/jni/soundpool/SoundPoolThread.cpp | 108 | ||||
| -rw-r--r-- | media/jni/soundpool/SoundPoolThread.h | 75 | ||||
| -rw-r--r-- | media/jni/soundpool/android_media_SoundPool.cpp | 270 |
6 files changed, 0 insertions, 1459 deletions
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk deleted file mode 100644 index 374ddeb..0000000 --- a/media/jni/soundpool/Android.mk +++ /dev/null @@ -1,18 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - android_media_SoundPool.cpp \ - SoundPool.cpp \ - SoundPoolThread.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libandroid_runtime \ - libnativehelper \ - libmedia - -LOCAL_MODULE:= libsoundpool - -include $(BUILD_SHARED_LIBRARY) diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp deleted file mode 100644 index 02731825..0000000 --- a/media/jni/soundpool/SoundPool.cpp +++ /dev/null @@ -1,764 +0,0 @@ -/* - * 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 "SoundPool" -#include <utils/Log.h> - -//#define USE_SHARED_MEM_BUFFER - -// XXX needed for timing latency -#include <utils/Timers.h> - -#include <sys/resource.h> -#include <media/AudioTrack.h> -#include <media/mediaplayer.h> - -#include "SoundPool.h" -#include "SoundPoolThread.h" - -namespace android -{ - -int kDefaultBufferCount = 4; -uint32_t kMaxSampleRate = 48000; -uint32_t kDefaultSampleRate = 44100; -uint32_t kDefaultFrameCount = 1200; - -SoundPool::SoundPool(jobject soundPoolRef, int maxChannels, int streamType, int srcQuality) -{ - LOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d", - maxChannels, streamType, srcQuality); - - if (maxChannels > 32) { - LOGW("App requested %d channels, capped at 32", maxChannels); - maxChannels = 32; - } - - mQuit = false; - mSoundPoolRef = soundPoolRef; - mDecodeThread = 0; - mMaxChannels = maxChannels; - mStreamType = streamType; - mSrcQuality = srcQuality; - mAllocated = 0; - mNextSampleID = 0; - mNextChannelID = 0; - - mChannelPool = new SoundChannel[maxChannels]; - for (int i = 0; i < maxChannels; ++i) { - mChannelPool[i].init(this); - mChannels.push_back(&mChannelPool[i]); - } - - // start decode thread - startThreads(); -} - -SoundPool::~SoundPool() -{ - LOGV("SoundPool destructor"); - mDecodeThread->quit(); - quit(); - - Mutex::Autolock lock(&mLock); - mChannels.clear(); - if (mChannelPool) - delete [] mChannelPool; - - // clean up samples - LOGV("clear samples"); - mSamples.clear(); - - if (mDecodeThread) - delete mDecodeThread; -} - -void SoundPool::addToRestartList(SoundChannel* channel) -{ - Mutex::Autolock lock(&mLock); - mRestart.push_back(channel); - mCondition.signal(); -} - -int SoundPool::beginThread(void* arg) -{ - SoundPool* p = (SoundPool*)arg; - return p->run(); -} - -int SoundPool::run() -{ - mLock.lock(); - while (!mQuit) { - mCondition.wait(mLock); - LOGV("awake"); - if (mQuit) break; - - while (!mRestart.empty()) { - SoundChannel* channel; - LOGV("Getting channel from list"); - List<SoundChannel*>::iterator iter = mRestart.begin(); - channel = *iter; - mRestart.erase(iter); - if (channel) channel->nextEvent(); - if (mQuit) break; - } - } - - mRestart.clear(); - mCondition.signal(); - mLock.unlock(); - LOGV("goodbye"); - return 0; -} - -void SoundPool::quit() -{ - mLock.lock(); - mQuit = true; - mCondition.signal(); - mCondition.wait(mLock); - LOGV("return from quit"); - mLock.unlock(); -} - -bool SoundPool::startThreads() -{ - createThread(beginThread, this); - if (mDecodeThread == NULL) - mDecodeThread = new SoundPoolThread(this); - return mDecodeThread != NULL; -} - -SoundChannel* SoundPool::findChannel(int channelID) -{ - for (int i = 0; i < mMaxChannels; ++i) { - if (mChannelPool[i].channelID() == channelID) { - return &mChannelPool[i]; - } - } - return NULL; -} - -SoundChannel* SoundPool::findNextChannel(int channelID) -{ - for (int i = 0; i < mMaxChannels; ++i) { - if (mChannelPool[i].nextChannelID() == channelID) { - return &mChannelPool[i]; - } - } - return NULL; -} - -int SoundPool::load(const char* path, int priority) -{ - LOGV("load: path=%s, priority=%d", path, priority); - Mutex::Autolock lock(&mLock); - sp<Sample> sample = new Sample(++mNextSampleID, path); - mSamples.add(sample->sampleID(), sample); - doLoad(sample); - return sample->sampleID(); -} - -int SoundPool::load(int fd, int64_t offset, int64_t length, int priority) -{ - LOGV("load: fd=%d, offset=%lld, length=%lld, priority=%d", - fd, offset, length, priority); - Mutex::Autolock lock(&mLock); - sp<Sample> sample = new Sample(++mNextSampleID, fd, offset, length); - mSamples.add(sample->sampleID(), sample); - doLoad(sample); - return sample->sampleID(); -} - -void SoundPool::doLoad(sp<Sample>& sample) -{ - LOGV("doLoad: loading sample sampleID=%d", sample->sampleID()); - sample->startLoad(); - mDecodeThread->loadSample(sample->sampleID()); -} - -bool SoundPool::unload(int sampleID) -{ - LOGV("unload: sampleID=%d", sampleID); - Mutex::Autolock lock(&mLock); - return mSamples.removeItem(sampleID); -} - -int SoundPool::play(int sampleID, float leftVolume, float rightVolume, - int priority, int loop, float rate) -{ - LOGV("sampleID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f", - sampleID, leftVolume, rightVolume, priority, loop, rate); - sp<Sample> sample; - SoundChannel* channel; - int channelID; - - // scope for lock - { - Mutex::Autolock lock(&mLock); - - // is sample ready? - sample = findSample(sampleID); - if ((sample == 0) || (sample->state() != Sample::READY)) { - LOGW(" sample %d not READY", sampleID); - return 0; - } - - dump(); - - // allocate a channel - channel = allocateChannel(priority); - - // no channel allocated - return 0 - if (!channel) { - LOGV("No channel allocated"); - return 0; - } - - channelID = ++mNextChannelID; - } - - LOGV("channel state = %d", channel->state()); - channel->play(sample, channelID, leftVolume, rightVolume, priority, loop, rate); - return channelID; -} - -SoundChannel* SoundPool::allocateChannel(int priority) -{ - List<SoundChannel*>::iterator iter; - SoundChannel* channel = NULL; - - // allocate a channel - if (!mChannels.empty()) { - iter = mChannels.begin(); - if (priority >= (*iter)->priority()) { - channel = *iter; - mChannels.erase(iter); - LOGV("Allocated active channel"); - } - } - - // update priority and put it back in the list - if (channel) { - channel->setPriority(priority); - for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) { - if (priority < (*iter)->priority()) { - break; - } - } - mChannels.insert(iter, channel); - } - return channel; -} - -// move a channel from its current position to the front of the list -void SoundPool::moveToFront(SoundChannel* channel) -{ - for (List<SoundChannel*>::iterator iter = mChannels.begin(); iter != mChannels.end(); ++iter) { - if (*iter == channel) { - mChannels.erase(iter); - mChannels.push_front(channel); - break; - } - } -} - -void SoundPool::pause(int channelID) -{ - LOGV("pause(%d)", channelID); - Mutex::Autolock lock(&mLock); - SoundChannel* channel = findChannel(channelID); - if (channel) { - channel->pause(); - } -} - -void SoundPool::resume(int channelID) -{ - LOGV("resume(%d)", channelID); - Mutex::Autolock lock(&mLock); - SoundChannel* channel = findChannel(channelID); - if (channel) { - channel->resume(); - } -} - -void SoundPool::stop(int channelID) -{ - LOGV("stop(%d)", channelID); - Mutex::Autolock lock(&mLock); - SoundChannel* channel = findChannel(channelID); - if (channel) { - channel->stop(); - } else { - channel = findNextChannel(channelID); - if (channel) - channel->clearNextEvent(); - } -} - -void SoundPool::setVolume(int channelID, float leftVolume, float rightVolume) -{ - Mutex::Autolock lock(&mLock); - SoundChannel* channel = findChannel(channelID); - if (channel) { - channel->setVolume(leftVolume, rightVolume); - } -} - -void SoundPool::setPriority(int channelID, int priority) -{ - LOGV("setPriority(%d, %d)", channelID, priority); - Mutex::Autolock lock(&mLock); - SoundChannel* channel = findChannel(channelID); - if (channel) { - channel->setPriority(priority); - } -} - -void SoundPool::setLoop(int channelID, int loop) -{ - LOGV("setLoop(%d, %d)", channelID, loop); - Mutex::Autolock lock(&mLock); - SoundChannel* channel = findChannel(channelID); - if (channel) { - channel->setLoop(loop); - } -} - -void SoundPool::setRate(int channelID, float rate) -{ - LOGV("setRate(%d, %f)", channelID, rate); - Mutex::Autolock lock(&mLock); - SoundChannel* channel = findChannel(channelID); - if (channel) { - channel->setRate(rate); - } -} - -// call with lock held -void SoundPool::done(SoundChannel* channel) -{ - LOGV("done(%d)", channel->channelID()); - - // if "stolen", play next event - if (channel->nextChannelID() != 0) { - LOGV("add to restart list"); - addToRestartList(channel); - } - - // return to idle state - else { - LOGV("move to front"); - moveToFront(channel); - } -} - -void SoundPool::dump() -{ - for (int i = 0; i < mMaxChannels; ++i) { - mChannelPool[i].dump(); - } -} - - -Sample::Sample(int sampleID, const char* url) -{ - init(); - mSampleID = sampleID; - mUrl = strdup(url); - LOGV("create sampleID=%d, url=%s", mSampleID, mUrl); -} - -Sample::Sample(int sampleID, int fd, int64_t offset, int64_t length) -{ - init(); - mSampleID = sampleID; - mFd = dup(fd); - mOffset = offset; - mLength = length; - LOGV("create sampleID=%d, fd=%d, offset=%lld, length=%lld", mSampleID, mFd, mLength, mOffset); -} - -void Sample::init() -{ - mData = 0; - mSize = 0; - mRefCount = 0; - mSampleID = 0; - mState = UNLOADED; - mFd = -1; - mOffset = 0; - mLength = 0; - mUrl = 0; -} - -Sample::~Sample() -{ - LOGV("Sample::destructor sampleID=%d, fd=%d", mSampleID, mFd); - if (mFd > 0) { - LOGV("close(%d)", mFd); - ::close(mFd); - } - mData.clear(); - delete mUrl; -} - -void Sample::doLoad() -{ - uint32_t sampleRate; - int numChannels; - int format; - sp<IMemory> p; - LOGV("Start decode"); - if (mUrl) { - p = MediaPlayer::decode(mUrl, &sampleRate, &numChannels, &format); - } else { - p = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format); - LOGV("close(%d)", mFd); - ::close(mFd); - mFd = -1; - } - if (p == 0) { - LOGE("Unable to load sample: %s", mUrl); - return; - } - LOGV("pointer = %p, size = %u, sampleRate = %u, numChannels = %d", - p->pointer(), p->size(), sampleRate, numChannels); - - if (sampleRate > kMaxSampleRate) { - LOGE("Sample rate (%u) out of range", sampleRate); - return; - } - - if ((numChannels < 1) || (numChannels > 2)) { - LOGE("Sample channel count (%d) out of range", numChannels); - return; - } - - //_dumpBuffer(p->pointer(), p->size()); - uint8_t* q = static_cast<uint8_t*>(p->pointer()) + p->size() - 10; - //_dumpBuffer(q, 10, 10, false); - - mData = p; - mSize = p->size(); - mSampleRate = sampleRate; - mNumChannels = numChannels; - mFormat = format; - mState = READY; -} - - -void SoundChannel::init(SoundPool* soundPool) -{ - mSoundPool = soundPool; -} - -void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume, - float rightVolume, int priority, int loop, float rate) -{ - AudioTrack* oldTrack; - - LOGV("play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f", - this, sample->sampleID(), nextChannelID, leftVolume, rightVolume, priority, loop, rate); - - // if not idle, this voice is being stolen - if (mState != IDLE) { - LOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID); - stop_l(); - mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate); -#ifdef USE_SHARED_MEM_BUFFER - mSoundPool->done(this); -#endif - return; - } - - // initialize track - int afFrameCount; - int afSampleRate; - int streamType = mSoundPool->streamType(); - if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { - afFrameCount = kDefaultFrameCount; - } - if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { - afSampleRate = kDefaultSampleRate; - } - int numChannels = sample->numChannels(); - uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5); - uint32_t bufferFrames = (afFrameCount * sampleRate) / afSampleRate; - uint32_t frameCount = 0; - - if (loop) { - frameCount = sample->size()/numChannels/((sample->format() == AudioSystem::PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t)); - } - - // Ensure minimum audio buffer size in case of short looped sample - if(frameCount < kDefaultBufferCount * bufferFrames) { - frameCount = kDefaultBufferCount * bufferFrames; - } - - AudioTrack* newTrack; - - // mToggle toggles each time a track is started on a given channel. - // The toggle is concatenated with the SoundChannel address and passed to AudioTrack - // as callback user data. This enables the detection of callbacks received from the old - // audio track while the new one is being started and avoids processing them with - // wrong audio audio buffer size (mAudioBufferSize) - unsigned long toggle = mToggle ^ 1; - void *userData = (void *)((unsigned long)this | toggle); - -#ifdef USE_SHARED_MEM_BUFFER - newTrack = new AudioTrack(streamType, sampleRate, sample->format(), - numChannels, sample->getIMemory(), 0, callback, userData); -#else - newTrack = new AudioTrack(streamType, sampleRate, sample->format(), - numChannels, frameCount, 0, callback, userData, bufferFrames); -#endif - if (newTrack->initCheck() != NO_ERROR) { - LOGE("Error creating AudioTrack"); - delete newTrack; - return; - } - LOGV("setVolume %p", newTrack); - newTrack->setVolume(leftVolume, rightVolume); - newTrack->setLoop(0, frameCount, loop); - - { - Mutex::Autolock lock(&mLock); - // From now on, AudioTrack callbacks recevieved with previous toggle value will be ignored. - mToggle = toggle; - oldTrack = mAudioTrack; - mAudioTrack = newTrack; - mPos = 0; - mSample = sample; - mChannelID = nextChannelID; - mPriority = priority; - mLoop = loop; - mLeftVolume = leftVolume; - mRightVolume = rightVolume; - mNumChannels = numChannels; - mRate = rate; - clearNextEvent(); - mState = PLAYING; - mAudioTrack->start(); - mAudioBufferSize = newTrack->frameCount()*newTrack->frameSize(); - } - - LOGV("delete oldTrack %p", oldTrack); - delete oldTrack; -} - -void SoundChannel::nextEvent() -{ - sp<Sample> sample; - int nextChannelID; - float leftVolume; - float rightVolume; - int priority; - int loop; - float rate; - - // check for valid event - { - Mutex::Autolock lock(&mLock); - nextChannelID = mNextEvent.channelID(); - if (nextChannelID == 0) { - LOGV("stolen channel has no event"); - return; - } - - sample = mNextEvent.sample(); - leftVolume = mNextEvent.leftVolume(); - rightVolume = mNextEvent.rightVolume(); - priority = mNextEvent.priority(); - loop = mNextEvent.loop(); - rate = mNextEvent.rate(); - } - - LOGV("Starting stolen channel %d -> %d", channelID(), nextChannelID); - play(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate); -} - -void SoundChannel::callback(int event, void* user, void *info) -{ - unsigned long toggle = (unsigned long)user & 1; - SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1)); - - if (channel->mToggle != toggle) { - LOGV("callback with wrong toggle"); - return; - } - channel->process(event, info); -} - -void SoundChannel::process(int event, void *info) -{ - //LOGV("process(%d)", mChannelID); - sp<Sample> sample = mSample; - -// LOGV("SoundChannel::process event %d", event); - - if (event == AudioTrack::EVENT_MORE_DATA) { - AudioTrack::Buffer* b = static_cast<AudioTrack::Buffer *>(info); - - // check for stop state - if (b->size == 0) return; - - if (sample != 0) { - // fill buffer - uint8_t* q = (uint8_t*) b->i8; - size_t count = 0; - - if (mPos < (int)sample->size()) { - uint8_t* p = sample->data() + mPos; - count = sample->size() - mPos; - if (count > b->size) { - count = b->size; - } - memcpy(q, p, count); - LOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size, count); - } else if (mPos < mAudioBufferSize) { - count = mAudioBufferSize - mPos; - if (count > b->size) { - count = b->size; - } - memset(q, 0, count); - LOGV("fill extra: q=%p, mPos=%u, b->size=%u, count=%d", q, mPos, b->size, count); - } - - mPos += count; - b->size = count; - //LOGV("buffer=%p, [0]=%d", b->i16, b->i16[0]); - } - } else if (event == AudioTrack::EVENT_UNDERRUN) { - LOGV("stopping track"); - stop(); - } else if (event == AudioTrack::EVENT_LOOP_END) { - LOGV("End loop: %d", *(int *)info); - } -} - - -// call with lock held -void SoundChannel::stop_l() -{ - if (mState != IDLE) { - setVolume_l(0, 0); - LOGV("stop"); - mAudioTrack->stop(); - mSample.clear(); - mState = IDLE; - mPriority = IDLE_PRIORITY; - } -} - -void SoundChannel::stop() -{ - { - Mutex::Autolock lock(&mLock); - stop_l(); - } - mSoundPool->done(this); -} - -//FIXME: Pause is a little broken right now -void SoundChannel::pause() -{ - Mutex::Autolock lock(&mLock); - if (mState == PLAYING) { - LOGV("pause track"); - mState = PAUSED; - mAudioTrack->pause(); - } -} - -void SoundChannel::resume() -{ - Mutex::Autolock lock(&mLock); - if (mState == PAUSED) { - LOGV("resume track"); - mState = PLAYING; - mAudioTrack->start(); - } -} - -void SoundChannel::setRate(float rate) -{ - Mutex::Autolock lock(&mLock); - if (mAudioTrack != 0 && mSample.get() != 0) { - uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5); - mAudioTrack->setSampleRate(sampleRate); - mRate = rate; - } -} - -// call with lock held -void SoundChannel::setVolume_l(float leftVolume, float rightVolume) -{ - mLeftVolume = leftVolume; - mRightVolume = rightVolume; - if (mAudioTrack != 0) mAudioTrack->setVolume(leftVolume, rightVolume); -} - -void SoundChannel::setVolume(float leftVolume, float rightVolume) -{ - Mutex::Autolock lock(&mLock); - setVolume_l(leftVolume, rightVolume); -} - -void SoundChannel::setLoop(int loop) -{ - Mutex::Autolock lock(&mLock); - if (mAudioTrack != 0 && mSample.get() != 0) { - mAudioTrack->setLoop(0, mSample->size()/mNumChannels/((mSample->format() == AudioSystem::PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t)), loop); - mLoop = loop; - } -} - -SoundChannel::~SoundChannel() -{ - LOGV("SoundChannel destructor"); - if (mAudioTrack) { - LOGV("stop track"); - mAudioTrack->stop(); - delete mAudioTrack; - } - clearNextEvent(); - mSample.clear(); -} - -void SoundChannel::dump() -{ - LOGV("mState = %d mChannelID=%d, mNumChannels=%d, mPos = %d, mPriority=%d, mLoop=%d", - mState, mChannelID, mNumChannels, mPos, mPriority, mLoop); -} - -void SoundEvent::set(const sp<Sample>& sample, int channelID, float leftVolume, - float rightVolume, int priority, int loop, float rate) -{ - mSample =sample; - mChannelID = channelID; - mLeftVolume = leftVolume; - mRightVolume = rightVolume; - mPriority = priority; - mLoop = loop; - mRate =rate; -} - -} // end namespace android - diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h deleted file mode 100644 index 7802781..0000000 --- a/media/jni/soundpool/SoundPool.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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 <cutils/atomic.h> - -#include <nativehelper/jni.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; -}; - -// JNI for calling back Java SoundPool object -extern void android_soundpool_SoundPool_notify(jobject ref, const SoundPoolEvent *event); - -// tracks samples used by application -class Sample : public RefBase { -public: - enum sample_state { UNLOADED, LOADING, READY, UNLOADING }; - Sample(int sampleID, const char* url); - Sample(int sampleID, int fd, int64_t offset, int64_t length); - ~Sample(); - int sampleID() { return mSampleID; } - int numChannels() { return mNumChannels; } - int sampleRate() { return mSampleRate; } - int format() { return mFormat; } - size_t size() { return mSize; } - int state() { return mState; } - uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); } - void doLoad(); - void startLoad() { mState = LOADING; } - sp<IMemory> getIMemory() { return mData; } - - // hack - void init(int numChannels, int sampleRate, int format, size_t size, sp<IMemory> data ) { - mNumChannels = numChannels; mSampleRate = sampleRate; mFormat = format; mSize = size; mData = data; } - -private: - void init(); - - size_t mSize; - volatile int32_t mRefCount; - uint16_t mSampleID; - uint16_t mSampleRate; - uint8_t mState : 3; - uint8_t mNumChannels : 2; - uint8_t mFormat : 2; - int mFd; - int64_t mOffset; - int64_t mLength; - char* mUrl; - sp<IMemory> mData; -}; - -// 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() : mAudioTrack(0), mState(IDLE), mNumChannels(1), mPos(0), mToggle(0) {} - ~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 resume(); - 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); - - SoundPool* mSoundPool; - AudioTrack* mAudioTrack; - SoundEvent mNextEvent; - Mutex mLock; - int mState; - int mNumChannels; - int mPos; - int mAudioBufferSize; - unsigned long mToggle; -}; - -// application object for managing a pool of sounds -class SoundPool { - friend class SoundPoolThread; - friend class SoundChannel; -public: - SoundPool(jobject soundPoolRef, int maxChannels, int streamType, int srcQuality); - ~SoundPool(); - int load(const char* url, int priority); - 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 resume(int channelID); - 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); - int streamType() const { return mStreamType; } - int srcQuality() const { return mSrcQuality; } - - // called from SoundPoolThread - void sampleLoaded(int sampleID); - - // called from AudioTrack thread - void done(SoundChannel* channel); - -private: - SoundPool() {} // no default constructor - bool startThreads(); - void doLoad(sp<Sample>& sample); - inline void notify(const SoundPoolEvent* event) { - android_soundpool_SoundPool_notify(mSoundPoolRef, event); - } - sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); } - SoundChannel* findChannel (int channelID); - SoundChannel* findNextChannel (int channelID); - SoundChannel* allocateChannel(int priority); - void moveToFront(SoundChannel* channel); - void dump(); - - // restart thread - void addToRestartList(SoundChannel* channel); - static int beginThread(void* arg); - int run(); - void quit(); - - jobject mSoundPoolRef; - Mutex mLock; - Condition mCondition; - SoundPoolThread* mDecodeThread; - SoundChannel* mChannelPool; - List<SoundChannel*> mChannels; - List<SoundChannel*> mRestart; - DefaultKeyedVector< int, sp<Sample> > mSamples; - int mMaxChannels; - int mStreamType; - int mSrcQuality; - int mAllocated; - int mNextSampleID; - int mNextChannelID; - bool mQuit; -}; - -} // end namespace android - -#endif /*SOUNDPOOL_H_*/ diff --git a/media/jni/soundpool/SoundPoolThread.cpp b/media/jni/soundpool/SoundPoolThread.cpp deleted file mode 100644 index 4e6798d..0000000 --- a/media/jni/soundpool/SoundPoolThread.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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::MessageQueue::write(SoundPoolMsg msg) { - LOGV("MessageQueue::write - acquiring lock\n"); - Mutex::Autolock lock(&mLock); - while (mQueue.size() >= maxMessages) { - LOGV("MessageQueue::write - wait\n"); - mCondition.wait(mLock); - } - LOGV("MessageQueue::write - push message\n"); - mQueue.push(msg); - mCondition.signal(); -} - -const SoundPoolMsg SoundPoolThread::MessageQueue::read() { - LOGV("MessageQueue::read - acquiring lock\n"); - Mutex::Autolock lock(&mLock); - while (mQueue.size() == 0) { - LOGV("MessageQueue::read - wait\n"); - mCondition.wait(mLock); - } - SoundPoolMsg msg = mQueue[0]; - LOGV("MessageQueue::read - retrieve message\n"); - mQueue.removeAt(0); - mCondition.signal(); - return msg; -} - -void SoundPoolThread::MessageQueue::quit() { - Mutex::Autolock lock(&mLock); - mQueue.clear(); - mQueue.push(SoundPoolMsg(SoundPoolMsg::KILL, 0)); - mCondition.signal(); - mCondition.wait(mLock); - LOGV("return from quit"); -} - -SoundPoolThread::SoundPoolThread(SoundPool* soundPool) : - mSoundPool(soundPool) -{ - mMessages.setCapacity(maxMessages); - createThread(beginThread, this); -} - -SoundPoolThread::~SoundPoolThread() -{ -} - -int SoundPoolThread::beginThread(void* arg) { - LOGV("beginThread"); - SoundPoolThread* soundPoolThread = (SoundPoolThread*)arg; - return soundPoolThread->run(); -} - -int SoundPoolThread::run() { - LOGV("run"); - for (;;) { - SoundPoolMsg msg = mMessages.read(); - LOGV("Got message m=%d, mData=%d", msg.mMessageType, msg.mData); - switch (msg.mMessageType) { - case SoundPoolMsg::KILL: - LOGV("goodbye"); - return NO_ERROR; - case SoundPoolMsg::LOAD_SAMPLE: - doLoadSample(msg.mData); - break; - default: - LOGW("run: Unrecognized message %d\n", - msg.mMessageType); - break; - } - } -} - -void SoundPoolThread::loadSample(int sampleID) { - mMessages.write(SoundPoolMsg(SoundPoolMsg::LOAD_SAMPLE, sampleID)); -} - -void SoundPoolThread::doLoadSample(int sampleID) { - sp <Sample> sample = mSoundPool->findSample(sampleID); - if (sample != 0) { - sample->doLoad(); - } -} - -} // end namespace android diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h deleted file mode 100644 index 459a764..0000000 --- a/media/jni/soundpool/SoundPoolThread.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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, PLAY_SAMPLE, SAMPLE_DONE }; - SoundPoolMsg() : mMessageType(INVALID), mData(0) {} - SoundPoolMsg(MessageType MessageType, int data) : - mMessageType(MessageType), mData(data) {} - uint8_t mMessageType; - uint8_t mData; - uint8_t mData2; - uint8_t mData3; -}; - -/* - * This class handles background requests from the SoundPool - */ -class SoundPoolThread { -public: - SoundPoolThread(SoundPool* SoundPool); - ~SoundPoolThread(); - void loadSample(int sampleID); - void quit() { mMessages.quit(); } - -private: - static const size_t maxMessages = 5; - - class MessageQueue { - public: - void write(SoundPoolMsg msg); - const SoundPoolMsg read(); - void setCapacity(size_t size) { mQueue.setCapacity(size); } - void quit(); - private: - Vector<SoundPoolMsg> mQueue; - Mutex mLock; - Condition mCondition; - }; - - static int beginThread(void* arg); - int run(); - void doLoadSample(int sampleID); - - SoundPool* mSoundPool; - MessageQueue mMessages; -}; - -} // end namespace android - -#endif /*SOUNDPOOLTHREAD_H_*/ diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp deleted file mode 100644 index 0ce2d6f..0000000 --- a/media/jni/soundpool/android_media_SoundPool.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#include <stdio.h> - -//#define LOG_NDEBUG 0 -#define LOG_TAG "SoundPool" - -#include <utils/Log.h> -#include <nativehelper/jni.h> -#include <nativehelper/JNIHelp.h> -#include <android_runtime/AndroidRuntime.h> -#include "SoundPool.h" - -using namespace android; - -static struct fields_t { - jfieldID mNativeContext; - jclass mSoundPoolClass; -} fields; - -static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) { - return (SoundPool*)env->GetIntField(thiz, fields.mNativeContext); -} - -// ---------------------------------------------------------------------------- -static int -android_media_SoundPool_load_URL(JNIEnv *env, jobject thiz, jstring path, jint priority) -{ - LOGV("android_media_SoundPool_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 id; -} - -static int -android_media_SoundPool_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor, - jlong offset, jlong length, jint priority) -{ - LOGV("android_media_SoundPool_load_FD"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return 0; - return ap->load(getParcelFileDescriptorFD(env, fileDescriptor), - int64_t(offset), int64_t(length), int(priority)); -} - -static bool -android_media_SoundPool_unload(JNIEnv *env, jobject thiz, jint sampleID) { - LOGV("android_media_SoundPool_unload\n"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return 0; - return ap->unload(sampleID); -} - -static int -android_media_SoundPool_play(JNIEnv *env, jobject thiz, jint sampleID, - jfloat leftVolume, jfloat rightVolume, jint priority, jint loop, - jfloat rate) -{ - LOGV("android_media_SoundPool_play\n"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return 0; - return ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate); -} - -static void -android_media_SoundPool_pause(JNIEnv *env, jobject thiz, jint channelID) -{ - LOGV("android_media_SoundPool_pause"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->pause(channelID); -} - -static void -android_media_SoundPool_resume(JNIEnv *env, jobject thiz, jint channelID) -{ - LOGV("android_media_SoundPool_resume"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->resume(channelID); -} - -static void -android_media_SoundPool_stop(JNIEnv *env, jobject thiz, jint channelID) -{ - LOGV("android_media_SoundPool_stop"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->stop(channelID); -} - -static void -android_media_SoundPool_setVolume(JNIEnv *env, jobject thiz, jint channelID, - float leftVolume, float rightVolume) -{ - LOGV("android_media_SoundPool_setVolume"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->setVolume(channelID, leftVolume, rightVolume); -} - -static void -android_media_SoundPool_setPriority(JNIEnv *env, jobject thiz, jint channelID, - int priority) -{ - LOGV("android_media_SoundPool_setPriority"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->setPriority(channelID, priority); -} - -static void -android_media_SoundPool_setLoop(JNIEnv *env, jobject thiz, jint channelID, - int loop) -{ - LOGV("android_media_SoundPool_setLoop"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->setLoop(channelID, loop); -} - -static void -android_media_SoundPool_setRate(JNIEnv *env, jobject thiz, jint channelID, - float rate) -{ - LOGV("android_media_SoundPool_setRate"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->setRate(channelID, rate); -} - -static void -android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, - jobject weak_this, jint maxChannels, jint streamType, jint srcQuality) -{ - LOGV("android_media_SoundPool_native_setup"); - SoundPool *ap = new SoundPool(weak_this, maxChannels, streamType, srcQuality); - if (ap == NULL) { - jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); - return; - } - - // save pointer to SoundPool C++ object in opaque field in Java object - env->SetIntField(thiz, fields.mNativeContext, (int)ap); -} - -static void -android_media_SoundPool_release(JNIEnv *env, jobject thiz) -{ - LOGV("android_media_SoundPool_release"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap != NULL) { - env->SetIntField(thiz, fields.mNativeContext, 0); - delete ap; - } -} - -// ---------------------------------------------------------------------------- - -// Dalvik VM type signatures -static JNINativeMethod gMethods[] = { - { "_load", - "(Ljava/lang/String;I)I", - (void *)android_media_SoundPool_load_URL - }, - { "_load", - "(Ljava/io/FileDescriptor;JJI)I", - (void *)android_media_SoundPool_load_FD - }, - { "unload", - "(I)Z", - (void *)android_media_SoundPool_unload - }, - { "play", - "(IFFIIF)I", - (void *)android_media_SoundPool_play - }, - { "pause", - "(I)V", - (void *)android_media_SoundPool_pause - }, - { "resume", - "(I)V", - (void *)android_media_SoundPool_resume - }, - { "stop", - "(I)V", - (void *)android_media_SoundPool_stop - }, - { "setVolume", - "(IFF)V", - (void *)android_media_SoundPool_setVolume - }, - { "setPriority", - "(II)V", - (void *)android_media_SoundPool_setPriority - }, - { "setLoop", - "(II)V", - (void *)android_media_SoundPool_setLoop - }, - { "setRate", - "(IF)V", - (void *)android_media_SoundPool_setRate - }, - { "native_setup", - "(Ljava/lang/Object;III)V", - (void*)android_media_SoundPool_native_setup - }, - { "release", - "()V", - (void*)android_media_SoundPool_release - } -}; - -static const char* const kClassPathName = "android/media/SoundPool"; - -jint JNI_OnLoad(JavaVM* vm, void* reserved) -{ - JNIEnv* env = NULL; - jint result = -1; - jclass clazz; - - if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { - LOGE("ERROR: GetEnv failed\n"); - goto bail; - } - assert(env != NULL); - - clazz = env->FindClass(kClassPathName); - if (clazz == NULL) { - LOGE("Can't find %s", kClassPathName); - goto bail; - } - - fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "I"); - if (fields.mNativeContext == NULL) { - LOGE("Can't find SoundPool.mNativeContext"); - goto bail; - } - - if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0) - goto bail; - - /* success -- return valid version number */ - result = JNI_VERSION_1_4; - -bail: - return result; -} |
