Home | History | Annotate | Download | only in soundpool
      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