Loading media/jni/soundpool/Stream.cpp +56 −38 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ */ //#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0 #include <utility> #define LOG_TAG "SoundPool::Stream" #define LOG_TAG "SoundPool::Stream" #include <utils/Log.h> #include <utils/Log.h> #include <android/content/AttributionSourceState.h> #include <android/content/AttributionSourceState.h> Loading Loading @@ -309,13 +310,11 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, } } if (mAudioTrack == nullptr) { if (mAudioTrack == 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 // This enables the detection of callbacks received from the old // as callback user data. This enables the detection of callbacks received from the old // audio track while the new one is being started and avoids processing them with // audio track while the new one is being started and avoids processing them with // wrong audio audio buffer size (mAudioBufferSize) // wrong audio audio buffer size (mAudioBufferSize) auto toggle = mToggle ^ 1; auto toggle = mToggle ^ 1; // NOLINTNEXTLINE(performance-no-int-to-ptr) // NOLINTNEXTLINE(performance-no-int-to-ptr) void* userData = reinterpret_cast<void*>((uintptr_t)this | toggle); audio_channel_mask_t soundChannelMask = sound->getChannelMask(); audio_channel_mask_t soundChannelMask = sound->getChannelMask(); // When sound contains a valid channel mask, use it as is. // When sound contains a valid channel mask, use it as is. // Otherwise, use stream count to calculate channel mask. // Otherwise, use stream count to calculate channel mask. Loading @@ -327,10 +326,11 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, android::content::AttributionSourceState attributionSource; android::content::AttributionSourceState attributionSource; attributionSource.packageName = mStreamManager->getOpPackageName(); attributionSource.packageName = mStreamManager->getOpPackageName(); attributionSource.token = sp<BBinder>::make(); attributionSource.token = sp<BBinder>::make(); mCallback = sp<StreamCallback>::make(this, toggle), // TODO b/182469354 make consistent with AudioRecord, add util for native source // TODO b/182469354 make consistent with AudioRecord, add util for native source mAudioTrack = new AudioTrack(streamType, sampleRate, sound->getFormat(), mAudioTrack = new AudioTrack(streamType, sampleRate, sound->getFormat(), channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, staticCallback, userData, mCallback, 0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE, 0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE, AudioTrack::TRANSFER_DEFAULT, AudioTrack::TRANSFER_DEFAULT, nullptr /*offloadInfo*/, attributionSource, nullptr /*offloadInfo*/, attributionSource, Loading Loading @@ -375,16 +375,55 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, mStreamID = nextStreamID; // prefer this to be the last, as it is an atomic sync point mStreamID = nextStreamID; // prefer this to be the last, as it is an atomic sync point } } /* static */ int Stream::getCorrespondingStreamID() { void Stream::staticCallback(int event, void* user, void* info) std::lock_guard lock(mLock); { return static_cast<int>(mAudioTrack ? mStreamID : getPairStream()->mStreamID); const auto userAsInt = (uintptr_t)user; } // NOLINTNEXTLINE(performance-no-int-to-ptr) size_t Stream::StreamCallback::onMoreData(const AudioTrack::Buffer&) { auto stream = reinterpret_cast<Stream*>(userAsInt & ~1); ALOGW("%s streamID %d Unexpected EVENT_MORE_DATA for static track", stream->callback(event, info, int(userAsInt & 1), 0 /* tries */); __func__, mStream->getCorrespondingStreamID()); return 0; } void Stream::StreamCallback::onUnderrun() { ALOGW("%s streamID %d Unexpected EVENT_UNDERRUN for static track", __func__, mStream->getCorrespondingStreamID()); } } void Stream::callback(int event, void* info, int toggle, int tries) void Stream::StreamCallback::onLoopEnd(int32_t) { ALOGV("%s streamID %d EVENT_LOOP_END", __func__, mStream->getCorrespondingStreamID()); } void Stream::StreamCallback::onMarker(uint32_t) { ALOGW("%s streamID %d Unexpected EVENT_MARKER for static track", __func__, mStream->getCorrespondingStreamID()); } void Stream::StreamCallback::onNewPos(uint32_t) { ALOGW("%s streamID %d Unexpected EVENT_NEW_POS for static track", __func__, mStream->getCorrespondingStreamID()); } void Stream::StreamCallback::onBufferEnd() { mStream->onBufferEnd(mToggle, 0); } void Stream::StreamCallback::onNewIAudioTrack() { ALOGV("%s streamID %d NEW_IAUDIOTRACK", __func__, mStream->getCorrespondingStreamID()); } void Stream::StreamCallback::onStreamEnd() { ALOGW("%s streamID %d Unexpected EVENT_STREAM_END for static track", __func__, mStream->getCorrespondingStreamID()); } size_t Stream::StreamCallback::onCanWriteMoreData(const AudioTrack::Buffer&) { ALOGW("%s streamID %d Unexpected EVENT_CAN_WRITE_MORE_DATA for static track", __func__, mStream->getCorrespondingStreamID()); return 0; } void Stream::onBufferEnd(int toggle, int tries) { { int32_t activeStreamIDToRestart = 0; int32_t activeStreamIDToRestart = 0; { { Loading @@ -400,7 +439,7 @@ void Stream::callback(int event, void* info, int toggle, int tries) if (tries < 3) { if (tries < 3) { lock.unlock(); lock.unlock(); ALOGV("%s streamID %d going to pair stream", __func__, (int)mStreamID); ALOGV("%s streamID %d going to pair stream", __func__, (int)mStreamID); getPairStream()->callback(event, info, toggle, tries + 1); getPairStream()->onBufferEnd(toggle, tries + 1); } else { } else { ALOGW("%s streamID %d cannot find track", __func__, (int)mStreamID); ALOGW("%s streamID %d cannot find track", __func__, (int)mStreamID); } } Loading @@ -410,32 +449,11 @@ void Stream::callback(int event, void* info, int toggle, int tries) ALOGD("%s streamID %d wrong toggle", __func__, (int)mStreamID); ALOGD("%s streamID %d wrong toggle", __func__, (int)mStreamID); return; return; } } switch (event) { case AudioTrack::EVENT_MORE_DATA: ALOGW("%s streamID %d Invalid EVENT_MORE_DATA for static track", __func__, (int)mStreamID); break; case AudioTrack::EVENT_UNDERRUN: ALOGW("%s streamID %d Invalid EVENT_UNDERRUN for static track", __func__, (int)mStreamID); break; case AudioTrack::EVENT_BUFFER_END: ALOGV("%s streamID %d EVENT_BUFFER_END", __func__, (int)mStreamID); ALOGV("%s streamID %d EVENT_BUFFER_END", __func__, (int)mStreamID); if (mState != IDLE) { if (mState != IDLE) { activeStreamIDToRestart = mStreamID; activeStreamIDToRestart = mStreamID; mStopTimeNs = systemTime(); mStopTimeNs = systemTime(); } } break; case AudioTrack::EVENT_LOOP_END: ALOGV("%s streamID %d EVENT_LOOP_END", __func__, (int)mStreamID); break; case AudioTrack::EVENT_NEW_IAUDIOTRACK: ALOGV("%s streamID %d NEW_IAUDIOTRACK", __func__, (int)mStreamID); break; default: ALOGW("%s streamID %d Invalid event %d", __func__, (int)mStreamID, event); break; } } // lock ends here. This is on the callback thread, no need to be precise. } // lock ends here. This is on the callback thread, no need to be precise. if (activeStreamIDToRestart > 0) { if (activeStreamIDToRestart > 0) { // Restart only if a particular streamID is still current and active. // Restart only if a particular streamID is still current and active. Loading media/jni/soundpool/Stream.h +30 −3 Original line number Original line Diff line number Diff line Loading @@ -124,6 +124,35 @@ public: // This never changes. See top of header. // This never changes. See top of header. Stream* getPairStream() const; Stream* getPairStream() const; // Stream ID of ourselves, or the pair depending on who holds the AudioTrack int getCorrespondingStreamID(); protected: // AudioTrack callback interface implementation class StreamCallback : public AudioTrack::IAudioTrackCallback { public: StreamCallback(Stream * stream, bool toggle) : mStream(stream), mToggle(toggle) {} size_t onMoreData(const AudioTrack::Buffer& buffer) override; void onUnderrun() override; void onLoopEnd(int32_t loopsRemaining) override; void onMarker(uint32_t markerPosition) override; void onNewPos(uint32_t newPos) override; void onBufferEnd() override; void onNewIAudioTrack() override; void onStreamEnd() override; size_t onCanWriteMoreData(const AudioTrack::Buffer& buffer) override; // Holding a raw ptr is technically unsafe, but, Stream objects persist // through the lifetime of the StreamManager through the use of a // unique_ptr<Stream[]>. Ensuring lifetime will cause us to give up // locality as well as pay RefBase/sp performance cost, which we are // unwilling to do. Non-owning refs to unique_ptrs are idiomatically raw // ptrs, as below. Stream * const mStream; const bool mToggle; }; sp<StreamCallback> mCallback; private: private: // garbage is used to release tracks and data outside of any lock. // garbage is used to release tracks and data outside of any lock. void play_l(const std::shared_ptr<Sound>& sound, int streamID, void play_l(const std::shared_ptr<Sound>& sound, int streamID, Loading @@ -133,9 +162,7 @@ private: void setVolume_l(float leftVolume, float rightVolume) REQUIRES(mLock); 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); void onBufferEnd(int toggle, int tries) NO_THREAD_SAFETY_ANALYSIS; 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 Loading Loading
media/jni/soundpool/Stream.cpp +56 −38 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ */ //#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0 #include <utility> #define LOG_TAG "SoundPool::Stream" #define LOG_TAG "SoundPool::Stream" #include <utils/Log.h> #include <utils/Log.h> #include <android/content/AttributionSourceState.h> #include <android/content/AttributionSourceState.h> Loading Loading @@ -309,13 +310,11 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, } } if (mAudioTrack == nullptr) { if (mAudioTrack == 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 // This enables the detection of callbacks received from the old // as callback user data. This enables the detection of callbacks received from the old // audio track while the new one is being started and avoids processing them with // audio track while the new one is being started and avoids processing them with // wrong audio audio buffer size (mAudioBufferSize) // wrong audio audio buffer size (mAudioBufferSize) auto toggle = mToggle ^ 1; auto toggle = mToggle ^ 1; // NOLINTNEXTLINE(performance-no-int-to-ptr) // NOLINTNEXTLINE(performance-no-int-to-ptr) void* userData = reinterpret_cast<void*>((uintptr_t)this | toggle); audio_channel_mask_t soundChannelMask = sound->getChannelMask(); audio_channel_mask_t soundChannelMask = sound->getChannelMask(); // When sound contains a valid channel mask, use it as is. // When sound contains a valid channel mask, use it as is. // Otherwise, use stream count to calculate channel mask. // Otherwise, use stream count to calculate channel mask. Loading @@ -327,10 +326,11 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, android::content::AttributionSourceState attributionSource; android::content::AttributionSourceState attributionSource; attributionSource.packageName = mStreamManager->getOpPackageName(); attributionSource.packageName = mStreamManager->getOpPackageName(); attributionSource.token = sp<BBinder>::make(); attributionSource.token = sp<BBinder>::make(); mCallback = sp<StreamCallback>::make(this, toggle), // TODO b/182469354 make consistent with AudioRecord, add util for native source // TODO b/182469354 make consistent with AudioRecord, add util for native source mAudioTrack = new AudioTrack(streamType, sampleRate, sound->getFormat(), mAudioTrack = new AudioTrack(streamType, sampleRate, sound->getFormat(), channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, staticCallback, userData, mCallback, 0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE, 0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE, AudioTrack::TRANSFER_DEFAULT, AudioTrack::TRANSFER_DEFAULT, nullptr /*offloadInfo*/, attributionSource, nullptr /*offloadInfo*/, attributionSource, Loading Loading @@ -375,16 +375,55 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, mStreamID = nextStreamID; // prefer this to be the last, as it is an atomic sync point mStreamID = nextStreamID; // prefer this to be the last, as it is an atomic sync point } } /* static */ int Stream::getCorrespondingStreamID() { void Stream::staticCallback(int event, void* user, void* info) std::lock_guard lock(mLock); { return static_cast<int>(mAudioTrack ? mStreamID : getPairStream()->mStreamID); const auto userAsInt = (uintptr_t)user; } // NOLINTNEXTLINE(performance-no-int-to-ptr) size_t Stream::StreamCallback::onMoreData(const AudioTrack::Buffer&) { auto stream = reinterpret_cast<Stream*>(userAsInt & ~1); ALOGW("%s streamID %d Unexpected EVENT_MORE_DATA for static track", stream->callback(event, info, int(userAsInt & 1), 0 /* tries */); __func__, mStream->getCorrespondingStreamID()); return 0; } void Stream::StreamCallback::onUnderrun() { ALOGW("%s streamID %d Unexpected EVENT_UNDERRUN for static track", __func__, mStream->getCorrespondingStreamID()); } } void Stream::callback(int event, void* info, int toggle, int tries) void Stream::StreamCallback::onLoopEnd(int32_t) { ALOGV("%s streamID %d EVENT_LOOP_END", __func__, mStream->getCorrespondingStreamID()); } void Stream::StreamCallback::onMarker(uint32_t) { ALOGW("%s streamID %d Unexpected EVENT_MARKER for static track", __func__, mStream->getCorrespondingStreamID()); } void Stream::StreamCallback::onNewPos(uint32_t) { ALOGW("%s streamID %d Unexpected EVENT_NEW_POS for static track", __func__, mStream->getCorrespondingStreamID()); } void Stream::StreamCallback::onBufferEnd() { mStream->onBufferEnd(mToggle, 0); } void Stream::StreamCallback::onNewIAudioTrack() { ALOGV("%s streamID %d NEW_IAUDIOTRACK", __func__, mStream->getCorrespondingStreamID()); } void Stream::StreamCallback::onStreamEnd() { ALOGW("%s streamID %d Unexpected EVENT_STREAM_END for static track", __func__, mStream->getCorrespondingStreamID()); } size_t Stream::StreamCallback::onCanWriteMoreData(const AudioTrack::Buffer&) { ALOGW("%s streamID %d Unexpected EVENT_CAN_WRITE_MORE_DATA for static track", __func__, mStream->getCorrespondingStreamID()); return 0; } void Stream::onBufferEnd(int toggle, int tries) { { int32_t activeStreamIDToRestart = 0; int32_t activeStreamIDToRestart = 0; { { Loading @@ -400,7 +439,7 @@ void Stream::callback(int event, void* info, int toggle, int tries) if (tries < 3) { if (tries < 3) { lock.unlock(); lock.unlock(); ALOGV("%s streamID %d going to pair stream", __func__, (int)mStreamID); ALOGV("%s streamID %d going to pair stream", __func__, (int)mStreamID); getPairStream()->callback(event, info, toggle, tries + 1); getPairStream()->onBufferEnd(toggle, tries + 1); } else { } else { ALOGW("%s streamID %d cannot find track", __func__, (int)mStreamID); ALOGW("%s streamID %d cannot find track", __func__, (int)mStreamID); } } Loading @@ -410,32 +449,11 @@ void Stream::callback(int event, void* info, int toggle, int tries) ALOGD("%s streamID %d wrong toggle", __func__, (int)mStreamID); ALOGD("%s streamID %d wrong toggle", __func__, (int)mStreamID); return; return; } } switch (event) { case AudioTrack::EVENT_MORE_DATA: ALOGW("%s streamID %d Invalid EVENT_MORE_DATA for static track", __func__, (int)mStreamID); break; case AudioTrack::EVENT_UNDERRUN: ALOGW("%s streamID %d Invalid EVENT_UNDERRUN for static track", __func__, (int)mStreamID); break; case AudioTrack::EVENT_BUFFER_END: ALOGV("%s streamID %d EVENT_BUFFER_END", __func__, (int)mStreamID); ALOGV("%s streamID %d EVENT_BUFFER_END", __func__, (int)mStreamID); if (mState != IDLE) { if (mState != IDLE) { activeStreamIDToRestart = mStreamID; activeStreamIDToRestart = mStreamID; mStopTimeNs = systemTime(); mStopTimeNs = systemTime(); } } break; case AudioTrack::EVENT_LOOP_END: ALOGV("%s streamID %d EVENT_LOOP_END", __func__, (int)mStreamID); break; case AudioTrack::EVENT_NEW_IAUDIOTRACK: ALOGV("%s streamID %d NEW_IAUDIOTRACK", __func__, (int)mStreamID); break; default: ALOGW("%s streamID %d Invalid event %d", __func__, (int)mStreamID, event); break; } } // lock ends here. This is on the callback thread, no need to be precise. } // lock ends here. This is on the callback thread, no need to be precise. if (activeStreamIDToRestart > 0) { if (activeStreamIDToRestart > 0) { // Restart only if a particular streamID is still current and active. // Restart only if a particular streamID is still current and active. Loading
media/jni/soundpool/Stream.h +30 −3 Original line number Original line Diff line number Diff line Loading @@ -124,6 +124,35 @@ public: // This never changes. See top of header. // This never changes. See top of header. Stream* getPairStream() const; Stream* getPairStream() const; // Stream ID of ourselves, or the pair depending on who holds the AudioTrack int getCorrespondingStreamID(); protected: // AudioTrack callback interface implementation class StreamCallback : public AudioTrack::IAudioTrackCallback { public: StreamCallback(Stream * stream, bool toggle) : mStream(stream), mToggle(toggle) {} size_t onMoreData(const AudioTrack::Buffer& buffer) override; void onUnderrun() override; void onLoopEnd(int32_t loopsRemaining) override; void onMarker(uint32_t markerPosition) override; void onNewPos(uint32_t newPos) override; void onBufferEnd() override; void onNewIAudioTrack() override; void onStreamEnd() override; size_t onCanWriteMoreData(const AudioTrack::Buffer& buffer) override; // Holding a raw ptr is technically unsafe, but, Stream objects persist // through the lifetime of the StreamManager through the use of a // unique_ptr<Stream[]>. Ensuring lifetime will cause us to give up // locality as well as pay RefBase/sp performance cost, which we are // unwilling to do. Non-owning refs to unique_ptrs are idiomatically raw // ptrs, as below. Stream * const mStream; const bool mToggle; }; sp<StreamCallback> mCallback; private: private: // garbage is used to release tracks and data outside of any lock. // garbage is used to release tracks and data outside of any lock. void play_l(const std::shared_ptr<Sound>& sound, int streamID, void play_l(const std::shared_ptr<Sound>& sound, int streamID, Loading @@ -133,9 +162,7 @@ private: void setVolume_l(float leftVolume, float rightVolume) REQUIRES(mLock); 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); void onBufferEnd(int toggle, int tries) NO_THREAD_SAFETY_ANALYSIS; 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 Loading