frameworks/av: squashed CM commits

Revert "av: unbreak mako build"

This reverts commit bca52a9e48563198e8425c0f0a6fd2b2d998c87e.

Revert "Fix mako build."

This reverts commit 3e8a2aef873001f4e168d738f596899ba8673ab8.

Revert "stagefright: Fix tunnel mode ifdefs"

This reverts commit d9e8f7a8e085b121e0bc6518c3cf3f9a0b3e6f48.

Revert "Revert "libstagefright: Convert mono to stereo for LPA clips""

This reverts commit 93319b90415114286ee96b01a65df35f30b78aa0.

Fix the build on non-QCOM

Change-Id: Idb8d5c98fbdc01e6063ad0eb224baba66acc813d

audioflinger: Allow mixed use of JB A2DP HALs and ICS policy

Old policies don't address the modules by handle and expect them
all to be scanned for supported devices; new modules stopped
listing supported devices. The combination of a new A2DP with
an old policy left policy unable to find A2DP outputs, so the
new HALs couldn't be used.

So... if an old policy is in use, searching for an A2DP output,
and finds a non-primary HAL that doesn't list any device, assume
it's A2DP and use it.

Change-Id: Ie946c065b5c325afd02ba3437077f634e079b386

frameworks/av : Playing AAC and MP3 clips using LPA.

-AAC and MP3 clips are not playing.
-AAC and MP3 are not using LPA path.
-Enable LPA decoder path and implement LPAPlayer class.

Change-Id: I76438319fc72c4898fad5910f8de874f89287687

Revert "libstagefright: Convert mono to stereo for LPA clips"

Change-Id: Ib6cc3401c889a8ec52dc83e3bea367f94a582a40

Fix mako build.

Change-Id: Ic73cb2f4152ac77a83fcda7e89b4a8202df440c6

stagefright: Fix tunnel mode ifdefs

 * Was breaking on 8660 due to previous commit.

Change-Id: Ia9f5c45552cc933db336a66b6d1214b65e810488

libstagefright: Adjustment for TunnelPlayer buffer size

- Make necessary adjustments to align the buffer size
  for TunnelPlayer to satisfy the following conditions
- Buffer size is a multiple of LCM(1,2,4,6,8)
- Buffer size is aligned to 4k.
CRs-Fixed: 447274, 442365

Change-Id: I1b7f9ac3cf8ff86f972a8b6798bfcff3a4ba7c64

audio: apply volume on DirectOutput streams

- Call stream->set_volume to apply volume on
  particular stream of DirectOutputs

Change-Id: I98e3b856ee508d407f893afad66caade5eda3e4a
CRs-Fixed: 445953

libmediaplayerservice: Add new player for DASH

- Add new player factory to support dash playback.
- DASH urls end with .mpd. When media player receives
  an url with .mpd, it will use new factory to instantiate the player
  to be used for supporting DASH playback.

Change-Id: I69e5a08fb2baf89d97b1e0711dbe52a8b1c39c29

ACodec: Support for dynamic port reconfig

- On port settings changed first flush output port
- Move ACodec to new state called FlushingOutputState
- Flush all output buffers, wait till all decoded buffers
  are rendered
- Then disable output port, and allocate output buffers
  with new resolution, and reset native window

Change-Id: Iafa266371ed2a87b909fbcb4eeae6b64208df617

libstagefright: Add support for frame-by-frame mode

- Set decoder in frame-by-frame mode always, except for interlaced
  content, for which arbitary mode should be set

Change-Id: I8195a40549898b43a0e03d65663c7148f458c448

audioflinger: Fix to set correct volume in Tunnel playback

- After a pause and resume, tunnel playback volume is always
  set to maximum irrespective of the volume value before pause.
- The cause for this is, the stream volume is not used to set
  the volume in directaudiotrack.
- Fix is to use the stream volume to set volume during tunnel
  playback.

Change-Id: I59cda146ed88bd5c4186aeb9ae5d165f4a27493f
CRs-fixed: 452285

libstagefright: Check for duration > 0 to avoid DivideByZero crash

- duration = 0 can cause divide by zero and for this clip duration
  is indiacted as 0.
- check for duration > 0 rather than duration >= 0

Change-Id: I58ccacbf7ede892dff9626715162ea7b1f2ddbc6
CRs-Fixed: 451855

libstagefright: Squashed commit of LPA/tunnel updates from CAF

libstagefright: Exceptions in using Tunnel mode decode

- Accumulate all known exceptions to a separate function

Change-Id: I61bbc288c9a087559db210e76141b8c57e67fff0
CRs-Fixed: 432080

libstagefright : Stability fixes for Tunnel Player (part 2)

- Synchronize b/w reset() and onPauseTimeout
- Synchronize b/w seekTo() and onPauseTimeout

Change-Id: Ia5cfc6b4dcc326ead440fba35d809d4f3f1b5a81
CRs-Fixed: 449122

Revert "Revert "libstagefright: Convert mono to stereo for LPA clips""

This reverts commit 0db8a19fb3216a8a83d5d6cbd5f1ccbf997a20d8.

libstagefright: Port Tunnel mode fixes to LPA

- Miscellaneous fixes for seek, pause/resume, EOS handling
- Miscellaneous fixes for synchronization between the decoder thread,
  TimedEventQueue and the player thread.
- This change is a port of a similar set of changes made for
  TunnelPlayer

Change-Id: I82c2904f7aedfb9c4f03200419fcba8b038e3d54

libstagefright: Avoid use of extra bytes to signal seek processed

- A few bytes were reserved in the buffer sent by Tunnel/LPA
  player to audio HAL to indicate a seek has been processed and
  there is no need to skip it.
- We won't need this method anymore as this can be fixed instead
  by synchronizing seekTo() and the extractor/decoder threads.

Change-Id: Ic02ae1699bb59e2f6b8d9fb599d0fa43fd3f19e3

libstagefright: LPAPlayer synchronization fixes

- synchronize b/w seekTo() and onPauseTimeout()
- synchronize b/w reset() and onPauseTimeout()

Change-Id: I29a4ccf02e28fe7b7c00e35a679ff2b5271ffb6f

libstagefright: TunnelPlayer performance tweaks

Some tweaks when TunnelPlayer is used for audio/video playback

- Keep the extractor thread at ANDROID_PRIORITY_NORMAL
- sched_yield() after reading a frame to give the video thread(s)
  (CallbackDispatcher and/or TimedEventQueue) to be scheduled

Change-Id: If0d86d629fd0e15aff917af8589472578cd28bf4
CRs-Fixed: 444041

libstagefright: Fix incorrectness nPortIndex value for QueryCodec
                The query index is wrong, it will make a death loop in
my ME722 when get resource thumbnail for MPEG4 video.

Change-Id: I64532156e762b847a8eae59560fb828549c29519

libstagefright: Stop the logspam from LPAPlayer

Change-Id: Id6319774806e152333d468b9ff62d148e476555a
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index a583d48..1cc21d6 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -35,6 +35,7 @@
     libstagefright_omx          \
     libstagefright_wfd          \
     libutils                    \
+    libdl                       \
     libvorbisidec               \
 
 LOCAL_STATIC_LIBRARIES :=       \
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 3f69c11..57f6743 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -30,6 +30,7 @@
 #include "TestPlayerStub.h"
 #include "StagefrightPlayer.h"
 #include "nuplayer/NuPlayerDriver.h"
+#include <dlfcn.h>
 
 namespace android {
 
@@ -334,6 +335,30 @@
     registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
     registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
 
+    const char* FACTORY_LIB           = "libdashplayer.so";
+    const char* FACTORY_CREATE_FN     = "CreateDASHFactory";
+
+    MediaPlayerFactory::IFactory* pFactory  = NULL;
+    void* pFactoryLib = NULL;
+    typedef MediaPlayerFactory::IFactory* (*CreateDASHDriverFn)();
+
+    pFactoryLib = ::dlopen(FACTORY_LIB, RTLD_LAZY);
+    if (pFactoryLib == NULL) {
+        ALOGE("Failed to open FACTORY_LIB Error : %s ",::dlerror());
+    } else {
+        CreateDASHDriverFn pCreateFnPtr;
+        pCreateFnPtr = (CreateDASHDriverFn) dlsym(pFactoryLib, FACTORY_CREATE_FN);
+        if (pCreateFnPtr == NULL) {
+            ALOGE("Could not locate pCreateFnPtr");
+        } else {
+            pFactory = pCreateFnPtr();
+            if(pFactory == NULL) {
+                ALOGE("Failed to invoke CreateDASHDriverFn...");
+            } else {
+                registerFactory_l(pFactory,DASH_PLAYER);
+            }
+        }
+    }
     sInitComplete = true;
 }
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index ba7d7a7..5eb1e8a 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -334,8 +334,33 @@
     DISALLOW_EVIL_CONSTRUCTORS(FlushingState);
 };
 
+#ifdef QCOM_HARDWARE
 ////////////////////////////////////////////////////////////////////////////////
 
