Merge "audioflinger: fix noise when skipping to next song" into ics-mr1
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 9aa6700..534afce 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -54,6 +54,7 @@
     METADATA_KEY_BITRATE         = 20,
     METADATA_KEY_TIMED_TEXT_LANGUAGES      = 21,
     METADATA_KEY_IS_DRM          = 22,
+    METADATA_KEY_LOCATION        = 23,
 
     // Add more here...
 };
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 57f678c..4cdee17 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -85,6 +85,7 @@
     kKeyDate              = 'date',  // cstring
     kKeyWriter            = 'writ',  // cstring
     kKeyCompilation       = 'cpil',  // cstring
+    kKeyLocation          = 'loc ',  // cstring
     kKeyTimeScale         = 'tmsl',  // int32_t
 
     // video profile and level
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 3c3af8f..1a06cc6 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -47,17 +47,22 @@
     VISUALIZER_STATE_ACTIVE,
 };
 
+// maximum number of reads from same buffer before resetting capture buffer. This means
+// that the framework has stopped playing audio and we must start returning silence
+#define MAX_STALL_COUNT 10
+
 struct VisualizerContext {
     const struct effect_interface_s *mItfe;
     effect_config_t mConfig;
-    uint32_t mState;
     uint32_t mCaptureIdx;
     uint32_t mCaptureSize;
-    uint32_t mCurrentBuf;
+    uint8_t mState;
+    uint8_t mCurrentBuf;
+    uint8_t mLastBuf;
+    uint8_t mStallCount;
     uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
 };
 
-
 //
 //--- Local functions
 //
@@ -66,6 +71,8 @@
 {
     pContext->mCaptureIdx = 0;
     pContext->mCurrentBuf = 0;
+    pContext->mLastBuf = 1;
+    pContext->mStallCount = 0;
     memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
     memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
 }
@@ -417,9 +424,24 @@
             memcpy(pReplyData,
                    pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
                    pContext->mCaptureSize);
+            // if audio framework has stopped playing audio although the effect is still
+            // active we must clear the capture buffer to return silence
+            if (pContext->mLastBuf == pContext->mCurrentBuf) {
+                if (pContext->mStallCount < MAX_STALL_COUNT) {
+                    if (++pContext->mStallCount == MAX_STALL_COUNT) {
+                        memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
+                                0x80,
+                                pContext->mCaptureSize);
+                    }
+                }
+            } else {
+                pContext->mStallCount = 0;
+            }
+            pContext->mLastBuf = pContext->mCurrentBuf;
         } else {
             memset(pReplyData, 0x80, pContext->mCaptureSize);
         }
+
         break;
 
     default:
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 1e24599..1ebf0a8 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1136,6 +1136,41 @@
             break;
         }
 
+        // @xyz
+        case FOURCC('\xA9', 'x', 'y', 'z'):
+        {
+            // Best case the total data length inside "@xyz" box
+            // would be 8, for instance "@xyz" + "\x00\x04\x15\xc7" + "0+0/",
+            // where "\x00\x04" is the text string length with value = 4,
+            // "\0x15\xc7" is the language code = en, and "0+0" is a
+            // location (string) value with longitude = 0 and latitude = 0.
+            if (chunk_data_size < 8) {
+                return ERROR_MALFORMED;
+            }
+
+            // Worst case the location string length would be 18,
+            // for instance +90.0000-180.0000, without the trailing "/" and
+            // the string length + language code.
+            char buffer[18];
+
+            // Substracting 5 from the data size is because the text string length +
+            // language code takes 4 bytes, and the trailing slash "/" takes 1 byte.
+            off64_t location_length = chunk_data_size - 5;
+            if (location_length >= (off64_t) sizeof(buffer)) {
+                return ERROR_MALFORMED;
+            }
+
+            if (mDataSource->readAt(
+                        data_offset + 4, buffer, location_length) < location_length) {
+                return ERROR_IO;
+            }
+
+            buffer[location_length] = '\0';
+            mFileMetaData->setCString(kKeyLocation, buffer);
+            *offset += chunk_size;
+            break;
+        }
+
         case FOURCC('e', 's', 'd', 's'):
         {
             if (chunk_data_size < 4) {
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index c74cb5a..4491c97 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -418,6 +418,7 @@
         { kKeyYear, METADATA_KEY_YEAR },
         { kKeyWriter, METADATA_KEY_WRITER },
         { kKeyCompilation, METADATA_KEY_COMPILATION },
+        { kKeyLocation, METADATA_KEY_LOCATION },
     };
     static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
 
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 47de4e0..cd374e2 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -220,7 +220,7 @@
     }
 
     if (it == mStreams.end()) {
-        TRESPASS();
+        return;
     }
 
     mStreams.erase(it);
