• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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