Disable vorbis seek when streaming from localhost.

Change-Id: Icda523ae1c89e26482f1c1767fe3a8b9222bb30f
related-to-bug: 2654400
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 913da47..6f7dc38 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -33,7 +33,8 @@
 class DataSource : public RefBase {
 public:
     enum Flags {
-        kWantsPrefetching = 1,
+        kWantsPrefetching      = 1,
+        kStreamedFromLocalHost = 2,
     };
 
     static sp<DataSource> CreateFromURI(
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
index ea31942..f3b44fd 100644
--- a/include/media/stagefright/HTTPDataSource.h
+++ b/include/media/stagefright/HTTPDataSource.h
@@ -45,9 +45,7 @@
 
     virtual status_t getSize(off_t *size);
 
-    virtual uint32_t flags() {
-        return kWantsPrefetching;
-    }
+    virtual uint32_t flags();
 
 protected:
     virtual ~HTTPDataSource();
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 0ed7b40..21338ca 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -44,6 +44,16 @@
     // returns an empty metadata object.
     virtual sp<MetaData> getMetaData();
 
+    enum Flags {
+        CAN_SEEK_BACKWARD  = 1,
+        CAN_SEEK_FORWARD   = 2,
+        CAN_PAUSE          = 4,
+    };
+
+    // If subclasses do _not_ override this, the default is
+    // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE
+    virtual uint32_t flags() const;
+
 protected:
     MediaExtractor() {}
     virtual ~MediaExtractor() {}
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 7776b4e..2c96d6d 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -6,6 +6,9 @@
 
 #include "AwesomePlayer.h"
 
+#include <media/Metadata.h>
+#include <media/stagefright/MediaExtractor.h>
+
 namespace android {
 
 StagefrightPlayer::StagefrightPlayer()
@@ -109,7 +112,8 @@
     status_t err = mPlayer->getDuration(&durationUs);
 
     if (err != OK) {
-        return err;
+        *msec = 0;
+        return OK;
     }
 
     *msec = (durationUs + 500) / 1000;
@@ -156,4 +160,27 @@
     mPlayer->setAudioSink(audioSink);
 }
 
+status_t StagefrightPlayer::getMetadata(
+        const media::Metadata::Filter& ids, Parcel *records) {
+    using media::Metadata;
+
+    uint32_t flags = mPlayer->flags();
+
+    Metadata metadata(records);
+
+    metadata.appendBool(
+            Metadata::kPauseAvailable,
+            flags & MediaExtractor::CAN_PAUSE);
+
+    metadata.appendBool(
+            Metadata::kSeekBackwardAvailable,
+            flags & MediaExtractor::CAN_SEEK_BACKWARD);
+
+    metadata.appendBool(
+            Metadata::kSeekForwardAvailable,
+            flags & MediaExtractor::CAN_SEEK_FORWARD);
+
+    return OK;
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index 4446582..781eb44 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -53,6 +53,9 @@
     virtual status_t suspend();
     virtual status_t resume();
 
+    virtual status_t getMetadata(
+            const media::Metadata::Filter& ids, Parcel *records);
+
 private:
     AwesomePlayer *mPlayer;
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b14a03c..475160e 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -184,6 +184,7 @@
       mVideoRendererIsPreview(false),
       mAudioPlayer(NULL),
       mFlags(0),
+      mExtractorFlags(0),
       mLastVideoBuffer(NULL),
       mVideoBuffer(NULL),
       mSuspensionState(NULL) {
@@ -310,7 +311,13 @@
         }
     }
 
-    return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK;
+    if (!haveAudio && !haveVideo) {
+        return UNKNOWN_ERROR;
+    }
+
+    mExtractorFlags = extractor->flags();
+
+    return OK;
 }
 
 void AwesomePlayer::reset() {
@@ -390,6 +397,7 @@
 
     mDurationUs = -1;
     mFlags = 0;
+    mExtractorFlags = 0;
     mVideoWidth = mVideoHeight = -1;
     mTimeSourceDeltaUs = 0;
     mVideoTimeUs = 0;
@@ -683,8 +691,14 @@
 }
 
 status_t AwesomePlayer::seekTo(int64_t timeUs) {
-    Mutex::Autolock autoLock(mLock);
-    return seekTo_l(timeUs);
+    if (mExtractorFlags
+            & (MediaExtractor::CAN_SEEK_FORWARD
+                | MediaExtractor::CAN_SEEK_BACKWARD)) {
+        Mutex::Autolock autoLock(mLock);
+        return seekTo_l(timeUs);
+    }
+
+    return OK;
 }
 
 status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
@@ -1362,5 +1376,9 @@
     return OK;
 }
 