+struct ACodec::FlushingOutputState : public ACodec::BaseState {
+    FlushingOutputState(ACodec *codec);
+
+protected:
+    virtual PortMode getPortMode(OMX_U32 portIndex);
+    virtual bool onMessageReceived(const sp<AMessage> &msg);
+    virtual void stateEntered();
+
+    virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
+
+    virtual void onOutputBufferDrained(const sp<AMessage> &msg);
+    virtual void onInputBufferFilled(const sp<AMessage> &msg);
+
+private:
+    bool mFlushComplete;
+
+    void changeStateIfWeOwnAllBuffers();
+
+    DISALLOW_EVIL_CONSTRUCTORS(FlushingOutputState);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+#endif
+
 ACodec::ACodec()
     : mQuirks(0),
       mNode(NULL),
@@ -358,6 +383,9 @@
     mExecutingToIdleState = new ExecutingToIdleState(this);
     mIdleToLoadedState = new IdleToLoadedState(this);
     mFlushingState = new FlushingState(this);
+#ifdef QCOM_HARDWARE
+    mFlushingOutputState = new FlushingOutputState(this);
+#endif
 
     mPortEOS[kPortIndexInput] = mPortEOS[kPortIndexOutput] = false;
     mInputEOSResult = OK;
@@ -3595,14 +3623,22 @@
             CHECK_EQ(data1, (OMX_U32)kPortIndexOutput);
 
             if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
+#ifdef QCOM_HARDWARE
+                ALOGV("Flush output port before disable");
+                CHECK_EQ(mCodec->mOMX->sendCommand(
+                        mCodec->mNode, OMX_CommandFlush, kPortIndexOutput),
+                     (status_t)OK);
+
+                mCodec->changeState(mCodec->mFlushingOutputState);
+#else
                 CHECK_EQ(mCodec->mOMX->sendCommand(
                             mCodec->mNode,
                             OMX_CommandPortDisable, kPortIndexOutput),
-                         (status_t)OK);
+                        (status_t)OK);
 
                 mCodec->freeOutputBuffersNotOwnedByComponent();
-
                 mCodec->changeState(mCodec->mOutputPortSettingsChangedState);
+#endif
             } else if (data2 == OMX_IndexConfigCommonOutputCrop) {
                 mCodec->mSentFormat = false;
             } else {
@@ -4014,4 +4050,131 @@
     }
 }
 
+#ifdef QCOM_HARDWARE
+////////////////////////////////////////////////////////////////////////////////
+
+ACodec::FlushingOutputState::FlushingOutputState(ACodec *codec)
+    : BaseState(codec) {
+}
+
+ACodec::BaseState::PortMode ACodec::FlushingOutputState::getPortMode(OMX_U32 portIndex) {
+    if (portIndex == kPortIndexOutput)
+    {
+        return KEEP_BUFFERS;
+    }
+    return RESUBMIT_BUFFERS;
+}
+
+void ACodec::FlushingOutputState::stateEntered() {
+    ALOGV("[%s] Now Flushing Output Port", mCodec->mComponentName.c_str());
+
+    mFlushComplete = false;
+}
+
+bool ACodec::FlushingOutputState::onMessageReceived(const sp<AMessage> &msg) {
+    bool handled = false;
+
+    switch (msg->what()) {
+        case kWhatShutdown:
+        {
+            mCodec->deferMessage(msg);
+            handled = true;
+            break;
+        }
+
+        case kWhatFlush:
+        {
+            ALOGV("Flush received during port reconfig, deferring it");
+            mCodec->deferMessage(msg);
+            handled = true;
+            break;
+        }
+
+        case kWhatInputBufferFilled:
+        {
+            mCodec->deferMessage(msg);
+            changeStateIfWeOwnAllBuffers();
+            handled = true;
+            break;
+        }
+
+        default:
+            handled = BaseState::onMessageReceived(msg);
+            break;
+    }
+
+    return handled;
+}
+
+bool ACodec::FlushingOutputState::onOMXEvent(
+        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
+    switch (event) {
+        case OMX_EventCmdComplete:
+        {
+            CHECK_EQ(data1, (OMX_U32)OMX_CommandFlush);
+            CHECK_EQ(data2,(OMX_U32)kPortIndexOutput);
+            ALOGV("FlushingOutputState::onOMXEvent Output port flush complete");
+            mFlushComplete = true;
+            changeStateIfWeOwnAllBuffers();
+            return true;
+        }
+
+        case OMX_EventPortSettingsChanged:
+        {
+            sp<AMessage> msg = new AMessage(kWhatOMXMessage, mCodec->id());
+            msg->setInt32("type", omx_message::EVENT);
+            msg->setPointer("node", mCodec->mNode);
+            msg->setInt32("event", event);
+            msg->setInt32("data1", data1);
+            msg->setInt32("data2", data2);
+
+            ALOGV("[%s] Deferring OMX_EventPortSettingsChanged",
+                 mCodec->mComponentName.c_str());
+
+            mCodec->deferMessage(msg);
+
+            return true;
+        }
+
+        default:
+            return BaseState::onOMXEvent(event, data1, data2);
+    }
+
+    return true;
+}
+
+void ACodec::FlushingOutputState::onOutputBufferDrained(const sp<AMessage> &msg) {
+    BaseState::onOutputBufferDrained(msg);
+
+    changeStateIfWeOwnAllBuffers();
+}
+
+void ACodec::FlushingOutputState::onInputBufferFilled(const sp<AMessage> &msg) {
+    BaseState::onInputBufferFilled(msg);
+
+    changeStateIfWeOwnAllBuffers();
+}
+
+void ACodec::FlushingOutputState::changeStateIfWeOwnAllBuffers() {
+   ALOGV("FlushingOutputState::ChangeState %d",mFlushComplete);
+
+   if (mFlushComplete && mCodec->allYourBuffersAreBelongToUs( kPortIndexOutput )) {
+        ALOGV("FlushingOutputState Sending port disable ");
+        CHECK_EQ(mCodec->mOMX->sendCommand(
+                            mCodec->mNode,
+                            OMX_CommandPortDisable, kPortIndexOutput),
+                         (status_t)OK);
+
+        mCodec->mPortEOS[kPortIndexInput] = false;
+        mCodec->mPortEOS[kPortIndexOutput] = false;
+
+        ALOGV("FlushingOutputState Calling freeOutputBuffersNotOwnedByComponent");
+        mCodec->freeOutputBuffersNotOwnedByComponent();
+
+        ALOGV("FlushingOutputState Change state to port settings changed");
+        mCodec->changeState(mCodec->mOutputPortSettingsChangedState);
+    }
+}
+#endif
+
 }  // namespace android
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
old mode 100644
new mode 100755
index ac4d748..bbc338c
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -81,17 +81,19 @@
         $(TOP)/hardware/qcom/media/mm-core/inc
 
 ifeq ($(TARGET_QCOM_AUDIO_VARIANT),caf)
-    ifeq ($(filter msm8660 msm7x27a msm7x30,$(TARGET_BOARD_PLATFORM)),)
+    ifeq ($(call is-board-platform-in-list,msm8660 msm7x27a msm7x30),true)
         LOCAL_SRC_FILES += LPAPlayer.cpp
     else
         LOCAL_SRC_FILES += LPAPlayerALSA.cpp
     endif
     ifeq ($(BOARD_USES_ALSA_AUDIO),true)
-        ifeq ($(TARGET_BOARD_PLATFORM),msm8960)
+        ifeq ($(call is-chipset-in-board-platform,msm8960),true)
             LOCAL_CFLAGS += -DUSE_TUNNEL_MODE
             LOCAL_CFLAGS += -DTUNNEL_MODE_SUPPORTS_AMRWB
         endif
     endif
