summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorPhil Burk <philburk@google.com>2015-07-14 09:42:29 -0700
committerLajos Molnar <lajos@google.com>2015-07-17 20:56:04 +0000
commitca5e6143740299c877d69e97f7968cd04476d32c (patch)
tree50101b57406c5abce066ec90120d91d3dfd0152b /services
parentbc24bb8a552097e7975d0c16fad80158b542ba62 (diff)
downloadframeworks_av-ca5e6143740299c877d69e97f7968cd04476d32c.zip
frameworks_av-ca5e6143740299c877d69e97f7968cd04476d32c.tar.gz
frameworks_av-ca5e6143740299c877d69e97f7968cd04476d32c.tar.bz2
AudioFlinger: fix repeated underruns for compressed audio
The AudioFlinger kept pausing the audio when playing compressed AC3 or DTS. This caused pause/resume loops that were hard to break out of. The AudioFlinger was thinking that the compressed audio was PCM because the HAL was in PCM mode playing SPDIF data bursts. It also thought that EAC3 was at 192000 Hz instead of 48000 Hz because the data bursts are played at a higher rate. This CL adds more calls to the shim that separates the AudioFlinger. Now the AudioFlinger gets information about the HAL sample rate, channel masks and format from the shim instead of calling the HAL directly. The AudioFlinger now uses a different threshold for detecting underruns when the audio is compressed. Bug: 19938315 Bug: 20891646 Change-Id: Ib16f539346d1c7a273ea4feb3d3afcc3dc60237d Signed-off-by: Phil Burk <philburk@google.com>
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioStreamOut.cpp15
-rw-r--r--services/audioflinger/AudioStreamOut.h23
-rw-r--r--services/audioflinger/SpdifStreamOut.cpp16
-rw-r--r--services/audioflinger/SpdifStreamOut.h25
-rw-r--r--services/audioflinger/Threads.cpp16
5 files changed, 79 insertions, 16 deletions
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp
index f953cc8..b6d1be7 100644
--- a/services/audioflinger/AudioStreamOut.cpp
+++ b/services/audioflinger/AudioStreamOut.cpp
@@ -143,9 +143,19 @@ status_t AudioStreamOut::open(
return status;
}
-size_t AudioStreamOut::getFrameSize()
+audio_format_t AudioStreamOut::getFormat() const
{
- return mHalFrameSize;
+ return stream->common.get_format(&stream->common);
+}
+
+uint32_t AudioStreamOut::getSampleRate() const
+{
+ return stream->common.get_sample_rate(&stream->common);
+}
+
+audio_channel_mask_t AudioStreamOut::getChannelMask() const
+{
+ return stream->common.get_channels(&stream->common);
}
int AudioStreamOut::flush()
@@ -165,7 +175,6 @@ int AudioStreamOut::standby()
ALOG_ASSERT(stream != NULL);
mRenderPosition = 0;
mFramesWrittenAtStandby = mFramesWritten;
- ALOGI("AudioStreamOut::standby(), mFramesWrittenAtStandby = %llu", mFramesWrittenAtStandby);
return stream->common.standby(&stream->common);
}
diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h
index 761e771..06a2277 100644
--- a/services/audioflinger/AudioStreamOut.h
+++ b/services/audioflinger/AudioStreamOut.h
@@ -75,7 +75,28 @@ public:
*/
virtual ssize_t write(const void *buffer, size_t bytes);
- virtual size_t getFrameSize();
+ /**
+ * @return frame size from the perspective of the application and the AudioFlinger.
+ */
+ virtual size_t getFrameSize() const { return mHalFrameSize; }
+
+ /**
+ * @return format from the perspective of the application and the AudioFlinger.
+ */
+ virtual audio_format_t getFormat() const;
+
+ /**
+ * The HAL may be running at a higher sample rate if, for example, playing wrapped EAC3.
+ * @return sample rate from the perspective of the application and the AudioFlinger.
+ */
+ virtual uint32_t getSampleRate() const;
+
+ /**
+ * The HAL is in stereo mode when playing multi-channel compressed audio over HDMI.
+ * @return channel mask from the perspective of the application and the AudioFlinger.
+ */
+ virtual audio_channel_mask_t getChannelMask() const;
+
virtual status_t flush();
virtual status_t standby();
diff --git a/services/audioflinger/SpdifStreamOut.cpp b/services/audioflinger/SpdifStreamOut.cpp
index 6af7bce..6b6f5db 100644
--- a/services/audioflinger/SpdifStreamOut.cpp
+++ b/services/audioflinger/SpdifStreamOut.cpp
@@ -37,6 +37,9 @@ SpdifStreamOut::SpdifStreamOut(AudioHwDevice *dev,
audio_format_t format)
: AudioStreamOut(dev,flags)
, mSpdifEncoder(this, format)
+ , mApplicationFormat(AUDIO_FORMAT_DEFAULT)
+ , mApplicationSampleRate(0)
+ , mApplicationChannelMask(0)
{
}
@@ -48,6 +51,10 @@ status_t SpdifStreamOut::open(
{
struct audio_config customConfig = *config;
+ mApplicationFormat = config->format;
+ mApplicationSampleRate = config->sample_rate;
+ mApplicationChannelMask = config->channel_mask;
+
// Some data bursts run at a higher sample rate.
// TODO Move this into the audio_utils as a static method.
switch(config->format) {
@@ -106,20 +113,15 @@ int SpdifStreamOut::standby()
return AudioStreamOut::standby();
}
-size_t SpdifStreamOut::getFrameSize()
-{
- return sizeof(int8_t);
-}
-
ssize_t SpdifStreamOut::writeDataBurst(const void* buffer, size_t bytes)
{
return AudioStreamOut::write(buffer, bytes);
}
-ssize_t SpdifStreamOut::write(const void* buffer, size_t bytes)
+ssize_t SpdifStreamOut::write(const void* buffer, size_t numBytes)
{
// Write to SPDIF wrapper. It will call back to writeDataBurst().
- return mSpdifEncoder.write(buffer, bytes);
+ return mSpdifEncoder.write(buffer, numBytes);
}
} // namespace android
diff --git a/services/audioflinger/SpdifStreamOut.h b/services/audioflinger/SpdifStreamOut.h
index a61a7bd..c870250 100644
--- a/services/audioflinger/SpdifStreamOut.h
+++ b/services/audioflinger/SpdifStreamOut.h
@@ -64,7 +64,27 @@ public:
*/
virtual ssize_t write(const void* buffer, size_t bytes);
- virtual size_t getFrameSize();
+ /**
+ * @return frame size from the perspective of the application and the AudioFlinger.
+ */
+ virtual size_t getFrameSize() const { return sizeof(int8_t); }
+
+ /**
+ * @return format from the perspective of the application and the AudioFlinger.
+ */
+ virtual audio_format_t getFormat() const { return mApplicationFormat; }
+
+ /**
+ * The HAL may be running at a higher sample rate if, for example, playing wrapped EAC3.
+ * @return sample rate from the perspective of the application and the AudioFlinger.
+ */
+ virtual uint32_t getSampleRate() const { return mApplicationSampleRate; }
+
+ /**
+ * The HAL is in stereo mode when playing multi-channel compressed audio over HDMI.
+ * @return channel mask from the perspective of the application and the AudioFlinger.
+ */
+ virtual audio_channel_mask_t getChannelMask() const { return mApplicationChannelMask; }
virtual status_t flush();
virtual status_t standby();
@@ -89,6 +109,9 @@ private:
};
MySPDIFEncoder mSpdifEncoder;
+ audio_format_t mApplicationFormat;
+ uint32_t mApplicationSampleRate;
+ audio_channel_mask_t mApplicationChannelMask;
ssize_t writeDataBurst(const void* data, size_t bytes);
ssize_t writeInternal(const void* buffer, size_t bytes);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d9f1a83..c360051 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2081,8 +2081,8 @@ int AudioFlinger::PlaybackThread::asyncCallback(stream_callback_event_t event,
void AudioFlinger::PlaybackThread::readOutputParameters_l()
{
// unfortunately we have no way of recovering from errors here, hence the LOG_ALWAYS_FATAL
- mSampleRate = mOutput->stream->common.get_sample_rate(&mOutput->stream->common);
- mChannelMask = mOutput->stream->common.get_channels(&mOutput->stream->common);
+ mSampleRate = mOutput->getSampleRate();
+ mChannelMask = mOutput->getChannelMask();
if (!audio_is_output_channel(mChannelMask)) {
LOG_ALWAYS_FATAL("HAL channel mask %#x not valid for output", mChannelMask);
}
@@ -2092,8 +2092,12 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
mChannelMask);
}
mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
+
+ // Get actual HAL format.
mHALFormat = mOutput->stream->common.get_format(&mOutput->stream->common);
- mFormat = mHALFormat;
+ // Get format from the shim, which will be different than the HAL format
+ // if playing compressed audio over HDMI passthrough.
+ mFormat = mOutput->getFormat();
if (!audio_is_valid_format(mFormat)) {
LOG_ALWAYS_FATAL("HAL format %#x not valid for output", mFormat);
}
@@ -4559,9 +4563,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
// app does not call stop() and relies on underrun to stop:
// hence the test on (track->mRetryCount > 1).
// If retryCount<=1 then track is about to underrun and be removed.
+ // Do not use a high threshold for compressed audio.
uint32_t minFrames;
if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing()
- && (track->mRetryCount > 1)) {
+ && (track->mRetryCount > 1) && audio_is_linear_pcm(mFormat)) {
minFrames = mNormalFrameCount;
} else {
minFrames = 1;
@@ -4650,6 +4655,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
// it will then automatically call start() when data is available
android_atomic_or(CBLK_DISABLED, &cblk->mFlags);
} else if (last) {
+ ALOGW("pause because of UNDERRUN, framesReady = %zu,"
+ "minFrames = %u, mFormat = %#x",
+ track->framesReady(), minFrames, mFormat);
mixerStatus = MIXER_TRACKS_ENABLED;
if (mHwSupportsPause && !mHwPaused && !mStandby) {
doHwPause = true;