AudioFlinger: reset frame position on standby
The HAL does not reset the frame position on standby().
But applications expect the frame position to be reset.
So we subtract the position at standby from the current position.
Bug: 21724210
Bug: 21930805
Change-Id: I0c4520ba1c6c06a580f45f6bafc8cf1d56969f07
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp
index e6d8f09..f953cc8 100644
--- a/services/audioflinger/AudioStreamOut.cpp
+++ b/services/audioflinger/AudioStreamOut.cpp
@@ -27,25 +27,59 @@
namespace android {
// ----------------------------------------------------------------------------
-
AudioStreamOut::AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags)
: audioHwDev(dev)
, stream(NULL)
, flags(flags)
+ , mFramesWritten(0)
+ , mFramesWrittenAtStandby(0)
+ , mRenderPosition(0)
+ , mRateMultiplier(1)
+ , mHalFormatIsLinearPcm(false)
+ , mHalFrameSize(0)
{
}
-audio_hw_device_t* AudioStreamOut::hwDev() const
+audio_hw_device_t *AudioStreamOut::hwDev() const
{
return audioHwDev->hwDevice();
}
-status_t AudioStreamOut::getRenderPosition(uint32_t *frames)
+status_t AudioStreamOut::getRenderPosition(uint64_t *frames)
{
if (stream == NULL) {
return NO_INIT;
}
- return stream->get_render_position(stream, frames);
+
+ uint32_t halPosition = 0;
+ status_t status = stream->get_render_position(stream, &halPosition);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ // Maintain a 64-bit render position using the 32-bit result from the HAL.
+ // This delta calculation relies on the arithmetic overflow behavior
+ // of integers. For example (100 - 0xFFFFFFF0) = 116.
+ uint32_t truncatedPosition = (uint32_t)mRenderPosition;
+ int32_t deltaHalPosition = (int32_t)(halPosition - truncatedPosition);
+ if (deltaHalPosition > 0) {
+ mRenderPosition += deltaHalPosition;
+ }
+ // Scale from HAL sample rate to application rate.
+ *frames = mRenderPosition / mRateMultiplier;
+
+ return status;
+}
+
+// return bottom 32-bits of the render position
+status_t AudioStreamOut::getRenderPosition(uint32_t *frames)
+{
+ uint64_t position64 = 0;
+ status_t status = getRenderPosition(&position64);
+ if (status == NO_ERROR) {
+ *frames = (uint32_t)position64;
+ }
+ return status;
}
status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timespec *timestamp)
@@ -53,7 +87,26 @@
if (stream == NULL) {
return NO_INIT;
}
- return stream->get_presentation_position(stream, frames, timestamp);
+
+ uint64_t halPosition = 0;
+ status_t status = stream->get_presentation_position(stream, &halPosition, timestamp);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ // Adjust for standby using HAL rate frames.
+ // Only apply this correction if the HAL is getting PCM frames.
+ if (mHalFormatIsLinearPcm) {
+ uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ?
+ 0 : (halPosition - mFramesWrittenAtStandby);
+ // Scale from HAL sample rate to application rate.
+ *frames = adjustedPosition / mRateMultiplier;
+ } else {
+ // For offloaded MP3 and other compressed formats.
+ *frames = halPosition;
+ }
+
+ return status;
}
status_t AudioStreamOut::open(
@@ -62,7 +115,7 @@
struct audio_config *config,
const char *address)
{
- audio_stream_out_t* outStream;
+ audio_stream_out_t *outStream;
int status = hwDev()->open_output_stream(
hwDev(),
handle,
@@ -82,6 +135,9 @@
if (status == NO_ERROR) {
stream = outStream;
+ mHalFormatIsLinearPcm = audio_is_linear_pcm(config->format);
+ ALOGI("AudioStreamOut::open(), mHalFormatIsLinearPcm = %d", (int)mHalFormatIsLinearPcm);
+ mHalFrameSize = audio_stream_out_frame_size(stream);
}
return status;
@@ -89,13 +145,15 @@
size_t AudioStreamOut::getFrameSize()
{
- ALOG_ASSERT(stream != NULL);
- return audio_stream_out_frame_size(stream);
+ return mHalFrameSize;
}
int AudioStreamOut::flush()
{
ALOG_ASSERT(stream != NULL);
+ mRenderPosition = 0;
+ mFramesWritten = 0;
+ mFramesWrittenAtStandby = 0;
if (stream->flush != NULL) {
return stream->flush(stream);
}
@@ -105,13 +163,20 @@
int AudioStreamOut::standby()
{
ALOG_ASSERT(stream != NULL);
+ mRenderPosition = 0;
+ mFramesWrittenAtStandby = mFramesWritten;
+ ALOGI("AudioStreamOut::standby(), mFramesWrittenAtStandby = %llu", mFramesWrittenAtStandby);
return stream->common.standby(&stream->common);
}
-ssize_t AudioStreamOut::write(const void* buffer, size_t bytes)
+ssize_t AudioStreamOut::write(const void *buffer, size_t numBytes)
{
ALOG_ASSERT(stream != NULL);
- return stream->write(stream, buffer, bytes);
+ ssize_t bytesWritten = stream->write(stream, buffer, numBytes);
+ if (bytesWritten > 0 && mHalFrameSize > 0) {
+ mFramesWritten += bytesWritten / mHalFrameSize;
+ }
+ return bytesWritten;
}
} // namespace android
diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h
index e91ca9c..761e771 100644
--- a/services/audioflinger/AudioStreamOut.h
+++ b/services/audioflinger/AudioStreamOut.h
@@ -53,7 +53,10 @@
virtual ~AudioStreamOut() { }
- virtual status_t getRenderPosition(uint32_t *frames);
+ // Get the bottom 32-bits of the 64-bit render position.
+ status_t getRenderPosition(uint32_t *frames);
+
+ virtual status_t getRenderPosition(uint64_t *frames);
virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);
@@ -76,6 +79,14 @@
virtual status_t flush();
virtual status_t standby();
+
+protected:
+ uint64_t mFramesWritten; // reset by flush
+ uint64_t mFramesWrittenAtStandby;
+ uint64_t mRenderPosition; // reset by flush or standby
+ int mRateMultiplier;
+ bool mHalFormatIsLinearPcm;
+ size_t mHalFrameSize;
};
} // namespace android
diff --git a/services/audioflinger/SpdifStreamOut.cpp b/services/audioflinger/SpdifStreamOut.cpp
index ac637ef..6af7bce 100644
--- a/services/audioflinger/SpdifStreamOut.cpp
+++ b/services/audioflinger/SpdifStreamOut.cpp
@@ -36,10 +36,7 @@
audio_output_flags_t flags,
audio_format_t format)
: AudioStreamOut(dev,flags)
- , mRateMultiplier(1)
, mSpdifEncoder(this, format)
- , mRenderPositionHal(0)
- , mPreviousHalPosition32(0)
{
}
@@ -97,62 +94,18 @@
return status;
}
-// Account for possibly higher sample rate.
-status_t SpdifStreamOut::getRenderPosition(uint32_t *frames)
-{
- uint32_t halPosition = 0;
- status_t status = AudioStreamOut::getRenderPosition(&halPosition);
- if (status != NO_ERROR) {
- return status;
- }
-
- // Accumulate a 64-bit position so that we wrap at the right place.
- if (mRateMultiplier != 1) {
- // Maintain a 64-bit render position.
- int32_t deltaHalPosition = (int32_t)(halPosition - mPreviousHalPosition32);
- mPreviousHalPosition32 = halPosition;
- mRenderPositionHal += deltaHalPosition;
-
- // Scale from device sample rate to application rate.
- uint64_t renderPositionApp = mRenderPositionHal / mRateMultiplier;
- ALOGV("SpdifStreamOut::getRenderPosition() "
- "renderPositionAppRate = %llu = %llu / %u\n",
- renderPositionApp, mRenderPositionHal, mRateMultiplier);
-
- *frames = (uint32_t)renderPositionApp;
- } else {
- *frames = halPosition;
- }
- return status;
-}
-
int SpdifStreamOut::flush()
{
mSpdifEncoder.reset();
- mRenderPositionHal = 0;
- mPreviousHalPosition32 = 0;
return AudioStreamOut::flush();
}
int SpdifStreamOut::standby()
{
mSpdifEncoder.reset();
- mRenderPositionHal = 0;
- mPreviousHalPosition32 = 0;
return AudioStreamOut::standby();
}
-// Account for possibly higher sample rate.
-// This is much easier when all the values are 64-bit.
-status_t SpdifStreamOut::getPresentationPosition(uint64_t *frames,
- struct timespec *timestamp)
-{
- uint64_t halFrames = 0;
- status_t status = AudioStreamOut::getPresentationPosition(&halFrames, timestamp);
- *frames = halFrames / mRateMultiplier;
- return status;
-}
-
size_t SpdifStreamOut::getFrameSize()
{
return sizeof(int8_t);
diff --git a/services/audioflinger/SpdifStreamOut.h b/services/audioflinger/SpdifStreamOut.h
index d81c064..a61a7bd 100644
--- a/services/audioflinger/SpdifStreamOut.h
+++ b/services/audioflinger/SpdifStreamOut.h
@@ -49,10 +49,6 @@
struct audio_config *config,
const char *address);
- virtual status_t getRenderPosition(uint32_t *frames);
-
- virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);
-
/**
* Write audio buffer to driver. Returns number of bytes written, or a
* negative status_t. If at least one frame was written successfully prior to the error,
@@ -92,13 +88,8 @@
SpdifStreamOut * const mSpdifStreamOut;
};
- int mRateMultiplier;
MySPDIFEncoder mSpdifEncoder;
- // Used to implement getRenderPosition()
- int64_t mRenderPositionHal;
- uint32_t mPreviousHalPosition32;
-
ssize_t writeDataBurst(const void* data, size_t bytes);
ssize_t writeInternal(const void* buffer, size_t bytes);