1 /* 2 * Copyright (C) 2019 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 #pragma once 18 19 #include "Sound.h" 20 21 #include <android-base/thread_annotations.h> 22 #include <audio_utils/clock.h> 23 #include <media/AudioTrack.h> 24 25 namespace android::soundpool { 26 27 // This is the amount of time to wait after stop is called when stealing an 28 // AudioTrack to allow the sound to ramp down. If this is 0, glitches 29 // may occur when stealing an AudioTrack. 30 inline constexpr int64_t kStopWaitTimeNs = 20 * NANOS_PER_MILLISECOND; 31 32 inline constexpr size_t kCacheLineSize = 64; /* std::hardware_constructive_interference_size */ 33 34 class StreamManager; // forward decl 35 36 /** 37 * A Stream is associated with a StreamID exposed to the app to play a Sound. 38 * 39 * The Stream uses monitor locking strategy on mLock. 40 * https://en.wikipedia.org/wiki/Monitor_(synchronization) 41 * 42 * where public methods are guarded by a lock (as needed) 43 * 44 * For Java equivalent APIs, see 45 * https://developer.android.com/reference/android/media/SoundPool 46 * 47 * Streams are paired by the StreamManager, so one stream in the pair may be "stopping" 48 * while the other stream of the pair has been prepared to run 49 * (and the streamID returned to the app) pending its pair to be stopped. 50 * The pair of a Stream may be obtained by calling getPairStream(), 51 * where this->getPairStream()->getPairStream() == this; (pair is a commutative relationship). 52 * 53 * playPairStream() and getPairPriority() access the paired stream. 54 * See also StreamManager.h for details of physical layout implications of paired streams. 55 */ 56 class alignas(kCacheLineSize) Stream { 57 public: 58 enum state { IDLE, PAUSED, PLAYING }; 59 // The PAUSED, PLAYING state directly corresponds to the AudioTrack state of an active Stream. 60 // 61 // The IDLE state indicates an inactive Stream. An IDLE Stream may have a non-nullptr 62 // AudioTrack, which may be recycled for use if the SoundID matches the next Stream playback. 63 // 64 // PAUSED -> PLAYING through resume() (see also autoResume()) 65 // PLAYING -> PAUSED through pause() (see also autoPause()) 66 // 67 // IDLE is the initial state of a Stream and also when a stream becomes inactive. 68 // {PAUSED, PLAYING} -> IDLE through stop() (or if the Sound finishes playing) 69 // IDLE -> PLAYING through play(). (there is no way to start a Stream in paused mode). 70 71 ~Stream(); setStreamManager(StreamManager * streamManager)72 void setStreamManager(StreamManager* streamManager) { // non-nullptr 73 mStreamManager = streamManager; // set in StreamManager constructor, not changed 74 } 75 76 // The following methods are monitor locked by mLock. 77 // 78 // For methods taking a streamID: 79 // if the streamID matches the Stream's mStreamID, then method proceeds 80 // else the command is ignored with no effect. 81 82 // returns true if the stream needs to be explicitly stopped. 83 bool requestStop(int32_t streamID); 84 void stop(); // explicit stop(), typically called from the worker thread. 85 void clearAudioTrack(); 86 void pause(int32_t streamID); 87 void autoPause(); // see the Java SoundPool.autoPause documentation for details. 88 void resume(int32_t streamID); 89 void autoResume(); 90 void mute(bool muting); 91 void dump() const NO_THREAD_SAFETY_ANALYSIS; // disable for ALOGV (see func for details). 92 93 // returns the pair stream if successful, nullptr otherwise 94 Stream* playPairStream(); 95 96 // These parameters are explicitly checked in the SoundPool class 97 // so never deviate from the Java API specified values. 98 void setVolume(int32_t streamID, float leftVolume, float rightVolume); 99 void setRate(int32_t streamID, float rate); 100 void setPriority(int32_t streamID, int priority); 101 void setLoop(int32_t streamID, int loop); 102 void setPlay(int32_t streamID, const std::shared_ptr<Sound> &sound, int32_t soundID, 103 float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate); 104 void setStopTimeNs(int64_t stopTimeNs); // systemTime() clock monotonic. 105 106 // The following getters are not locked and have weak consistency. 107 // These are considered advisory only - being stale is of nuisance. getPriority()108 int32_t getPriority() const NO_THREAD_SAFETY_ANALYSIS { return mPriority; } getPairPriority()109 int32_t getPairPriority() const NO_THREAD_SAFETY_ANALYSIS { 110 return getPairStream()->getPriority(); 111 } getStopTimeNs()112 int64_t getStopTimeNs() const NO_THREAD_SAFETY_ANALYSIS { return mStopTimeNs; } 113 114 // Can change with setPlay() getStreamID()115 int32_t getStreamID() const NO_THREAD_SAFETY_ANALYSIS { return mStreamID; } 116 117 // Can change with play_l() getSoundID()118 int32_t getSoundID() const NO_THREAD_SAFETY_ANALYSIS { return mSoundID; } 119 hasSound()120 bool hasSound() const NO_THREAD_SAFETY_ANALYSIS { return mSound.get() != nullptr; } 121 122 // This never changes. See top of header. 123 Stream* getPairStream() const; 124 125 private: 126 void play_l(const std::shared_ptr<Sound>& sound, int streamID, 127 float leftVolume, float rightVolume, int priority, int loop, float rate, 128 sp<AudioTrack> releaseTracks[2]) REQUIRES(mLock); 129 void stop_l() REQUIRES(mLock); 130 void setVolume_l(float leftVolume, float rightVolume) REQUIRES(mLock); 131 132 // For use with AudioTrack callback. 133 static void staticCallback(int event, void* user, void* info); 134 void callback(int event, void* info, int toggle, int tries) 135 NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock 136 137 // StreamManager should be set on construction and not changed. 138 // release mLock before calling into StreamManager 139 StreamManager* mStreamManager = nullptr; 140 141 mutable std::mutex mLock; 142 std::atomic_int32_t mStreamID GUARDED_BY(mLock) = 0; // Valid streamIDs are always positive. 143 int mState GUARDED_BY(mLock) = IDLE; 144 std::shared_ptr<Sound> mSound GUARDED_BY(mLock); // Non-null if playing. 145 int32_t mSoundID GUARDED_BY(mLock) = 0; // SoundID associated with AudioTrack. 146 float mLeftVolume GUARDED_BY(mLock) = 0.f; 147 float mRightVolume GUARDED_BY(mLock) = 0.f; 148 int32_t mPriority GUARDED_BY(mLock) = INT32_MIN; 149 int32_t mLoop GUARDED_BY(mLock) = 0; 150 float mRate GUARDED_BY(mLock) = 0.f; 151 bool mAutoPaused GUARDED_BY(mLock) = false; 152 bool mMuted GUARDED_BY(mLock) = false; 153 154 sp<AudioTrack> mAudioTrack GUARDED_BY(mLock); 155 int mToggle GUARDED_BY(mLock) = 0; 156 int64_t mStopTimeNs GUARDED_BY(mLock) = 0; // if nonzero, time to wait for stop. 157 }; 158 159 } // namespace android::soundpool 160