SoundPool.h revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
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
29namespace android {
30
31static const int IDLE_PRIORITY = -1;
32
33// forward declarations
34class SoundEvent;
35class SoundPoolThread;
36class SoundPool;
37
38// for queued events
39class SoundPoolEvent {
40public:
41    SoundPoolEvent(int msg, int arg1=0, int arg2=0) :
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
49extern void android_soundpool_SoundPool_notify(jobject ref, const SoundPoolEvent *event);
50
51// tracks samples used by application
52class Sample  : public RefBase {
53public:
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();
58    int sampleID() { return mSampleID; }
59    int numChannels() { return mNumChannels; }
60    int sampleRate() { return mSampleRate; }
61    int format() { return mFormat; }
62    size_t size() { return mSize; }
63    int state() { return mState; }
64    uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); }
65    void doLoad();
66    void startLoad() { mState = LOADING; }
67    sp<IMemory> getIMemory() { return mData; }
68
69    // hack
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
73private:
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
91class SoundEvent
92{
93public:
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);
98    sp<Sample>      sample() { return mSample; }
99    int             channelID() { return mChannelID; }
100    float           leftVolume() { return mLeftVolume; }
101    float           rightVolume() { return mRightVolume; }
102    int             priority() { return mPriority; }
103    int             loop() { return mLoop; }
104    float           rate() { return mRate; }
105    void            clear() { mChannelID = 0; mSample.clear(); }
106
107protected:
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
118class SoundChannel : public SoundEvent {
119public:
120    enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
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);
133    int state() { return mState; }
134    void setPriority(int priority) { mPriority = priority; }
135    void setLoop(int loop);
136    int numChannels() { return mNumChannels; }
137    void clearNextEvent() { mNextEvent.clear(); }
138    void nextEvent();
139    int nextChannelID() { return mNextEvent.channelID(); }
140    void dump();
141
142private:
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
158class SoundPool {
159    friend class SoundPoolThread;
160    friend class SoundChannel;
161public:
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);
176    int streamType() const { return mStreamType; }
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
185private:
186    SoundPool() {} // no default constructor
187    bool startThreads();
188    void doLoad(sp<Sample>& sample);
189    inline void notify(const SoundPoolEvent* event) {
190        android_soundpool_SoundPool_notify(mSoundPoolRef, event);
191    }
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    Condition               mCondition;
208    SoundPoolThread*        mDecodeThread;
209    SoundChannel*           mChannelPool;
210    List<SoundChannel*>     mChannels;
211    List<SoundChannel*>     mRestart;
212    DefaultKeyedVector< int, sp<Sample> >   mSamples;
213    int                     mMaxChannels;
214    int                     mStreamType;
215    int                     mSrcQuality;
216    int                     mAllocated;
217    int                     mNextSampleID;
218    int                     mNextChannelID;
219    bool                    mQuit;
220};
221
222} // end namespace android
223
224#endif /*SOUNDPOOL_H_*/
225