Merge "SoundPool: Add clang-tidy and fix" into rvc-dev

This commit is contained in:
Andy Hung
2020-05-27 19:31:29 +00:00
committed by Android (Google) Code Review
11 changed files with 222 additions and 104 deletions

View File

@@ -1,5 +1,92 @@
tidy_errors = [
// https://clang.llvm.org/extra/clang-tidy/checks/list.html
// For many categories, the checks are too many to specify individually.
// Feel free to disable as needed - as warnings are generally ignored,
// we treat warnings as errors.
"android-*",
"bugprone-*",
"cert-*",
"clang-analyzer-security*",
"google-*",
"misc-*",
//"modernize-*", // explicitly list the modernize as they can be subjective.
"modernize-avoid-bind",
//"modernize-avoid-c-arrays", // std::array<> can be verbose
"modernize-concat-nested-namespaces",
//"modernize-deprecated-headers", // C headers still ok even if there is C++ equivalent.
"modernize-deprecated-ios-base-aliases",
"modernize-loop-convert",
"modernize-make-shared",
"modernize-make-unique",
"modernize-pass-by-value",
"modernize-raw-string-literal",
"modernize-redundant-void-arg",
"modernize-replace-auto-ptr",
"modernize-replace-random-shuffle",
"modernize-return-braced-init-list",
"modernize-shrink-to-fit",
"modernize-unary-static-assert",
"modernize-use-auto", // debatable - auto can obscure type
"modernize-use-bool-literals",
"modernize-use-default-member-init",
"modernize-use-emplace",
"modernize-use-equals-default",
"modernize-use-equals-delete",
"modernize-use-nodiscard",
"modernize-use-noexcept",
"modernize-use-nullptr",
"modernize-use-override",
//"modernize-use-trailing-return-type", // not necessarily more readable
"modernize-use-transparent-functors",
"modernize-use-uncaught-exceptions",
"modernize-use-using",
"performance-*",
// Remove some pedantic stylistic requirements.
"-google-readability-casting", // C++ casts not always necessary and may be verbose
"-google-readability-todo", // do not require TODO(info)
"-google-build-using-namespace", // Reenable and fix later.
]
cc_defaults {
name: "soundpool_flags_defaults",
// https://clang.llvm.org/docs/UsersManual.html#command-line-options
// https://clang.llvm.org/docs/DiagnosticsReference.html
cflags: [
"-Wall",
"-Wdeprecated",
"-Werror",
"-Werror=implicit-fallthrough",
"-Werror=sometimes-uninitialized",
//"-Werror=conditional-uninitialized",
"-Wextra",
"-Wredundant-decls",
"-Wshadow",
"-Wstrict-aliasing",
"-fstrict-aliasing",
"-Wthread-safety",
//"-Wthread-safety-negative", // experimental - looks broken in R.
"-Wunreachable-code",
"-Wunreachable-code-break",
"-Wunreachable-code-return",
"-Wunused",
"-Wused-but-marked-unused",
],
// https://clang.llvm.org/extra/clang-tidy/
tidy: true,
tidy_checks: tidy_errors,
tidy_checks_as_errors: tidy_errors,
tidy_flags: [
"-format-style='file'",
"--header-filter='frameworks/base/media/jni/soundpool'",
],
}
cc_library_shared { cc_library_shared {
name: "libsoundpool", name: "libsoundpool",
defaults: [
"soundpool_flags_defaults",
],
srcs: [ srcs: [
"android_media_SoundPool.cpp", "android_media_SoundPool.cpp",

View File

@@ -31,7 +31,7 @@ constexpr size_t kDefaultHeapSize = 1024 * 1024; // 1MB (compatible with low m
Sound::Sound(int32_t soundID, int fd, int64_t offset, int64_t length) Sound::Sound(int32_t soundID, int fd, int64_t offset, int64_t length)
: mSoundID(soundID) : mSoundID(soundID)
, mFd(dup(fd)) , mFd(fcntl(fd, F_DUPFD_CLOEXEC)) // like dup(fd) but closes on exec to prevent leaks.
, mOffset(offset) , mOffset(offset)
, mLength(length) , mLength(length)
{ {
@@ -47,7 +47,7 @@ Sound::~Sound()
static status_t decode(int fd, int64_t offset, int64_t length, static status_t decode(int fd, int64_t offset, int64_t length,
uint32_t *rate, int32_t *channelCount, audio_format_t *audioFormat, uint32_t *rate, int32_t *channelCount, audio_format_t *audioFormat,
audio_channel_mask_t *channelMask, sp<MemoryHeapBase> heap, audio_channel_mask_t *channelMask, const sp<MemoryHeapBase>& heap,
size_t *sizeInBytes) { size_t *sizeInBytes) {
ALOGV("%s(fd=%d, offset=%lld, length=%lld, ...)", ALOGV("%s(fd=%d, offset=%lld, length=%lld, ...)",
__func__, fd, (long long)offset, (long long)length); __func__, fd, (long long)offset, (long long)length);
@@ -81,7 +81,7 @@ static status_t decode(int fd, int64_t offset, int64_t length,
bool sawInputEOS = false; bool sawInputEOS = false;
bool sawOutputEOS = false; bool sawOutputEOS = false;
uint8_t* writePos = static_cast<uint8_t*>(heap->getBase()); auto writePos = static_cast<uint8_t*>(heap->getBase());
size_t available = heap->getSize(); size_t available = heap->getSize();
size_t written = 0; size_t written = 0;
format.reset(AMediaCodec_getOutputFormat(codec.get())); // update format. format.reset(AMediaCodec_getOutputFormat(codec.get())); // update format.
@@ -204,7 +204,7 @@ status_t Sound::doLoad()
int32_t channelCount; int32_t channelCount;
audio_format_t format; audio_format_t format;
audio_channel_mask_t channelMask; audio_channel_mask_t channelMask;
status_t status = decode(mFd.get(), mOffset, mLength, &sampleRate, &channelCount, &format, status = decode(mFd.get(), mOffset, mLength, &sampleRate, &channelCount, &format,
&channelMask, mHeap, &mSizeInBytes); &channelMask, mHeap, &mSizeInBytes);
ALOGV("%s: close(%d)", __func__, mFd.get()); ALOGV("%s: close(%d)", __func__, mFd.get());
mFd.reset(); // close mFd.reset(); // close

View File

@@ -57,7 +57,7 @@ void SoundDecoder::quit()
mThreadPool->quit(); mThreadPool->quit();
} }
void SoundDecoder::run(int32_t id __unused /* ALOGV only */) void SoundDecoder::run(int32_t id)
{ {
ALOGV("%s(%d): entering", __func__, id); ALOGV("%s(%d): entering", __func__, id);
std::unique_lock lock(mLock); std::unique_lock lock(mLock);

View File

@@ -30,21 +30,22 @@ class SoundDecoder {
public: public:
SoundDecoder(SoundManager* soundManager, size_t threads); SoundDecoder(SoundManager* soundManager, size_t threads);
~SoundDecoder(); ~SoundDecoder();
void loadSound(int32_t soundID); void loadSound(int32_t soundID) NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock
void quit(); void quit();
private: private:
void run(int32_t id); // The decode thread function. // The decode thread function.
void run(int32_t id) NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock
SoundManager* const mSoundManager; // set in constructor, has own lock SoundManager* const mSoundManager; // set in constructor, has own lock
std::unique_ptr<ThreadPool> mThreadPool; // set in constructor, has own lock std::unique_ptr<ThreadPool> mThreadPool; // set in constructor, has own lock
std::mutex mLock; std::mutex mLock;
std::condition_variable mQueueSpaceAvailable; std::condition_variable mQueueSpaceAvailable GUARDED_BY(mLock);
std::condition_variable mQueueDataAvailable; std::condition_variable mQueueDataAvailable GUARDED_BY(mLock);
std::deque<int32_t> mSoundIDs; // GUARDED_BY(mLock); std::deque<int32_t> mSoundIDs GUARDED_BY(mLock);
bool mQuit = false; // GUARDED_BY(mLock); bool mQuit GUARDED_BY(mLock) = false;
}; };
} // end namespace android::soundpool } // end namespace android::soundpool

View File

@@ -43,7 +43,7 @@ SoundManager::~SoundManager()
mSounds.clear(); mSounds.clear();
} }
int32_t SoundManager::load(int fd, int64_t offset, int64_t length, int32_t priority __unused) int32_t SoundManager::load(int fd, int64_t offset, int64_t length, int32_t priority)
{ {
ALOGV("%s(fd=%d, offset=%lld, length=%lld, priority=%d)", ALOGV("%s(fd=%d, offset=%lld, length=%lld, priority=%d)",
__func__, fd, (long long)offset, (long long)length, priority); __func__, fd, (long long)offset, (long long)length, priority);

View File

@@ -21,6 +21,8 @@
#include <mutex> #include <mutex>
#include <unordered_map> #include <unordered_map>
#include <android-base/thread_annotations.h>
namespace android { namespace android {
class SoundPool; class SoundPool;
@@ -91,20 +93,21 @@ private:
} }
private: private:
mutable std::recursive_mutex mCallbackLock; // allow mCallback to setCallback(). mutable std::recursive_mutex mCallbackLock; // allow mCallback to setCallback().
// No thread-safety checks in R for recursive_mutex.
SoundPool* mSoundPool = nullptr; // GUARDED_BY(mCallbackLock) SoundPool* mSoundPool = nullptr; // GUARDED_BY(mCallbackLock)
SoundPoolCallback* mCallback = nullptr; // GUARDED_BY(mCallbackLock) SoundPoolCallback* mCallback = nullptr; // GUARDED_BY(mCallbackLock)
void* mUserData = nullptr; // GUARDED_BY(mCallbackLock) void* mUserData = nullptr; // GUARDED_BY(mCallbackLock)
}; };
std::shared_ptr<Sound> findSound_l(int32_t soundID) const; std::shared_ptr<Sound> findSound_l(int32_t soundID) const REQUIRES(mSoundManagerLock);
// The following variables are initialized in constructor and can be accessed anytime. // The following variables are initialized in constructor and can be accessed anytime.
CallbackHandler mCallbackHandler; // has its own lock CallbackHandler mCallbackHandler; // has its own lock
const std::unique_ptr<SoundDecoder> mDecoder; // has its own lock const std::unique_ptr<SoundDecoder> mDecoder; // has its own lock
mutable std::mutex mSoundManagerLock; mutable std::mutex mSoundManagerLock;
std::unordered_map<int, std::shared_ptr<Sound>> mSounds; // GUARDED_BY(mSoundManagerLock) std::unordered_map<int, std::shared_ptr<Sound>> mSounds GUARDED_BY(mSoundManagerLock);
int32_t mNextSoundID = 0; // GUARDED_BY(mSoundManagerLock) int32_t mNextSoundID GUARDED_BY(mSoundManagerLock) = 0;
}; };
} // namespace android::soundpool } // namespace android::soundpool

View File

@@ -105,7 +105,7 @@ void Stream::setRate(int32_t streamID, float rate)
if (streamID == mStreamID) { if (streamID == mStreamID) {
mRate = rate; mRate = rate;
if (mAudioTrack != nullptr && mSound != nullptr) { if (mAudioTrack != nullptr && mSound != nullptr) {
const uint32_t sampleRate = uint32_t(float(mSound->getSampleRate()) * rate + 0.5); const auto sampleRate = (uint32_t)lround(double(mSound->getSampleRate()) * rate);
mAudioTrack->setSampleRate(sampleRate); mAudioTrack->setSampleRate(sampleRate);
} }
} }
@@ -214,8 +214,11 @@ void Stream::stop_l()
void Stream::clearAudioTrack() void Stream::clearAudioTrack()
{ {
sp<AudioTrack> release; // release outside of lock.
std::lock_guard lock(mLock);
// This will invoke the destructor which waits for the AudioTrack thread to join, // This will invoke the destructor which waits for the AudioTrack thread to join,
// and is currently the only safe way to ensure there are no callbacks afterwards. // and is currently the only safe way to ensure there are no callbacks afterwards.
release = mAudioTrack; // or std::swap if we had move semantics.
mAudioTrack.clear(); mAudioTrack.clear();
} }
@@ -288,7 +291,7 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID,
const audio_stream_type_t streamType = const audio_stream_type_t streamType =
AudioSystem::attributesToStreamType(*mStreamManager->getAttributes()); AudioSystem::attributesToStreamType(*mStreamManager->getAttributes());
const int32_t channelCount = sound->getChannelCount(); const int32_t channelCount = sound->getChannelCount();
const uint32_t sampleRate = uint32_t(float(sound->getSampleRate()) * rate + 0.5); const auto sampleRate = (uint32_t)lround(double(sound->getSampleRate()) * rate);
size_t frameCount = 0; size_t frameCount = 0;
if (loop) { if (loop) {
@@ -307,7 +310,7 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID,
__func__, mAudioTrack.get(), sound->getSoundID()); __func__, mAudioTrack.get(), sound->getSoundID());
} }
} }
if (newTrack == 0) { if (newTrack == nullptr) {
// mToggle toggles each time a track is started on a given stream. // mToggle toggles each time a track is started on a given stream.
// The toggle is concatenated with the Stream address and passed to AudioTrack // The toggle is concatenated with the Stream address and passed to AudioTrack
// as callback user data. This enables the detection of callbacks received from the old // as callback user data. This enables the detection of callbacks received from the old
@@ -380,9 +383,9 @@ exit:
/* static */ /* static */
void Stream::staticCallback(int event, void* user, void* info) void Stream::staticCallback(int event, void* user, void* info)
{ {
const uintptr_t userAsInt = (uintptr_t)user; const auto userAsInt = (uintptr_t)user;
Stream* stream = reinterpret_cast<Stream*>(userAsInt & ~1); auto stream = reinterpret_cast<Stream*>(userAsInt & ~1);
stream->callback(event, info, userAsInt & 1, 0 /* tries */); stream->callback(event, info, int(userAsInt & 1), 0 /* tries */);
} }
void Stream::callback(int event, void* info, int toggle, int tries) void Stream::callback(int event, void* info, int toggle, int tries)

View File

@@ -18,6 +18,7 @@
#include "Sound.h" #include "Sound.h"
#include <android-base/thread_annotations.h>
#include <audio_utils/clock.h> #include <audio_utils/clock.h>
#include <media/AudioTrack.h> #include <media/AudioTrack.h>
@@ -104,47 +105,55 @@ public:
// The following getters are not locked and have weak consistency. // The following getters are not locked and have weak consistency.
// These are considered advisory only - being stale is of nuisance. // These are considered advisory only - being stale is of nuisance.
int32_t getPriority() const { return mPriority; } int32_t getPriority() const NO_THREAD_SAFETY_ANALYSIS { return mPriority; }
int32_t getPairPriority() const { return getPairStream()->getPriority(); } int32_t getPairPriority() const NO_THREAD_SAFETY_ANALYSIS {
int64_t getStopTimeNs() const { return mStopTimeNs; } return getPairStream()->getPriority();
}
int64_t getStopTimeNs() const NO_THREAD_SAFETY_ANALYSIS { return mStopTimeNs; }
int32_t getStreamID() const { return mStreamID; } // Can change with setPlay() // Can change with setPlay()
int32_t getSoundID() const { return mSoundID; } // Can change with play_l() int32_t getStreamID() const NO_THREAD_SAFETY_ANALYSIS { return mStreamID; }
bool hasSound() const { return mSound.get() != nullptr; }
Stream* getPairStream() const; // this never changes. See top of header. // Can change with play_l()
int32_t getSoundID() const NO_THREAD_SAFETY_ANALYSIS { return mSoundID; }
bool hasSound() const NO_THREAD_SAFETY_ANALYSIS { return mSound.get() != nullptr; }
// This never changes. See top of header.
Stream* getPairStream() const;
private: private:
void play_l(const std::shared_ptr<Sound>& sound, int streamID, void play_l(const std::shared_ptr<Sound>& sound, int streamID,
float leftVolume, float rightVolume, int priority, int loop, float rate, float leftVolume, float rightVolume, int priority, int loop, float rate,
sp<AudioTrack> releaseTracks[2]); sp<AudioTrack> releaseTracks[2]) REQUIRES(mLock);
void stop_l(); void stop_l() REQUIRES(mLock);
void setVolume_l(float leftVolume, float rightVolume); void setVolume_l(float leftVolume, float rightVolume) REQUIRES(mLock);
// For use with AudioTrack callback. // For use with AudioTrack callback.
static void staticCallback(int event, void* user, void* info); static void staticCallback(int event, void* user, void* info);
void callback(int event, void* info, int toggle, int tries); void callback(int event, void* info, int toggle, int tries)
NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock
// StreamManager should be set on construction and not changed. // StreamManager should be set on construction and not changed.
// release mLock before calling into StreamManager // release mLock before calling into StreamManager
StreamManager* mStreamManager = nullptr; StreamManager* mStreamManager = nullptr;
mutable std::mutex mLock; mutable std::mutex mLock;
std::atomic_int32_t mStreamID = 0; // Note: valid streamIDs are always positive. std::atomic_int32_t mStreamID GUARDED_BY(mLock) = 0; // Valid streamIDs are always positive.
int mState = IDLE; int mState GUARDED_BY(mLock) = IDLE;
std::shared_ptr<Sound> mSound; // Non-null if playing. std::shared_ptr<Sound> mSound GUARDED_BY(mLock); // Non-null if playing.
int32_t mSoundID = 0; // The sound ID associated with the AudioTrack. int32_t mSoundID GUARDED_BY(mLock) = 0; // SoundID associated with AudioTrack.
float mLeftVolume = 0.f; float mLeftVolume GUARDED_BY(mLock) = 0.f;
float mRightVolume = 0.f; float mRightVolume GUARDED_BY(mLock) = 0.f;
int32_t mPriority = INT32_MIN; int32_t mPriority GUARDED_BY(mLock) = INT32_MIN;
int32_t mLoop = 0; int32_t mLoop GUARDED_BY(mLock) = 0;
float mRate = 0.f; float mRate GUARDED_BY(mLock) = 0.f;
bool mAutoPaused = false; bool mAutoPaused GUARDED_BY(mLock) = false;
bool mMuted = false; bool mMuted GUARDED_BY(mLock) = false;
sp<AudioTrack> mAudioTrack; sp<AudioTrack> mAudioTrack GUARDED_BY(mLock);
int mToggle = 0; int mToggle GUARDED_BY(mLock) = 0;
int64_t mStopTimeNs = 0; // if nonzero, time to wait for stop. int64_t mStopTimeNs GUARDED_BY(mLock) = 0; // if nonzero, time to wait for stop.
}; };
} // namespace android::soundpool } // namespace android::soundpool

