Merge "AudioFlinger: fix repeated underruns for compressed audio" into mnc-dev
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 @@
     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 @@
     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 @@
     */
     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 @@
             audio_format_t format)
         : AudioStreamOut(dev,flags)
         , mSpdifEncoder(this, format)
+        , mApplicationFormat(AUDIO_FORMAT_DEFAULT)
+        , mApplicationSampleRate(0)
+        , mApplicationChannelMask(0)
 {
 }
 
@@ -48,6 +51,10 @@
 {
     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 @@
     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 @@
     */
     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 @@
     };
 
     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 @@
 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 @@
                 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 @@
         // 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 @@
                     // 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;