@@ -274,41 +274,52 @@
     }
 
     int res = select(maxSocket + 1, &rs, NULL, NULL, &tv);
-    CHECK_GE(res, 0);
 
     if (res > 0) {
-        for (List<StreamInfo>::iterator it = mStreams.begin();
-             it != mStreams.end(); ++it) {
+        List<StreamInfo>::iterator it = mStreams.begin();
+        while (it != mStreams.end()) {
             if ((*it).mIsInjected) {
+                ++it;
                 continue;
             }
 
+            status_t err = OK;
             if (FD_ISSET(it->mRTPSocket, &rs)) {
-                receive(&*it, true);
+                err = receive(&*it, true);
             }
-            if (FD_ISSET(it->mRTCPSocket, &rs)) {
-                receive(&*it, false);
+            if (err == OK && FD_ISSET(it->mRTCPSocket, &rs)) {
+                err = receive(&*it, false);
             }
+
+            if (err == -ECONNRESET) {
+                // socket failure, this stream is dead, Jim.
+
+                LOGW("failed to receive RTP/RTCP datagram.");
+                it = mStreams.erase(it);
+                continue;
+            }
+
+            ++it;
         }
     }
 
-    postPollEvent();
-
     int64_t nowUs = ALooper::GetNowUs();
     if (mLastReceiverReportTimeUs <= 0
             || mLastReceiverReportTimeUs + 5000000ll <= nowUs) {
         sp<ABuffer> buffer = new ABuffer(kMaxUDPSize);
-        for (List<StreamInfo>::iterator it = mStreams.begin();
-             it != mStreams.end(); ++it) {
+        List<StreamInfo>::iterator it = mStreams.begin();
+        while (it != mStreams.end()) {
             StreamInfo *s = &*it;
 
             if (s->mIsInjected) {
+                ++it;
                 continue;
             }
 
             if (s->mNumRTCPPacketsReceived == 0) {
                 // We have never received any RTCP packets on this stream,
                 // we don't even know where to send a report.
+                ++it;
                 continue;
             }
 
@@ -327,16 +338,34 @@
             if (buffer->size() > 0) {
                 LOGV("Sending RR...");
 
-                ssize_t n = sendto(
+                ssize_t n;
+                do {
+                    n = sendto(
                         s->mRTCPSocket, buffer->data(), buffer->size(), 0,
                         (const struct sockaddr *)&s->mRemoteRTCPAddr,
                         sizeof(s->mRemoteRTCPAddr));
+                } while (n < 0 && errno == EINTR);
+
+                if (n <= 0) {
+                    LOGW("failed to send RTCP receiver report (%s).",
+                         n == 0 ? "connection gone" : strerror(errno));
+
+                    it = mStreams.erase(it);
+                    continue;
+                }
+
                 CHECK_EQ(n, (ssize_t)buffer->size());
 
                 mLastReceiverReportTimeUs = nowUs;
             }
+
+            ++it;
         }
     }
+
+    if (!mStreams.empty()) {
+        postPollEvent();
+    }
 }
 
 status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) {
@@ -350,16 +379,19 @@
         (!receiveRTP && s->mNumRTCPPacketsReceived == 0)
             ? sizeof(s->mRemoteRTCPAddr) : 0;
 
-    ssize_t nbytes = recvfrom(
+    ssize_t nbytes;
+    do {
+        nbytes = recvfrom(
             receiveRTP ? s->mRTPSocket : s->mRTCPSocket,
             buffer->data(),
             buffer->capacity(),
             0,
             remoteAddrLen > 0 ? (struct sockaddr *)&s->mRemoteRTCPAddr : NULL,
             remoteAddrLen > 0 ? &remoteAddrLen : NULL);
+    } while (nbytes < 0 && errno == EINTR);
 
-    if (nbytes < 0) {
-        return -1;
+    if (nbytes <= 0) {
+        return -ECONNRESET;
     }
 
     buffer->setRange(0, nbytes);
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index bd0e491..4f0363b 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -187,10 +187,13 @@
     return true;
 }
 
-static void MakeSocketBlocking(int s, bool blocking) {
+static status_t MakeSocketBlocking(int s, bool blocking) {
     // Make socket non-blocking.
     int flags = fcntl(s, F_GETFL, 0);
-    CHECK_NE(flags, -1);
+
+    if (flags == -1) {
+        return UNKNOWN_ERROR;
+    }
 
     if (blocking) {
         flags &= ~O_NONBLOCK;
@@ -198,7 +201,9 @@
         flags |= O_NONBLOCK;
     }
 
-    CHECK_NE(fcntl(s, F_SETFL, flags), -1);
+    flags = fcntl(s, F_SETFL, flags);
+
+    return flags == -1 ? UNKNOWN_ERROR : OK;
 }
 
 void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
@@ -302,27 +307,32 @@
     reply->post();
 }
 
+void ARTSPConnection::performDisconnect() {
+    if (mUIDValid) {
+        HTTPBase::UnRegisterSocketUserTag(mSocket);
+    }
+    close(mSocket);
+    mSocket = -1;
+
+    flushPendingRequests();
+
+    mUser.clear();
+    mPass.clear();
+    mAuthType = NONE;
+    mNonce.clear();
+
+    mState = DISCONNECTED;
+}
+
 void ARTSPConnection::onDisconnect(const sp<AMessage> &msg) {
     if (mState == CONNECTED || mState == CONNECTING) {
-        if (mUIDValid) {
-            HTTPBase::UnRegisterSocketUserTag(mSocket);
-        }
-        close(mSocket);
-        mSocket = -1;
-
-        flushPendingRequests();
+        performDisconnect();
     }
 
     sp<AMessage> reply;
     CHECK(msg->findMessage("reply", &reply));
 
     reply->setInt32("result", OK);
-    mState = DISCONNECTED;
-
-    mUser.clear();
-    mPass.clear();
-    mAuthType = NONE;
-    mNonce.clear();
 
     reply->post();
 }
@@ -427,21 +437,25 @@
             send(mSocket, request.c_str() + numBytesSent,
                  request.size() - numBytesSent, 0);
 
-        if (n == 0) {
-            // Server closed the connection.
-            LOGE("Server unexpectedly closed the connection.");
+        if (n < 0 && errno == EINTR) {
+            continue;
+        }
 
-            reply->setInt32("result", ERROR_IO);
-            reply->post();
-            return;
-        } else if (n < 0) {
-            if (errno == EINTR) {
-                continue;
+        if (n <= 0) {
+            performDisconnect();
+
+            if (n == 0) {
+                // Server closed the connection.
+                LOGE("Server unexpectedly closed the connection.");
+
+                reply->setInt32("result", ERROR_IO);
+                reply->post();
+            } else {
+                LOGE("Error sending rtsp request. (%s)", strerror(errno));
+                reply->setInt32("result", -errno);
+                reply->post();
             }
 
-            LOGE("Error sending rtsp request.");
-            reply->setInt32("result", -errno);
-            reply->post();
             return;
         }
 
@@ -512,17 +526,22 @@
     size_t offset = 0;
     while (offset < size) {
         ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0);
-        if (n == 0) {
-            // Server closed the connection.
-            LOGE("Server unexpectedly closed the connection.");
-            return ERROR_IO;
-        } else if (n < 0) {
-            if (errno == EINTR) {
-                continue;
-            }
 
-            LOGE("Error reading rtsp response.");
-            return -errno;
+        if (n < 0 && errno == EINTR) {
+            continue;
+        }
+
+        if (n <= 0) {
+            performDisconnect();
+
+            if (n == 0) {
+                // Server closed the connection.
+                LOGE("Server unexpectedly closed the connection.");
+                return ERROR_IO;
+            } else {
+                LOGE("Error reading rtsp response. (%s)", strerror(errno));
+                return -errno;
+            }
         }
 
         offset += (size_t)n;
@@ -681,24 +700,8 @@
     if (contentLength > 0) {
         response->mContent = new ABuffer(contentLength);
 
-        size_t numBytesRead = 0;
-        while (numBytesRead < contentLength) {
-            ssize_t n = recv(
-                    mSocket, response->mContent->data() + numBytesRead,
-                    contentLength - numBytesRead, 0);
-
-            if (n == 0) {
-                // Server closed the connection.
-                TRESPASS();
-            } else if (n < 0) {
-                if (errno == EINTR) {
-                    continue;
-                }
-
-                TRESPASS();
-            }
-
-            numBytesRead += (size_t)n;
+        if (receive(response->mContent->data(), contentLength) != OK) {
+            return false;
         }
     }
 
@@ -765,17 +768,20 @@
             send(mSocket, response.c_str() + numBytesSent,
                  response.size() - numBytesSent, 0);
 
-        if (n == 0) {
-            // Server closed the connection.
-            LOGE("Server unexpectedly closed the connection.");
+        if (n < 0 && errno == EINTR) {
+            continue;
+        }
 
-            return false;
-        } else if (n < 0) {
-            if (errno == EINTR) {
-                continue;
+        if (n <= 0) {
+            if (n == 0) {
+                // Server closed the connection.
+                LOGE("Server unexpectedly closed the connection.");
+            } else {
+                LOGE("Error sending rtsp response (%s).", strerror(errno));
             }
 
-            LOGE("Error sending rtsp response.");
+            performDisconnect();
+
             return false;
         }
 
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 5cb84fd..68f2d59 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -91,6 +91,8 @@
 
     AString mUserAgent;
 
+    void performDisconnect();
+
     void onConnect(const sp<AMessage> &msg);
     void onDisconnect(const sp<AMessage> &msg);
     void onCompleteConnection(const sp<AMessage> &msg);
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 6a5efa4..794c60b 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -463,8 +463,17 @@
                                 mBaseURL = tmp;
                             }
 
-                            CHECK_GT(mSessionDesc->countTracks(), 1u);
-                            setupTrack(1);
+                            if (mSessionDesc->countTracks() < 2) {
+                                // There's no actual tracks in this session.
+                                // The first "track" is merely session meta
+                                // data.
+
+                                LOGW("Session doesn't contain any playable "
+                                     "tracks. Aborting.");
+                                result = ERROR_UNSUPPORTED;
+                            } else {
+                                setupTrack(1);
+                            }
                         }
                     }
                 }
@@ -783,9 +792,13 @@
                 }
 
                 if (mNumAccessUnitsReceived == 0) {
+#if 1
                     LOGI("stream ended? aborting.");
                     (new AMessage('abor', id()))->post();
                     break;
+#else
+                    LOGI("haven't seen an AU in a looong time.");
+#endif
                 }
 
                 mNumAccessUnitsReceived = 0;