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 */
alignas(kCacheLineSize)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();
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.
108 int32_t getPriority() const NO_THREAD_SAFETY_ANALYSIS { return mPriority; }
109 int32_t getPairPriority() const NO_THREAD_SAFETY_ANALYSIS {
110 return getPairStream()->getPriority();
111 }
112 int64_t getStopTimeNs() const NO_THREAD_SAFETY_ANALYSIS { return mStopTimeNs; }
113
114 // Can change with setPlay()
115 int32_t getStreamID() const NO_THREAD_SAFETY_ANALYSIS { return mStreamID; }
116
117 // Can change with play_l()
118 int32_t getSoundID() const NO_THREAD_SAFETY_ANALYSIS { return mSoundID; }
119
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