diff options
Diffstat (limited to 'media/jni')
-rw-r--r-- | media/jni/soundpool/Android.mk | 8 | ||||
-rw-r--r-- | media/jni/soundpool/SoundPool.cpp | 908 | ||||
-rw-r--r-- | media/jni/soundpool/SoundPool.h | 238 | ||||
-rw-r--r-- | media/jni/soundpool/SoundPoolThread.cpp | 114 | ||||
-rw-r--r-- | media/jni/soundpool/SoundPoolThread.h | 66 | ||||
-rw-r--r-- | media/jni/soundpool/android_media_SoundPool.cpp | 2 |
6 files changed, 5 insertions, 1331 deletions
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk index 98d6449..70dbfb3 100644 --- a/media/jni/soundpool/Android.mk +++ b/media/jni/soundpool/Android.mk @@ -2,14 +2,14 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - android_media_SoundPool.cpp \ - SoundPool.cpp \ - SoundPoolThread.cpp + android_media_SoundPool.cpp + +LOCAL_C_INCLUDES := \ + frameworks/base/media/libmedia LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ - libbinder \ libandroid_runtime \ libnativehelper \ libmedia \ diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp deleted file mode 100644 index 5aed8a1..0000000 --- a/media/jni/soundpool/SoundPool.cpp +++ /dev/null @@ -1,908 +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 <media/AudioTrack.h> -#include <media/mediaplayer.h> - -#include <system/audio.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(int maxChannels, audio_stream_type_t streamType, int srcQuality) -{ - ALOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d", - maxChannels, streamType, srcQuality); - - // check limits - mMaxChannels = maxChannels; - if (mMaxChannels < 1) { - mMaxChannels = 1; - } - else if (mMaxChannels > 32) { - mMaxChannels = 32; - } - ALOGW_IF(maxChannels != mMaxChannels, "App requested %d channels", maxChannels); - - mQuit = false; - mDecodeThread = 0; - mStreamType = streamType; - mSrcQuality = srcQuality; - mAllocated = 0; - mNextSampleID = 0; - mNextChannelID = 0; - - mCallback = 0; - mUserData = 0; - - mChannelPool = new SoundChannel[mMaxChannels]; - for (int i = 0; i < mMaxChannels; ++i) { - mChannelPool[i].init(this); - mChannels.push_back(&mChannelPool[i]); - } - - // start decode thread - startThreads(); -} - -SoundPool::~SoundPool() -{ - ALOGV("SoundPool destructor"); - mDecodeThread->quit(); - quit(); - - Mutex::Autolock lock(&mLock); - - mChannels.clear(); - if (mChannelPool) - delete [] mChannelPool; - // clean up samples - ALOGV("clear samples"); - mSamples.clear(); - - if (mDecodeThread) - delete mDecodeThread; -} - -void SoundPool::addToRestartList(SoundChannel* channel) -{ - Mutex::Autolock lock(&mRestartLock); - if (!mQuit) { - mRestart.push_back(channel); - mCondition.signal(); - } -} - -void SoundPool::addToStopList(SoundChannel* channel) -{ - Mutex::Autolock lock(&mRestartLock); - if (!mQuit) { - mStop.push_back(channel); - mCondition.signal(); - } -} - -int SoundPool::beginThread(void* arg) -{ - SoundPool* p = (SoundPool*)arg; - return p->run(); -} - -int SoundPool::run() -{ - mRestartLock.lock(); - while (!mQuit) { - mCondition.wait(mRestartLock); - ALOGV("awake"); - if (mQuit) break; - - while (!mStop.empty()) { - SoundChannel* channel; - ALOGV("Getting channel from stop list"); - List<SoundChannel* >::iterator iter = mStop.begin(); - channel = *iter; - mStop.erase(iter); - mRestartLock.unlock(); - if (channel != 0) { - Mutex::Autolock lock(&mLock); - channel->stop(); - } - mRestartLock.lock(); - if (mQuit) break; - } - - while (!mRestart.empty()) { - SoundChannel* channel; - ALOGV("Getting channel from list"); - List<SoundChannel*>::iterator iter = mRestart.begin(); - channel = *iter; - mRestart.erase(iter); - mRestartLock.unlock(); - if (channel != 0) { - Mutex::Autolock lock(&mLock); - channel->nextEvent(); - } - mRestartLock.lock(); - if (mQuit) break; - } - } - - mStop.clear(); - mRestart.clear(); - mCondition.signal(); - mRestartLock.unlock(); - ALOGV("goodbye"); - return 0; -} - -void SoundPool::quit() -{ - mRestartLock.lock(); - mQuit = true; - mCondition.signal(); - mCondition.wait(mRestartLock); - ALOGV("return from quit"); - mRestartLock.unlock(); -} - -bool SoundPool::startThreads() -{ - createThreadEtc(beginThread, this, "SoundPool"); - 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) -{ - ALOGV("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) -{ - ALOGV("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) -{ - ALOGV("doLoad: loading sample sampleID=%d", sample->sampleID()); - sample->startLoad(); - mDecodeThread->loadSample(sample->sampleID()); -} - -bool SoundPool::unload(int sampleID) -{ - ALOGV("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) -{ - ALOGV("play 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; - - Mutex::Autolock lock(&mLock); - - if (mQuit) { - return 0; - } - // is sample ready? - sample = findSample(sampleID); - if ((sample == 0) || (sample->state() != Sample::READY)) { - ALOGW(" sample %d not READY", sampleID); - return 0; - } - - dump(); - - // allocate a channel - channel = allocateChannel_l(priority); - - // no channel allocated - return 0 - if (!channel) { - ALOGV("No channel allocated"); - return 0; - } - - channelID = ++mNextChannelID; - - ALOGV("play channel %p state = %d", channel, channel->state()); - channel->play(sample, channelID, leftVolume, rightVolume, priority, loop, rate); - return channelID; -} - -SoundChannel* SoundPool::allocateChannel_l(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); - ALOGV("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_l(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) -{ - ALOGV("pause(%d)", channelID); - Mutex::Autolock lock(&mLock); - SoundChannel* channel = findChannel(channelID); - if (channel) { - channel->pause(); - } -} - -void SoundPool::autoPause() -{ - ALOGV("autoPause()"); - Mutex::Autolock lock(&mLock); - for (int i = 0; i < mMaxChannels; ++i) { - SoundChannel* channel = &mChannelPool[i]; - channel->autoPause(); - } -} - -void SoundPool::resume(int channelID) -{ - ALOGV("resume(%d)", channelID); - Mutex::Autolock lock(&mLock); - SoundChannel* channel = findChannel(channelID); - if (channel) { - channel->resume(); - } -} - -void SoundPool::autoResume() -{ - ALOGV("autoResume()"); - Mutex::Autolock lock(&mLock); - for (int i = 0; i < mMaxChannels; ++i) { - SoundChannel* channel = &mChannelPool[i]; - channel->autoResume(); - } -} - -void SoundPool::stop(int channelID) -{ - ALOGV("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) -{ - ALOGV("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) -{ - ALOGV("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) -{ - ALOGV("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_l(SoundChannel* channel) -{ - ALOGV("done_l(%d)", channel->channelID()); - // if "stolen", play next event - if (channel->nextChannelID() != 0) { - ALOGV("add to restart list"); - addToRestartList(channel); - } - - // return to idle state - else { - ALOGV("move to front"); - moveToFront_l(channel); - } -} - -void SoundPool::setCallback(SoundPoolCallback* callback, void* user) -{ - Mutex::Autolock lock(&mCallbackLock); - mCallback = callback; - mUserData = user; -} - -void SoundPool::notify(SoundPoolEvent event) -{ - Mutex::Autolock lock(&mCallbackLock); - if (mCallback != NULL) { - mCallback(event, this, mUserData); - } -} - -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); - ALOGV("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; - ALOGV("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() -{ - ALOGV("Sample::destructor sampleID=%d, fd=%d", mSampleID, mFd); - if (mFd > 0) { - ALOGV("close(%d)", mFd); - ::close(mFd); - } - mData.clear(); - delete mUrl; -} - -status_t Sample::doLoad() -{ - uint32_t sampleRate; - int numChannels; - audio_format_t format; - sp<IMemory> p; - ALOGV("Start decode"); - if (mUrl) { - p = MediaPlayer::decode(mUrl, &sampleRate, &numChannels, &format); - } else { - p = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format); - ALOGV("close(%d)", mFd); - ::close(mFd); - mFd = -1; - } - if (p == 0) { - ALOGE("Unable to load sample: %s", mUrl); - return -1; - } - ALOGV("pointer = %p, size = %u, sampleRate = %u, numChannels = %d", - p->pointer(), p->size(), sampleRate, numChannels); - - if (sampleRate > kMaxSampleRate) { - ALOGE("Sample rate (%u) out of range", sampleRate); - return - 1; - } - - if ((numChannels < 1) || (numChannels > 2)) { - ALOGE("Sample channel count (%d) out of range", numChannels); - return - 1; - } - - //_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; - return 0; -} - - -void SoundChannel::init(SoundPool* soundPool) -{ - mSoundPool = soundPool; -} - -// call with sound pool lock held -void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume, - float rightVolume, int priority, int loop, float rate) -{ - AudioTrack* oldTrack; - AudioTrack* newTrack; - status_t status; - - { // scope for the lock - Mutex::Autolock lock(&mLock); - - ALOGV("SoundChannel::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) { - ALOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID); - mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate); - stop_l(); - return; - } - - // initialize track - int afFrameCount; - int afSampleRate; - audio_stream_type_t 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 totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate; - uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount; - uint32_t frameCount = 0; - - if (loop) { - frameCount = sample->size()/numChannels/ - ((sample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t)); - } - -#ifndef USE_SHARED_MEM_BUFFER - // Ensure minimum audio buffer size in case of short looped sample - if(frameCount < totalFrames) { - frameCount = totalFrames; - } -#endif - - // 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); - uint32_t channels = (numChannels == 2) ? - AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO; - - // do not create a new audio track if current track is compatible with sample parameters -#ifdef USE_SHARED_MEM_BUFFER - newTrack = new AudioTrack(streamType, sampleRate, sample->format(), - channels, sample->getIMemory(), AUDIO_POLICY_OUTPUT_FLAG_NONE, callback, userData); -#else - newTrack = new AudioTrack(streamType, sampleRate, sample->format(), - channels, frameCount, AUDIO_POLICY_OUTPUT_FLAG_NONE, callback, userData, - bufferFrames); -#endif - oldTrack = mAudioTrack; - status = newTrack->initCheck(); - if (status != NO_ERROR) { - ALOGE("Error creating AudioTrack"); - goto exit; - } - ALOGV("setVolume %p", newTrack); - newTrack->setVolume(leftVolume, rightVolume); - newTrack->setLoop(0, frameCount, loop); - - // From now on, AudioTrack callbacks received with previous toggle value will be ignored. - mToggle = toggle; - 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(); - } - -exit: - ALOGV("delete oldTrack %p", oldTrack); - delete oldTrack; - if (status != NO_ERROR) { - delete newTrack; - mAudioTrack = NULL; - } -} - -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) { - ALOGV("stolen channel has no event"); - return; - } - - sample = mNextEvent.sample(); - leftVolume = mNextEvent.leftVolume(); - rightVolume = mNextEvent.rightVolume(); - priority = mNextEvent.priority(); - loop = mNextEvent.loop(); - rate = mNextEvent.rate(); - } - - ALOGV("Starting stolen channel %d -> %d", channelID(), nextChannelID); - play(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate); -} - -void SoundChannel::callback(int event, void* user, void *info) -{ - SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1)); - - channel->process(event, info, (unsigned long)user & 1); -} - -void SoundChannel::process(int event, void *info, unsigned long toggle) -{ - //ALOGV("process(%d)", mChannelID); - - Mutex::Autolock lock(&mLock); - - AudioTrack::Buffer* b = NULL; - if (event == AudioTrack::EVENT_MORE_DATA) { - b = static_cast<AudioTrack::Buffer *>(info); - } - - if (mToggle != toggle) { - ALOGV("process wrong toggle %p channel %d", this, mChannelID); - if (b != NULL) { - b->size = 0; - } - return; - } - - sp<Sample> sample = mSample; - -// ALOGV("SoundChannel::process event %d", event); - - if (event == AudioTrack::EVENT_MORE_DATA) { - - // check for stop state - if (b->size == 0) return; - - if (mState == IDLE) { - 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); -// ALOGV("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); -// ALOGV("fill extra: q=%p, mPos=%u, b->size=%u, count=%d", q, mPos, b->size, count); - } - - mPos += count; - b->size = count; - //ALOGV("buffer=%p, [0]=%d", b->i16, b->i16[0]); - } - } else if (event == AudioTrack::EVENT_UNDERRUN) { - ALOGV("process %p channel %d EVENT_UNDERRUN", this, mChannelID); - mSoundPool->addToStopList(this); - } else if (event == AudioTrack::EVENT_LOOP_END) { - ALOGV("End loop %p channel %d count %d", this, mChannelID, *(int *)info); - } -} - - -// call with lock held -bool SoundChannel::doStop_l() -{ - if (mState != IDLE) { - setVolume_l(0, 0); - ALOGV("stop"); - mAudioTrack->stop(); - mSample.clear(); - mState = IDLE; - mPriority = IDLE_PRIORITY; - return true; - } - return false; -} - -// call with lock held and sound pool lock held -void SoundChannel::stop_l() -{ - if (doStop_l()) { - mSoundPool->done_l(this); - } -} - -// call with sound pool lock held -void SoundChannel::stop() -{ - bool stopped; - { - Mutex::Autolock lock(&mLock); - stopped = doStop_l(); - } - - if (stopped) { - mSoundPool->done_l(this); - } -} - -//FIXME: Pause is a little broken right now -void SoundChannel::pause() -{ - Mutex::Autolock lock(&mLock); - if (mState == PLAYING) { - ALOGV("pause track"); - mState = PAUSED; - mAudioTrack->pause(); - } -} - -void SoundChannel::autoPause() -{ - Mutex::Autolock lock(&mLock); - if (mState == PLAYING) { - ALOGV("pause track"); - mState = PAUSED; - mAutoPaused = true; - mAudioTrack->pause(); - } -} - -void SoundChannel::resume() -{ - Mutex::Autolock lock(&mLock); - if (mState == PAUSED) { - ALOGV("resume track"); - mState = PLAYING; - mAutoPaused = false; - mAudioTrack->start(); - } -} - -void SoundChannel::autoResume() -{ - Mutex::Autolock lock(&mLock); - if (mAutoPaused && (mState == PAUSED)) { - ALOGV("resume track"); - mState = PLAYING; - mAutoPaused = false; - mAudioTrack->start(); - } -} - -void SoundChannel::setRate(float rate) -{ - Mutex::Autolock lock(&mLock); - if (mAudioTrack != NULL && mSample != 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 != NULL) - 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 != NULL && mSample != 0) { - uint32_t loopEnd = mSample->size()/mNumChannels/ - ((mSample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t)); - mAudioTrack->setLoop(0, loopEnd, loop); - mLoop = loop; - } -} - -SoundChannel::~SoundChannel() -{ - ALOGV("SoundChannel destructor %p", this); - { - Mutex::Autolock lock(&mLock); - clearNextEvent(); - doStop_l(); - } - // do not call AudioTrack destructor with mLock held as it will wait for the AudioTrack - // callback thread to exit which may need to execute process() and acquire the mLock. - delete mAudioTrack; -} - -void SoundChannel::dump() -{ - ALOGV("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 002b045..0000000 --- a/media/jni/soundpool/SoundPool.h +++ /dev/null @@ -1,238 +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> - -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, 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; } - 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; } - - // hack - void init(int numChannels, int sampleRate, audio_format_t 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; - audio_format_t mFormat; - 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(NULL), 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; - 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, audio_stream_type_t 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 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); - audio_stream_type_t streamType() const { return mStreamType; } - int srcQuality() const { return mSrcQuality; } - - // 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_stream_type_t mStreamType; - int mSrcQuality; - int mAllocated; - int mNextSampleID; - int mNextChannelID; - bool mQuit; - - // callback - Mutex mCallbackLock; - SoundPoolCallback* mCallback; - void* mUserData; -}; - -} // 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 ba3b482..0000000 --- a/media/jni/soundpool/SoundPoolThread.cpp +++ /dev/null @@ -1,114 +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::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 diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h deleted file mode 100644 index d388388..0000000 --- a/media/jni/soundpool/SoundPoolThread.h +++ /dev/null @@ -1,66 +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 }; - 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_*/ diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp index da3af9d..c6dee06 100644 --- a/media/jni/soundpool/android_media_SoundPool.cpp +++ b/media/jni/soundpool/android_media_SoundPool.cpp @@ -23,7 +23,7 @@ #include <nativehelper/jni.h> #include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> -#include "SoundPool.h" +#include <SoundPool.h> using namespace android; |