+LOCAL_CFLAGS += -DQCOM_ENHANCED_AUDIO
+LOCAL_SRC_FILES += TunnelPlayer.cpp
 endif
 endif
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index af29be0..acc2aaf 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -637,7 +637,7 @@
 
 bool AwesomePlayer::getBitrate(int64_t *bitrate) {
     off64_t size;
-    if (mDurationUs >= 0 && mCachedSource != NULL
+    if (mDurationUs > 0 && mCachedSource != NULL
             && mCachedSource->getSize(&size) == OK) {
         *bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
         return true;
@@ -994,7 +994,7 @@
                 property_get("lpa.min_duration",minUserDefDuration,"LPA_MIN_DURATION_USEC_DEFAULT");
                 minDurationForLPA = atoi(minUserDefDuration);
                 if(minDurationForLPA < LPA_MIN_DURATION_USEC_ALLOWED) {
-                    ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
+                    ALOGV("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
                     minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
                 }
                 if((strcmp("true",lpaDecode) == 0) && (mAudioPlayer == NULL) &&
@@ -1536,9 +1536,10 @@
     int32_t isADTS = 0;
     meta->findInt32( kKeyChannelCount, &nchannels );
     meta->findInt32(kKeyIsADTS, &isADTS);
-    if(isADTS == 1){
+    if (isADTS == 1) {
         ALOGV("Widevine content\n");
     }
+
     ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0",
            nchannels);
 #endif
@@ -1554,7 +1555,7 @@
 
     //widevine will fallback to software decoder
     if (sys_prop_enabled && (TunnelPlayer::mTunnelObjectsAlive == 0) &&
-        mTunnelAliveAP == 0 && (isADTS == 0) &&
+       (mTunnelAliveAP == 0) && (isADTS == 0) &&
         mAudioSink->realtime() &&
         inSupportedTunnelFormats(mime)) {
 
@@ -1575,10 +1576,7 @@
     else
        ALOGD("Normal Audio Playback");
 
-    if (isStreamingHTTP()) {
-      ALOGV("Streaming, force disable tunnel mode playback");
-      mIsTunnelAudio = false;
-    }
+    checkTunnelExceptions();
 
     if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW) ||
              (mIsTunnelAudio && (mTunnelAliveAP == 0))) {
@@ -1603,7 +1601,7 @@
         property_get("lpa.min_duration",minUserDefDuration,"LPA_MIN_DURATION_USEC_DEFAULT");
         minDurationForLPA = atoi(minUserDefDuration);
         if(minDurationForLPA < LPA_MIN_DURATION_USEC_ALLOWED) {
-            ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
+            ALOGV("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
             minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
         }
         if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
@@ -2049,8 +2047,8 @@
 
         if (latenessUs > 40000) {
             // We're more than 40ms late.
-            ALOGV("we're late by %lld us (%.2f secs)",
-                 latenessUs, latenessUs / 1E6);
+            ALOGE("we're late by %lld us nowUs %lld, timeUs %lld",
+                  latenessUs, nowUs, timeUs);
 
             if (!(mFlags & SLOW_DECODER_HACK)
                     || mSinceLastDropped > FRAME_DROP_FREQ)
@@ -3046,6 +3044,45 @@
     ALOGW("Tunnel playback unsupported for %s", mime);
     return false;
 }
+
+void AwesomePlayer::checkTunnelExceptions()
+{
+    /* exception 1: No streaming */
+    if (isStreamingHTTP()) {
+        ALOGV("Streaming, force disable tunnel mode playback");
+        mIsTunnelAudio = false;
+        return;
+    }
+
+    /* below exceptions are only for av content */
+    if (mVideoTrack == NULL) return;
+
+    /* exception 2: No avi having video + mp3 */
+    if (mExtractor == NULL) return;
+
+    sp<MetaData> metaData = mExtractor->getMetaData();
+    const char * container;
+
+    /*only proceed for avi content.*/
+    if (!metaData->findCString(kKeyMIMEType, &container) ||
+        strcmp(container, MEDIA_MIMETYPE_CONTAINER_AVI)) {
+        return;
+    }
+
+    CHECK(mAudioTrack != NULL);
+
+    const char * mime;
+    metaData = mAudioTrack->getFormat();
+    /*disable for av content having mp3*/
+    if (metaData->findCString(kKeyMIMEType, &mime) &&
+        !strcmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+        ALOGV("Clip has AVI extractor and mp3 content, disable tunnel mode");
+        mIsTunnelAudio = false;
+        return;
+    }
+
+    return;
+}
 #endif
 
 }  // namespace android
diff --git a/media/libstagefright/LPAPlayer.cpp b/media/libstagefright/LPAPlayer.cpp
new file mode 100755
index 0000000..1855804
--- /dev/null
+++ b/media/libstagefright/LPAPlayer.cpp
@@ -0,0 +1,833 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution. Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LPAPlayer"
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <signal.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/poll.h>
+#include <sys/eventfd.h>
+#include <binder/IPCThreadState.h>
+#include <media/AudioTrack.h>
+
+#include <media/stagefright/LPAPlayer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaErrors.h>
+
+#include <hardware_legacy/power.h>
+
+#include <linux/unistd.h>
+
+#include "include/AwesomePlayer.h"
+#include <powermanager/PowerManager.h>
+
+static const char   mName[] = "LPAPlayer";
+
+#define MEM_BUFFER_SIZE 524288
+#define MEM_BUFFER_COUNT 2
+
+#define PCM_FORMAT 2
+#define NUM_FDS 2
+namespace android {
+int LPAPlayer::objectsAlive = 0;
+bool LPAPlayer::mLpaInProgress = false;
+
+LPAPlayer::LPAPlayer(
+                    const sp<MediaPlayerBase::AudioSink> &audioSink, bool &initCheck,
+                    AwesomePlayer *observer)
+:AudioPlayer(audioSink,observer),
+mPositionTimeMediaUs(-1),
+mPositionTimeRealUs(-1),
+mInternalSeeking(false),
+mStarted(false),
+mA2DPEnabled(false),
+mSampleRate(0),
+mLatencyUs(0),
+mFrameSize(0),
+mNumFramesPlayed(0),
+mNumFramesPlayedSysTimeUs(0),
+mInputBuffer(NULL),
+mSeeking(false),
+mReachedEOS(false),
+mReachedOutputEOS(false),
+mFinalStatus(OK),
+mSeekTimeUs(0),
+mPauseTime(0),
+mIsFirstBuffer(false),
+mFirstBufferResult(OK),
+mFirstBuffer(NULL),
+mAudioSink(audioSink),
+mObserver(observer),
+mTrackType(TRACK_NONE){
+    ALOGV("LPAPlayer::LPAPlayer() ctor");
+    objectsAlive++;
+    mLpaInProgress = true;
+    mTimeStarted = 0;
+    mTimePlayed = 0;
+    numChannels =0;
+    mPaused = false;
+    mIsA2DPEnabled = false;
+    mAudioFlinger = NULL;
+    AudioFlingerClient = NULL;
+    /* Initialize Suspend/Resume related variables */
+    mQueue.start();
+    mQueueStarted      = true;
+    mPauseEvent        = new TimedEvent(this, &LPAPlayer::onPauseTimeOut);
+    mPauseEventPending = false;
+    getAudioFlinger();
+    ALOGV("Registering client with AudioFlinger");
+    mAudioFlinger->registerClient(AudioFlingerClient);
+
+    mIsAudioRouted = false;
+
+    initCheck = true;
+
+}
+
+LPAPlayer::~LPAPlayer() {
+    ALOGV("LPAPlayer::~LPAPlayer()");
+    if (mQueueStarted) {
+        mQueue.stop();
+    }
+
+    reset();
+    if (mAudioFlinger != NULL) {
+        mAudioFlinger->deregisterClient(AudioFlingerClient);
+    }
+    objectsAlive--;
+    mLpaInProgress = false;
+
+}
+
+void LPAPlayer::getAudioFlinger() {
+    Mutex::Autolock _l(AudioFlingerLock);
+
+    if ( mAudioFlinger.get() == 0 ) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16("media.audio_flinger"));
+            if ( binder != 0 )
+                break;
+            ALOGW("AudioFlinger not published, waiting...");
+            usleep(500000); // 0.5 s
+        } while ( true );
+        if ( AudioFlingerClient == NULL ) {
+            AudioFlingerClient = new AudioFlingerLPAdecodeClient(this);
+        }
+
+        binder->linkToDeath(AudioFlingerClient);
+        mAudioFlinger = interface_cast<IAudioFlinger>(binder);
+    }
+    ALOGE_IF(mAudioFlinger==0, "no AudioFlinger!?");
+}
+
+LPAPlayer::AudioFlingerLPAdecodeClient::AudioFlingerLPAdecodeClient(void *obj)
+{
+    ALOGV("LPAPlayer::AudioFlingerLPAdecodeClient::AudioFlingerLPAdecodeClient");
+    pBaseClass = (LPAPlayer*)obj;
+}
+
+void LPAPlayer::AudioFlingerLPAdecodeClient::binderDied(const wp<IBinder>& who) {
+    Mutex::Autolock _l(pBaseClass->AudioFlingerLock);
+
+    pBaseClass->mAudioFlinger.clear();
+    ALOGW("AudioFlinger server died!");
+}
+
+void LPAPlayer::AudioFlingerLPAdecodeClient::ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2) {
+    ALOGV("ioConfigChanged() event %d", event);
+
+    if (event != AudioSystem::A2DP_OUTPUT_STATE) {
+        return;
+    }
+
+    switch ( event ) {
+    case AudioSystem::A2DP_OUTPUT_STATE:
+        {
+            ALOGV("ioConfigChanged() A2DP_OUTPUT_STATE iohandle is %d with A2DPEnabled in %d", ioHandle, pBaseClass->mIsA2DPEnabled);
+            if ( -1 == ioHandle ) {
+                if ( pBaseClass->mIsA2DPEnabled ) {
+                    pBaseClass->mIsA2DPEnabled = false;
+                    if (pBaseClass->mStarted) {
+                        pBaseClass->handleA2DPSwitch();
+                    }
+                    ALOGV("ioConfigChanged:: A2DP Disabled");
+                }
+            } else {
+                if ( !pBaseClass->mIsA2DPEnabled ) {
+
+                    pBaseClass->mIsA2DPEnabled = true;
+                    if (pBaseClass->mStarted) {
+                        pBaseClass->handleA2DPSwitch();
+                    }
+
+                    ALOGV("ioConfigChanged:: A2DP Enabled");
+                }
+            }
+        }
+        break;
+    }
+    ALOGV("ioConfigChanged Out");
+
+}
+
+void LPAPlayer::handleA2DPSwitch() {
+    pthread_cond_signal(&decoder_cv);
+}
+
+void LPAPlayer::setSource(const sp<MediaSource> &source) {
+    CHECK(mSource == NULL);
+    ALOGV("Setting source from LPA Player");
+    mSource = source;
+}
+
+status_t LPAPlayer::start(bool sourceAlreadyStarted) {
+    CHECK(!mStarted);
+    CHECK(mSource != NULL);
+
+    ALOGV("start: sourceAlreadyStarted %d", sourceAlreadyStarted);
+    //Check if the source is started, start it
+    status_t err;
+    if (!sourceAlreadyStarted) {
+        err = mSource->start();
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    //Create decoder and a2dp notification thread and initialize all the
+    //mutexes and coditional variables
+    createThreads();
+    ALOGV("All Threads Created.");
+
+    // We allow an optional INFO_FORMAT_CHANGED at the very beginning
+    // of playback, if there is one, getFormat below will retrieve the
+    // updated format, if there isn't, we'll stash away the valid buffer
+    // of data to be used on the first audio callback.
+
+    CHECK(mFirstBuffer == NULL);
+
+    MediaSource::ReadOptions options;
+    if (mSeeking) {
+        options.setSeekTo(mSeekTimeUs);
+        mSeeking = false;
+    }
+
+    mFirstBufferResult = mSource->read(&mFirstBuffer, &options);
+    if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
+        ALOGV("INFO_FORMAT_CHANGED!!!");
+        CHECK(mFirstBuffer == NULL);
+        mFirstBufferResult = OK;
+        mIsFirstBuffer = false;
+    } else {
+        mIsFirstBuffer = true;
+    }
+
+    sp<MetaData> format = mSource->getFormat();
+    const char *mime;
+
+    bool success = format->findCString(kKeyMIMEType, &mime);
+    CHECK(success);
+    CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
+
+    success = format->findInt32(kKeySampleRate, &mSampleRate);
+    CHECK(success);
+
+    success = format->findInt32(kKeyChannelCount, &numChannels);
+    CHECK(success);
+
+    if(!format->findInt32(kKeyChannelMask, &mChannelMask)) {
+        // log only when there's a risk of ambiguity of channel mask selection
+        ALOGI_IF(numChannels > 2,
+                "source format didn't specify channel mask, using (%d) channel order", numChannels);
+        mChannelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
+    }
+
+    err = setupAudioSink();
+
+    if (err != OK) {
+        if (mFirstBuffer != NULL) {
+            mFirstBuffer->release();
+            mFirstBuffer = NULL;
+        }
+
+        if (!sourceAlreadyStarted) {
+            mSource->stop();
+        }
+
+        ALOGE("Opening a routing session failed");
+        return err;
+    }
+
+    mIsAudioRouted = true;
+    mStarted = true;
+    mAudioSink->start();
+    mTimeStarted = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+    ALOGV("Waking up decoder thread");
+    pthread_cond_signal(&decoder_cv);
+
+    return OK;
+}
+
+status_t LPAPlayer::seekTo(int64_t time_us) {
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("seekTo: time_us %lld", time_us);
+    if ( mReachedEOS ) {
+        mReachedEOS = false;
+        mReachedOutputEOS = false;
+    }
+    mSeeking = true;
+    mSeekTimeUs = time_us;
+    mTimePlayed = time_us;
+    mTimeStarted = 0;
+    ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);
+    mAudioSink->flush();
+    pthread_cond_signal(&decoder_cv);
+    //TODO: Update the mPauseTime
+    return OK;
+}
+
+void LPAPlayer::pause(bool playPendingSamples) {
+    CHECK(mStarted);
+    if (mPaused) {
+        return;
+    }
+    ALOGV("pause: playPendingSamples %d", playPendingSamples);
+    mPaused = true;
+    if (playPendingSamples) {
+        if (!mIsA2DPEnabled) {
+            if (!mPauseEventPending) {
+                ALOGV("Posting an event for Pause timeout");
+                mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
+                mPauseEventPending = true;
+            }
+            if (mAudioSink.get() != NULL)
+                mAudioSink->pause();
+        }
+        else {
+            if (mAudioSink.get() != NULL)
+                mAudioSink->stop();
+
+        }
+    } else {
+        if (!mIsA2DPEnabled) {
+            if(!mPauseEventPending) {
+                ALOGV("Posting an event for Pause timeout");
+                mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
+                mPauseEventPending = true;
+            }
+            if (mAudioSink.get() != NULL)
+                mAudioSink->pause();
+            } else {
+            if (mAudioSink.get() != NULL) {
+                mAudioSink->pause();
+            }
+        }
+    }
+    if(mTimeStarted != 0) {
+        mTimePlayed += (nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC)) - mTimeStarted);
+    }
+}
+
+void LPAPlayer::resume() {
+    ALOGV("resume: mPaused %d",mPaused);
+    if ( mPaused) {
+        CHECK(mStarted);
+        if (!mIsA2DPEnabled) {
+            if(mPauseEventPending) {
+                ALOGV("Resume(): Cancelling the puaseTimeout event");
+                mPauseEventPending = false;
+                mQueue.cancelEvent(mPauseEvent->eventID());
+            }
+
+        }
+
+        setupAudioSink();
+
+        mPaused = false;
+        mIsAudioRouted = true;
+        mAudioSink->start();
+        mTimeStarted = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+        pthread_cond_signal(&decoder_cv);
+    }
+}
+
+//static
+size_t LPAPlayer::AudioSinkCallback(
+        MediaPlayerBase::AudioSink *audioSink,
+        void *buffer, size_t size, void *cookie) {
+    if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
+        LPAPlayer *me = (LPAPlayer *)cookie;
+        me->mReachedEOS = true;
+        me->mReachedOutputEOS = true;
+        ALOGV("postAudioEOS");
+        me->mObserver->postAudioEOS(0);
+    }
+    return 1;
+}
+
+void LPAPlayer::reset() {
+
+    // Close the audiosink after all the threads exited to make sure
+    ALOGV("Reset called!!!!!");
+    mReachedEOS = true;
+    //TODO: Release Wake lock
+
+    // make sure Decoder thread has exited
+    requestAndWaitForDecoderThreadExit();
+    requestAndWaitForA2DPNotificationThreadExit();
+    if (mIsAudioRouted) {
+        mAudioSink->stop();
+        mAudioSink->close();
+    }
+    mAudioSink.clear();
+    // Make sure to release any buffer we hold onto so that the
+    // source is able to stop().
+    if (mFirstBuffer != NULL) {
+        mFirstBuffer->release();
+        mFirstBuffer = NULL;
+    }
+
+    if (mInputBuffer != NULL) {
+        ALOGV("AudioPlayer releasing input buffer.");
+        mInputBuffer->release();
+        mInputBuffer = NULL;
+    }
+
+    mSource->stop();
+
+    // The following hack is necessary to ensure that the OMX
+    // component is completely released by the time we may try
+    // to instantiate it again.
+    wp<MediaSource> tmp = mSource;
+    mSource.clear();
+    while (tmp.promote() != NULL) {
+        usleep(1000);
+    }
+
+    mPositionTimeMediaUs = -1;
+    mPositionTimeRealUs = -1;
+    mSeeking = false;
+    mReachedEOS = false;
+    mReachedOutputEOS = false;
+    mFinalStatus = OK;
+    mStarted = false;
+}
+
+
+bool LPAPlayer::isSeeking() {
+    Mutex::Autolock autoLock(mLock);
+    return mSeeking;
+}
+
+bool LPAPlayer::reachedEOS(status_t *finalStatus) {
+    *finalStatus = OK;
+    Mutex::Autolock autoLock(mLock);
+    *finalStatus = mFinalStatus;
+    return mReachedOutputEOS;
+}
+
+
+void *LPAPlayer::decoderThreadWrapper(void *me) {
+    static_cast<LPAPlayer *>(me)->decoderThreadEntry();
+    return NULL;
+}
+
+
+void LPAPlayer::decoderThreadEntry() {
+
+    pthread_mutex_lock(&decoder_mutex);
+
+    pid_t tid  = gettid();
+    androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+    prctl(PR_SET_NAME, (unsigned long)"LPA DecodeThread", 0, 0, 0);
+
+    ALOGV("decoderThreadEntry wait for signal \n");
+    if (!mStarted) {
+        pthread_cond_wait(&decoder_cv, &decoder_mutex);
+    }
+    ALOGV("decoderThreadEntry ready to work \n");
+    pthread_mutex_unlock(&decoder_mutex);
+    if (killDecoderThread) {
+        return;
+    }
+    void* local_buf = malloc(MEM_BUFFER_SIZE);
+    int bytesWritten = 0;
+    while (!killDecoderThread) {
+
+        setupAudioSink();
+        if (mTimeStarted == 0) {
+            mTimeStarted = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+        }
+
+        if (mReachedEOS || mPaused || !mIsAudioRouted || mIsA2DPEnabled) {
+            ALOGD("DecoderThread taking mutex mReachedEOS %d mPaused %d mIsAudioRouted %d mIsA2DPEnabled %d"
+                       , mReachedEOS, mPaused, mIsAudioRouted, mIsA2DPEnabled);
+            pthread_mutex_lock(&decoder_mutex);
+            pthread_cond_wait(&decoder_cv, &decoder_mutex);
+            pthread_mutex_unlock(&decoder_mutex);
+            ALOGD("DecoderThread woken up ");
+            continue;
+        }
+
+        if (!mIsA2DPEnabled) {
+            ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE);
+            ALOGV("Fillbuffer started");
+            //TODO: Add memset
+            bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE);
+            ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+
+            if(!killDecoderThread) {
+                mAudioSink->write(local_buf, bytesWritten);
+            }
+        }
+    }
+
+    free(local_buf);
+
+    //TODO: Call fillbuffer with different size and write to mAudioSink()
+}
+
+void LPAPlayer::createThreads() {
+
+    //Initialize all the Mutexes and Condition Variables
+    pthread_mutex_init(&decoder_mutex, NULL);
+    pthread_mutex_init(&audio_sink_setup_mutex, NULL);
+    pthread_cond_init (&decoder_cv, NULL);
+
+    // Create 4 threads Effect, decoder, event and A2dp
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    killDecoderThread = false;
+    killA2DPNotificationThread = false;
+
+    decoderThreadAlive = true;
+
+    ALOGV("Creating decoder Thread");
+    pthread_create(&decoderThread, &attr, decoderThreadWrapper, this);
+
+    pthread_attr_destroy(&attr);
+}
+
+size_t LPAPlayer::fillBuffer(void *data, size_t size) {
+
+    if (mReachedEOS) {
+        return 0;
+    }
+
+    bool postSeekComplete = false;
+
+    size_t size_done = 0;
+    size_t size_remaining = size;
+    while (size_remaining > 0) {
+        MediaSource::ReadOptions options;
+
+        {
+            Mutex::Autolock autoLock(mLock);
+
+            if (mSeeking) {
+                mInternalSeeking = false;
+            }
+            if (mSeeking || mInternalSeeking) {
+                if (mIsFirstBuffer) {
+                    if (mFirstBuffer != NULL) {
+                        mFirstBuffer->release();
+                        mFirstBuffer = NULL;
+                    }
+                    mIsFirstBuffer = false;
+                }
+
+                options.setSeekTo(mSeekTimeUs);
+
+                if (mInputBuffer != NULL) {
+                    mInputBuffer->release();
+                    mInputBuffer = NULL;
+                }
+
+                mSeeking = false;
+                if (mObserver && !mInternalSeeking) {
+                    ALOGV("fillBuffer: Posting audio seek complete event");
+                    postSeekComplete = true;
+                }
+                mInternalSeeking = false;
+            }
+        }
+
+        if (mInputBuffer == NULL) {
+            status_t err;
+
+            if (mIsFirstBuffer) {
+                mInputBuffer = mFirstBuffer;
+                mFirstBuffer = NULL;
+                err = mFirstBufferResult;
+
+                mIsFirstBuffer = false;
+            } else {
+                err = mSource->read(&mInputBuffer, &options);
+            }
+
+            CHECK((err == OK && mInputBuffer != NULL)
+                   || (err != OK && mInputBuffer == NULL));
+
+            Mutex::Autolock autoLock(mLock);
+
+            if (err != OK) {
+                mReachedEOS = true;
+                mFinalStatus = err;
+                break;
+            }
+
+            CHECK(mInputBuffer->meta_data()->findInt64(
+                        kKeyTime, &mPositionTimeMediaUs));
+            mFrameSize = mAudioSink->frameSize();
+            mPositionTimeRealUs =
+                ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+                    / mSampleRate;
+        }
+        if (mInputBuffer->range_length() == 0) {
+            mInputBuffer->release();
+            mInputBuffer = NULL;
+
+            continue;
+        }
+
+        size_t copy = size_remaining;
+        if (copy > mInputBuffer->range_length()) {
+            copy = mInputBuffer->range_length();
+        }
+
+        memcpy((char *)data + size_done,
+               (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
+               copy);
+
+        mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
+                                mInputBuffer->range_length() - copy);
+
+        size_done += copy;
+        size_remaining -= copy;
+    }
+
+    if (postSeekComplete) {
+        mObserver->postAudioSeekComplete();
+    }
+
+    return size_done;
+}
+
+int64_t LPAPlayer::getRealTimeUs() {
+    Mutex::Autolock autoLock(mLock);
+    return getRealTimeUsLocked();
+}
+
+
+int64_t LPAPlayer::getRealTimeUsLocked(){
+    //Used for AV sync: irrelevant API for LPA.
+    return 0;
+}
+
+
+int64_t LPAPlayer::getMediaTimeUs() {
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld", mPaused, mSeekTimeUs);
+    if(mPaused || mTimeStarted == 0) {
+       return mTimePlayed;
+    } else {
+       return nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC)) - mTimeStarted + mTimePlayed;
+    }
+}
+
+bool LPAPlayer::getMediaTimeMapping(
+                                   int64_t *realtime_us, int64_t *mediatime_us) {
+    Mutex::Autolock autoLock(mLock);
+
+    *realtime_us = mPositionTimeRealUs;
+    *mediatime_us = mPositionTimeMediaUs;
+
+    return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
+}
+
+void LPAPlayer::requestAndWaitForDecoderThreadExit() {
+
+    if (!decoderThreadAlive)
+        return;
+    killDecoderThread = true;
+    if (mIsAudioRouted)
+        mAudioSink->flush();
+    pthread_cond_signal(&decoder_cv);
+    pthread_join(decoderThread,NULL);
+    ALOGV("decoder thread killed");
+
+}
+
+void LPAPlayer::requestAndWaitForA2DPNotificationThreadExit() {
+    if (!a2dpNotificationThreadAlive)
+        return;
+    killA2DPNotificationThread = true;
+    pthread_cond_signal(&a2dp_notification_cv);
+    pthread_join(A2DPNotificationThread,NULL);
+    ALOGV("a2dp notification thread killed");
+}
+
+void LPAPlayer::onPauseTimeOut() {
+    ALOGV("onPauseTimeOut");
+    if (!mPauseEventPending) {
+        return;
+    }
+    mPauseEventPending = false;
+    if(!mIsA2DPEnabled) {
+        // 1.) Set seek flags
+        mReachedEOS = false;
+        mReachedOutputEOS = false;
+        mSeekTimeUs = mTimePlayed;
+
+        // 2.) Close routing Session
+        mAudioSink->close();
+        mIsAudioRouted = false;
+        mTrackType = TRACK_NONE;
+    }
+}
+
+status_t  LPAPlayer::setupAudioSink()
+{
+    status_t err = NO_ERROR;
+
+    ALOGD("setupAudioSink with A2DP(%d) tracktype(%d)", mIsA2DPEnabled, mTrackType);
+    pthread_mutex_lock(&audio_sink_setup_mutex);
+
+    if(true == mIsA2DPEnabled) {
+        ALOGE("setupAudioSink:dIRECT track --> rEGULAR track");
+
+        if(mTrackType == TRACK_REGULAR) {
+            ALOGD("setupAudioSink:rEGULAR Track already opened");
+            pthread_mutex_unlock(&audio_sink_setup_mutex);
+            return err;
+        }
+
+        if(mTrackType == TRACK_DIRECT) {
+            ALOGD("setupAudioSink:Close dIRECT track");
+            mAudioSink->stop();
+            mAudioSink->close();
+        }
+
+        ALOGD("setupAudioSink:Open rEGULAR track");
+
+        ALOGD("setupAudioSink:mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",
+                mSampleRate, numChannels, mChannelMask, 0);
+
+        err = mAudioSink->open(
+            mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+            DEFAULT_AUDIOSINK_BUFFERCOUNT,
+            &LPAPlayer::AudioCallback,
+            this,
+            (audio_output_flags_t)0);
+        if (err != NO_ERROR){
+            ALOGE("setupAudioSink:Audio sink open failed.");
+        }
+
+        ALOGD("setupAudioSink:Start rEGULAR track");
+        mAudioSink->start();
+
+        ALOGD("setupAudioSink:rEGULAR track opened");
+        mTrackType = TRACK_REGULAR;
+
+    } else if (false == mIsA2DPEnabled){
+        ALOGE("setupAudioSink:rEGULAR track --> dIRECT track");
+
+        if(mTrackType == TRACK_DIRECT) {
+            ALOGD("setupAudioSink:Direct Track already opened");
+            pthread_mutex_unlock(&audio_sink_setup_mutex);
+            return err;
+        }
+
+        if(mTrackType == TRACK_REGULAR) {
+            ALOGD("setupAudioSink:Close rEGULAR track");
+            mAudioSink->stop();
+            mAudioSink->close();
+        }
+
+        ALOGD("setupAudioSink:Open dIRECT track");
+
+        ALOGD("setupAudioSink:mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",
+                mSampleRate, numChannels, mChannelMask, (AUDIO_OUTPUT_FLAG_LPA | AUDIO_OUTPUT_FLAG_DIRECT));
+
+        err = mAudioSink->open(
+            mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+            DEFAULT_AUDIOSINK_BUFFERCOUNT,
+            &LPAPlayer::AudioSinkCallback,
+            this,
+            (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_LPA | AUDIO_OUTPUT_FLAG_DIRECT));
+        if (err != NO_ERROR){
+            ALOGE("setupAudioSink:Audio sink open failed.");
+        }
+
+        mTrackType = TRACK_DIRECT;
+        ALOGD("setupAudioSink:dIRECT track opened");
+    }
+    pthread_mutex_unlock(&audio_sink_setup_mutex);
+
+    return err;
+
+}
+
+
+size_t LPAPlayer::AudioCallback(
+        MediaPlayerBase::AudioSink *audioSink,
+        void *buffer, size_t size, void *cookie) {
+
+    return (static_cast<LPAPlayer *>(cookie)->AudioCallback(cookie, buffer, size));
+}
+
+size_t LPAPlayer::AudioCallback(void *cookie, void *buffer, size_t size) {
+    size_t size_done = 0;
+    uint32_t numFramesPlayedOut;
+    LPAPlayer *me = (LPAPlayer *)cookie;
+
+    if(me->mReachedOutputEOS)
+        return 0;
+
+    if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
+        ALOGE("Underrun");
+        return 0;
+     } else {
+        size_done = fillBuffer(buffer, size);
+        ALOGD("RegularTrack:fillbuffersize %d %d", size_done, size);
+        if(mReachedEOS) {
+            me->mReachedOutputEOS = true;
+            me->mObserver->postAudioEOS();
+            ALOGE("postEOSDelayUs ");
+        }
+        return size_done;
+    }
+}
+
+} //namespace android
diff --git a/media/libstagefright/LPAPlayerALSA.cpp b/media/libstagefright/LPAPlayerALSA.cpp
index 978884e..c587f31 100644
--- a/media/libstagefright/LPAPlayerALSA.cpp
+++ b/media/libstagefright/LPAPlayerALSA.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009 The Android Open Source Project
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  * Not a Contribution, Apache license notifications and license are retained
  * for attribution purposes only.
  *
