Loading services/audioflinger/AudioFlinger.cpp +29 −2 Original line number Original line Diff line number Diff line Loading @@ -813,7 +813,33 @@ sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input, continue; continue; } } size_t frameCount = std::lcm(thread->frameCount(), secondaryThread->frameCount()); size_t sourceFrameCount = thread->frameCount() * output.sampleRate / thread->sampleRate(); size_t sinkFrameCount = secondaryThread->frameCount() * output.sampleRate / secondaryThread->sampleRate(); // If the secondary output has just been opened, the first secondaryThread write // will not block as it will fill the empty startup buffer of the HAL, // so a second sink buffer needs to be ready for the immediate next blocking write. // Additionally, have a margin of one main thread buffer as the scheduling jitter // can reorder the writes (eg if thread A&B have the same write intervale, // the scheduler could schedule AB...BA) size_t frameCountToBeReady = 2 * sinkFrameCount + sourceFrameCount; // Total secondary output buffer must be at least as the read frames plus // the margin of a few buffers on both sides in case the // threads scheduling has some jitter. // That value should not impact latency as the secondary track is started before // its buffer is full, see frameCountToBeReady. size_t frameCount = frameCountToBeReady + 2 * (sourceFrameCount + sinkFrameCount); // The frameCount should also not be smaller than the secondary thread min frame // count size_t minFrameCount = AudioSystem::calculateMinFrameCount( [&] { Mutex::Autolock _l(secondaryThread->mLock); return secondaryThread->latency_l(); }(), secondaryThread->mNormalFrameCount, secondaryThread->mSampleRate, output.sampleRate, input.speed); frameCount = std::max(frameCount, minFrameCount); using namespace std::chrono_literals; using namespace std::chrono_literals; auto inChannelMask = audio_channel_mask_out_to_in(input.config.channel_mask); auto inChannelMask = audio_channel_mask_out_to_in(input.config.channel_mask); Loading Loading @@ -846,7 +872,8 @@ sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input, patchRecord->buffer(), patchRecord->buffer(), patchRecord->bufferSize(), patchRecord->bufferSize(), outputFlags, outputFlags, 0ns /* timeout */); 0ns /* timeout */, frameCountToBeReady); status = patchTrack->initCheck(); status = patchTrack->initCheck(); if (status != NO_ERROR) { if (status != NO_ERROR) { ALOGE("Secondary output patchTrack init failed: %d", status); ALOGE("Secondary output patchTrack init failed: %d", status); Loading services/audioflinger/PlaybackTracks.h +11 −3 Original line number Original line Diff line number Diff line Loading @@ -74,7 +74,10 @@ public: uid_t uid, uid_t uid, audio_output_flags_t flags, audio_output_flags_t flags, track_type type, track_type type, audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE); audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE, /** default behaviour is to start when there are as many frames * ready as possible (aka. Buffer is full). */ size_t frameCountToBeReady = SIZE_MAX); virtual ~Track(); virtual ~Track(); virtual status_t initCheck() const; virtual status_t initCheck() const; Loading Loading @@ -263,6 +266,8 @@ protected: }; }; sp<AudioVibrationController> mAudioVibrationController; sp<AudioVibrationController> mAudioVibrationController; sp<os::ExternalVibration> mExternalVibration; sp<os::ExternalVibration> mExternalVibration; /** How many frames should be in the buffer before the track is considered ready */ const size_t mFrameCountToBeReady; private: private: void interceptBuffer(const AudioBufferProvider::Buffer& buffer); void interceptBuffer(const AudioBufferProvider::Buffer& buffer); Loading Loading @@ -382,7 +387,11 @@ public: void *buffer, void *buffer, size_t bufferSize, size_t bufferSize, audio_output_flags_t flags, audio_output_flags_t flags, const Timeout& timeout = {}); const Timeout& timeout = {}, size_t frameCountToBeReady = 1 /** Default behaviour is to start * as soon as possible to have * the lowest possible latency * even if it might glitch. */); virtual ~PatchTrack(); virtual ~PatchTrack(); size_t framesReady() const override; size_t framesReady() const override; Loading @@ -402,5 +411,4 @@ public: private: private: void restartIfDisabled(); void restartIfDisabled(); }; // end of PatchTrack }; // end of PatchTrack services/audioflinger/Tracks.cpp +15 −7 Original line number Original line Diff line number Diff line Loading @@ -508,7 +508,8 @@ AudioFlinger::PlaybackThread::Track::Track( uid_t uid, uid_t uid, audio_output_flags_t flags, audio_output_flags_t flags, track_type type, track_type type, audio_port_handle_t portId) audio_port_handle_t portId, size_t frameCountToBeReady) : TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount, : TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount, // TODO: Using unsecurePointer() has some associated security pitfalls // TODO: Using unsecurePointer() has some associated security pitfalls // (see declaration for details). // (see declaration for details). Loading @@ -531,6 +532,7 @@ AudioFlinger::PlaybackThread::Track::Track( mVolumeHandler(new media::VolumeHandler(sampleRate)), mVolumeHandler(new media::VolumeHandler(sampleRate)), mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(uid, attr, id(), streamType)), mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(uid, attr, id(), streamType)), // mSinkTimestamp // mSinkTimestamp mFrameCountToBeReady(frameCountToBeReady), mFastIndex(-1), mFastIndex(-1), mCachedVolume(1.0), mCachedVolume(1.0), /* The track might not play immediately after being active, similarly as if its volume was 0. /* The track might not play immediately after being active, similarly as if its volume was 0. Loading Loading @@ -833,7 +835,7 @@ void AudioFlinger::PlaybackThread::Track::interceptBuffer( auto spent = ceil<std::chrono::microseconds>(std::chrono::steady_clock::now() - start); auto spent = ceil<std::chrono::microseconds>(std::chrono::steady_clock::now() - start); using namespace std::chrono_literals; using namespace std::chrono_literals; // Average is ~20us per track, this should virtually never be logged (Logging takes >200us) // Average is ~20us per track, this should virtually never be logged (Logging takes >200us) ALOGD_IF(spent > 200us, "%s: took %lldus to intercept %zu tracks", __func__, ALOGD_IF(spent > 500us, "%s: took %lldus to intercept %zu tracks", __func__, spent.count(), mTeePatches.size()); spent.count(), mTeePatches.size()); } } Loading Loading @@ -886,8 +888,12 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const { return true; return true; } } if (framesReady() >= mServerProxy->getBufferSizeInFrames() || size_t bufferSizeInFrames = mServerProxy->getBufferSizeInFrames(); (mCblk->mFlags & CBLK_FORCEREADY)) { size_t framesToBeReady = std::min(mFrameCountToBeReady, bufferSizeInFrames); if (framesReady() >= framesToBeReady || (mCblk->mFlags & CBLK_FORCEREADY)) { ALOGV("%s(%d): consider track ready with %zu/%zu, target was %zu)", __func__, mId, framesReady(), bufferSizeInFrames, framesToBeReady); mFillingUpStatus = FS_FILLED; mFillingUpStatus = FS_FILLED; android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags); android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags); return true; return true; Loading Loading @@ -1389,6 +1395,7 @@ void AudioFlinger::PlaybackThread::Track::invalidate() void AudioFlinger::PlaybackThread::Track::disable() void AudioFlinger::PlaybackThread::Track::disable() { { // TODO(b/142394888): the filling status should also be reset to filling signalClientFlag(CBLK_DISABLED); signalClientFlag(CBLK_DISABLED); } } Loading Loading @@ -1766,12 +1773,14 @@ AudioFlinger::PlaybackThread::PatchTrack::PatchTrack(PlaybackThread *playbackThr void *buffer, void *buffer, size_t bufferSize, size_t bufferSize, audio_output_flags_t flags, audio_output_flags_t flags, const Timeout& timeout) const Timeout& timeout, size_t frameCountToBeReady) : Track(playbackThread, NULL, streamType, : Track(playbackThread, NULL, streamType, audio_attributes_t{} /* currently unused for patch track */, audio_attributes_t{} /* currently unused for patch track */, sampleRate, format, channelMask, frameCount, sampleRate, format, channelMask, frameCount, buffer, bufferSize, nullptr /* sharedBuffer */, buffer, bufferSize, nullptr /* sharedBuffer */, AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, flags, TYPE_PATCH), AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, flags, TYPE_PATCH, AUDIO_PORT_HANDLE_NONE, frameCountToBeReady), PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true), PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true), *playbackThread, timeout) *playbackThread, timeout) { { Loading Loading @@ -1864,7 +1873,6 @@ void AudioFlinger::PlaybackThread::PatchTrack::releaseBuffer(Proxy::Buffer* buff { { mProxy->releaseBuffer(buffer); mProxy->releaseBuffer(buffer); restartIfDisabled(); restartIfDisabled(); android_atomic_or(CBLK_FORCEREADY, &mCblk->mFlags); } } void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled() void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled() Loading Loading
services/audioflinger/AudioFlinger.cpp +29 −2 Original line number Original line Diff line number Diff line Loading @@ -813,7 +813,33 @@ sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input, continue; continue; } } size_t frameCount = std::lcm(thread->frameCount(), secondaryThread->frameCount()); size_t sourceFrameCount = thread->frameCount() * output.sampleRate / thread->sampleRate(); size_t sinkFrameCount = secondaryThread->frameCount() * output.sampleRate / secondaryThread->sampleRate(); // If the secondary output has just been opened, the first secondaryThread write // will not block as it will fill the empty startup buffer of the HAL, // so a second sink buffer needs to be ready for the immediate next blocking write. // Additionally, have a margin of one main thread buffer as the scheduling jitter // can reorder the writes (eg if thread A&B have the same write intervale, // the scheduler could schedule AB...BA) size_t frameCountToBeReady = 2 * sinkFrameCount + sourceFrameCount; // Total secondary output buffer must be at least as the read frames plus // the margin of a few buffers on both sides in case the // threads scheduling has some jitter. // That value should not impact latency as the secondary track is started before // its buffer is full, see frameCountToBeReady. size_t frameCount = frameCountToBeReady + 2 * (sourceFrameCount + sinkFrameCount); // The frameCount should also not be smaller than the secondary thread min frame // count size_t minFrameCount = AudioSystem::calculateMinFrameCount( [&] { Mutex::Autolock _l(secondaryThread->mLock); return secondaryThread->latency_l(); }(), secondaryThread->mNormalFrameCount, secondaryThread->mSampleRate, output.sampleRate, input.speed); frameCount = std::max(frameCount, minFrameCount); using namespace std::chrono_literals; using namespace std::chrono_literals; auto inChannelMask = audio_channel_mask_out_to_in(input.config.channel_mask); auto inChannelMask = audio_channel_mask_out_to_in(input.config.channel_mask); Loading Loading @@ -846,7 +872,8 @@ sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input, patchRecord->buffer(), patchRecord->buffer(), patchRecord->bufferSize(), patchRecord->bufferSize(), outputFlags, outputFlags, 0ns /* timeout */); 0ns /* timeout */, frameCountToBeReady); status = patchTrack->initCheck(); status = patchTrack->initCheck(); if (status != NO_ERROR) { if (status != NO_ERROR) { ALOGE("Secondary output patchTrack init failed: %d", status); ALOGE("Secondary output patchTrack init failed: %d", status); Loading
services/audioflinger/PlaybackTracks.h +11 −3 Original line number Original line Diff line number Diff line Loading @@ -74,7 +74,10 @@ public: uid_t uid, uid_t uid, audio_output_flags_t flags, audio_output_flags_t flags, track_type type, track_type type, audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE); audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE, /** default behaviour is to start when there are as many frames * ready as possible (aka. Buffer is full). */ size_t frameCountToBeReady = SIZE_MAX); virtual ~Track(); virtual ~Track(); virtual status_t initCheck() const; virtual status_t initCheck() const; Loading Loading @@ -263,6 +266,8 @@ protected: }; }; sp<AudioVibrationController> mAudioVibrationController; sp<AudioVibrationController> mAudioVibrationController; sp<os::ExternalVibration> mExternalVibration; sp<os::ExternalVibration> mExternalVibration; /** How many frames should be in the buffer before the track is considered ready */ const size_t mFrameCountToBeReady; private: private: void interceptBuffer(const AudioBufferProvider::Buffer& buffer); void interceptBuffer(const AudioBufferProvider::Buffer& buffer); Loading Loading @@ -382,7 +387,11 @@ public: void *buffer, void *buffer, size_t bufferSize, size_t bufferSize, audio_output_flags_t flags, audio_output_flags_t flags, const Timeout& timeout = {}); const Timeout& timeout = {}, size_t frameCountToBeReady = 1 /** Default behaviour is to start * as soon as possible to have * the lowest possible latency * even if it might glitch. */); virtual ~PatchTrack(); virtual ~PatchTrack(); size_t framesReady() const override; size_t framesReady() const override; Loading @@ -402,5 +411,4 @@ public: private: private: void restartIfDisabled(); void restartIfDisabled(); }; // end of PatchTrack }; // end of PatchTrack
services/audioflinger/Tracks.cpp +15 −7 Original line number Original line Diff line number Diff line Loading @@ -508,7 +508,8 @@ AudioFlinger::PlaybackThread::Track::Track( uid_t uid, uid_t uid, audio_output_flags_t flags, audio_output_flags_t flags, track_type type, track_type type, audio_port_handle_t portId) audio_port_handle_t portId, size_t frameCountToBeReady) : TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount, : TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount, // TODO: Using unsecurePointer() has some associated security pitfalls // TODO: Using unsecurePointer() has some associated security pitfalls // (see declaration for details). // (see declaration for details). Loading @@ -531,6 +532,7 @@ AudioFlinger::PlaybackThread::Track::Track( mVolumeHandler(new media::VolumeHandler(sampleRate)), mVolumeHandler(new media::VolumeHandler(sampleRate)), mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(uid, attr, id(), streamType)), mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(uid, attr, id(), streamType)), // mSinkTimestamp // mSinkTimestamp mFrameCountToBeReady(frameCountToBeReady), mFastIndex(-1), mFastIndex(-1), mCachedVolume(1.0), mCachedVolume(1.0), /* The track might not play immediately after being active, similarly as if its volume was 0. /* The track might not play immediately after being active, similarly as if its volume was 0. Loading Loading @@ -833,7 +835,7 @@ void AudioFlinger::PlaybackThread::Track::interceptBuffer( auto spent = ceil<std::chrono::microseconds>(std::chrono::steady_clock::now() - start); auto spent = ceil<std::chrono::microseconds>(std::chrono::steady_clock::now() - start); using namespace std::chrono_literals; using namespace std::chrono_literals; // Average is ~20us per track, this should virtually never be logged (Logging takes >200us) // Average is ~20us per track, this should virtually never be logged (Logging takes >200us) ALOGD_IF(spent > 200us, "%s: took %lldus to intercept %zu tracks", __func__, ALOGD_IF(spent > 500us, "%s: took %lldus to intercept %zu tracks", __func__, spent.count(), mTeePatches.size()); spent.count(), mTeePatches.size()); } } Loading Loading @@ -886,8 +888,12 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const { return true; return true; } } if (framesReady() >= mServerProxy->getBufferSizeInFrames() || size_t bufferSizeInFrames = mServerProxy->getBufferSizeInFrames(); (mCblk->mFlags & CBLK_FORCEREADY)) { size_t framesToBeReady = std::min(mFrameCountToBeReady, bufferSizeInFrames); if (framesReady() >= framesToBeReady || (mCblk->mFlags & CBLK_FORCEREADY)) { ALOGV("%s(%d): consider track ready with %zu/%zu, target was %zu)", __func__, mId, framesReady(), bufferSizeInFrames, framesToBeReady); mFillingUpStatus = FS_FILLED; mFillingUpStatus = FS_FILLED; android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags); android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags); return true; return true; Loading Loading @@ -1389,6 +1395,7 @@ void AudioFlinger::PlaybackThread::Track::invalidate() void AudioFlinger::PlaybackThread::Track::disable() void AudioFlinger::PlaybackThread::Track::disable() { { // TODO(b/142394888): the filling status should also be reset to filling signalClientFlag(CBLK_DISABLED); signalClientFlag(CBLK_DISABLED); } } Loading Loading @@ -1766,12 +1773,14 @@ AudioFlinger::PlaybackThread::PatchTrack::PatchTrack(PlaybackThread *playbackThr void *buffer, void *buffer, size_t bufferSize, size_t bufferSize, audio_output_flags_t flags, audio_output_flags_t flags, const Timeout& timeout) const Timeout& timeout, size_t frameCountToBeReady) : Track(playbackThread, NULL, streamType, : Track(playbackThread, NULL, streamType, audio_attributes_t{} /* currently unused for patch track */, audio_attributes_t{} /* currently unused for patch track */, sampleRate, format, channelMask, frameCount, sampleRate, format, channelMask, frameCount, buffer, bufferSize, nullptr /* sharedBuffer */, buffer, bufferSize, nullptr /* sharedBuffer */, AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, flags, TYPE_PATCH), AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, flags, TYPE_PATCH, AUDIO_PORT_HANDLE_NONE, frameCountToBeReady), PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true), PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true), *playbackThread, timeout) *playbackThread, timeout) { { Loading Loading @@ -1864,7 +1873,6 @@ void AudioFlinger::PlaybackThread::PatchTrack::releaseBuffer(Proxy::Buffer* buff { { mProxy->releaseBuffer(buffer); mProxy->releaseBuffer(buffer); restartIfDisabled(); restartIfDisabled(); android_atomic_or(CBLK_FORCEREADY, &mCblk->mFlags); } } void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled() void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled() Loading