Loading services/oboeservice/AAudioMixer.cpp +26 −18 Original line number Diff line number Diff line Loading @@ -49,10 +49,9 @@ void AAudioMixer::clear() { memset(mOutputBuffer, 0, mBufferSizeInBytes); } bool AAudioMixer::mix(int trackIndex, FifoBuffer *fifo, float volume) { bool AAudioMixer::mix(int streamIndex, FifoBuffer *fifo, bool allowUnderflow) { WrappingBuffer wrappingBuffer; float *destination = mOutputBuffer; fifo_frames_t framesLeft = mFramesPerBurst; #if AAUDIO_MIXER_ATRACE_ENABLED ATRACE_BEGIN("aaMix"); Loading @@ -63,35 +62,44 @@ bool AAudioMixer::mix(int trackIndex, FifoBuffer *fifo, float volume) { #if AAUDIO_MIXER_ATRACE_ENABLED if (ATRACE_ENABLED()) { char rdyText[] = "aaMixRdy#"; char letter = 'A' + (trackIndex % 26); char letter = 'A' + (streamIndex % 26); rdyText[sizeof(rdyText) - 2] = letter; ATRACE_INT(rdyText, fullFrames); } #else /* MIXER_ATRACE_ENABLED */ (void) trackIndex; (void) fullFrames; #endif /* AAUDIO_MIXER_ATRACE_ENABLED */ // If allowUnderflow then always advance by one burst even if we do not have the data. // Otherwise the stream timing will drift whenever there is an underflow. // This actual underflow can then be detected by the client for XRun counting. // // Generally, allowUnderflow will be false when stopping a stream and we want to // use up whatever data is in the queue. fifo_frames_t framesDesired = mFramesPerBurst; if (!allowUnderflow && fullFrames < framesDesired) { framesDesired = fullFrames; // just use what is available then stop } // Mix data in one or two parts. int partIndex = 0; int32_t framesLeft = framesDesired; while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { fifo_frames_t framesToMix = framesLeft; fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex]; if (framesAvailable > 0) { if (framesToMix > framesAvailable) { framesToMix = framesAvailable; fifo_frames_t framesToMixFromPart = framesLeft; fifo_frames_t framesAvailableFromPart = wrappingBuffer.numFrames[partIndex]; if (framesAvailableFromPart > 0) { if (framesToMixFromPart > framesAvailableFromPart) { framesToMixFromPart = framesAvailableFromPart; } mixPart(destination, (float *)wrappingBuffer.data[partIndex], framesToMix, volume); mixPart(destination, (float *)wrappingBuffer.data[partIndex], framesToMixFromPart); destination += framesToMix * mSamplesPerFrame; framesLeft -= framesToMix; destination += framesToMixFromPart * mSamplesPerFrame; framesLeft -= framesToMixFromPart; } partIndex++; } // Always advance by one burst even if we do not have the data. // Otherwise the stream timing will drift whenever there is an underflow. // This actual underflow can then be detected by the client for XRun counting. fifo->getFifoControllerBase()->advanceReadIndex(mFramesPerBurst); fifo->getFifoControllerBase()->advanceReadIndex(framesDesired); #if AAUDIO_MIXER_ATRACE_ENABLED ATRACE_END(); Loading @@ -100,11 +108,11 @@ bool AAudioMixer::mix(int trackIndex, FifoBuffer *fifo, float volume) { return (framesLeft > 0); // did not get all the frames we needed, ie. "underflow" } void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames, float volume) { void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames) { int32_t numSamples = numFrames * mSamplesPerFrame; // TODO maybe optimize using SIMD for (int sampleIndex = 0; sampleIndex < numSamples; sampleIndex++) { *destination++ += *source++ * volume; *destination++ += *source++; } } Loading services/oboeservice/AAudioMixer.h +6 −6 Original line number Diff line number Diff line Loading @@ -33,13 +33,14 @@ public: /** * Mix from this FIFO * @param fifo * @param volume * @return true if underflowed * @param streamIndex for marking stream variables in systrace * @param fifo to read from * @param allowUnderflow if true then allow mixer to advance read index past the write index * @return true if actually underflowed */ bool mix(int trackIndex, android::FifoBuffer *fifo, float volume); bool mix(int streamIndex, android::FifoBuffer *fifo, bool allowUnderflow); void mixPart(float *destination, float *source, int32_t numFrames, float volume); void mixPart(float *destination, float *source, int32_t numFrames); float *getOutputBuffer(); Loading @@ -50,5 +51,4 @@ private: int32_t mBufferSizeInBytes = 0; }; #endif //AAUDIO_AAUDIO_MIXER_H services/oboeservice/AAudioServiceEndpointPlay.cpp +7 −4 Original line number Diff line number Diff line Loading @@ -82,9 +82,13 @@ void *AAudioServiceEndpointPlay::callbackLoop() { std::lock_guard <std::mutex> lock(mLockStreams); for (const auto clientStream : mRegisteredStreams) { int64_t clientFramesRead = 0; bool allowUnderflow = true; if (!clientStream->isRunning()) { continue; aaudio_stream_state_t state = clientStream->getState(); if (state == AAUDIO_STREAM_STATE_STOPPING) { allowUnderflow = false; // just read what is already in the FIFO } else if (state != AAUDIO_STREAM_STATE_STARTED) { continue; // this stream is not running so skip it. } sp<AAudioServiceStreamShared> streamShared = Loading @@ -104,8 +108,7 @@ void *AAudioServiceEndpointPlay::callbackLoop() { int64_t positionOffset = mmapFramesWritten - clientFramesRead; streamShared->setTimestampPositionOffset(positionOffset); float volume = 1.0; // to match legacy volume bool underflowed = mMixer.mix(index, fifo, volume); bool underflowed = mMixer.mix(index, fifo, allowUnderflow); if (underflowed) { streamShared->incrementXRunCount(); } Loading services/oboeservice/AAudioServiceStreamBase.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -231,6 +231,8 @@ aaudio_result_t AAudioServiceStreamBase::stop() { return AAUDIO_ERROR_INVALID_STATE; } setState(AAUDIO_STREAM_STATE_STOPPING); sendCurrentTimestamp(); // warning - this calls a virtual function result = stopTimestampThread(); if (result != AAUDIO_OK) { Loading Loading
services/oboeservice/AAudioMixer.cpp +26 −18 Original line number Diff line number Diff line Loading @@ -49,10 +49,9 @@ void AAudioMixer::clear() { memset(mOutputBuffer, 0, mBufferSizeInBytes); } bool AAudioMixer::mix(int trackIndex, FifoBuffer *fifo, float volume) { bool AAudioMixer::mix(int streamIndex, FifoBuffer *fifo, bool allowUnderflow) { WrappingBuffer wrappingBuffer; float *destination = mOutputBuffer; fifo_frames_t framesLeft = mFramesPerBurst; #if AAUDIO_MIXER_ATRACE_ENABLED ATRACE_BEGIN("aaMix"); Loading @@ -63,35 +62,44 @@ bool AAudioMixer::mix(int trackIndex, FifoBuffer *fifo, float volume) { #if AAUDIO_MIXER_ATRACE_ENABLED if (ATRACE_ENABLED()) { char rdyText[] = "aaMixRdy#"; char letter = 'A' + (trackIndex % 26); char letter = 'A' + (streamIndex % 26); rdyText[sizeof(rdyText) - 2] = letter; ATRACE_INT(rdyText, fullFrames); } #else /* MIXER_ATRACE_ENABLED */ (void) trackIndex; (void) fullFrames; #endif /* AAUDIO_MIXER_ATRACE_ENABLED */ // If allowUnderflow then always advance by one burst even if we do not have the data. // Otherwise the stream timing will drift whenever there is an underflow. // This actual underflow can then be detected by the client for XRun counting. // // Generally, allowUnderflow will be false when stopping a stream and we want to // use up whatever data is in the queue. fifo_frames_t framesDesired = mFramesPerBurst; if (!allowUnderflow && fullFrames < framesDesired) { framesDesired = fullFrames; // just use what is available then stop } // Mix data in one or two parts. int partIndex = 0; int32_t framesLeft = framesDesired; while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { fifo_frames_t framesToMix = framesLeft; fifo_frames_t framesAvailable = wrappingBuffer.numFrames[partIndex]; if (framesAvailable > 0) { if (framesToMix > framesAvailable) { framesToMix = framesAvailable; fifo_frames_t framesToMixFromPart = framesLeft; fifo_frames_t framesAvailableFromPart = wrappingBuffer.numFrames[partIndex]; if (framesAvailableFromPart > 0) { if (framesToMixFromPart > framesAvailableFromPart) { framesToMixFromPart = framesAvailableFromPart; } mixPart(destination, (float *)wrappingBuffer.data[partIndex], framesToMix, volume); mixPart(destination, (float *)wrappingBuffer.data[partIndex], framesToMixFromPart); destination += framesToMix * mSamplesPerFrame; framesLeft -= framesToMix; destination += framesToMixFromPart * mSamplesPerFrame; framesLeft -= framesToMixFromPart; } partIndex++; } // Always advance by one burst even if we do not have the data. // Otherwise the stream timing will drift whenever there is an underflow. // This actual underflow can then be detected by the client for XRun counting. fifo->getFifoControllerBase()->advanceReadIndex(mFramesPerBurst); fifo->getFifoControllerBase()->advanceReadIndex(framesDesired); #if AAUDIO_MIXER_ATRACE_ENABLED ATRACE_END(); Loading @@ -100,11 +108,11 @@ bool AAudioMixer::mix(int trackIndex, FifoBuffer *fifo, float volume) { return (framesLeft > 0); // did not get all the frames we needed, ie. "underflow" } void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames, float volume) { void AAudioMixer::mixPart(float *destination, float *source, int32_t numFrames) { int32_t numSamples = numFrames * mSamplesPerFrame; // TODO maybe optimize using SIMD for (int sampleIndex = 0; sampleIndex < numSamples; sampleIndex++) { *destination++ += *source++ * volume; *destination++ += *source++; } } Loading
services/oboeservice/AAudioMixer.h +6 −6 Original line number Diff line number Diff line Loading @@ -33,13 +33,14 @@ public: /** * Mix from this FIFO * @param fifo * @param volume * @return true if underflowed * @param streamIndex for marking stream variables in systrace * @param fifo to read from * @param allowUnderflow if true then allow mixer to advance read index past the write index * @return true if actually underflowed */ bool mix(int trackIndex, android::FifoBuffer *fifo, float volume); bool mix(int streamIndex, android::FifoBuffer *fifo, bool allowUnderflow); void mixPart(float *destination, float *source, int32_t numFrames, float volume); void mixPart(float *destination, float *source, int32_t numFrames); float *getOutputBuffer(); Loading @@ -50,5 +51,4 @@ private: int32_t mBufferSizeInBytes = 0; }; #endif //AAUDIO_AAUDIO_MIXER_H
services/oboeservice/AAudioServiceEndpointPlay.cpp +7 −4 Original line number Diff line number Diff line Loading @@ -82,9 +82,13 @@ void *AAudioServiceEndpointPlay::callbackLoop() { std::lock_guard <std::mutex> lock(mLockStreams); for (const auto clientStream : mRegisteredStreams) { int64_t clientFramesRead = 0; bool allowUnderflow = true; if (!clientStream->isRunning()) { continue; aaudio_stream_state_t state = clientStream->getState(); if (state == AAUDIO_STREAM_STATE_STOPPING) { allowUnderflow = false; // just read what is already in the FIFO } else if (state != AAUDIO_STREAM_STATE_STARTED) { continue; // this stream is not running so skip it. } sp<AAudioServiceStreamShared> streamShared = Loading @@ -104,8 +108,7 @@ void *AAudioServiceEndpointPlay::callbackLoop() { int64_t positionOffset = mmapFramesWritten - clientFramesRead; streamShared->setTimestampPositionOffset(positionOffset); float volume = 1.0; // to match legacy volume bool underflowed = mMixer.mix(index, fifo, volume); bool underflowed = mMixer.mix(index, fifo, allowUnderflow); if (underflowed) { streamShared->incrementXRunCount(); } Loading
services/oboeservice/AAudioServiceStreamBase.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -231,6 +231,8 @@ aaudio_result_t AAudioServiceStreamBase::stop() { return AAUDIO_ERROR_INVALID_STATE; } setState(AAUDIO_STREAM_STATE_STOPPING); sendCurrentTimestamp(); // warning - this calls a virtual function result = stopTimestampThread(); if (result != AAUDIO_OK) { Loading