@@ -51,11 +51,14 @@
 
 static const char   mName[] = "LPAPlayer";
 
-#define MEM_BUFFER_SIZE 262144
+#define MEM_PADDING 64
+#define MEM_BUFFER_SIZE (256*1024)
 #define MEM_BUFFER_COUNT 4
 
 #define PCM_FORMAT 2
 #define NUM_FDS 2
+#define LPA_BUFFER_TIME 1500000
+
 namespace android {
 int LPAPlayer::objectsAlive = 0;
 
@@ -87,7 +90,8 @@
 mObserver(observer) {
     ALOGV("LPAPlayer::LPAPlayer() ctor");
     objectsAlive++;
-    numChannels =0;
+    mNumOutputChannels =0;
+    mNumInputChannels = 0;
     mPaused = false;
     mIsA2DPEnabled = false;
     mAudioFlinger = NULL;
@@ -256,20 +260,24 @@
     success = format->findInt32(kKeySampleRate, &mSampleRate);
     CHECK(success);
 
-    success = format->findInt32(kKeyChannelCount, &numChannels);
+    success = format->findInt32(kKeyChannelCount, &mNumInputChannels);
     CHECK(success);
 
+    // Always produce stereo output
+    mNumOutputChannels = 2;
+
     if(!format->findInt32(kKeyChannelMask, &mChannelMask)) {
         // log only when there's a risk of ambiguity of channel mask selection
-        ALOGI_IF(numChannels > 2,
-                "source format didn't specify channel mask, using (%d) channel order", numChannels);
+        ALOGI_IF(mNumInputChannels > 2,
+                "source format didn't specify channel mask, using (%d) channel order", mNumInputChannels);
         mChannelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
     }
     audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA |
                                                          AUDIO_OUTPUT_FLAG_DIRECT);
-    ALOGV("mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",mSampleRate, numChannels, mChannelMask, flags);
+    ALOGV("mAudiosink->open() mSampleRate %d, numOutputChannels %d, mChannelMask %d, flags %d",mSampleRate,
+          mNumOutputChannels, mChannelMask, flags);
     err = mAudioSink->open(
-        mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+        mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
         DEFAULT_AUDIOSINK_BUFFERCOUNT,
         &LPAPlayer::AudioSinkCallback,
         this,
@@ -301,16 +309,40 @@
 status_t LPAPlayer::seekTo(int64_t time_us) {
     Mutex::Autolock autoLock(mLock);
     ALOGV("seekTo: time_us %lld", time_us);
-    if ( mReachedEOS ) {
-        mReachedEOS = false;
-        mReachedOutputEOS = false;
+
+    int64_t mediaTimeUs = getMediaTimeUs_l();
+
+    if (mediaTimeUs != 0) {
+      //check for return conditions only if seektime
+      // is set
+      int64_t diffUs = time_us - mediaTimeUs;
+
+      if (labs(diffUs) < LPA_BUFFER_TIME) {
+          ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs);
+          mObserver->postAudioSeekComplete();
+          return OK;
+      }
     }
+
     mSeeking = true;
     mSeekTimeUs = time_us;
     mPauseTime = mSeekTimeUs;
     ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);
-    mAudioSink->flush();
-    pthread_cond_signal(&decoder_cv);
+
+    if (mIsAudioRouted) {
+        mAudioSink->flush();
+    }
+
+    if (mReachedEOS) {
+        mReachedEOS = false;
+        mReachedOutputEOS = false;
+        if(mPaused == false) {
+            ALOGV("Going to signal decoder thread since playback is already going on ");
+            pthread_cond_signal(&decoder_cv);
+            ALOGV("Signalled extractor thread.");
+        }
+    }
+    ALOGV("seek done.");
     return OK;
 }
 
@@ -322,41 +354,26 @@
     ALOGV("pause: playPendingSamples %d", playPendingSamples);
     mPaused = true;
     A2DPState state;
-    if (playPendingSamples) {
-        if (!mIsA2DPEnabled) {
-            if (!mPauseEventPending) {
-                ALOGV("Posting an event for Pause timeout");
-                mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
-                mPauseEventPending = true;
-            }
-            mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_DISABLED);
-        }
-        else {
-            mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_ENABLED);
-        }
-        if (mAudioSink.get() != NULL)
-            mAudioSink->pause();
+    if (!mIsA2DPEnabled) {
+       if (!mPauseEventPending) {
+           ALOGV("Posting an event for Pause timeout");
+           mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
+           mPauseEventPending = true;
+       }
+       mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_DISABLED);
     } else {
-        if (!mIsA2DPEnabled) {
-            if(!mPauseEventPending) {
-                ALOGV("Posting an event for Pause timeout");
-                mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
-                mPauseEventPending = true;
-            }
-            mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_DISABLED);
-        } else {
-            mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_ENABLED);
-        }
-        if (mAudioSink.get() != NULL) {
-            ALOGV("AudioSink pause");
-            mAudioSink->pause();
-        }
+        mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_ENABLED);
+    }
+
+    if (mAudioSink.get() != NULL) {
+        ALOGV("AudioSink pause");
+        mAudioSink->pause();
     }
 }
 
 void LPAPlayer::resume() {
     ALOGV("resume: mPaused %d",mPaused);
-    Mutex::Autolock autoLock(mResumeLock);
+    Mutex::Autolock autoLock(mLock);
     if ( mPaused) {
         CHECK(mStarted);
         if (!mIsA2DPEnabled) {
@@ -372,7 +389,7 @@
             audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA |
                                                                 AUDIO_OUTPUT_FLAG_DIRECT);
             status_t err = mAudioSink->open(
-                mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+                mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
                 DEFAULT_AUDIOSINK_BUFFERCOUNT,
                 &LPAPlayer::AudioSinkCallback,
                 this,
@@ -394,30 +411,42 @@
         void *buffer, size_t size, void *cookie) {
     if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
         LPAPlayer *me = (LPAPlayer *)cookie;
-        me->mReachedEOS = true;
-        me->mReachedOutputEOS = true;
-        ALOGV("postAudioEOS");
-        me->mObserver->postAudioEOS(0);
+        if(me->mReachedEOS == true) {
+            //in the case of seek all these flags will be reset
+            me->mReachedOutputEOS = true;
+            ALOGV("postAudioEOS mSeeking %d", me->mSeeking);
+            me->mObserver->postAudioEOS(0);
+        }else {
+            ALOGV("postAudioEOS ignored since %d", me->mSeeking);
+        }
     }
     return 1;
 }
 
 void LPAPlayer::reset() {
+    ALOGD("Reset");
 
-    ALOGV("Reset");
+    Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
+
+    //cancel any pending onpause timeout events
+    //doesnt matter if the event is really present or not
+    mPauseEventPending = false;
+    mQueue.cancelEvent(mPauseEvent->eventID());
+
     // Close the audiosink after all the threads exited to make sure
     mReachedEOS = true;
 
     // make sure Decoder thread has exited
-    ALOGV("Closing all the threads");
+    ALOGD("Closing all the threads");
     requestAndWaitForDecoderThreadExit();
     requestAndWaitForA2DPNotificationThreadExit();
 
-    ALOGV("Close the Sink");
+    ALOGD("Close the Sink");
     if (mIsAudioRouted) {
 	    mAudioSink->stop();
         mAudioSink->close();
         mAudioSink.clear();
+        mIsAudioRouted = false;
     }
     // Make sure to release any buffer we hold onto so that the
     // source is able to stop().
@@ -490,25 +519,80 @@
         return;
     }
     void* local_buf = malloc(MEM_BUFFER_SIZE);
+    if(local_buf == (void*) NULL) {
+        killDecoderThread = true;
+        ALOGE("Malloc failed");
+        return;
+    }
+    int *lptr = ((int*)local_buf);
     int bytesWritten = 0;
+
+    if (!local_buf) {
+      ALOGE("Failed to allocate temporary buffer for decoderThread");
+      return;
+    }
+
+    bool lSeeking = false;
+    bool lPaused = false;
+
     while (!killDecoderThread) {
 
         if (mReachedEOS || mPaused || !mIsAudioRouted) {
+            ALOGV("Going to sleep before write since "
+                  "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+                  mReachedEOS, mPaused, mIsAudioRouted);
             pthread_mutex_lock(&decoder_mutex);
             pthread_cond_wait(&decoder_cv, &decoder_mutex);
             pthread_mutex_unlock(&decoder_mutex);
+            ALOGV("Woke up from sleep before write since "
+                  "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+                  mReachedEOS, mPaused, mIsAudioRouted);
             continue;
         }
 
         if (!mIsA2DPEnabled) {
             ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE);
             ALOGV("Fillbuffer started");
-            //TODO: Add memset
-            bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE);
-            ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+            if (mNumInputChannels == 1) {
+                bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE/2);
+                CHECK(bytesWritten <= MEM_BUFFER_SIZE/2);
 
+                convertMonoToStereo((int16_t*)local_buf, bytesWritten);
+                bytesWritten *= 2;
+            } else {
+                bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE);
+                CHECK(bytesWritten <= MEM_BUFFER_SIZE);
+            }
+
+            ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
             if(!killDecoderThread) {
-                mAudioSink->write(local_buf, bytesWritten);
+                mLock.lock();
+                lPaused = mPaused;
+                mLock.unlock();
+
+                if(lPaused == true) {
+                    //write only if player is not in paused state. Sleep on lock
+                    // resume is called
+                    ALOGV("Going to sleep in decodethreadiwrite since sink is paused");
+                    pthread_mutex_lock(&decoder_mutex);
+                    pthread_cond_wait(&decoder_cv, &decoder_mutex);
+                    ALOGV("Going to unlock n decodethreadwrite since sink "
+                          "resumed mPaused %d, mIsAudioRouted %d, mReachedEOS %d",
+                          mPaused, mIsAudioRouted, mReachedEOS);
+                    pthread_mutex_unlock(&decoder_mutex);
+                }
+                mLock.lock();
+                lSeeking = mSeeking||mInternalSeeking;
+                mLock.unlock();
+
+                if(lSeeking == false && (killDecoderThread == false)){
+                    //if we are seeking, ignore write, otherwise write
+                    ALOGV("Fillbuffer before seeling flag %d", mSeeking);
+                    int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten);
+                    ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking);
+                } else {
+                    ALOGV("Fillbuffer ignored since we seeked after fillBuffer was set %d", mSeeking);
+                }
             }
         }
     }
