Merge "SoundPool: Add clang-tidy and fix" into rvc-dev am: 8b5bc1ff73
Change-Id: I19dfbe5e7304ad348ad51427db85bd2bb24dd449
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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__);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user