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 namespace android { 28 29 static const int IDLE_PRIORITY = -1; 30 31 // forward declarations 32 class SoundEvent; 33 class SoundPoolThread; 34 class SoundPool; 35 36 // for queued events 37 class SoundPoolEvent { 38 public: 39 SoundPoolEvent(int msg, int arg1=0, int arg2=0) : 40 mMsg(msg), mArg1(arg1), mArg2(arg2) {} 41 int mMsg; 42 int mArg1; 43 int mArg2; 44 enum MessageType { INVALID, SAMPLE_LOADED }; 45 }; 46 47 // callback function prototype 48 typedef void SoundPoolCallback(SoundPoolEvent event, SoundPool* soundPool, void* user); 49 50 // tracks samples used by application 51 class Sample : public RefBase { 52 public: 53 enum sample_state { UNLOADED, LOADING, READY, UNLOADING }; 54 Sample(int sampleID, const char* url); 55 Sample(int sampleID, int fd, int64_t offset, int64_t length); 56 ~Sample(); 57 int sampleID() { return mSampleID; } 58 int numChannels() { return mNumChannels; } 59 int sampleRate() { return mSampleRate; } 60 int format() { return mFormat; } 61 size_t size() { return mSize; } 62 int state() { return mState; } 63 uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); } 64 status_t doLoad(); 65 void startLoad() { mState = LOADING; } 66 sp<IMemory> getIMemory() { return mData; } 67 68 // hack 69 void init(int numChannels, int sampleRate, int format, size_t size, sp<IMemory> data ) { 70 mNumChannels = numChannels; mSampleRate = sampleRate; mFormat = format; mSize = size; mData = data; } 71 72 private: 73 void init(); 74 75 size_t mSize; 76 volatile int32_t mRefCount; 77 uint16_t mSampleID; 78 uint16_t mSampleRate; 79 uint8_t mState : 3; 80 uint8_t mNumChannels : 2; 81 uint8_t mFormat : 2; 82 int mFd; 83 int64_t mOffset; 84 int64_t mLength; 85 char* mUrl; 86 sp<IMemory> mData; 87 }; 88 89 // stores pending events for stolen channels 90 class SoundEvent 91 { 92 public: 93 SoundEvent() : mChannelID(0), mLeftVolume(0), mRightVolume(0), 94 mPriority(IDLE_PRIORITY), mLoop(0), mRate(0) {} 95 void set(const sp<Sample>& sample, int channelID, float leftVolume, 96 float rightVolume, int priority, int loop, float rate); 97 sp<Sample> sample() { return mSample; } 98 int channelID() { return mChannelID; } 99 float leftVolume() { return mLeftVolume; } 100 float rightVolume() { return mRightVolume; } 101 int priority() { return mPriority; } 102 int loop() { return mLoop; } 103 float rate() { return mRate; } 104 void clear() { mChannelID = 0; mSample.clear(); } 105 106 protected: 107 sp<Sample> mSample; 108 int mChannelID; 109 float mLeftVolume; 110 float mRightVolume; 111 int mPriority; 112 int mLoop; 113 float mRate; 114 }; 115 116 // for channels aka AudioTracks 117 class SoundChannel : public SoundEvent { 118 public: 119 enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING }; 120 SoundChannel() : mAudioTrack(0), mState(IDLE), mNumChannels(1), 121 mPos(0), mToggle(0), mAutoPaused(false) {} 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 autoPause(); 132 void resume(); 133 void autoResume(); 134 void setRate(float rate); 135 int state() { return mState; } 136 void setPriority(int priority) { mPriority = priority; } 137 void setLoop(int loop); 138 int numChannels() { return mNumChannels; } 139 void clearNextEvent() { mNextEvent.clear(); } 140 void nextEvent(); 141 int nextChannelID() { return mNextEvent.channelID(); } 142 void dump(); 143 144 private: 145 static void callback(int event, void* user, void *info); 146 void process(int event, void *info); 147 148 SoundPool* mSoundPool; 149 AudioTrack* mAudioTrack; 150 SoundEvent mNextEvent; 151 Mutex mLock; 152 int mState; 153 int mNumChannels; 154 int mPos; 155 int mAudioBufferSize; 156 unsigned long mToggle; 157 bool mAutoPaused; 158 }; 159 160 // application object for managing a pool of sounds 161 class SoundPool { 162 friend class SoundPoolThread; 163 friend class SoundChannel; 164 public: 165 SoundPool(int maxChannels, int streamType, int srcQuality); 166 ~SoundPool(); 167 int load(const char* url, int priority); 168 int load(int fd, int64_t offset, int64_t length, int priority); 169 bool unload(int sampleID); 170 int play(int sampleID, float leftVolume, float rightVolume, int priority, 171 int loop, float rate); 172 void pause(int channelID); 173 void autoPause(); 174 void resume(int channelID); 175 void autoResume(); 176 void stop(int channelID); 177 void setVolume(int channelID, float leftVolume, float rightVolume); 178 void setPriority(int channelID, int priority); 179 void setLoop(int channelID, int loop); 180 void setRate(int channelID, float rate); 181 int streamType() const { return mStreamType; } 182 int srcQuality() const { return mSrcQuality; } 183 184 // called from SoundPoolThread 185 void sampleLoaded(int sampleID); 186 187 // called from AudioTrack thread 188 void done(SoundChannel* channel); 189 190 // callback function 191 void setCallback(SoundPoolCallback* callback, void* user); 192 void* getUserData() { return mUserData; } 193 194 private: 195 SoundPool() {} // no default constructor 196 bool startThreads(); 197 void doLoad(sp<Sample>& sample); 198 sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); } 199 SoundChannel* findChannel (int channelID); 200 SoundChannel* findNextChannel (int channelID); 201 SoundChannel* allocateChannel(int priority); 202 void moveToFront(SoundChannel* channel); 203 void notify(SoundPoolEvent event); 204 void dump(); 205 206 // restart thread 207 void addToRestartList(SoundChannel* channel); 208 static int beginThread(void* arg); 209 int run(); 210 void quit(); 211 212 Mutex mLock; 213 Mutex mRestartLock; 214 Condition mCondition; 215 SoundPoolThread* mDecodeThread; 216 SoundChannel* mChannelPool; 217 List<SoundChannel*> mChannels; 218 List<SoundChannel*> mRestart; 219 DefaultKeyedVector< int, sp<Sample> > mSamples; 220 int mMaxChannels; 221 int mStreamType; 222 int mSrcQuality; 223 int mAllocated; 224 int mNextSampleID; 225 int mNextChannelID; 226 bool mQuit; 227 228 // callback 229 Mutex mCallbackLock; 230 SoundPoolCallback* mCallback; 231 void* mUserData; 232 }; 233 234 } // end namespace android 235 236 #endif /*SOUNDPOOL_H_*/ 237