Merge "Report underruns for fast tracks also"
diff --git a/camera/camera2/ICameraDeviceCallbacks.cpp b/camera/camera2/ICameraDeviceCallbacks.cpp
index 188bd8e..3cec1f4 100644
--- a/camera/camera2/ICameraDeviceCallbacks.cpp
+++ b/camera/camera2/ICameraDeviceCallbacks.cpp
@@ -57,11 +57,12 @@
         data.writeNoException();
     }
 
-    void onResultReceived(int32_t frameId, const CameraMetadata& result) {
+    void onResultReceived(int32_t requestId, const CameraMetadata& result) {
         ALOGV("onResultReceived");
         Parcel data, reply;
         data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor());
-        data.writeInt32(frameId);
+        data.writeInt32(requestId);
+        data.writeInt32(1); // to mark presence of metadata object
         result.writeToParcel(&data);
         remote()->transact(RESULT_RECEIVED, data, &reply, IBinder::FLAG_ONEWAY);
         data.writeNoException();
@@ -91,10 +92,14 @@
         case RESULT_RECEIVED: {
             ALOGV("RESULT_RECEIVED");
             CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply);
-            int32_t frameId = data.readInt32();
+            int32_t requestId = data.readInt32();
             CameraMetadata result;
-            result.readFromParcel(const_cast<Parcel*>(&data));
-            onResultReceived(frameId, result);
+            if (data.readInt32() != 0) {
+                result.readFromParcel(const_cast<Parcel*>(&data));
+            } else {
+                ALOGW("No metadata object is present in result");
+            }
+            onResultReceived(requestId, result);
             data.readExceptionCode();
             return NO_ERROR;
             break;
diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/include/media/stagefright/foundation/ALooperRoster.h
index 2e5fd73..940fc55 100644
--- a/include/media/stagefright/foundation/ALooperRoster.h
+++ b/include/media/stagefright/foundation/ALooperRoster.h
@@ -30,6 +30,7 @@
             const sp<ALooper> looper, const sp<AHandler> &handler);
 
     void unregisterHandler(ALooper::handler_id handlerID);
+    void unregisterStaleHandlers();
 
     status_t postMessage(const sp<AMessage> &msg, int64_t delayUs = 0);
     void deliverMessage(const sp<AMessage> &msg);
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index 22777a2..ebf9d8d 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -72,6 +72,10 @@
 
 ALooper::~ALooper() {
     stop();
+
+    // Since this looper is "dead" (or as good as dead by now),
+    // have ALooperRoster unregister any handlers still registered for it.
+    gLooperRoster.unregisterStaleHandlers();
 }
 
 void ALooper::setName(const char *name) {
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index ad10d2b..0c181ff 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -71,6 +71,20 @@
     mHandlers.removeItemsAt(index);
 }
 
+void ALooperRoster::unregisterStaleHandlers() {
+    Mutex::Autolock autoLock(mLock);
+
+    for (size_t i = mHandlers.size(); i-- > 0;) {
+        const HandlerInfo &info = mHandlers.valueAt(i);
+
+        sp<ALooper> looper = info.mLooper.promote();
+        if (looper == NULL) {
+            ALOGV("Unregistering stale handler %d", mHandlers.keyAt(i));
+            mHandlers.removeItemsAt(i);
+        }
+    }
+}
+
 status_t ALooperRoster::postMessage(
         const sp<AMessage> &msg, int64_t delayUs) {
     Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 906aef3..5116550 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -571,6 +571,9 @@
         if (sawCR && c == '\n') {
             line->erase(line->size() - 1, 1);
             return true;
+        } else if (c == '\n') {
+            // some reponse line ended with '\n', instead of '\r\n'.
+            return true;
         }
 
         line->append(&c, 1);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 0c1cc35..f0c27c3 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4908,9 +4908,9 @@
 
 void AudioFlinger::RecordThread::readInputParameters()
 {
-    delete mRsmpInBuffer;
+    delete[] mRsmpInBuffer;
     // mRsmpInBuffer is always assigned a new[] below
-    delete mRsmpOutBuffer;
+    delete[] mRsmpOutBuffer;
     mRsmpOutBuffer = NULL;
     delete mResampler;
     mResampler = NULL;
diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.cpp b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
index 10bc6ea..e7b440a 100644
--- a/services/camera/libcameraservice/common/FrameProcessorBase.cpp
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
@@ -143,7 +143,7 @@
                 __FUNCTION__, device->getId());
         return BAD_VALUE;
     }
-    int32_t frameId = entry.data.i32[0];
+    int32_t requestId = entry.data.i32[0];
 
     List<sp<FilteredListener> > listeners;
     {
@@ -151,8 +151,8 @@
 
         List<RangeListener>::iterator item = mRangeListeners.begin();
         while (item != mRangeListeners.end()) {
-            if (frameId >= item->minId &&
-                    frameId < item->maxId) {
+            if (requestId >= item->minId &&
+                    requestId < item->maxId) {
                 sp<FilteredListener> listener = item->listener.promote();
                 if (listener == 0) {
                     item = mRangeListeners.erase(item);
@@ -167,7 +167,7 @@
     ALOGV("Got %d range listeners out of %d", listeners.size(), mRangeListeners.size());
     List<sp<FilteredListener> >::iterator item = listeners.begin();
     for (; item != listeners.end(); item++) {
-        (*item)->onFrameAvailable(frameId, frame);
+        (*item)->onFrameAvailable(requestId, frame);
     }
     return OK;
 }