+uint32_t AwesomePlayer::flags() const {
+    return mExtractorFlags;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index cca6062..8e26c37e 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -425,5 +425,16 @@
     }
 }
 
+uint32_t HTTPDataSource::flags() {
+    uint32_t f = kWantsPrefetching;
+
+    if (!strcasecmp(mStartingHost.string(), "localhost")
+            || !strcmp(mStartingHost.string(), "127.0.0.1")) {
+        f |= kStreamedFromLocalHost;
+    }
+
+    return f;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 832db04..dfddbe0 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -36,6 +36,10 @@
     return new MetaData;
 }
 
+uint32_t MediaExtractor::flags() const {
+    return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE;
+}
+
 // static
 sp<MediaExtractor> MediaExtractor::Create(
         const sp<DataSource> &source, const char *mime) {
diff --git a/media/libstagefright/VorbisExtractor.cpp b/media/libstagefright/VorbisExtractor.cpp
index 96b05c0..e7b62d6 100644
--- a/media/libstagefright/VorbisExtractor.cpp
+++ b/media/libstagefright/VorbisExtractor.cpp
@@ -20,6 +20,7 @@
 
 #include "include/VorbisExtractor.h"
 
+#include <cutils/properties.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
@@ -37,8 +38,23 @@
 struct VorbisDataSource {
     sp<DataSource> mDataSource;
     off_t mOffset;
+    bool mSeekDisabled;
 };
 
+static bool ShouldDisableSeek(const sp<DataSource> &source) {
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.vorbis.always-allow-seek", value, NULL)
+            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+        return false;
+    }
+
+    // This is a workaround for an application streaming data through
+    // a local HTTP proxy that doesn't really conform to the HTTP/1.1
+    // specs. We have to disable seek functionality in this case.
+
+    return source->flags() & DataSource::kStreamedFromLocalHost;
+}
+
 static size_t VorbisRead(
         void *ptr, size_t size, size_t nmemb, void *datasource) {
     VorbisDataSource *vds = (VorbisDataSource *)datasource;
@@ -58,6 +74,11 @@
         void *datasource, ogg_int64_t offset, int whence) {
     VorbisDataSource *vds = (VorbisDataSource *)datasource;
 
+    if (vds->mSeekDisabled) {
+        errno = ESPIPE;
+        return -1;
+    }
+
     switch (whence) {
         case SEEK_SET:
             vds->mOffset = offset;
@@ -218,6 +239,7 @@
       mInitCheck(NO_INIT) {
     mVorbisDataSource->mDataSource = mDataSource;
     mVorbisDataSource->mOffset = 0;
+    mVorbisDataSource->mSeekDisabled = ShouldDisableSeek(mDataSource);
 
     int res = ov_open_callbacks(
             mVorbisDataSource, mFile, NULL, 0, gVorbisCallbacks);
@@ -291,6 +313,7 @@
     VorbisDataSource vds;
     vds.mDataSource = source;
     vds.mOffset = 0;
+    vds.mSeekDisabled = ShouldDisableSeek(source);
 
     int res = ov_test_callbacks(&vds, &file, NULL, 0, gVorbisCallbacks);
 
@@ -308,4 +331,13 @@
     return true;
 }
 
+uint32_t VorbisExtractor::flags() const {
+    if (ShouldDisableSeek(mDataSource)) {
+        LOGI("This is streamed from local host, seek disabled");
+        return CAN_PAUSE;
+    } else {
+        return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE;
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 9e8a674..9455743 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -84,10 +84,13 @@
     status_t suspend();
     status_t resume();
 
+    // This is a mask of MediaExtractor::Flags.
+    uint32_t flags() const;
+
 private:
     friend struct AwesomeEvent;
 
-    enum Flags {
+    enum {
         PLAYING             = 1,
         LOOPING             = 2,
         FIRST_FRAME         = 4,
@@ -126,6 +129,7 @@
     int64_t mDurationUs;
 
     uint32_t mFlags;
+    uint32_t mExtractorFlags;
 
     int32_t mVideoWidth, mVideoHeight;
     int64_t mTimeSourceDeltaUs;
diff --git a/media/libstagefright/include/VorbisExtractor.h b/media/libstagefright/include/VorbisExtractor.h
index 8e38a93..2bb7deb 100644
--- a/media/libstagefright/include/VorbisExtractor.h
+++ b/media/libstagefright/include/VorbisExtractor.h
@@ -38,6 +38,8 @@
 
     virtual sp<MetaData> getMetaData();
 
+    uint32_t flags() const;
+
 protected:
     virtual ~VorbisExtractor();