Merge "Fix issue 3225810."
diff --git a/services/audioflinger/A2dpAudioInterface.cpp b/services/audioflinger/A2dpAudioInterface.cpp
index 995e31c..aee01ab 100644
--- a/services/audioflinger/A2dpAudioInterface.cpp
+++ b/services/audioflinger/A2dpAudioInterface.cpp
@@ -23,10 +23,13 @@
 
 #include "A2dpAudioInterface.h"
 #include "audio/liba2dp.h"
-
+#include <hardware_legacy/power.h>
 
 namespace android {
 
+static const char *sA2dpWakeLock = "A2dpOutputStream";
+#define MAX_WRITE_RETRIES  5
+
 // ----------------------------------------------------------------------------
 
 //AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface()
@@ -263,44 +266,55 @@
 A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
 {
     LOGV("A2dpAudioStreamOut destructor");
-    standby();
     close();
     LOGV("A2dpAudioStreamOut destructor returning from close()");
 }
 
 ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
 {
-    Mutex::Autolock lock(mLock);
-
-    size_t remaining = bytes;
     status_t status = -1;
+    {
+        Mutex::Autolock lock(mLock);
 
-    if (!mBluetoothEnabled || mClosing || mSuspended) {
-        LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \
-               mBluetoothEnabled %d, mClosing %d, mSuspended %d",
-                mBluetoothEnabled, mClosing, mSuspended);
-        goto Error;
-    }
+        size_t remaining = bytes;
 
-    status = init();
-    if (status < 0)
-        goto Error;
-
-    while (remaining > 0) {
-        status = a2dp_write(mData, buffer, remaining);
-        if (status <= 0) {
-            LOGE("a2dp_write failed err: %d\n", status);
+        if (!mBluetoothEnabled || mClosing || mSuspended) {
+            LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \
+                   mBluetoothEnabled %d, mClosing %d, mSuspended %d",
+                    mBluetoothEnabled, mClosing, mSuspended);
             goto Error;
         }
-        remaining -= status;
-        buffer = ((char *)buffer) + status;
+
+        if (mStandby) {
+            acquire_wake_lock (PARTIAL_WAKE_LOCK, sA2dpWakeLock);
+            mStandby = false;
+        }
+
+        status = init();
+        if (status < 0)
+            goto Error;
+
+        int retries = MAX_WRITE_RETRIES;
+        while (remaining > 0 && retries) {
+            status = a2dp_write(mData, buffer, remaining);
+            if (status < 0) {
+                LOGE("a2dp_write failed err: %d\n", status);
+                goto Error;
+            }
+            if (status == 0) {
+                retries--;
+            }
+            remaining -= status;
+            buffer = (char *)buffer + status;
+        }
+
+        return bytes;
+
     }
-
-    mStandby = false;
-
-    return bytes;
-
 Error:
+
+    standby();
+
     // Simulate audio output timing in case of error
     usleep(((bytes * 1000 )/ frameSize() / sampleRate()) * 1000);
 
@@ -324,19 +338,22 @@
 
 status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
 {
-    int result = 0;
-
-    if (mClosing) {
-        LOGV("Ignore standby, closing");
-        return result;
-    }
-
     Mutex::Autolock lock(mLock);
+    return standby_l();
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::standby_l()
+{
+    int result = NO_ERROR;
 
     if (!mStandby) {
-        result = a2dp_stop(mData);
-        if (result == 0)
-            mStandby = true;
+        LOGV_IF(mClosing || !mBluetoothEnabled, "Standby skip stop: closing %d enabled %d",
+                mClosing, mBluetoothEnabled);
+        if (!mClosing && mBluetoothEnabled) {
+            result = a2dp_stop(mData);
+        }
+        release_wake_lock(sA2dpWakeLock);
+        mStandby = true;
     }
 
     return result;
@@ -362,6 +379,9 @@
     key = String8("closing");
     if (param.get(key, value) == NO_ERROR) {
         mClosing = (value == "true");
+        if (mClosing) {
+            standby();
+        }
         param.remove(key);
     }
     key = AudioParameter::keyRouting;
@@ -444,6 +464,7 @@
 
 status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
 {
+    standby_l();
     if (mData) {
         LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
         a2dp_cleanup(mData);
diff --git a/services/audioflinger/A2dpAudioInterface.h b/services/audioflinger/A2dpAudioInterface.h
index 48154f9..cef1926 100644
--- a/services/audioflinger/A2dpAudioInterface.h
+++ b/services/audioflinger/A2dpAudioInterface.h
@@ -103,6 +103,7 @@
                 status_t    setAddress(const char* address);
                 status_t    setBluetoothEnabled(bool enabled);
                 status_t    setSuspended(bool onOff);
+                status_t    standby_l();
 
     private:
                 int         mFd;