@@ -580,19 +664,27 @@
         return 0;
     }
 
+    if ((data == (void*) NULL) || size > MEM_BUFFER_SIZE) {
+        ALOGE("fillBuffer given wrong buffer");
+        return 0;
+    }
+
     bool postSeekComplete = false;
 
     size_t size_done = 0;
     size_t size_remaining = size;
+    ALOGV("fillBuffer: Clearing seek flag in fill buffer");
+
     while (size_remaining > 0) {
         MediaSource::ReadOptions options;
 
         {
             Mutex::Autolock autoLock(mLock);
 
-            if (mSeeking) {
+            if(mSeeking) {
                 mInternalSeeking = false;
             }
+
             if (mSeeking || mInternalSeeking) {
                 if (mIsFirstBuffer) {
                     if (mFirstBuffer != NULL) {
@@ -609,8 +701,9 @@
                     mInputBuffer = NULL;
                 }
 
-                size_remaining = size;
+                // This is to ignore the data already filled in the output buffer
                 size_done = 0;
+                size_remaining = size;
 
                 mSeeking = false;
                 if (mObserver && !mInternalSeeking) {
@@ -618,6 +711,7 @@
                     postSeekComplete = true;
                 }
                 mInternalSeeking = false;
+                ALOGV("fillBuffer: Setting seek flag in fill buffer");
             }
         }
 
@@ -635,14 +729,16 @@
             }
 
             CHECK((err == OK && mInputBuffer != NULL)
-                   || (err != OK && mInputBuffer == NULL));
+                  || (err != OK && mInputBuffer == NULL));
+            {
+                Mutex::Autolock autoLock(mLock);
 
-            Mutex::Autolock autoLock(mLock);
-
-            if (err != OK) {
-                mReachedEOS = true;
-                mFinalStatus = err;
-                break;
+                if (err != OK) {
+                    ALOGD("fill buffer - reached eos true");
+                    mReachedEOS = true;
+                    mFinalStatus = err;
+                    break;
+                }
             }
 
             CHECK(mInputBuffer->meta_data()->findInt64(
@@ -662,7 +758,7 @@
         size_t copy = size_remaining;
         if (copy > mInputBuffer->range_length()) {
             copy = mInputBuffer->range_length();
-        }
+        } //is size_remaining < range_length impossible?
 
         memcpy((char *)data + size_done,
                (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
@@ -712,9 +808,7 @@
     return timestamp;
 }
 
-int64_t LPAPlayer::getMediaTimeUs() {
-    Mutex::Autolock autoLock(mLock);
-    ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime);
+int64_t LPAPlayer::getMediaTimeUs_l() {
     if (mPaused) {
         return mPauseTime;
     } else {
@@ -723,16 +817,21 @@
     }
 }
 
-bool LPAPlayer::getMediaTimeMapping(
-                                   int64_t *realtime_us, int64_t *mediatime_us) {
+int64_t LPAPlayer::getMediaTimeUs() {
     Mutex::Autolock autoLock(mLock);
-
-    *realtime_us = mPositionTimeRealUs;
-    *mediatime_us = mPositionTimeMediaUs;
-
-    return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
+    ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime);
+    return getMediaTimeUs_l();
 }
 
+bool LPAPlayer::getMediaTimeMapping(
+                                   int64_t *realtime_us, int64_t *mediatime_us) {
+    ALOGE("getMediaTimeMapping is invalid for LPA Player");
+    *realtime_us = -1;
+    *mediatime_us = -1;
+    return false;
+}
+
+//lock taken in reset()
 void LPAPlayer::requestAndWaitForDecoderThreadExit() {
 
     if (!decoderThreadAlive)
@@ -745,8 +844,10 @@
         mAudioSink->flush();
 
     pthread_cond_signal(&decoder_cv);
+    mLock.unlock();
     pthread_join(decoderThread,NULL);
-    ALOGV("decoder thread killed");
+    mLock.lock();
+    ALOGD("decoder thread killed");
 
 }
 
@@ -761,7 +862,7 @@
 
 void LPAPlayer::onPauseTimeOut() {
     ALOGV("onPauseTimeOut");
-    Mutex::Autolock autoLock(mResumeLock);
+    Mutex::Autolock autoLock(mLock);
     if (!mPauseEventPending) {
         return;
     }
@@ -790,4 +891,18 @@
 
 }
 
+//dup each mono frame
+void LPAPlayer::convertMonoToStereo(int16_t *data, size_t size)
+{
+    int i =0;
+    int16_t *start_pointer = data;
+    int monoFrameCount = (size) / (sizeof(int16_t));
+
+    for (i = monoFrameCount; i > 0 ; i--) {
+      int16_t temp_sample = *(start_pointer + i - 1);
+      *(start_pointer + (i*2) - 1) = temp_sample;
+      *(start_pointer + (i*2) - 2) = temp_sample;
+    }
+}
+
 } //namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 488c2a3..dd1e60b 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -42,6 +42,7 @@
 #include <utils/String8.h>
 #ifdef QCOM_HARDWARE
 #include <QCMediaDefs.h>
+#include <QCMetaData.h>
 #endif
 
 namespace android {
@@ -2002,6 +2003,12 @@
         // The number of bytes used to encode the length of a NAL unit.
         mNALLengthSize = 1 + (ptr[4] & 3);
     }
+
+#ifdef QCOM_HARDWARE
+    //MPEG4 extractor can give complete frames,
+    //set arbitrary mode to false
+    mFormat->setInt32(kKeyUseArbitraryMode, 0);
+#endif
 }
 
 MPEG4Source::~MPEG4Source() {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index a1021f2..5910290 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009 The Android Open Source Project
- * Copyright (c) 2010 - 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010 - 2013, The Linux Foundation. All rights reserved.
  *
  * Not a Contribution, Apache license notifications and license are retained
  * for attribution purposes only.
@@ -630,6 +630,10 @@
                 return err;
             }
 
+#ifdef QCOM_HARDWARE
+            QCOMXCodec::checkIfInterlaced((const uint8_t *)data, meta);
+#endif
+
             CODEC_LOGI(
                     "AVC profile = %u (%s), level = %u",
                     profile, AVCProfileToString(profile), level);
@@ -5278,7 +5282,7 @@
     // Color format query
     OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
     InitOMXParams(&portFormat);
-    portFormat.nPortIndex = !isEncoder ? 1 : 0;
+    portFormat.nPortIndex = !isEncoder ? 0 : 1;
     for (portFormat.nIndex = 0;; ++portFormat.nIndex)  {
         err = omx->getParameter(
                 node, OMX_IndexParamVideoPortFormat,
diff --git a/media/libstagefright/QCOMXCodec.cpp b/media/libstagefright/QCOMXCodec.cpp
index 0d5768a..fcc57f2 100644
--- a/media/libstagefright/QCOMXCodec.cpp
+++ b/media/libstagefright/QCOMXCodec.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -45,6 +45,7 @@
 #include <OMX_Component.h>
 #include <QOMX_AudioExtensions.h>
 
+#include "include/avc_utils.h"
 
 namespace android {
 
@@ -589,4 +590,21 @@
     }
 }
 
+void QCOMXCodec::checkIfInterlaced(const uint8_t *ptr, const sp<MetaData> &meta)
+{
+    uint16_t spsSize = (((uint16_t)ptr[6]) << 8) + (uint16_t)(ptr[7]);
+    int32_t width = 0, height = 0, isInterlaced = 0;
+    const uint8_t *spsStart = &ptr[8];
+
+    sp<ABuffer> seqParamSet = new ABuffer(spsSize);
+    memcpy(seqParamSet->data(), spsStart, spsSize);
+    FindAVCDimensions(seqParamSet, &width, &height, &isInterlaced);
+
+    ALOGV("height is %d, width is %d, isInterlaced is %d\n", height, width, isInterlaced);
+    if (isInterlaced) {
+        meta->setInt32(kKeyUseArbitraryMode, 1);
+    }
+    return;
+}
+
 }
diff --git a/media/libstagefright/TunnelPlayer.cpp b/media/libstagefright/TunnelPlayer.cpp
index 564f916..3b45db4 100644
--- a/media/libstagefright/TunnelPlayer.cpp
+++ b/media/libstagefright/TunnelPlayer.cpp
@@ -51,7 +51,14 @@
 static const char   mName[] = "TunnelPlayer";
 #define MEM_METADATA_SIZE 64
 #define MEM_PADDING 64
-#define MEM_BUFFER_SIZE (256*1024 - MEM_METADATA_SIZE)
+/*
+ * We need to reserve some space in the
+ * ion buffer (used in HAL) to save the
+ * metadata. so read from the extractor
+ * a somewhat smaller number of bytes.
+ * ideally this number should be bufer_size - sizeof(struct output_metadata_t)
+ */
+#define MEM_BUFFER_SIZE (240*1024 - MEM_METADATA_SIZE)
 #define MEM_BUFFER_COUNT 4
 #define TUNNEL_BUFFER_TIME 1500000
 
@@ -374,7 +381,9 @@
 
 status_t TunnelPlayer::seekTo(int64_t time_us) {
 
-    ALOGV("seekTo: time_us %lld", time_us);
+    ALOGD("seekTo: time_us %lld", time_us);
+
+    Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
 
     //This can happen if the client calls seek
     //without ever calling getPosition
@@ -385,19 +394,26 @@
     if (mPositionTimeRealUs > 0) {
       //check for return conditions only if seektime
       // is set
+      bool postSeekComplete = false;
+
       if (time_us > mPositionTimeRealUs){
-           if((time_us - mPositionTimeRealUs) < TUNNEL_BUFFER_TIME){
+           if ((time_us - mPositionTimeRealUs) < TUNNEL_BUFFER_TIME){
              ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs);
-             mObserver->postAudioSeekComplete();
-             return OK;
+             postSeekComplete = true;
            }
       } else {
-           if((mPositionTimeRealUs - time_us) < TUNNEL_BUFFER_TIME){
+           if ((mPositionTimeRealUs - time_us) < TUNNEL_BUFFER_TIME){
                ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs);
-               mObserver->postAudioSeekComplete();
-               return OK;
+               postSeekComplete = true;
            }
       }
+
+      if (postSeekComplete) {
+          mLock.unlock(); //unlock and post
+          mObserver->postAudioSeekComplete();
+          mLock.lock();
+          return OK;
+      }
     }
 
     mSeeking = true;
@@ -502,6 +518,13 @@
 void TunnelPlayer::reset() {
     ALOGV("Reset");
 
+    Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
+
+    //cancel any pending onpause timeout events
+    //doesnt matter if the event is really present or not
+    mPauseEventPending = false;
+    mQueue.cancelEvent(mPauseEvent->eventID());
+
     mReachedEOS = true;
 
     // make sure Decoder thread has exited
@@ -568,7 +591,8 @@
     uint32_t BufferSizeToUse = MEM_BUFFER_SIZE;
 
     pid_t tid  = gettid();
-    androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+    androidSetThreadPriority(tid, mHasVideo ? ANDROID_PRIORITY_NORMAL :
+                                              ANDROID_PRIORITY_AUDIO);
     prctl(PR_SET_NAME, (unsigned long)"Extractor Thread", 0, 0, 0);
 
     ALOGV("extractorThreadEntry wait for signal \n");
@@ -585,7 +609,7 @@
         const char *mime;
         bool success = format->findCString(kKeyMIMEType, &mime);
     }
-    void* local_buf = malloc(BufferSizeToUse + MEM_PADDING);
+    void* local_buf = malloc(BufferSizeToUse);
     int *lptr = ((int*)local_buf);
     int bytesWritten = 0;
     bool lSeeking = false;
@@ -632,8 +656,7 @@
 
                 if(lSeeking == false && (killExtractorThread == false)){
                     //if we are seeking, ignore write, otherwise write
-                    ALOGV("Fillbuffer before write %d and seek flag %d", mSeeking,
-                          lptr[MEM_BUFFER_SIZE/sizeof(int)]);
+                  ALOGV("Fillbuffer before seek flag %d", mSeeking);
                     int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten);
                     ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking);
                     if(lWrittenBytes > 0) {
@@ -660,6 +683,7 @@
                 }
             }
         }
