summaryrefslogtreecommitdiffstats
path: root/include/media/SoundPool.h
blob: 2dd78cc07f7119c6f36b15a5603d6c31d431ecc8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SOUNDPOOL_H_
#define SOUNDPOOL_H_

#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Vector.h>
#include <utils/KeyedVector.h>
#include <media/AudioTrack.h>
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryBase.h>

namespace android {

static const int IDLE_PRIORITY = -1;

// forward declarations
class SoundEvent;
class SoundPoolThread;
class SoundPool;

// for queued events
class SoundPoolEvent {
public:
    SoundPoolEvent(int msg, int arg1=0, int arg2=0) :
        mMsg(msg), mArg1(arg1), mArg2(arg2) {}
    int         mMsg;
    int         mArg1;
    int         mArg2;
    enum MessageType { INVALID, SAMPLE_LOADED };
};

// callback function prototype
typedef void SoundPoolCallback(SoundPoolEvent event, SoundPool* soundPool, void* user);

// tracks samples used by application
class Sample  : public RefBase {
public:
    enum sample_state { UNLOADED, LOADING, READY, UNLOADING };
    Sample(int sampleID, const char* url);
    Sample(int sampleID, int fd, int64_t offset, int64_t length);
    ~Sample();
    int sampleID() { return mSampleID; }
    int numChannels() { return mNumChannels; }
    int sampleRate() { return mSampleRate; }
    audio_format_t format() { return mFormat; }
    size_t size() { return mSize; }
    int state() { return mState; }
    uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); }
    status_t doLoad();
    void startLoad() { mState = LOADING; }
    sp<IMemory> getIMemory() { return mData; }

    // hack
    void init(int numChannels, int sampleRate, audio_format_t format, size_t size,
            sp<IMemory> data ) {
        mNumChannels = numChannels; mSampleRate = sampleRate; mFormat = format; mSize = size;
            mData = data; }

private:
    void init();

    size_t              mSize;
    volatile int32_t    mRefCount;
    uint16_t            mSampleID;
    uint16_t            mSampleRate;
    uint8_t             mState : 3;
    uint8_t             mNumChannels : 2;
    audio_format_t      mFormat;
    int                 mFd;
    int64_t             mOffset;
    int64_t             mLength;
    char*               mUrl;
    sp<IMemory>         mData;
    sp<MemoryHeapBase>  mHeap;
};

// stores pending events for stolen channels
class SoundEvent
{
public:
    SoundEvent() : mChannelID(0), mLeftVolume(0), mRightVolume(0),
            mPriority(IDLE_PRIORITY), mLoop(0), mRate(0) {}
    void set(const sp<Sample>& sample, int channelID, float leftVolume,
            float rightVolume, int priority, int loop, float rate);
    sp<Sample>      sample() { return mSample; }
    int             channelID() { return mChannelID; }
    float           leftVolume() { return mLeftVolume; }
    float           rightVolume() { return mRightVolume; }
    int             priority() { return mPriority; }
    int             loop() { return mLoop; }
    float           rate() { return mRate; }
    void            clear() { mChannelID = 0; mSample.clear(); }

protected:
    sp<Sample>      mSample;
    int             mChannelID;
    float           mLeftVolume;
    float           mRightVolume;
    int             mPriority;
    int             mLoop;
    float           mRate;
};

// for channels aka AudioTracks
class SoundChannel : public SoundEvent {
public:
    enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
    SoundChannel() : mState(IDLE), mNumChannels(1),
            mPos(0), mToggle(0), mAutoPaused(false) {}
    ~SoundChannel();
    void init(SoundPool* soundPool);
    void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume,
            int priority, int loop, float rate);
    void setVolume_l(float leftVolume, float rightVolume);
    void setVolume(float leftVolume, float rightVolume);
    void stop_l();
    void stop();
    void pause();
    void autoPause();
    void resume();
    void autoResume();
    void setRate(float rate);
    int state() { return mState; }
    void setPriority(int priority) { mPriority = priority; }
    void setLoop(int loop);
    int numChannels() { return mNumChannels; }
    void clearNextEvent() { mNextEvent.clear(); }
    void nextEvent();
    int nextChannelID() { return mNextEvent.channelID(); }
    void dump();

private:
    static void callback(int event, void* user, void *info);
    void process(int event, void *info, unsigned long toggle);
    bool doStop_l();

    SoundPool*          mSoundPool;
    sp<AudioTrack>      mAudioTrack;
    SoundEvent          mNextEvent;
    Mutex               mLock;
    int                 mState;
    int                 mNumChannels;
    int                 mPos;
    int                 mAudioBufferSize;
    unsigned long       mToggle;
    bool                mAutoPaused;
};

// application object for managing a pool of sounds
class SoundPool {
    friend class SoundPoolThread;
    friend class SoundChannel;
public:
    SoundPool(int maxChannels, audio_stream_type_t streamType, int srcQuality);
    ~SoundPool();
    int load(const char* url, int priority);
    int load(int fd, int64_t offset, int64_t length, int priority);
    bool unload(int sampleID);
    int play(int sampleID, float leftVolume, float rightVolume, int priority,
            int loop, float rate);
    void pause(int channelID);
    void autoPause();
    void resume(int channelID);
    void autoResume();
    void stop(int channelID);
    void setVolume(int channelID, float leftVolume, float rightVolume);
    void setPriority(int channelID, int priority);
    void setLoop(int channelID, int loop);
    void setRate(int channelID, float rate);
    audio_stream_type_t streamType() const { return mStreamType; }
    int srcQuality() const { return mSrcQuality; }

    // called from SoundPoolThread
    void sampleLoaded(int sampleID);

    // called from AudioTrack thread
    void done_l(SoundChannel* channel);

    // callback function
    void setCallback(SoundPoolCallback* callback, void* user);
    void* getUserData() { return mUserData; }

private:
    SoundPool() {} // no default constructor
    bool startThreads();
    void doLoad(sp<Sample>& sample);
    sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); }
    SoundChannel* findChannel (int channelID);
    SoundChannel* findNextChannel (int channelID);
    SoundChannel* allocateChannel_l(int priority);
    void moveToFront_l(SoundChannel* channel);
    void notify(SoundPoolEvent event);
    void dump();

    // restart thread
    void addToRestartList(SoundChannel* channel);
    void addToStopList(SoundChannel* channel);
    static int beginThread(void* arg);
    int run();
    void quit();

    Mutex                   mLock;
    Mutex                   mRestartLock;
    Condition               mCondition;
    SoundPoolThread*        mDecodeThread;
    SoundChannel*           mChannelPool;
    List<SoundChannel*>     mChannels;
    List<SoundChannel*>     mRestart;
    List<SoundChannel*>     mStop;
    DefaultKeyedVector< int, sp<Sample> >   mSamples;
    int                     mMaxChannels;
    audio_stream_type_t     mStreamType;
    int                     mSrcQuality;
    int                     mAllocated;
    int                     mNextSampleID;
    int                     mNextChannelID;
    bool                    mQuit;

    // callback
    Mutex                   mCallbackLock;
    SoundPoolCallback*      mCallback;
    void*                   mUserData;
};

} // end namespace android

#endif /*SOUNDPOOL_H_*/