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
26namespace android {
27
28static const int IDLE_PRIORITY = -1;
29
30// forward declarations
31class SoundEvent;
32class SoundPoolThread;
33class SoundPool;
34
35// for queued events
36class SoundPoolEvent {
37public:
38    SoundPoolEvent(int msg, int arg1=0, int arg2=0) :
39        mMsg(msg), mArg1(arg1), mArg2(arg2) {}
40    int         mMsg;
41    int         mArg1;
42    int         mArg2;
43    enum MessageType { INVALID, SAMPLE_LOADED };
44};
45
46// callback function prototype
47typedef void SoundPoolCallback(SoundPoolEvent event, SoundPool* soundPool, void* user);
48
49// tracks samples used by application
50class Sample  : public RefBase {
51public:
52    enum sample_state { UNLOADED, LOADING, READY, UNLOADING };
53    Sample(int sampleID, const char* url);
54    Sample(int sampleID, int fd, int64_t offset, int64_t length);
55    ~Sample();
56    int sampleID() { return mSampleID; }
57    int numChannels() { return mNumChannels; }
58    int sampleRate() { return mSampleRate; }
59    audio_format_t format() { return mFormat; }
60    size_t size() { return mSize; }
61    int state() { return mState; }
62    uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); }
63    status_t doLoad();
64    void startLoad() { mState = LOADING; }
65    sp<IMemory> getIMemory() { return mData; }
66
67    // hack
68    void init(int numChannels, int sampleRate, audio_format_t format, size_t size, sp<IMemory> data ) {
69        mNumChannels = numChannels; mSampleRate = sampleRate; mFormat = format; mSize = size; mData = data; }
70
71private:
72    void init();
73
74    size_t              mSize;
75    volatile int32_t    mRefCount;
76    uint16_t            mSampleID;
77    uint16_t            mSampleRate;
78    uint8_t             mState : 3;
79    uint8_t             mNumChannels : 2;
80    audio_format_t      mFormat;
81    int                 mFd;
82    int64_t             mOffset;
83    int64_t             mLength;
84    char*               mUrl;
85    sp<IMemory>         mData;
86};
87
88// stores pending events for stolen channels
89class SoundEvent
90{
91public:
92    SoundEvent() : mChannelID(0), mLeftVolume(0), mRightVolume(0),
93            mPriority(IDLE_PRIORITY), mLoop(0), mRate(0) {}
94    void set(const sp<Sample>& sample, int channelID, float leftVolume,
95            float rightVolume, int priority, int loop, float rate);
96    sp<Sample>      sample() { return mSample; }
97    int             channelID() { return mChannelID; }
98    float           leftVolume() { return mLeftVolume; }
99    float           rightVolume() { return mRightVolume; }
100    int             priority() { return mPriority; }
101    int             loop() { return mLoop; }
102    float           rate() { return mRate; }
103    void            clear() { mChannelID = 0; mSample.clear(); }
104
105protected:
106    sp<Sample>      mSample;
107    int             mChannelID;
108    float           mLeftVolume;
109    float           mRightVolume;
110    int             mPriority;
111    int             mLoop;
112    float           mRate;
113};
114
115// for channels aka AudioTracks
116class SoundChannel : public SoundEvent {
117public:
118    enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
119    SoundChannel() : mAudioTrack(NULL), mState(IDLE), mNumChannels(1),
120            mPos(0), mToggle(0), mAutoPaused(false) {}
121    ~SoundChannel();
122    void init(SoundPool* soundPool);
123    void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume,
124            int priority, int loop, float rate);
125    void setVolume_l(float leftVolume, float rightVolume);
126    void setVolume(float leftVolume, float rightVolume);
127    void stop_l();
128    void stop();
129    void pause();
130    void autoPause();
131    void resume();
132    void autoResume();
133    void setRate(float rate);
134    int state() { return mState; }
135    void setPriority(int priority) { mPriority = priority; }
136    void setLoop(int loop);
137    int numChannels() { return mNumChannels; }
138    void clearNextEvent() { mNextEvent.clear(); }
139    void nextEvent();
140    int nextChannelID() { return mNextEvent.channelID(); }
141    void dump();
142
143private:
144    static void callback(int event, void* user, void *info);
145    void process(int event, void *info, unsigned long toggle);
146    bool doStop_l();
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
161class SoundPool {
162    friend class SoundPoolThread;
163    friend class SoundChannel;
164public:
165    SoundPool(int maxChannels, audio_stream_type_t 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    audio_stream_type_t 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_l(SoundChannel* channel);
189
190    // callback function
191    void setCallback(SoundPoolCallback* callback, void* user);
192    void* getUserData() { return mUserData; }
193
194private:
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_l(int priority);
202    void moveToFront_l(SoundChannel* channel);
203    void notify(SoundPoolEvent event);
204    void dump();
205
206    // restart thread
207    void addToRestartList(SoundChannel* channel);
208    void addToStopList(SoundChannel* channel);
209    static int beginThread(void* arg);
210    int run();
211    void quit();
212
213    Mutex                   mLock;
214    Mutex                   mRestartLock;
215    Condition               mCondition;
216    SoundPoolThread*        mDecodeThread;
217    SoundChannel*           mChannelPool;
218    List<SoundChannel*>     mChannels;
219    List<SoundChannel*>     mRestart;
220    List<SoundChannel*>     mStop;
221    DefaultKeyedVector< int, sp<Sample> >   mSamples;
222    int                     mMaxChannels;
223    audio_stream_type_t     mStreamType;
224    int                     mSrcQuality;
225    int                     mAllocated;
226    int                     mNextSampleID;
227    int                     mNextChannelID;
228    bool                    mQuit;
229
230    // callback
231    Mutex                   mCallbackLock;
232    SoundPoolCallback*      mCallback;
233    void*                   mUserData;
234};
235
236} // end namespace android
237
238#endif /*SOUNDPOOL_H_*/
239