1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SOUNDPOOL_H_ 18 #define SOUNDPOOL_H_ 19 20 #include <utils/threads.h> 21 #include <utils/List.h> 22 #include <utils/Vector.h> 23 #include <utils/KeyedVector.h> 24 #include <media/AudioTrack.h> 25 #include <cutils/atomic.h> 26 27 #include <nativehelper/jni.h> 28 29 namespace android { 30 31 static const int IDLE_PRIORITY = -1; 32 33 // forward declarations 34 class SoundEvent; 35 class SoundPoolThread; 36 class SoundPool; 37 38 // for queued events 39 class SoundPoolEvent { 40 public: 41 SoundPoolEvent(int msg, int arg1=0, int arg2=0) : mMsg(msg)42 mMsg(msg), mArg1(arg1), mArg2(arg2) {} 43 int mMsg; 44 int mArg1; 45 int mArg2; 46 }; 47 48 // JNI for calling back Java SoundPool object 49 extern void android_soundpool_SoundPool_notify(jobject ref, const SoundPoolEvent *event); 50 51 // tracks samples used by application 52 class Sample : public RefBase { 53 public: 54 enum sample_state { UNLOADED, LOADING, READY, UNLOADING }; 55 Sample(int sampleID, const char* url); 56 Sample(int sampleID, int fd, int64_t offset, int64_t length); 57 ~Sample(); sampleID()58 int sampleID() { return mSampleID; } numChannels()59 int numChannels() { return mNumChannels; } sampleRate()60 int sampleRate() { return mSampleRate; } format()61 int format() { return mFormat; } size()62 size_t size() { return mSize; } state()63 int state() { return mState; } data()64 uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); } 65 void doLoad(); startLoad()66 void startLoad() { mState = LOADING; } getIMemory()67 sp<IMemory> getIMemory() { return mData; } 68 69 // hack init(int numChannels,int sampleRate,int format,size_t size,sp<IMemory> data)70 void init(int numChannels, int sampleRate, int format, size_t size, sp<IMemory> data ) { 71 mNumChannels = numChannels; mSampleRate = sampleRate; mFormat = format; mSize = size; mData = data; } 72 73 private: 74 void init(); 75 76 size_t mSize; 77 volatile int32_t mRefCount; 78 uint16_t mSampleID; 79 uint16_t mSampleRate; 80 uint8_t mState : 3; 81 uint8_t mNumChannels : 2; 82 uint8_t mFormat : 2; 83 int mFd; 84 int64_t mOffset; 85 int64_t mLength; 86 char* mUrl; 87 sp<IMemory> mData; 88 }; 89 90 // stores pending events for stolen channels 91 class SoundEvent 92 { 93 public: SoundEvent()94 SoundEvent() : mChannelID(0), mLeftVolume(0), mRightVolume(0), 95 mPriority(IDLE_PRIORITY), mLoop(0), mRate(0) {} 96 void set(const sp<Sample>& sample, int channelID, float leftVolume, 97 float rightVolume, int priority, int loop, float rate); sample()98 sp<Sample> sample() { return mSample; } channelID()99 int channelID() { return mChannelID; } leftVolume()100 float leftVolume() { return mLeftVolume; } rightVolume()101 float rightVolume() { return mRightVolume; } priority()102 int priority() { return mPriority; } loop()103 int loop() { return mLoop; } rate()104 float rate() { return mRate; } clear()105 void clear() { mChannelID = 0; mSample.clear(); } 106 107 protected: 108 sp<Sample> mSample; 109 int mChannelID; 110 float mLeftVolume; 111 float mRightVolume; 112 int mPriority; 113 int mLoop; 114 float mRate; 115 }; 116 117 // for channels aka AudioTracks 118 class SoundChannel : public SoundEvent { 119 public: 120 enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING }; SoundChannel()121 SoundChannel() : mAudioTrack(0), mState(IDLE), mNumChannels(1), mPos(0), mToggle(0) {} 122 ~SoundChannel(); 123 void init(SoundPool* soundPool); 124 void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume, 125 int priority, int loop, float rate); 126 void setVolume_l(float leftVolume, float rightVolume); 127 void setVolume(float leftVolume, float rightVolume); 128 void stop_l(); 129 void stop(); 130 void pause(); 131 void resume(); 132 void setRate(float rate); state()133 int state() { return mState; } setPriority(int priority)134 void setPriority(int priority) { mPriority = priority; } 135 void setLoop(int loop); numChannels()136 int numChannels() { return mNumChannels; } clearNextEvent()137 void clearNextEvent() { mNextEvent.clear(); } 138 void nextEvent(); nextChannelID()139 int nextChannelID() { return mNextEvent.channelID(); } 140 void dump(); 141 142 private: 143 static void callback(int event, void* user, void *info); 144 void process(int event, void *info); 145 146 SoundPool* mSoundPool; 147 AudioTrack* mAudioTrack; 148 SoundEvent mNextEvent; 149 Mutex mLock; 150 int mState; 151 int mNumChannels; 152 int mPos; 153 int mAudioBufferSize; 154 unsigned long mToggle; 155 }; 156 157 // application object for managing a pool of sounds 158 class SoundPool { 159 friend class SoundPoolThread; 160 friend class SoundChannel; 161 public: 162 SoundPool(jobject soundPoolRef, int maxChannels, int streamType, int srcQuality); 163 ~SoundPool(); 164 int load(const char* url, int priority); 165 int load(int fd, int64_t offset, int64_t length, int priority); 166 bool unload(int sampleID); 167 int play(int sampleID, float leftVolume, float rightVolume, int priority, 168 int loop, float rate); 169 void pause(int channelID); 170 void resume(int channelID); 171 void stop(int channelID); 172 void setVolume(int channelID, float leftVolume, float rightVolume); 173 void setPriority(int channelID, int priority); 174 void setLoop(int channelID, int loop); 175 void setRate(int channelID, float rate); streamType()176 int streamType() const { return mStreamType; } srcQuality()177 int srcQuality() const { return mSrcQuality; } 178 179 // called from SoundPoolThread 180 void sampleLoaded(int sampleID); 181 182 // called from AudioTrack thread 183 void done(SoundChannel* channel); 184 185 private: SoundPool()186 SoundPool() {} // no default constructor 187 bool startThreads(); 188 void doLoad(sp<Sample>& sample); notify(const SoundPoolEvent * event)189 inline void notify(const SoundPoolEvent* event) { 190 android_soundpool_SoundPool_notify(mSoundPoolRef, event); 191 } findSample(int sampleID)192 sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); } 193 SoundChannel* findChannel (int channelID); 194 SoundChannel* findNextChannel (int channelID); 195 SoundChannel* allocateChannel(int priority); 196 void moveToFront(SoundChannel* channel); 197 void dump(); 198 199 // restart thread 200 void addToRestartList(SoundChannel* channel); 201 static int beginThread(void* arg); 202 int run(); 203 void quit(); 204 205 jobject mSoundPoolRef; 206 Mutex mLock; 207 Mutex mRestartLock; 208 Condition mCondition; 209 SoundPoolThread* mDecodeThread; 210 SoundChannel* mChannelPool; 211 List<SoundChannel*> mChannels; 212 List<SoundChannel*> mRestart; 213 DefaultKeyedVector< int, sp<Sample> > mSamples; 214 int mMaxChannels; 215 int mStreamType; 216 int mSrcQuality; 217 int mAllocated; 218 int mNextSampleID; 219 int mNextChannelID; 220 bool mQuit; 221 }; 222 223 } // end namespace android 224 225 #endif /*SOUNDPOOL_H_*/ 226