| /* |
| * Copyright (C) 2019 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. |
| */ |
| |
| #pragma once |
| |
| #include "Sound.h" |
| |
| #include <audio_utils/clock.h> |
| #include <media/AudioTrack.h> |
| |
| namespace android::soundpool { |
| |
| // This is the amount of time to wait after stop is called when stealing an |
| // AudioTrack to allow the sound to ramp down. If this is 0, glitches |
| // may occur when stealing an AudioTrack. |
| inline constexpr int64_t kStopWaitTimeNs = 20 * NANOS_PER_MILLISECOND; |
| |
| inline constexpr size_t kCacheLineSize = 64; /* std::hardware_constructive_interference_size */ |
| |
| class StreamManager; // forward decl |
| |
| /** |
| * A Stream is associated with a StreamID exposed to the app to play a Sound. |
| * |
| * The Stream uses monitor locking strategy on mLock. |
| * https://en.wikipedia.org/wiki/Monitor_(synchronization) |
| * |
| * where public methods are guarded by a lock (as needed) |
| * |
| * For Java equivalent APIs, see |
| * https://developer.android.com/reference/android/media/SoundPool |
| * |
| * Streams are paired by the StreamManager, so one stream in the pair may be "stopping" |
| * while the other stream of the pair has been prepared to run |
| * (and the streamID returned to the app) pending its pair to be stopped. |
| * The pair of a Stream may be obtained by calling getPairStream(), |
| * where this->getPairStream()->getPairStream() == this; (pair is a commutative relationship). |
| * |
| * playPairStream() and getPairPriority() access the paired stream. |
| * See also StreamManager.h for details of physical layout implications of paired streams. |
| */ |
| class alignas(kCacheLineSize) Stream { |
| public: |
| enum state { IDLE, PAUSED, PLAYING }; |
| // The PAUSED, PLAYING state directly corresponds to the AudioTrack state of an active Stream. |
| // |
| // The IDLE state indicates an inactive Stream. An IDLE Stream may have a non-nullptr |
| // AudioTrack, which may be recycled for use if the SoundID matches the next Stream playback. |
| // |
| // PAUSED -> PLAYING through resume() (see also autoResume()) |
| // PLAYING -> PAUSED through pause() (see also autoPause()) |
| // |
| // IDLE is the initial state of a Stream and also when a stream becomes inactive. |
| // {PAUSED, PLAYING} -> IDLE through stop() (or if the Sound finishes playing) |
| // IDLE -> PLAYING through play(). (there is no way to start a Stream in paused mode). |
| |
| ~Stream(); |
| void setStreamManager(StreamManager* streamManager) { // non-nullptr |
| mStreamManager = streamManager; // set in StreamManager constructor, not changed |
| } |
| |
| // The following methods are monitor locked by mLock. |
| // |
| // For methods taking a streamID: |
| // if the streamID matches the Stream's mStreamID, then method proceeds |
| // else the command is ignored with no effect. |
| |
| // returns true if the stream needs to be explicitly stopped. |
| bool requestStop(int32_t streamID); |
| void stop(); // explicit stop(), typically called from the worker thread. |
| void clearAudioTrack(); |
| void pause(int32_t streamID); |
| void autoPause(); // see the Java SoundPool.autoPause documentation for details. |
| void resume(int32_t streamID); |
| void autoResume(); |
| void mute(bool muting); |
| void dump() const; |
| |
| // returns the pair stream if successful, nullptr otherwise |
| Stream* playPairStream(); |
| |
| // These parameters are explicitly checked in the SoundPool class |
| // so never deviate from the Java API specified values. |
| void setVolume(int32_t streamID, float leftVolume, float rightVolume); |
| void setRate(int32_t streamID, float rate); |
| void setPriority(int32_t streamID, int priority); |
| void setLoop(int32_t streamID, int loop); |
| void setPlay(int32_t streamID, const std::shared_ptr<Sound> &sound, int32_t soundID, |
| float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate); |
| void setStopTimeNs(int64_t stopTimeNs); // systemTime() clock monotonic. |
| |
| // The following getters are not locked and have weak consistency. |
| // These are considered advisory only - being stale is of nuisance. |
| int32_t getPriority() const { return mPriority; } |
| int32_t getPairPriority() const { return getPairStream()->getPriority(); } |
| int64_t getStopTimeNs() const { return mStopTimeNs; } |
| |
| int32_t getStreamID() const { return mStreamID; } // Can change with setPlay() |
| int32_t getSoundID() const { return mSoundID; } // Can change with play_l() |
| bool hasSound() const { return mSound.get() != nullptr; } |
| |
| Stream* getPairStream() const; // this never changes. See top of header. |
| |
| private: |
| void play_l(const std::shared_ptr<Sound>& sound, int streamID, |
| float leftVolume, float rightVolume, int priority, int loop, float rate, |
| sp<AudioTrack> releaseTracks[2]); |
| void stop_l(); |
| void setVolume_l(float leftVolume, float rightVolume); |
| |
| // For use with AudioTrack callback. |
| static void staticCallback(int event, void* user, void* info); |
| void callback(int event, void* info, int toggle, int tries); |
| |
| // StreamManager should be set on construction and not changed. |
| // release mLock before calling into StreamManager |
| StreamManager* mStreamManager = nullptr; |
| |
| mutable std::mutex mLock; |
| std::atomic_int32_t mStreamID = 0; // Note: valid streamIDs are always positive. |
| int mState = IDLE; |
| std::shared_ptr<Sound> mSound; // Non-null if playing. |
| int32_t mSoundID = 0; // The sound ID associated with the AudioTrack. |
| float mLeftVolume = 0.f; |
| float mRightVolume = 0.f; |
| int32_t mPriority = INT32_MIN; |
| int32_t mLoop = 0; |
| float mRate = 0.f; |
| bool mAutoPaused = false; |
| bool mMuted = false; |
| |
| sp<AudioTrack> mAudioTrack; |
| int mToggle = 0; |
| int64_t mStopTimeNs = 0; // if nonzero, time to wait for stop. |
| }; |
| |
| } // namespace android::soundpool |