+
     }
 
     free(local_buf);
@@ -696,11 +720,11 @@
 
     size_t size_done = 0;
     size_t size_remaining = size;
-    int *ldataptr = (int*) data;
     //clear the flag since we dont know whether we are seeking or not, yet
-    ldataptr[(MEM_BUFFER_SIZE/sizeof(int))] = 0;
     ALOGV("fillBuffer: Clearing seek flag in fill buffer");
 
+    bool yield = !mIsFirstBuffer;
+
     while (size_remaining > 0) {
         MediaSource::ReadOptions options;
         {
@@ -738,7 +762,6 @@
                 mInternalSeeking = false;
                 ALOGV("fillBuffer: Setting seek flag in fill buffer");
                 //set the flag since we know that this buffer is the new positions buffer
-                ldataptr[(MEM_BUFFER_SIZE/sizeof(int))] = 1;
             }
         }
         if (mInputBuffer == NULL) {
@@ -787,6 +810,10 @@
 
         size_done += copy;
         size_remaining -= copy;
+
+        if (mHasVideo && yield) {
+            sched_yield();
+        }
     }
     if(mReachedEOS)
         memset((char *)data + size_done, 0x0, size_remaining);
@@ -841,7 +868,9 @@
     return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
 }
 
+//lock has been taken in reset() to sync with onpausetimeout
 void TunnelPlayer::requestAndWaitForExtractorThreadExit() {
+    ALOGV("requestAndWaitForExtractorThreadExit -1");
 
     if (!extractorThreadAlive)
         return;
@@ -856,7 +885,9 @@
     ALOGV("requestAndWaitForExtractorThreadExit +1");
     pthread_cond_signal(&extractor_cv);
     ALOGV("requestAndWaitForExtractorThreadExit +2");
+    mLock.unlock();
     pthread_join(extractorThread,NULL);
+    mLock.lock();
     ALOGV("requestAndWaitForExtractorThreadExit +3");
 
     ALOGV("Extractor thread killed");
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index a141752..fbe98f1 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -41,7 +41,7 @@
 
 // Determine video dimensions from the sequence parameterset.
 void FindAVCDimensions(
-        const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height) {
+        const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height, int32_t *isInterlaced) {
     ABitReader br(seqParamSet->data() + 1, seqParamSet->size() - 1);
 
     unsigned profile_idc = br.getBits(8);
@@ -128,6 +128,10 @@
             (frame_crop_left_offset + frame_crop_right_offset) * cropUnitX;
         *height -=
             (frame_crop_top_offset + frame_crop_bottom_offset) * cropUnitY;
+
+        if (isInterlaced != NULL) {
+            *isInterlaced = !frame_mbs_only_flag;
+        }
     }
 }
 
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index ee885a5..8bda7f8 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -309,6 +309,9 @@
     void logLate(int64_t ts, int64_t clock, int64_t delta);
     void logOnTime(int64_t ts, int64_t clock, int64_t delta);
     int64_t getTimeOfDayUs();
+#ifdef QCOM_HARDWARE
+    void checkTunnelExceptions();
+#endif
     bool mStatistics;
 
     struct TrackStat {
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index e418822..d385bc1 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -37,7 +37,7 @@
 };
 
 void FindAVCDimensions(
-        const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height);
+        const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height, int32_t *isInterlaced = NULL);
 
 unsigned parseUE(ABitReader *br);