View File

@@ -55,7 +55,7 @@ StreamMap::StreamMap(int32_t streams) {
streams = 1; streams = 1;
} }
mStreamPoolSize = streams * 2; mStreamPoolSize = streams * 2;
mStreamPool.reset(new Stream[mStreamPoolSize]); mStreamPool = std::make_unique<Stream[]>(mStreamPoolSize); // create array of streams.
// we use a perfect hash table with 2x size to map StreamIDs to Stream pointers. // we use a perfect hash table with 2x size to map StreamIDs to Stream pointers.
mPerfectHash = std::make_unique<PerfectHash<int32_t, Stream *>>(roundup(mStreamPoolSize * 2)); mPerfectHash = std::make_unique<PerfectHash<int32_t, Stream *>>(roundup(mStreamPoolSize * 2));
} }
@@ -69,7 +69,7 @@ Stream* StreamMap::findStream(int32_t streamID) const
size_t StreamMap::streamPosition(const Stream* stream) const size_t StreamMap::streamPosition(const Stream* stream) const
{ {
ptrdiff_t index = stream - mStreamPool.get(); ptrdiff_t index = stream - mStreamPool.get();
LOG_ALWAYS_FATAL_IF(index < 0 || index >= mStreamPoolSize, LOG_ALWAYS_FATAL_IF(index < 0 || (size_t)index >= mStreamPoolSize,
"%s: stream position out of range: %td", __func__, index); "%s: stream position out of range: %td", __func__, index);
return (size_t)index; return (size_t)index;
} }
@@ -92,6 +92,11 @@ int32_t StreamMap::getNextIdForStream(Stream* stream) const {
//////////// ////////////
// Thread safety analysis is supposed to be disabled for constructors and destructors
// but clang in R seems to have a bug. We use pragma to disable.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wthread-safety-analysis"
StreamManager::StreamManager( StreamManager::StreamManager(
int32_t streams, size_t threads, const audio_attributes_t* attributes) int32_t streams, size_t threads, const audio_attributes_t* attributes)
: StreamMap(streams) : StreamMap(streams)
@@ -110,6 +115,8 @@ StreamManager::StreamManager(
"SoundPool_"); "SoundPool_");
} }
#pragma clang diagnostic pop
StreamManager::~StreamManager() StreamManager::~StreamManager()
{ {
ALOGV("%s", __func__); ALOGV("%s", __func__);

View File

@@ -183,9 +183,9 @@ private:
std::atomic_size_t mActiveThreadCount = 0; std::atomic_size_t mActiveThreadCount = 0;
std::mutex mThreadLock; std::mutex mThreadLock;
bool mQuit = false; // GUARDED_BY(mThreadLock) bool mQuit GUARDED_BY(mThreadLock) = false;
int32_t mNextThreadId = 0; // GUARDED_BY(mThreadLock) int32_t mNextThreadId GUARDED_BY(mThreadLock) = 0;
std::list<std::unique_ptr<JavaThread>> mThreads; // GUARDED_BY(mThreadLock) std::list<std::unique_ptr<JavaThread>> mThreads GUARDED_BY(mThreadLock);
}; };
/** /**
@@ -263,7 +263,7 @@ private:
mutable std::mutex mHashLock; mutable std::mutex mHashLock;
const size_t mHashCapacity; // size of mK2V no lock needed. const size_t mHashCapacity; // size of mK2V no lock needed.
std::unique_ptr<std::atomic<V>[]> mK2V; // no lock needed for read access. std::unique_ptr<std::atomic<V>[]> mK2V; // no lock needed for read access.
K mNextKey{}; // GUARDED_BY(mHashLock) K mNextKey GUARDED_BY(mHashLock) {};
}; };
/** /**
@@ -392,7 +392,8 @@ public:
// Returns positive streamID on success, 0 on failure. This is locked. // Returns positive streamID on success, 0 on failure. This is locked.
int32_t queueForPlay(const std::shared_ptr<Sound> &sound, int32_t queueForPlay(const std::shared_ptr<Sound> &sound,
int32_t soundID, float leftVolume, float rightVolume, int32_t soundID, float leftVolume, float rightVolume,
int32_t priority, int32_t loop, float rate); int32_t priority, int32_t loop, float rate)
NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// Called from soundpool::Stream // Called from soundpool::Stream
@@ -407,11 +408,11 @@ public:
private: private:
void run(int32_t id); // worker thread, takes lock internally. void run(int32_t id) NO_THREAD_SAFETY_ANALYSIS; // worker thread, takes unique_lock.
void dump() const; // no lock needed void dump() const; // no lock needed
// returns true if more worker threads are needed. // returns true if more worker threads are needed.
bool needMoreThreads_l() { bool needMoreThreads_l() REQUIRES(mStreamManagerLock) {
return mRestartStreams.size() > 0 && return mRestartStreams.size() > 0 &&
(mThreadPool->getActiveThreadCount() == 0 (mThreadPool->getActiveThreadCount() == 0
|| std::distance(mRestartStreams.begin(), || std::distance(mRestartStreams.begin(),
@@ -420,14 +421,16 @@ private:
} }
// returns true if the stream was added. // returns true if the stream was added.
bool moveToRestartQueue_l(Stream* stream, int32_t activeStreamIDToMatch = 0); bool moveToRestartQueue_l(
Stream* stream, int32_t activeStreamIDToMatch = 0) REQUIRES(mStreamManagerLock);
// returns number of queues the stream was removed from (should be 0 or 1); // returns number of queues the stream was removed from (should be 0 or 1);
// a special code of -1 is returned if activeStreamIDToMatch is > 0 and // a special code of -1 is returned if activeStreamIDToMatch is > 0 and
// the stream wasn't found on the active queue. // the stream wasn't found on the active queue.
ssize_t removeFromQueues_l(Stream* stream, int32_t activeStreamIDToMatch = 0); ssize_t removeFromQueues_l(
void addToRestartQueue_l(Stream *stream); Stream* stream, int32_t activeStreamIDToMatch = 0) REQUIRES(mStreamManagerLock);
void addToActiveQueue_l(Stream *stream); void addToRestartQueue_l(Stream *stream) REQUIRES(mStreamManagerLock);
void sanityCheckQueue_l() const; void addToActiveQueue_l(Stream *stream) REQUIRES(mStreamManagerLock);
void sanityCheckQueue_l() const REQUIRES(mStreamManagerLock);
const audio_attributes_t mAttributes; const audio_attributes_t mAttributes;
std::unique_ptr<ThreadPool> mThreadPool; // locked internally std::unique_ptr<ThreadPool> mThreadPool; // locked internally
@@ -436,9 +439,9 @@ private:
// 4 stream queues by the Manager Thread or by the user initiated play(). // 4 stream queues by the Manager Thread or by the user initiated play().
// A stream pair has exactly one stream on exactly one of the queues. // A stream pair has exactly one stream on exactly one of the queues.
std::mutex mStreamManagerLock; std::mutex mStreamManagerLock;
std::condition_variable mStreamManagerCondition; std::condition_variable mStreamManagerCondition GUARDED_BY(mStreamManagerLock);
bool mQuit = false; // GUARDED_BY(mStreamManagerLock) bool mQuit GUARDED_BY(mStreamManagerLock) = false;
// There are constructor arg "streams" pairs of streams, only one of each // There are constructor arg "streams" pairs of streams, only one of each
// pair on the 4 stream queues below. The other stream in the pair serves as // pair on the 4 stream queues below. The other stream in the pair serves as
@@ -452,24 +455,24 @@ private:
// The paired stream may be active (but with no AudioTrack), and will be restarted // The paired stream may be active (but with no AudioTrack), and will be restarted
// with an active AudioTrack when the current stream is stopped. // with an active AudioTrack when the current stream is stopped.
std::multimap<int64_t /* stopTimeNs */, Stream*> std::multimap<int64_t /* stopTimeNs */, Stream*>
mRestartStreams; // GUARDED_BY(mStreamManagerLock) mRestartStreams GUARDED_BY(mStreamManagerLock);
// 2) mActiveStreams: Streams that are active. // 2) mActiveStreams: Streams that are active.
// The paired stream will be inactive. // The paired stream will be inactive.
// This is in order of specified by kStealActiveStream_OldestFirst // This is in order of specified by kStealActiveStream_OldestFirst
std::list<Stream*> mActiveStreams; // GUARDED_BY(mStreamManagerLock) std::list<Stream*> mActiveStreams GUARDED_BY(mStreamManagerLock);
// 3) mAvailableStreams: Streams that are inactive. // 3) mAvailableStreams: Streams that are inactive.
// The paired stream will also be inactive. // The paired stream will also be inactive.
// No particular order. // No particular order.
std::unordered_set<Stream*> mAvailableStreams; // GUARDED_BY(mStreamManagerLock) std::unordered_set<Stream*> mAvailableStreams GUARDED_BY(mStreamManagerLock);
// 4) mProcessingStreams: Streams that are being processed by the ManagerThreads // 4) mProcessingStreams: Streams that are being processed by the ManagerThreads
// When on this queue, the stream and its pair are not available for stealing. // When on this queue, the stream and its pair are not available for stealing.
// Each ManagerThread will have at most one stream on the mProcessingStreams queue. // Each ManagerThread will have at most one stream on the mProcessingStreams queue.
// The paired stream may be active or restarting. // The paired stream may be active or restarting.
// No particular order. // No particular order.
std::unordered_set<Stream*> mProcessingStreams; // GUARDED_BY(mStreamManagerLock) std::unordered_set<Stream*> mProcessingStreams GUARDED_BY(mStreamManagerLock);
}; };
} // namespace android::soundpool } // namespace android::soundpool

