fix issue when capturing with pre processing

When capturing audio with AEC or NS enabled there is a risk that
audio buffers are lost. This happens if the capture is started with a particular
timing with regard to playback. A particular case if when placing an outgoing video
chat with gTalk.
The problem is with the mechanism used to pass buffers between the capture thread and
the preprocessing thread. It is possible that the preprocessing thread locks in with the
timing of the capture thread and always gets a condition where buffers are not ready in which
case it will read new data from the driver causing every other buffer to be dropped.

The fix consists in modifying the buffer sync mechanism and have the preprocessing thread
wait for a condition in case the read buffer is not available yet.

Change-Id: I8ff33f762d600d6dbe8b0dda58973e96d68d02f9
diff --git a/libaudio/AudioPostProcessor.cpp b/libaudio/AudioPostProcessor.cpp
index a94204d..2db86e5 100644
--- a/libaudio/AudioPostProcessor.cpp
+++ b/libaudio/AudioPostProcessor.cpp
@@ -141,6 +141,7 @@
 {
     if (mEcnsEnabled!=value) {
         LOGD("enableEcns() new %08x old %08x)", value, mEcnsEnabled);
+        mEcnsThread->broadcastReadCond();
         mEcnsThread->requestExitAndWait();
         stopEcns();
         cleanupEcns();
@@ -666,6 +667,7 @@
         run("AudioPostProcessor::EcnsThread", ANDROID_PRIORITY_HIGHEST);
         mIsRunning = true;
     }
+    mEcnsReadCond.signal();
     if (mEcnsReadCond.waitRelative(mEcnsReadLock, seconds(1)) != NO_ERROR) {
         LOGE("%s: ECNS thread is stalled.", __FUNCTION__);
         mClientBuf = 0;
@@ -712,6 +714,17 @@
         GETTIMEOFDAY(&mtv3, NULL);
         mEcnsReadLock.lock();
         ecnsStatus = mProcessor->applyUplinkEcns(mReadBuf, mReadSize, mRate);
+
+        // wait for client buffer if not ready
+        if (!mClientBuf) {
+            if(exitPending()) {
+                mEcnsReadLock.unlock();
+                goto error;
+            }
+            if (mEcnsReadCond.waitRelative(mEcnsReadLock, seconds(1)) != NO_ERROR) {
+                LOGE("%s: client stalled.", __FUNCTION__);
+            }
+        }
         if (mClientBuf && mReadSize) {
             // Give the buffer to the client.
             memcpy(mClientBuf, mReadBuf, mReadSize);
@@ -719,8 +732,8 @@
             ret1 = ::read(mFd, mReadBuf, mReadSize/2);
             half_done = true;
             GETTIMEOFDAY(&mtv7, NULL);
-            mEcnsReadCond.signal();
             mClientBuf = 0;
+            mEcnsReadCond.signal();
         } else {
             half_done = false;
             LOGV("%s: Read overflow (ECNS sanity preserved)", __FUNCTION__);
diff --git a/libaudio/AudioPostProcessor.h b/libaudio/AudioPostProcessor.h
index 5ecf898..3a9ea29 100644
--- a/libaudio/AudioPostProcessor.h
+++ b/libaudio/AudioPostProcessor.h
@@ -117,6 +117,8 @@
                         ~EcnsThread();
             int         readData(int fd, void * buffer, int bytes, int rate,
                                  AudioPostProcessor * pp);
+            void        broadcastReadCond() { mEcnsReadCond.broadcast(); }
+
 private:
             bool        threadLoop();
             Mutex       mEcnsReadLock;