View File

@@ -52,7 +52,7 @@ android_media_SoundPool_load_FD(JNIEnv *env, jobject thiz, jobject fileDescripto
{ {
ALOGV("android_media_SoundPool_load_FD"); ALOGV("android_media_SoundPool_load_FD");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return 0; if (ap == nullptr) return 0;
return (jint) ap->load(jniGetFDFromFileDescriptor(env, fileDescriptor), return (jint) ap->load(jniGetFDFromFileDescriptor(env, fileDescriptor),
int64_t(offset), int64_t(length), int(priority)); int64_t(offset), int64_t(length), int(priority));
} }
@@ -61,7 +61,7 @@ static jboolean
android_media_SoundPool_unload(JNIEnv *env, jobject thiz, jint sampleID) { android_media_SoundPool_unload(JNIEnv *env, jobject thiz, jint sampleID) {
ALOGV("android_media_SoundPool_unload\n"); ALOGV("android_media_SoundPool_unload\n");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return JNI_FALSE; if (ap == nullptr) return JNI_FALSE;
return ap->unload(sampleID) ? JNI_TRUE : JNI_FALSE; return ap->unload(sampleID) ? JNI_TRUE : JNI_FALSE;
} }
@@ -72,7 +72,7 @@ android_media_SoundPool_play(JNIEnv *env, jobject thiz, jint sampleID,
{ {
ALOGV("android_media_SoundPool_play\n"); ALOGV("android_media_SoundPool_play\n");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return 0; if (ap == nullptr) return 0;
return (jint) ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate); return (jint) ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate);
} }
@@ -81,7 +81,7 @@ android_media_SoundPool_pause(JNIEnv *env, jobject thiz, jint channelID)
{ {
ALOGV("android_media_SoundPool_pause"); ALOGV("android_media_SoundPool_pause");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return; if (ap == nullptr) return;
ap->pause(channelID); ap->pause(channelID);
} }
@@ -90,7 +90,7 @@ android_media_SoundPool_resume(JNIEnv *env, jobject thiz, jint channelID)
{ {
ALOGV("android_media_SoundPool_resume"); ALOGV("android_media_SoundPool_resume");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return; if (ap == nullptr) return;
ap->resume(channelID); ap->resume(channelID);
} }
@@ -99,7 +99,7 @@ android_media_SoundPool_autoPause(JNIEnv *env, jobject thiz)
{ {
ALOGV("android_media_SoundPool_autoPause"); ALOGV("android_media_SoundPool_autoPause");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return; if (ap == nullptr) return;
ap->autoPause(); ap->autoPause();
} }
@@ -108,7 +108,7 @@ android_media_SoundPool_autoResume(JNIEnv *env, jobject thiz)
{ {
ALOGV("android_media_SoundPool_autoResume"); ALOGV("android_media_SoundPool_autoResume");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return; if (ap == nullptr) return;
ap->autoResume(); ap->autoResume();
} }
@@ -117,7 +117,7 @@ android_media_SoundPool_stop(JNIEnv *env, jobject thiz, jint channelID)
{ {
ALOGV("android_media_SoundPool_stop"); ALOGV("android_media_SoundPool_stop");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return; if (ap == nullptr) return;
ap->stop(channelID); ap->stop(channelID);
} }
@@ -127,7 +127,7 @@ android_media_SoundPool_setVolume(JNIEnv *env, jobject thiz, jint channelID,
{ {
ALOGV("android_media_SoundPool_setVolume"); ALOGV("android_media_SoundPool_setVolume");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return; if (ap == nullptr) return;
ap->setVolume(channelID, (float) leftVolume, (float) rightVolume); ap->setVolume(channelID, (float) leftVolume, (float) rightVolume);
} }
@@ -136,7 +136,7 @@ android_media_SoundPool_mute(JNIEnv *env, jobject thiz, jboolean muting)
{ {
ALOGV("android_media_SoundPool_mute(%d)", muting); ALOGV("android_media_SoundPool_mute(%d)", muting);
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return; if (ap == nullptr) return;
ap->mute(muting == JNI_TRUE); ap->mute(muting == JNI_TRUE);
} }
@@ -146,7 +146,7 @@ android_media_SoundPool_setPriority(JNIEnv *env, jobject thiz, jint channelID,
{ {
ALOGV("android_media_SoundPool_setPriority"); ALOGV("android_media_SoundPool_setPriority");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return; if (ap == nullptr) return;
ap->setPriority(channelID, (int) priority); ap->setPriority(channelID, (int) priority);
} }
@@ -156,7 +156,7 @@ android_media_SoundPool_setLoop(JNIEnv *env, jobject thiz, jint channelID,
{ {
ALOGV("android_media_SoundPool_setLoop"); ALOGV("android_media_SoundPool_setLoop");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return; if (ap == nullptr) return;
ap->setLoop(channelID, loop); ap->setLoop(channelID, loop);
} }
@@ -166,7 +166,7 @@ android_media_SoundPool_setRate(JNIEnv *env, jobject thiz, jint channelID,
{ {
ALOGV("android_media_SoundPool_setRate"); ALOGV("android_media_SoundPool_setRate");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return; if (ap == nullptr) return;
ap->setRate(channelID, (float) rate); ap->setRate(channelID, (float) rate);
} }
@@ -174,24 +174,26 @@ static void android_media_callback(SoundPoolEvent event, SoundPool* soundPool, v
{ {
ALOGV("callback: (%d, %d, %d, %p, %p)", event.mMsg, event.mArg1, event.mArg2, soundPool, user); ALOGV("callback: (%d, %d, %d, %p, %p)", event.mMsg, event.mArg1, event.mArg2, soundPool, user);
JNIEnv *env = AndroidRuntime::getJNIEnv(); JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallStaticVoidMethod(fields.mSoundPoolClass, fields.mPostEvent, user, event.mMsg, event.mArg1, event.mArg2, NULL); env->CallStaticVoidMethod(
fields.mSoundPoolClass, fields.mPostEvent, user, event.mMsg, event.mArg1, event.mArg2,
nullptr /* object */);
} }
static jint static jint
android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, jobject weakRef,
jint maxChannels, jobject jaa) jint maxChannels, jobject jaa)
{ {
if (jaa == 0) { if (jaa == nullptr) {
ALOGE("Error creating SoundPool: invalid audio attributes"); ALOGE("Error creating SoundPool: invalid audio attributes");
return -1; return -1;
} }
audio_attributes_t *paa = NULL; audio_attributes_t *paa = nullptr;
// read the AudioAttributes values // read the AudioAttributes values
paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
const jstring jtags = const auto jtags =
(jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags); (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
const char* tags = env->GetStringUTFChars(jtags, NULL); const char* tags = env->GetStringUTFChars(jtags, nullptr);
// copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1); strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
env->ReleaseStringUTFChars(jtags, tags); env->ReleaseStringUTFChars(jtags, tags);
@@ -201,8 +203,8 @@ android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, jobject weakRef,
paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags); paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
ALOGV("android_media_SoundPool_native_setup"); ALOGV("android_media_SoundPool_native_setup");
SoundPool *ap = new SoundPool(maxChannels, paa); auto *ap = new SoundPool(maxChannels, paa);
if (ap == NULL) { if (ap == nullptr) {
return -1; return -1;
} }
@@ -224,12 +226,12 @@ android_media_SoundPool_release(JNIEnv *env, jobject thiz)
{ {
ALOGV("android_media_SoundPool_release"); ALOGV("android_media_SoundPool_release");
SoundPool *ap = MusterSoundPool(env, thiz); SoundPool *ap = MusterSoundPool(env, thiz);
if (ap != NULL) { if (ap != nullptr) {
// release weak reference and clear callback // release weak reference and clear callback
jobject weakRef = (jobject) ap->getUserData(); auto weakRef = (jobject) ap->getUserData();
ap->setCallback(NULL, NULL); ap->setCallback(nullptr /* callback */, nullptr /* user */);
if (weakRef != NULL) { if (weakRef != nullptr) {
env->DeleteGlobalRef(weakRef); env->DeleteGlobalRef(weakRef);
} }
@@ -309,7 +311,7 @@ static const char* const kClassPathName = "android/media/SoundPool";
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{ {
JNIEnv* env = NULL; JNIEnv* env = nullptr;
jint result = -1; jint result = -1;
jclass clazz; jclass clazz;
@@ -317,23 +319,23 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
ALOGE("ERROR: GetEnv failed\n"); ALOGE("ERROR: GetEnv failed\n");
return result; return result;
} }
assert(env != NULL); assert(env != nullptr);
clazz = env->FindClass(kClassPathName); clazz = env->FindClass(kClassPathName);
if (clazz == NULL) { if (clazz == nullptr) {
ALOGE("Can't find %s", kClassPathName); ALOGE("Can't find %s", kClassPathName);
return result; return result;
} }
fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "J"); fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "J");
if (fields.mNativeContext == NULL) { if (fields.mNativeContext == nullptr) {
ALOGE("Can't find SoundPool.mNativeContext"); ALOGE("Can't find SoundPool.mNativeContext");
return result; return result;
} }
fields.mPostEvent = env->GetStaticMethodID(clazz, "postEventFromNative", fields.mPostEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V"); "(Ljava/lang/Object;IIILjava/lang/Object;)V");
if (fields.mPostEvent == NULL) { if (fields.mPostEvent == nullptr) {
ALOGE("Can't find android/media/SoundPool.postEventFromNative"); ALOGE("Can't find android/media/SoundPool.postEventFromNative");
return result; return result;
} }
@@ -342,16 +344,18 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
// since it's a static object. // since it's a static object.
fields.mSoundPoolClass = (jclass) env->NewGlobalRef(clazz); fields.mSoundPoolClass = (jclass) env->NewGlobalRef(clazz);
if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0) if (AndroidRuntime::registerNativeMethods(
env, kClassPathName, gMethods, NELEM(gMethods)) < 0) {
return result; return result;
}
// Get the AudioAttributes class and fields // Get the AudioAttributes class and fields
jclass audioAttrClass = env->FindClass(kAudioAttributesClassPathName); jclass audioAttrClass = env->FindClass(kAudioAttributesClassPathName);
if (audioAttrClass == NULL) { if (audioAttrClass == nullptr) {
ALOGE("Can't find %s", kAudioAttributesClassPathName); ALOGE("Can't find %s", kAudioAttributesClassPathName);
return result; return result;
} }
jclass audioAttributesClassRef = (jclass)env->NewGlobalRef(audioAttrClass); auto audioAttributesClassRef = (jclass)env->NewGlobalRef(audioAttrClass);
javaAudioAttrFields.fieldUsage = env->GetFieldID(audioAttributesClassRef, "mUsage", "I"); javaAudioAttrFields.fieldUsage = env->GetFieldID(audioAttributesClassRef, "mUsage", "I");
javaAudioAttrFields.fieldContentType javaAudioAttrFields.fieldContentType
= env->GetFieldID(audioAttributesClassRef, "mContentType", "I"); = env->GetFieldID(audioAttributesClassRef, "mContentType", "I");
@@ -359,9 +363,10 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
javaAudioAttrFields.fieldFormattedTags = javaAudioAttrFields.fieldFormattedTags =
env->GetFieldID(audioAttributesClassRef, "mFormattedTags", "Ljava/lang/String;"); env->GetFieldID(audioAttributesClassRef, "mFormattedTags", "Ljava/lang/String;");
env->DeleteGlobalRef(audioAttributesClassRef); env->DeleteGlobalRef(audioAttributesClassRef);
if (javaAudioAttrFields.fieldUsage == NULL || javaAudioAttrFields.fieldContentType == NULL if (javaAudioAttrFields.fieldUsage == nullptr
|| javaAudioAttrFields.fieldFlags == NULL || javaAudioAttrFields.fieldContentType == nullptr
|| javaAudioAttrFields.fieldFormattedTags == NULL) { || javaAudioAttrFields.fieldFlags == nullptr
|| javaAudioAttrFields.fieldFormattedTags == nullptr) {
ALOGE("Can't initialize AudioAttributes fields"); ALOGE("Can't initialize AudioAttributes fields");
return result; return result;
} }