Squashed commit of audio changes from CodeAurora

libstagefright: Add QC specific media format

- Add QC specific media extensions
- Add QC specific media definitions

Change-Id: I7dca90be3b977701d9537f5e017117790a030f1f

audio: Compile AudioParameter as shared library

- AudioParameter as shared lib is needed by BT
  support in WFD source.

Change-Id: I464b428ace0cbb57ce6bf7bf3b57d51a7d56f032

libstagefright: Send flush on both i/p and o/p ports together

- ANR occurs in music due to race condition in OMX component if
  flush is issued separately for i/p and o/p ports as DSP only
  handles simultaneous flush on i/p and o/p ports.

Change-Id: I5b16cd5a9b57c857dc8bed489d2663b8f54769e3

libstagefright: Enable extended A\V format

- Add new files to support extended A\V format

Change-Id: I1e61d78d35b868d55fd8e99f95de8cab9c465db4

libstagefright: Framework to plug-in propritory parser

- Extend the current framework to plug-in propritory
  parser

Change-Id: Ia586a3048420ddf1515261f20035589447263b7b

audio: add support for QCOM audio formats

- Add support for EVRC, QCELP, and WMA formats.

Change-Id: Iaf80f982fc8b08617132dbd7d524a1748866745c

frameworks/av: Support Tunnel Playback

- Implement DirectTrack and DirectTrackClient
- DirectTrack exposes API to client so it can create a direct
  output.
- DirectTrackClient allows notifications to be sent to the
  client from DirectTrack
- DirectTrack is being used for Tunnel Audio

Change-Id: I2fbb18a781d8e44b8d65da9a357f6e39375f063a

frameworks/av: Support LPA Playback

Add support to enable Playback in LPA mode

Change-Id: I1b8ac4904f4735017d62f3757ede7bbb56e62fd3

audio: Send correct channel mask in voice call recording.

-Using popCount function to get channel count gives incorrect value on
voice call recording.
-Only STEREO and MONO bits to be considered to count
channels on input

Change-Id: I04c2c802422e868bdba0538ff8623dbf9eb659fe

libstagefright: Thumbnail mode initial commit

- use sync frame decoding mode when kClientNeedsFrameBuffer
  is set for hardware decoders
- hardware decoder will only expect I frames, OMXCodec will
  set EOS on first ETB to stop more frames from being pulled
- skip EOS check on FTB so that the first frame will be
  handled

Change-Id: I0e8974e088fdcc468e27764861c128cfe291499f

audio: Add support for QCOM's VOIP solution

Change-Id: I1150f536fa204b535ca4019fdaa84f33f4695d93

audio: define QCOM audio parameters

- Define QCOM audio paramters for FM, VOIP,
  fluence, SSR, and A2DP

Change-Id: I29d02e37685846f6d4f00dee02e2726b015eaae7

Add ifdefs for QCOM enhanced features

Change-Id: Ic8e5fe6ecc058466ced71030883b1af6c2bc055c
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 54666fb..69361fa 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -11,6 +11,17 @@
 
 include $(CLEAR_VARS)
 
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+LOCAL_SRC_FILES:= AudioParameter.cpp
+LOCAL_MODULE:= libaudioparameter
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libutils
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+endif
+
 LOCAL_SRC_FILES:= \
     AudioTrack.cpp \
     IAudioFlinger.cpp \
@@ -51,6 +62,16 @@
     SoundPool.cpp \
     SoundPoolThread.cpp
 
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+LOCAL_SRC_FILES += \
+    IDirectTrack.cpp \
+    IDirectTrackClient.cpp
+
+ifeq ($(TARGET_QCOM_AUDIO_VARIANT),caf)
+LOCAL_CFLAGS += -DQCOM_ENHANCED_AUDIO
+endif
+endif
+
 LOCAL_SHARED_LIBRARIES := \
 	libui libcutils libutils libbinder libsonivox libicuuc libexpat \
         libcamera_client libstagefright_foundation \
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index e3fea77..fbb34f4 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2006-2011 The Android Open Source Project
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +33,13 @@
 const char * const AudioParameter::keyFrameCount = AUDIO_PARAMETER_STREAM_FRAME_COUNT;
 const char * const AudioParameter::keyInputSource = AUDIO_PARAMETER_STREAM_INPUT_SOURCE;
 const char * const AudioParameter::keyScreenState = AUDIO_PARAMETER_KEY_SCREEN_STATE;
+#ifdef QCOM_HARDWARE
+const char * const AudioParameter::keyHandleFm = AUDIO_PARAMETER_KEY_HANDLE_FM;
+const char * const AudioParameter::keyVoipCheck = AUDIO_PARAMETER_KEY_VOIP_CHECK;
+const char * const AudioParameter::keyFluenceType = AUDIO_PARAMETER_KEY_FLUENCE_TYPE;
+const char * const AudioParameter::keySSR = AUDIO_PARAMETER_KEY_SSR;
+const char * const AudioParameter::keyHandleA2dpDevice = AUDIO_PARAMETER_KEY_HANDLE_A2DP_DEVICE;
+#endif
 
 AudioParameter::AudioParameter(const String8& keyValuePairs)
 {
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 8ea6306..ce03754 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -1,6 +1,7 @@
 /*
 **
 ** Copyright 2008, The Android Open Source Project
+** Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
@@ -156,7 +157,11 @@
         return BAD_VALUE;
     }
 
+#ifdef QCOM_HARDWARE
+    int channelCount = popcount((channelMask) & (AUDIO_CHANNEL_IN_STEREO | AUDIO_CHANNEL_IN_MONO | AUDIO_CHANNEL_IN_5POINT1));
+#else
     int channelCount = popcount(channelMask);
+#endif
 
     if (sessionId == 0 ) {
         mSessionId = AudioSystem::newAudioSessionId();
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index fa52fa9..a2172c9 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -2,6 +2,10 @@
 **
 ** Copyright 2007, The Android Open Source Project
 **
+** Copyright (c) 2012, 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
@@ -96,6 +100,10 @@
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT)
+#ifdef QCOM_HARDWARE
+      ,mAudioFlinger(NULL),
+      mObserver(NULL)
+#endif
 {
 }
 
@@ -114,6 +122,10 @@
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT)
+#ifdef QCOM_HARDWARE
+      ,mAudioFlinger(NULL),
+      mObserver(NULL)
+#endif
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
@@ -135,6 +147,10 @@
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT)
+#ifdef QCOM_HARDWARE
+      ,mAudioFlinger(NULL),
+      mObserver(NULL)
+#endif
 {
     mStatus = set((audio_stream_type_t)streamType, sampleRate, (audio_format_t)format,
             (audio_channel_mask_t) channelMask,
@@ -157,6 +173,10 @@
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT)
+#ifdef QCOM_HARDWARE
+      ,mAudioFlinger(NULL),
+      mObserver(NULL)
+#endif
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             0 /*frameCount*/, flags, cbf, user, notificationFrames,
@@ -177,9 +197,22 @@
             mAudioTrackThread->requestExitAndWait();
             mAudioTrackThread.clear();
         }
+#ifdef QCOM_HARDWARE
+        if (mAudioTrack != 0) {
+            mAudioTrack.clear();
+            AudioSystem::releaseAudioSessionId(mSessionId);
+        }
+
+        if (mDirectTrack != 0) {
+            mDirectTrack.clear();
+        }
+#else
         mAudioTrack.clear();
+#endif
         IPCThreadState::self()->flushCommands();
+#ifndef QCOM_HARDWARE
         AudioSystem::releaseAudioSessionId(mSessionId);
+#endif
     }
 }
 
@@ -252,12 +285,24 @@
         flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
     }
 
+#ifdef QCOM_ENHANCED_AUDIO
+    if ((streamType == AUDIO_STREAM_VOICE_CALL)
+         && (channelMask == AUDIO_CHANNEL_OUT_MONO)
+         && ((sampleRate == 8000 || sampleRate == 16000)))
+    {
+        ALOGD("Turn on Direct Output for VOIP RX");
+        flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_VOIP_RX|AUDIO_OUTPUT_FLAG_DIRECT);
+    }
+#endif
+
     if (!audio_is_output_channel(channelMask)) {
         ALOGE("Invalid channel mask %#x", channelMask);
         return BAD_VALUE;
     }
     uint32_t channelCount = popcount(channelMask);
 
+    ALOGV("AudioTrack getOutput streamType %d, sampleRate %d, format %d, channelMask %d, flags %x",
+           streamType, sampleRate, format, channelMask, flags);
     audio_io_handle_t output = AudioSystem::getOutput(
                                     streamType,
                                     sampleRate, format, channelMask,
@@ -278,46 +323,86 @@
     mFlags = flags;
     mCbf = cbf;
 
-    if (cbf != NULL) {
-        mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
-        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
-    }
-
-    // create the IAudioTrack
-    status_t status = createTrack_l(streamType,
-                                  sampleRate,
-                                  format,
-                                  channelMask,
-                                  frameCount,
-                                  flags,
-                                  sharedBuffer,
-                                  output);
-
-    if (status != NO_ERROR) {
-        if (mAudioTrackThread != 0) {
-            mAudioTrackThread->requestExit();
-            mAudioTrackThread.clear();
+#ifdef QCOM_HARDWARE
+    if (flags & AUDIO_OUTPUT_FLAG_LPA || flags & AUDIO_OUTPUT_FLAG_TUNNEL) {
+        ALOGV("Creating Direct Track");
+        const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+        if (audioFlinger == 0) {
+            ALOGE("Could not get audioflinger");
+            return NO_INIT;
         }
-        return status;
+        mAudioFlinger = audioFlinger;
+        status_t status = NO_ERROR;
+        mAudioDirectOutput = output;
+        mDirectTrack = audioFlinger->createDirectTrack( getpid(),
+                                                        sampleRate,
+                                                        channelMask,
+                                                        mAudioDirectOutput,
+                                                        &mSessionId,
+                                                        this,
+                                                        streamType,
+                                                        &status);
+        if(status != NO_ERROR) {
+            ALOGE("createDirectTrack returned with status %d", status);
+            return status;
+        }
+        mAudioTrack = NULL;
+        mSharedBuffer = NULL;
     }
+    else {
+#endif
+        if (cbf != NULL) {
+            mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
+            mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
+        }
+        // create the IAudioTrack
+        status_t status = createTrack_l(streamType,
+                                      sampleRate,
+                                      format,
+                                      channelMask,
+                                      frameCount,
+                                      flags,
+                                      sharedBuffer,
+                                      output);
 
+        if (status != NO_ERROR) {
+            if (mAudioTrackThread != 0) {
+                mAudioTrackThread->requestExit();
+                mAudioTrackThread.clear();
+            }
+            return status;
+        }
+#ifdef QCOM_HARDWARE
+        AudioSystem::acquireAudioSessionId(mSessionId);
+        mAudioDirectOutput = -1;
+        mDirectTrack = NULL;
+        mSharedBuffer = sharedBuffer;
+    }
+    mUserData = user;
+#endif
     mStatus = NO_ERROR;
 
     mStreamType = streamType;
     mFormat = format;
     mChannelMask = channelMask;
     mChannelCount = channelCount;
-    mSharedBuffer = sharedBuffer;
+
     mMuted = false;
     mActive = false;
-    mUserData = user;
+
     mLoopCount = 0;
     mMarkerPosition = 0;
     mMarkerReached = false;
     mNewPosition = 0;
     mUpdatePeriod = 0;
     mFlushed = false;
+
+#ifndef QCOM_HARDWARE
+    mSharedBuffer = sharedBuffer;
+    mUserData = user;
     AudioSystem::acquireAudioSessionId(mSessionId);
+#endif
+
     mRestoreStatus = NO_ERROR;
     return NO_ERROR;
 }
@@ -331,6 +416,11 @@
 
 uint32_t AudioTrack::latency() const
 {
+#ifdef QCOM_HARDWARE
+    if(mAudioDirectOutput != -1) {
+        return mAudioFlinger->latency(mAudioDirectOutput);
+    }
+#endif
     return mLatency;
 }
 
@@ -351,6 +441,11 @@
 
 uint32_t AudioTrack::frameCount() const
 {
+#ifdef QCOM_HARDWARE
+    if(mAudioDirectOutput != -1) {
+        return mAudioFlinger->frameCount(mAudioDirectOutput);
+    }
+#endif
     return mCblk->frameCount;
 }
 
@@ -372,6 +467,16 @@
 
 void AudioTrack::start()
 {
+#ifdef QCOM_HARDWARE
+    if (mDirectTrack != NULL) {
+        if(mActive == 0) {
+            mActive = 1;
+            mDirectTrack->start();
+        }
+        return;
+    }
+#endif
+
     sp<AudioTrackThread> t = mAudioTrackThread;
 
     ALOGV("start %p", this);
@@ -436,26 +541,35 @@
 
     AutoMutex lock(mLock);
     if (mActive) {
-        mActive = false;
-        mCblk->cv.signal();
-        mAudioTrack->stop();
-        // Cancel loops (If we are in the middle of a loop, playback
-        // would not stop until loopCount reaches 0).
-        setLoop_l(0, 0, 0);
-        // the playback head position will reset to 0, so if a marker is set, we need
-        // to activate it again
-        mMarkerReached = false;
-        // Force flush if a shared buffer is used otherwise audioflinger
-        // will not stop before end of buffer is reached.
-        if (mSharedBuffer != 0) {
-            flush_l();
+#ifdef QCOM_HARDWARE
+        if(mDirectTrack != NULL) {
+            mActive = false;
+            mDirectTrack->stop();
+        } else if (mAudioTrack != NULL) {
+#endif
+            mActive = false;
+            mCblk->cv.signal();
+            mAudioTrack->stop();
+            // Cancel loops (If we are in the middle of a loop, playback
+            // would not stop until loopCount reaches 0).
+            setLoop_l(0, 0, 0);
+            // the playback head position will reset to 0, so if a marker is set, we need
+            // to activate it again
+            mMarkerReached = false;
+            // Force flush if a shared buffer is used otherwise audioflinger
+            // will not stop before end of buffer is reached.
+            if (mSharedBuffer != 0) {
+                flush_l();
+            }
+            if (t != 0) {
+                t->pause();
+            } else {
+                setpriority(PRIO_PROCESS, 0, mPreviousPriority);
+                set_sched_policy(0, mPreviousSchedulingGroup);
+            }
+#ifdef QCOM_HARDWARE
         }
-        if (t != 0) {
-            t->pause();
-        } else {
-            setpriority(PRIO_PROCESS, 0, mPreviousPriority);
-            set_sched_policy(0, mPreviousSchedulingGroup);
-        }
+#endif
     }
 
 }
@@ -469,7 +583,12 @@
 void AudioTrack::flush()
 {
     AutoMutex lock(mLock);
-    flush_l();
+#ifdef QCOM_HARDWARE
+    if(mDirectTrack != NULL) {
+        mDirectTrack->flush();
+    } else
+#endif
+        flush_l();
 }
 
 // must be called with mLock held
@@ -497,14 +616,28 @@
     AutoMutex lock(mLock);
     if (mActive) {
         mActive = false;
-        mCblk->cv.signal();
-        mAudioTrack->pause();
+#ifdef QCOM_HARDWARE
+        if(mDirectTrack != NULL) {
+            ALOGV("mDirectTrack pause");
+            mDirectTrack->pause();
+        } else {
+#endif
+            mCblk->cv.signal();
+            mAudioTrack->pause();
+#ifdef QCOM_HARDWARE
+        }
+#endif
     }
 }
 
 void AudioTrack::mute(bool e)
 {
-    mAudioTrack->mute(e);
+#ifdef QCOM_HARDWARE
+    if(mDirectTrack != NULL) {
+        mDirectTrack->mute(e);
+    } else
+#endif
+        mAudioTrack->mute(e);
     mMuted = e;
 }
 
@@ -522,8 +655,13 @@
     AutoMutex lock(mLock);
     mVolume[LEFT] = left;
     mVolume[RIGHT] = right;
-
-    mCblk->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
+#ifdef QCOM_HARDWARE
+    if(mDirectTrack != NULL) {
+        ALOGV("mDirectTrack->setVolume(left = %f , right = %f)", left,right);
+        mDirectTrack->setVolume(left, right);
+    } else
+#endif
+        mCblk->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
 
     return NO_ERROR;
 }
@@ -540,6 +678,11 @@
 
 status_t AudioTrack::setAuxEffectSendLevel(float level)
 {
+#ifdef QCOM_HARDWARE
+    if (mDirectTrack != NULL) {
+        return NO_ERROR;
+    }
+#endif
     ALOGV("setAuxEffectSendLevel(%f)", level);
     if (level < 0.0f || level > 1.0f) {
         return BAD_VALUE;
@@ -586,6 +729,11 @@
     }
 
     AutoMutex lock(mLock);
+#ifdef QCOM_HARDWARE
+    if(mAudioDirectOutput != -1) {
+        return mAudioFlinger->sampleRate(mAudioDirectOutput);
+    }
+#endif
     return mCblk->sampleRate;
 }
 
@@ -1076,7 +1224,12 @@
 
 ssize_t AudioTrack::write(const void* buffer, size_t userSize)
 {
-
+#ifdef QCOM_HARDWARE
+    if (mDirectTrack != NULL) {
+        mDirectTrack->write(buffer,userSize);
+        return userSize;
+    }
+#endif
     if (mSharedBuffer != 0) return INVALID_OPERATION;
     if (mIsTimed) return INVALID_OPERATION;
 
@@ -1456,6 +1609,23 @@
     return NO_ERROR;
 }
 
+#ifdef QCOM_HARDWARE
+void AudioTrack::notify(int msg) {
+    if (msg == EVENT_UNDERRUN) {
+        ALOGV("Posting event underrun to Audio Sink.");
+        mCbf(EVENT_UNDERRUN, mUserData, 0);
+    }
+}
+
+status_t AudioTrack::getTimeStamp(uint64_t *tstamp) {
+    if (mDirectTrack != NULL) {
+        *tstamp = mDirectTrack->getTimeStamp();
+        ALOGV("Timestamp %lld ", *tstamp);
+    }
+    return NO_ERROR;
+}
+#endif
+
 // =========================================================================
 
 AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index ce8ffc4..cc6a75c 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -1,6 +1,9 @@
 /*
 **
 ** Copyright 2007, The Android Open Source Project
+** Copyright (c) 2012, 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.
@@ -73,6 +76,9 @@
     LOAD_HW_MODULE,
     GET_PRIMARY_OUTPUT_SAMPLING_RATE,
     GET_PRIMARY_OUTPUT_FRAME_COUNT,
+#ifdef QCOM_HARDWARE
+    CREATE_DIRECT_TRACK
+#endif
 };
 
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -132,6 +138,49 @@
         return track;
     }
 
+#ifdef QCOM_HARDWARE
+    virtual sp<IDirectTrack> createDirectTrack(
+                                pid_t pid,
+                                uint32_t sampleRate,
+                                audio_channel_mask_t channelMask,
+                                audio_io_handle_t output,
+                                int *sessionId,
+                                IDirectTrackClient* client,
+                                audio_stream_type_t streamType,
+                                status_t *status)
+    {
+        Parcel data, reply;
+        sp<IDirectTrack> track;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        data.writeInt32(sampleRate);
+        data.writeInt32(channelMask);
+        data.writeInt32((int32_t)output);
+        int lSessionId = 0;
+        if (sessionId != NULL) {
+            lSessionId = *sessionId;
+        }
+        data.writeInt32(lSessionId);
+        data.write(client, sizeof(IDirectTrackClient));
+        data.writeInt32((int32_t) streamType);
+        status_t lStatus = remote()->transact(CREATE_DIRECT_TRACK, data, &reply);
+        if (lStatus != NO_ERROR) {
+            ALOGE("createDirectTrack error: %s", strerror(-lStatus));
+        } else {
+            lSessionId = reply.readInt32();
+            if (sessionId != NULL) {
+                *sessionId = lSessionId;
+            }
+            lStatus = reply.readInt32();
+            track = interface_cast<IDirectTrack>(reply.readStrongBinder());
+        }
+        if (status) {
+            *status = lStatus;
+        }
+        return track;
+    }
+#endif
+
     virtual sp<IAudioRecord> openRecord(
                                 pid_t pid,
                                 audio_io_handle_t input,
@@ -738,6 +787,26 @@
             reply->writeStrongBinder(track->asBinder());
             return NO_ERROR;
         } break;
+#ifdef QCOM_HARDWARE
+        case CREATE_DIRECT_TRACK: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            pid_t pid = data.readInt32();
+            uint32_t sampleRate = data.readInt32();
+            audio_channel_mask_t channelMask = data.readInt32();
+            audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
+            int sessionId = data.readInt32();
+            IDirectTrackClient* client;
+            data.read(client,sizeof(IDirectTrackClient));
+            int streamType = data.readInt32();
+            status_t status;
+            sp<IDirectTrack> track = createDirectTrack(pid,
+                    sampleRate, channelMask, output, &sessionId, client,(audio_stream_type_t) streamType, &status);
+            reply->writeInt32(sessionId);
+            reply->writeInt32(status);
+            reply->writeStrongBinder(track->asBinder());
+            return NO_ERROR;
+        } break;
+#endif
         case OPEN_RECORD: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             pid_t pid = data.readInt32();
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index 4178b29..e289703 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -1,4 +1,8 @@
 /*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
  * Copyright (C) 2009 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -49,7 +53,11 @@
             uint32_t stream = *(const uint32_t *)param2;
             ALOGV("ioConfigChanged stream %d", stream);
             data.writeInt32(stream);
-        } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) {
+        } else if (event != AudioSystem::OUTPUT_CLOSED &&
+#ifdef QCOM_HARDWARE
+                        event != AudioSystem::EFFECT_CONFIG_CHANGED &&
+#endif
+                        event != AudioSystem::INPUT_CLOSED) {
             const AudioSystem::OutputDescriptor *desc = (const AudioSystem::OutputDescriptor *)param2;
             data.writeInt32(desc->samplingRate);
             data.writeInt32(desc->format);
diff --git a/media/libmedia/IDirectTrack.cpp b/media/libmedia/IDirectTrack.cpp
new file mode 100644
index 0000000..480761f
--- /dev/null
+++ b/media/libmedia/IDirectTrack.cpp
@@ -0,0 +1,178 @@
+/*
+** Copyright (c) 2012, The Linux Foundation. All rights reserved.
+** Not a Contribution, Apache license notifications and license are retained
+** for attribution purposes only.
+**
+** Copyright 2007, The Android Open Source Project
+**
+** 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_TAG "IDirectTrack"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <media/IDirectTrack.h>
+
+namespace android {
+
+enum {
+    START = IBinder::FIRST_CALL_TRANSACTION,
+    STOP,
+    FLUSH,
+    MUTE,
+    PAUSE,
+    SET_VOLUME,
+    WRITE,
+    GET_TIMESTAMP
+};
+
+class BpDirectTrack : public BpInterface<IDirectTrack>
+{
+public:
+    BpDirectTrack(const sp<IBinder>& impl)
+        : BpInterface<IDirectTrack>(impl)
+    {
+    }
+
+    virtual status_t start()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+        status_t status = remote()->transact(START, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+        } else {
+            ALOGW("start() error: %s", strerror(-status));
+        }
+        return status;
+    }
+
+    virtual void stop()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+        remote()->transact(STOP, data, &reply);
+    }
+
+    virtual void flush()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+        remote()->transact(FLUSH, data, &reply);
+    }
+
+    virtual void mute(bool e)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+        data.writeInt32(e);
+        remote()->transact(MUTE, data, &reply);
+    }
+
+    virtual void pause()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+        remote()->transact(PAUSE, data, &reply);
+    }
+
+    virtual void setVolume(float left, float right)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+        remote()->transact(SET_VOLUME, data, &reply);
+    }
+
+    virtual ssize_t write(const void* buffer, size_t bytes)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+        ssize_t bytesWritten = remote()->transact(WRITE, data, &reply);
+        return bytesWritten;
+    }
+
+    virtual int64_t getTimeStamp() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+        int64_t tstamp = remote()->transact(GET_TIMESTAMP, data, &reply);
+        return tstamp;
+    }
+};
+
+IMPLEMENT_META_INTERFACE(DirectTrack, "android.media.IDirectTrack");
+
+// ----------------------------------------------------------------------
+
+status_t BnDirectTrack::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case START: {
+            CHECK_INTERFACE(IDirectTrack, data, reply);
+            reply->writeInt32(start());
+            return NO_ERROR;
+        } break;
+        case STOP: {
+            CHECK_INTERFACE(IDirectTrack, data, reply);
+            stop();
+            return NO_ERROR;
+        } break;
+        case FLUSH: {
+            CHECK_INTERFACE(IDirectTrack, data, reply);
+            flush();
+            return NO_ERROR;
+        } break;
+        case MUTE: {
+            CHECK_INTERFACE(IDirectTrack, data, reply);
+            mute( data.readInt32() );
+            return NO_ERROR;
+        } break;
+        case PAUSE: {
+            CHECK_INTERFACE(IDirectTrack, data, reply);
+            pause();
+            return NO_ERROR;
+        }
+        case SET_VOLUME: {
+            CHECK_INTERFACE(IDirectTrack, data, reply);
+            float left = 1.0;
+            float right = 1.0;
+            setVolume(left, right);
+            return NO_ERROR;
+        }
+        case WRITE: {
+            CHECK_INTERFACE(IDirectTrack, data, reply);
+            const void *buffer = (void *)data.readInt32();
+            size_t bytes = data.readInt32();
+            ssize_t bytesWritten = write(buffer, bytes);
+            reply->writeInt32(bytesWritten);
+            return NO_ERROR;
+        }
+        case GET_TIMESTAMP: {
+            CHECK_INTERFACE(IDirectTrack, data, reply);
+            int64_t time = getTimeStamp();
+            reply->writeInt32(time);
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/IDirectTrackClient.cpp b/media/libmedia/IDirectTrackClient.cpp
new file mode 100644
index 0000000..86a47ec
--- /dev/null
+++ b/media/libmedia/IDirectTrackClient.cpp
@@ -0,0 +1,69 @@
+/*
+** Copyright (c) 2012, The Linux Foundation. All rights reserved.
+** Not a Contribution, Apache license notifications and license are retained
+** for attribution purposes only.
+**
+** Copyright 2007, The Android Open Source Project
+**
+** 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.
+*/
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+#include <media/IDirectTrackClient.h>
+
+namespace android {
+
+enum {
+    NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpDirectTrackClient: public BpInterface<IDirectTrackClient>
+{
+public:
+    BpDirectTrackClient(const sp<IBinder>& impl)
+        : BpInterface<IDirectTrackClient>(impl)
+    {
+    }
+
+    virtual void notify(int msg)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDirectTrackClient::getInterfaceDescriptor());
+        data.writeInt32(msg);
+        remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(DirectTrackClient, "android.media.IDirectTrackClient");
+
+// ----------------------------------------------------------------------
+
+status_t BnDirectTrackClient::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case NOTIFY: {
+            CHECK_INTERFACE(IDirectTrackClient, data, reply);
+            int msg = data.readInt32();
+            notify(msg);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index f69dbea..fa536a6 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -1,6 +1,7 @@
 /*
 **
 ** Copyright 2010, The Android Open Source Project
+** Copyright (c) 2010 - 2012, The Linux Foundation. All rights reserved.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
@@ -45,7 +46,10 @@
     {"amrwb",  AUDIO_ENCODER_AMR_WB},
     {"aac",    AUDIO_ENCODER_AAC},
     {"heaac",  AUDIO_ENCODER_HE_AAC},
-    {"aaceld", AUDIO_ENCODER_AAC_ELD}
+    {"aaceld", AUDIO_ENCODER_AAC_ELD},
+#ifdef QCOM_HARDWARE
+    {"lpcm",  AUDIO_ENCODER_LPCM},
+#endif
 };
 
 const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
@@ -804,6 +808,10 @@
 MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
 {
     profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
+#ifdef QCOM_HARDWARE
+    profiles->mAudioEncoders.add(createDefaultAacEncoderCap());
+    profiles->mAudioEncoders.add(createDefaultLpcmEncoderCap());
+#endif
 }
 
 /*static*/ void
@@ -838,6 +846,22 @@
         AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
 }
 
+#ifdef QCOM_HARDWARE
+/*static*/ MediaProfiles::AudioEncoderCap*
+MediaProfiles::createDefaultAacEncoderCap()
+{
+    return new MediaProfiles::AudioEncoderCap(
+        AUDIO_ENCODER_AAC, 64000, 156000, 8000, 48000, 1, 2);
+}
+
+/*static*/ MediaProfiles::AudioEncoderCap*
+MediaProfiles::createDefaultLpcmEncoderCap()
+{
+    return new MediaProfiles::AudioEncoderCap(
+        AUDIO_ENCODER_LPCM, 768000, 4608000, 48000, 48000, 1, 6);
+}
+#endif
+
 /*static*/ void
 MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
 {
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 5b5ed71..a583d48 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -47,7 +47,12 @@
     $(TOP)/frameworks/av/media/libstagefright/rtsp                  \
     $(TOP)/frameworks/av/media/libstagefright/wifi-display          \
     $(TOP)/frameworks/native/include/media/openmax                  \
-    $(TOP)/external/tremolo/Tremolo                                 \
+    $(TOP)/external/tremolo/Tremolo
+
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+LOCAL_C_INCLUDES += \
+    $(TOP)/hardware/qcom/media/mm-core/inc
+endif
 
 LOCAL_MODULE:= libmediaplayerservice
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9bedff1..414c262 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1,5 +1,9 @@
 /*
 **
+** Copyright (c) 2012, The Linux Foundation. All rights reserved.
+** Not a Contribution, Apache license notifications and license are retained
+** for attribution purposes only.
+**
 ** Copyright 2008, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -74,6 +78,7 @@
 #include "Crypto.h"
 #include "HDCP.h"
 #include "RemoteDisplay.h"
+#define DEFAULT_SAMPLE_RATE 44100
 
 namespace {
 using android::media::Metadata;
@@ -1363,6 +1368,22 @@
     return mTrack->getPosition(position);
 }
 
+#ifdef QCOM_HARDWARE
+ssize_t MediaPlayerService::AudioOutput::sampleRate() const
+{
+    if (mTrack == 0) return NO_INIT;
+    return DEFAULT_SAMPLE_RATE;
+}
+
+status_t MediaPlayerService::AudioOutput::getTimeStamp(uint64_t *tstamp)
+{
+    if (tstamp == 0) return BAD_VALUE;
+    if (mTrack == 0) return NO_INIT;
+    mTrack->getTimeStamp(tstamp);
+    return NO_ERROR;
+}
+#endif
+
 status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
 {
     if (mTrack == 0) return NO_INIT;
@@ -1379,6 +1400,65 @@
     mCallback = cb;
     mCallbackCookie = cookie;
 
+#ifdef QCOM_HARDWARE
+    if (flags & AUDIO_OUTPUT_FLAG_LPA || flags & AUDIO_OUTPUT_FLAG_TUNNEL) {
+        ALOGV("AudioOutput open: with flags %x",flags);
+        channelMask = audio_channel_out_mask_from_count(channelCount);
+        if (0 == channelMask) {
+            ALOGE("open() error, can't derive mask for %d audio channels", channelCount);
+            return NO_INIT;
+        }
+        AudioTrack *audioTrack = NULL;
+        CallbackData *newcbd = NULL;
+        if (mCallback != NULL) {
+            newcbd = new CallbackData(this);
+            audioTrack = new AudioTrack(
+                             mStreamType,
+                             sampleRate,
+                             format,
+                             channelMask,
+                             0,
+                             flags,
+                             CallbackWrapper,
+                             newcbd,
+                             0,
+                             mSessionId);
+            if ((audioTrack == 0) || (audioTrack->initCheck() != NO_ERROR)) {
+                ALOGE("Unable to create audio track");
+                delete audioTrack;
+                delete newcbd;
+                return NO_INIT;
+            }
+        } else {
+            ALOGE("no callback supplied");
+            return NO_INIT;
+        }
+
+        if (mRecycledTrack) {
+            //usleep(500000);
+            // if we're not going to reuse the track, unblock and flush it
+            if (mCallbackData != NULL) {
+                mCallbackData->setOutput(NULL);
+                mCallbackData->endTrackSwitch();
+            }
+            mRecycledTrack->flush();
+            delete mRecycledTrack;
+            mRecycledTrack = NULL;
+            delete mCallbackData;
+            mCallbackData = NULL;
+            close();
+        }
+
+        ALOGV("setVolume");
+        mCallbackData = newcbd;
+        audioTrack->setVolume(mLeftVolume, mRightVolume);
+        mSampleRateHz = sampleRate;
+        mFlags = flags;
+        mTrack = audioTrack;
+        return NO_ERROR;
+    }
+#endif
+
     // Check argument "bufferCount" against the mininum buffer count
     if (bufferCount < mMinBufferCount) {
         ALOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
@@ -1551,7 +1631,7 @@
 
 ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
 {
-    LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
+    //LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
 
     //ALOGV("write(%p, %u)", buffer, size);
     if (mTrack) {
@@ -1637,35 +1717,56 @@
 void MediaPlayerService::AudioOutput::CallbackWrapper(
         int event, void *cookie, void *info) {
     //ALOGV("callbackwrapper");
-    if (event != AudioTrack::EVENT_MORE_DATA) {
-        return;
-    }
-
-    CallbackData *data = (CallbackData*)cookie;
-    data->lock();
-    AudioOutput *me = data->getOutput();
-    AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
-    if (me == NULL) {
-        // no output set, likely because the track was scheduled to be reused
-        // by another player, but the format turned out to be incompatible.
+#ifdef QCOM_HARDWARE
+    if (event == AudioTrack::EVENT_UNDERRUN) {
+        ALOGW("Event underrun");
+        CallbackData *data = (CallbackData*)cookie;
+        data->lock();
+        AudioOutput *me = data->getOutput();
+        if (me == NULL) {
+            // no output set, likely because the track was scheduled to be reused
+            // by another player, but the format turned out to be incompatible.
+            data->unlock();
+            return;
+        }
+        ALOGD("Callback!!!");
+        (*me->mCallback)(
+            me, NULL, (size_t)AudioTrack::EVENT_UNDERRUN, me->mCallbackCookie);
         data->unlock();
-        buffer->size = 0;
         return;
     }
+#endif
+    if (event == AudioTrack::EVENT_MORE_DATA) {
+        CallbackData *data = (CallbackData*)cookie;
+        data->lock();
+        AudioOutput *me = data->getOutput();
+        AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+        if (me == NULL) {
+            // no output set, likely because the track was scheduled to be reused
+            // by another player, but the format turned out to be incompatible.
+            data->unlock();
+            buffer->size = 0;
+            return;
+        }
 
-    size_t actualSize = (*me->mCallback)(
-            me, buffer->raw, buffer->size, me->mCallbackCookie);
+        size_t actualSize = (*me->mCallback)(
+                me, buffer->raw, buffer->size, me->mCallbackCookie);
 
-    if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) {
-        // We've reached EOS but the audio track is not stopped yet,
-        // keep playing silence.
+        if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) {
+            // We've reached EOS but the audio track is not stopped yet,
+            // keep playing silence.
 
-        memset(buffer->raw, 0, buffer->size);
-        actualSize = buffer->size;
+            memset(buffer->raw, 0, buffer->size);
+            actualSize = buffer->size;
+        }
+
+        buffer->size = actualSize;
+        data->unlock();
     }
 
-    buffer->size = actualSize;
-    data->unlock();
+    return;
+
+
 }
 
 int MediaPlayerService::AudioOutput::getSessionId() const
@@ -1700,6 +1801,13 @@
     return NO_ERROR;
 }
 
+#ifdef QCOM_HARDWARE
+ssize_t MediaPlayerService::AudioCache::sampleRate() const
+{
+    return mSampleRate;
+}
+#endif
+
 status_t MediaPlayerService::AudioCache::getFramesWritten(uint32_t *written) const
 {
     if (written == 0) return BAD_VALUE;
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index fd648df..54df9d2 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -114,6 +114,10 @@
                 void            setNextOutput(const sp<AudioOutput>& nextOutput);
                 void            switchToNextOutput();
         virtual bool            needsTrailingPadding() { return mNextOutput == NULL; }
+#ifdef QCOM_HARDWARE
+        virtual ssize_t         sampleRate() const;
+        virtual status_t        getTimeStamp(uint64_t *tstamp);
+#endif
 
     private:
         static void             setMinBufferCount();
@@ -205,8 +209,10 @@
         virtual void            close() {}
                 void            setAudioStreamType(audio_stream_type_t streamType) {}
                 void            setVolume(float left, float right) {}
-        virtual status_t        setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; }
+#ifndef QCOM_HARDWARE
                 uint32_t        sampleRate() const { return mSampleRate; }
+#endif
+        virtual status_t        setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; }
                 audio_format_t  format() const { return mFormat; }
                 size_t          size() const { return mSize; }
                 status_t        wait();
@@ -216,6 +222,9 @@
         static  void            notify(void* cookie, int msg,
                                        int ext1, int ext2, const Parcel *obj);
         virtual status_t        dump(int fd, const Vector<String16>& args) const;
+#ifdef QCOM_HARDWARE
+        virtual ssize_t         sampleRate() const;
+#endif
 
     private:
                                 AudioCache();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 57b0ec2..aa25eff 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2010 - 2012, The Linux Foundation. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,6 +30,10 @@
 #include <media/stagefright/AudioSource.h>
 #include <media/stagefright/AMRWriter.h>
 #include <media/stagefright/AACWriter.h>
+#ifdef QCOM_HARDWARE
+#include <media/stagefright/ExtendedWriter.h>
+#include <media/stagefright/WAVEWriter.h>
+#endif
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/CameraSourceTimeLapse.h>
 #include <media/stagefright/MPEG2TSWriter.h>
@@ -49,6 +54,9 @@
 #include <unistd.h>
 
 #include <system/audio.h>
+#ifdef QCOM_HARDWARE
+#include <QCMediaDefs.h>
+#endif
 
 #include "ARTPWriter.h"
 
@@ -159,6 +167,26 @@
         mAudioEncoder = ae;
     }
 
+#ifdef QCOM_HARDWARE
+    // Use default values if appropriate setparam's weren't called.
+    if(mAudioEncoder == AUDIO_ENCODER_AAC) {
+        mSampleRate = mSampleRate ? mSampleRate : 48000;
+        mAudioChannels = mAudioChannels ? mAudioChannels : 2;
+        mAudioBitRate = mAudioBitRate ? mAudioBitRate : 156000;
+    } else if(mAudioEncoder == AUDIO_ENCODER_LPCM) {
+        mSampleRate = mSampleRate ? mSampleRate : 48000;
+        mAudioChannels = mAudioChannels ? mAudioChannels : 2;
+        mAudioBitRate = mAudioBitRate ? mAudioBitRate : 4608000;
+    } else if(mAudioEncoder == AUDIO_ENCODER_AMR_WB) {
+        mSampleRate = 16000;
+        mAudioChannels = 1;
+        mAudioBitRate = 23850;
+    } else {
+        mSampleRate = mSampleRate ? mSampleRate : 8000;
+        mAudioChannels = mAudioChannels ? mAudioChannels : 1;
+        mAudioBitRate = mAudioBitRate ? mAudioBitRate : 12200;
+    }
+#endif
     return OK;
 }
 
@@ -768,7 +796,15 @@
         case OUTPUT_FORMAT_MPEG2TS:
             status = startMPEG2TSRecording();
             break;
+#ifdef QCOM_HARDWARE
+        case OUTPUT_FORMAT_QCP:
+            status = startExtendedRecording( );
+            break;
 
+        case OUTPUT_FORMAT_WAVE:
+            status = startWAVERecording( );
+            break;
+#endif
         default:
             ALOGE("Unsupported output file format: %d", mOutputFormat);
             status = UNKNOWN_ERROR;
@@ -809,6 +845,11 @@
     sp<MetaData> encMeta = new MetaData;
     const char *mime;
     switch (mAudioEncoder) {
+#ifdef QCOM_HARDWARE
+        case AUDIO_ENCODER_LPCM:
+            mime = MEDIA_MIMETYPE_AUDIO_RAW;
+            break;
+#endif
         case AUDIO_ENCODER_AMR_NB:
         case AUDIO_ENCODER_DEFAULT:
             mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
@@ -828,6 +869,14 @@
             mime = MEDIA_MIMETYPE_AUDIO_AAC;
             encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD);
             break;
+#ifdef QCOM_HARDWARE
+        case AUDIO_ENCODER_EVRC:
+            mime = MEDIA_MIMETYPE_AUDIO_EVRC;
+            break;
+        case AUDIO_ENCODER_QCELP:
+            mime = MEDIA_MIMETYPE_AUDIO_QCELP;
+            break;
+#endif
 
         default:
             ALOGE("Unknown audio encoder: %d", mAudioEncoder);
@@ -852,6 +901,17 @@
     sp<MediaSource> audioEncoder =
         OMXCodec::Create(client.interface(), encMeta,
                          true /* createEncoder */, audioSource);
+#ifdef QCOM_HARDWARE
+    // If encoder could not be created (as in LPCM), then
+    // use the AudioSource directly as the MediaSource.
+    if (audioEncoder == NULL && AUDIO_ENCODER_LPCM) {
+        ALOGD("No encoder is needed, use the AudioSource directly as the MediaSource for LPCM format");
+        audioEncoder = audioSource;
+    }
+    if (mAudioSourceNode != NULL) {
+        mAudioSourceNode.clear();
+    }
+#endif
     mAudioSourceNode = audioSource;
 
     return audioEncoder;
@@ -888,14 +948,36 @@
                     mAudioEncoder);
             return BAD_VALUE;
         }
+#ifdef QCOM_HARDWARE
+        if (mSampleRate != 8000) {
+            ALOGE("Invalid sampling rate %d used for AMRNB recording",
+                    mSampleRate);
+            return BAD_VALUE;
+        }
+#endif
     } else {  // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
         if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
             ALOGE("Invlaid encoder %d used for AMRWB recording",
                     mAudioEncoder);
             return BAD_VALUE;
         }
+#ifdef QCOM_HARDWARE
+        if (mSampleRate != 16000) {
+            ALOGE("Invalid sample rate %d used for AMRWB recording",
+                    mSampleRate);
+            return BAD_VALUE;
+        }
+#endif
     }
 
+#ifdef QCOM_HARDWARE
+    if (mAudioChannels != 1) {
+        ALOGE("Invalid number of audio channels %d used for amr recording",
+                mAudioChannels);
+        return BAD_VALUE;
+    }
+#endif
+
     mWriter = new AMRWriter(mOutputFd);
     status_t status = startRawAudioRecording();
     if (status != OK) {
@@ -905,6 +987,24 @@
     return status;
 }
 
+#ifdef QCOM_HARDWARE
+status_t StagefrightRecorder::startWAVERecording() {
+    CHECK(mOutputFormat == OUTPUT_FORMAT_WAVE);
+
+    CHECK(mAudioEncoder == AUDIO_ENCODER_LPCM);
+    CHECK(mAudioSource != AUDIO_SOURCE_CNT);
+
+    mWriter = new WAVEWriter(mOutputFd);
+    status_t status = startRawAudioRecording();
+    if (status != OK) {
+        mWriter.clear();
+        mWriter = NULL;
+    }
+
+    return status;
+}
+#endif
+
 status_t StagefrightRecorder::startRawAudioRecording() {
     if (mAudioSource >= AUDIO_SOURCE_CNT) {
         ALOGE("Invalid audio source: %d", mAudioSource);
@@ -1450,6 +1550,9 @@
         case AUDIO_ENCODER_AAC:
         case AUDIO_ENCODER_HE_AAC:
         case AUDIO_ENCODER_AAC_ELD:
+#ifdef QCOM_HARDWARE
+        case AUDIO_ENCODER_LPCM:
+#endif
             break;
 
         default:
@@ -1611,7 +1714,12 @@
         ::close(mOutputFd);
         mOutputFd = -1;
     }
-
+#ifdef QCOM_HARDWARE
+    if (mAudioSourceNode != NULL) {
+        mAudioSourceNode.clear();
+        mAudioSourceNode = NULL;
+    }
+#endif
     if (mStarted) {
         mStarted = false;
 
@@ -1653,9 +1761,15 @@
     mVideoHeight   = 144;
     mFrameRate     = -1;
     mVideoBitRate  = 192000;
+#ifdef QCOM_HARDWARE
+    mSampleRate    = 0;
+    mAudioChannels = 0;
+    mAudioBitRate  = 0;
+#else
     mSampleRate    = 8000;
     mAudioChannels = 1;
     mAudioBitRate  = 12200;
+#endif
     mInterleaveDurationUs = 0;
     mIFramesIntervalSec = 1;
     mAudioSourceNode = 0;
@@ -1767,4 +1881,48 @@
     ::write(fd, result.string(), result.size());
     return OK;
 }
+
+#ifdef QCOM_HARDWARE
+status_t StagefrightRecorder::startExtendedRecording() {
+    CHECK(mOutputFormat == OUTPUT_FORMAT_QCP);
+
+    if (mSampleRate != 8000) {
+        ALOGE("Invalid sampling rate %d used for recording",
+             mSampleRate);
+        return BAD_VALUE;
+    }
+    if (mAudioChannels != 1) {
+        ALOGE("Invalid number of audio channels %d used for recording",
+                mAudioChannels);
+        return BAD_VALUE;
+    }
+
+    if (mAudioSource >= AUDIO_SOURCE_CNT) {
+        ALOGE("Invalid audio source: %d", mAudioSource);
+        return BAD_VALUE;
+    }
+
+    sp<MediaSource> audioEncoder = createAudioSource();
+
+    if (audioEncoder == NULL) {
+        ALOGE("AudioEncoder NULL");
+        return UNKNOWN_ERROR;
+    }
+
+    mWriter = new ExtendedWriter(dup(mOutputFd));
+    mWriter->addSource(audioEncoder);
+
+    if (mMaxFileDurationUs != 0) {
+        mWriter->setMaxFileDuration(mMaxFileDurationUs);
+    }
+    if (mMaxFileSizeBytes != 0) {
+        mWriter->setMaxFileSize(mMaxFileSizeBytes);
+    }
+    mWriter->setListener(mListener);
+    mWriter->start();
+
+    return OK;
+}
+#endif
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index ec5ce7e..3f0b821 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -132,6 +133,9 @@
     status_t startMPEG4Recording();
     status_t startAMRRecording();
     status_t startAACRecording();
+#ifdef QCOM_HARDWARE
+    status_t startWAVERecording();
+#endif
     status_t startRawAudioRecording();
     status_t startRTPRecording();
     status_t startMPEG2TSRecording();
@@ -187,6 +191,11 @@
 
     StagefrightRecorder(const StagefrightRecorder &);
     StagefrightRecorder &operator=(const StagefrightRecorder &);
+
+#ifdef QCOM_HARDWARE
+    /* extension */
+    status_t startExtendedRecording();
+#endif
 };
 
 }  // namespace android
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 7302692..35a5d05 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -1,6 +1,12 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+ifeq ($(BOARD_USES_ALSA_AUDIO),true)
+    ifeq ($(call is-chipset-in-board-platform,msm8960),true)
+        LOCAL_CFLAGS += -DUSE_TUNNEL_MODE
+    endif
+endif
+
 include frameworks/av/media/libstagefright/codecs/common/Config.mk
 
 LOCAL_SRC_FILES:=                         \
@@ -63,7 +69,27 @@
         $(TOP)/frameworks/native/include/media/openmax \
         $(TOP)/external/flac/include \
         $(TOP)/external/tremolo \
-        $(TOP)/external/openssl/include \
+        $(TOP)/external/openssl/include
+
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+LOCAL_SRC_FILES += \
+        ExtendedWriter.cpp                \
+        QCMediaDefs.cpp                   \
+        QCOMXCodec.cpp                    \
+        WAVEWriter.cpp                    \
+        ExtendedExtractor.cpp
+
+LOCAL_C_INCLUDES += \
+        $(TOP)/hardware/qcom/media/mm-core/inc
+
+ifeq ($(TARGET_QCOM_AUDIO_VARIANT),caf)
+LOCAL_CFLAGS += -DQCOM_ENHANCED_AUDIO
+LOCAL_SRC_FILES += \
+        LPAPlayerALSA.cpp                 \
+        TunnelPlayer.cpp
+endif
+endif
+
 
 LOCAL_SHARED_LIBRARIES := \
         libbinder \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 4208019..deb6b70 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -310,6 +310,13 @@
         void *buffer, size_t size, void *cookie) {
     AudioPlayer *me = (AudioPlayer *)cookie;
 
+#ifdef QCOM_ENHANCED_AUDIO
+    if (buffer == NULL) {
+        //Not applicable for AudioPlayer
+        ALOGE("This indicates the event underrun case for LPA/Tunnel");
+        return 0;
+    }
+#endif
     return me->fillBuffer(buffer, size);
 }
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 48b6371..5cffad8 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -2,6 +2,10 @@
  * Copyright (C) 2009 The Android Open Source Project
  * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
+ * Copyright (c) 2011-2012, 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
@@ -40,6 +44,12 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/timedtext/TimedTextDriver.h>
 #include <media/stagefright/AudioPlayer.h>
+#ifdef QCOM_ENHANCED_AUDIO
+#include <media/stagefright/LPAPlayer.h>
+#ifdef USE_TUNNEL_MODE
+#include <media/stagefright/TunnelPlayer.h>
+#endif
+#endif
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBuffer.h>
@@ -65,6 +75,9 @@
 static int64_t kHighWaterMarkUs = 5000000ll;  // 5secs
 static const size_t kLowWaterMarkBytes = 40000;
 static const size_t kHighWaterMarkBytes = 200000;
+#ifdef QCOM_ENHANCED_AUDIO
+int AwesomePlayer::mTunnelAliveAP = 0;
+#endif
 
 struct AwesomeEvent : public TimedEventQueue::Event {
     AwesomeEvent(
@@ -215,6 +228,9 @@
     mAudioStatusEventPending = false;
 
     reset();
+#ifdef QCOM_ENHANCED_AUDIO
+    mIsTunnelAudio = false;
+#endif
 }
 
 AwesomePlayer::~AwesomePlayer() {
@@ -224,6 +240,17 @@
 
     reset();
 
+#ifdef QCOM_ENHANCED_AUDIO
+    // Disable Tunnel Mode Audio
+    if (mIsTunnelAudio) {
+        if(mTunnelAliveAP > 0) {
+            mTunnelAliveAP--;
+            ALOGV("mTunnelAliveAP = %d", mTunnelAliveAP);
+        }
+    }
+    mIsTunnelAudio = false;
+#endif
+
     mClient.disconnect();
 }
 
@@ -858,6 +885,9 @@
 }
 
 status_t AwesomePlayer::play_l() {
+#ifdef QCOM_ENHANCED_AUDIO
+    int tunnelObjectsAlive = 0;
+#endif
     modifyFlags(SEEK_PREVIEW, CLEAR);
 
     if (mFlags & PLAYING) {
@@ -885,6 +915,13 @@
     if (mAudioSource != NULL) {
         if (mAudioPlayer == NULL) {
             if (mAudioSink != NULL) {
+#ifdef QCOM_ENHANCED_AUDIO
+                sp<MetaData> format = mAudioTrack->getFormat();
+                const char *mime;
+                bool success = format->findCString(kKeyMIMEType, &mime);
+                CHECK(success);
+#endif
+
                 bool allowDeepBuffering;
                 int64_t cachedDurationUs;
                 bool eos;
@@ -896,8 +933,64 @@
                 } else {
                     allowDeepBuffering = false;
                 }
+#ifdef QCOM_ENHANCED_AUDIO
+#ifdef USE_TUNNEL_MODE
+                // Create tunnel player if tunnel mode is enabled
+                ALOGW("Trying to create tunnel player mIsTunnelAudio %d, \
+                        LPAPlayer::objectsAlive %d, \
+                        TunnelPlayer::mTunnelObjectsAlive = %d,\
+                        (mAudioPlayer == NULL) %d",
+                        mIsTunnelAudio, TunnelPlayer::mTunnelObjectsAlive,
+                        LPAPlayer::objectsAlive,(mAudioPlayer == NULL));
 
-                mAudioPlayer = new AudioPlayer(mAudioSink, allowDeepBuffering, this);
+                if(mIsTunnelAudio && (mAudioPlayer == NULL) &&
+                        (LPAPlayer::objectsAlive == 0) &&
+                        (TunnelPlayer::mTunnelObjectsAlive == 0)) {
+                    ALOGD("Tunnel player created for  mime %s duration %lld\n",\
+                        mime, mDurationUs);
+                    bool initCheck =  false;
+                    if(mVideoSource != NULL) {
+                        // The parameter true is to inform tunnel player that
+                        // clip is audio video
+                        mAudioPlayer = new TunnelPlayer(mAudioSink, initCheck,
+                                this, true);
+                    }
+                    else {
+                        mAudioPlayer = new TunnelPlayer(mAudioSink, initCheck,
+                                this);
+                    }
+                    if(!initCheck) {
+                        ALOGE("deleting Tunnel Player - initCheck failed");
+                        delete mAudioPlayer;
+                        mAudioPlayer = NULL;
+                    }
+                }
+                tunnelObjectsAlive = (TunnelPlayer::mTunnelObjectsAlive);
+#endif
+                char lpaDecode[128];
+                property_get("lpa.decode",lpaDecode,"0");
+                if((strcmp("true",lpaDecode) == 0) && (mAudioPlayer == NULL) && tunnelObjectsAlive==0 )
+                {
+                    ALOGV("LPAPlayer::getObjectsAlive() %d",LPAPlayer::objectsAlive);
+                    if ( mDurationUs > 60000000
+                         && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC))
+                         && LPAPlayer::objectsAlive == 0 && mVideoSource == NULL) {
+                        ALOGD("LPAPlayer created, LPA MODE detected mime %s duration %lld", mime, mDurationUs);
+                        bool initCheck =  false;
+                        mAudioPlayer = new LPAPlayer(mAudioSink, initCheck, this);
+                        if(!initCheck) {
+                             delete mAudioPlayer;
+                             mAudioPlayer = NULL;
+                        }
+                    }
+                }
+                if(mAudioPlayer == NULL) {
+                    ALOGV("AudioPlayer created, Non-LPA mode mime %s duration %lld\n", mime, mDurationUs);
+#endif
+                    mAudioPlayer = new AudioPlayer(mAudioSink, allowDeepBuffering, this);
+#ifdef QCOM_ENHANCED_AUDIO
+                }
+#endif
                 mAudioPlayer->setSource(mAudioSource);
 
                 mTimeSource = mAudioPlayer;
@@ -915,9 +1008,14 @@
         if (mVideoSource == NULL) {
             // We don't want to post an error notification at this point,
             // the error returned from MediaPlayer::start() will suffice.
-
-            status_t err = startAudioPlayer_l(
-                    false /* sendErrorNotification */);
+            bool sendErrorNotification = false;
+#ifdef QCOM_ENHANCED_AUDIO
+            if(mIsTunnelAudio) {
+                // For tunnel Audio error has to be posted to the client
+                sendErrorNotification = true;
+            }
+#endif
+            status_t err = startAudioPlayer_l(sendErrorNotification);
 
             if (err != OK) {
                 delete mAudioPlayer;
@@ -1387,14 +1485,92 @@
 
     const char *mime;
     CHECK(meta->findCString(kKeyMIMEType, &mime));
+#ifdef QCOM_ENHANCED_AUDIO
+#ifdef USE_TUNNEL_MODE
+    char value[PROPERTY_VALUE_MAX];
+    char tunnelDecode[128];
+    property_get("tunnel.decode",tunnelDecode,"0");
+    // Enable tunnel mode for mp3 and aac and if the clip is not aac adif
+    // and if no other tunnel mode instances aare running.
+    ALOGD("Tunnel Mime Type: %s, object alive = %d, mTunnelAliveAP = %d",\
+            mime, (TunnelPlayer::mTunnelObjectsAlive), mTunnelAliveAP);
+    if(((strcmp("true",tunnelDecode) == 0)||(atoi(tunnelDecode))) &&
+            (TunnelPlayer::mTunnelObjectsAlive == 0) &&
+            mTunnelAliveAP == 0 &&
+            ((!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) ||
+            (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC)))) {
 
+        if(mVideoSource != NULL) {
+           char tunnelAVDecode[128];
+           property_get("tunnel.audiovideo.decode",tunnelAVDecode,"0");
+           if(((strncmp("true", tunnelAVDecode, 4) == 0)||(atoi(tunnelAVDecode)))) {
+               ALOGD("Enable Tunnel Mode for A-V playback");
+               mIsTunnelAudio = true;
+           }
+        }
+        else {
+            ALOGI("Tunnel Mode Audio Enabled");
+            mIsTunnelAudio = true;
+        }
+    }
+    else
+       ALOGD("Normal Audio Playback");
+#endif
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW) ||
+             (mIsTunnelAudio && (mTunnelAliveAP == 0))) {
+        ALOGD("Set Audio Track as Audio Source");
+        if(mIsTunnelAudio) {
+            mTunnelAliveAP++;
+        }
+#else
     if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
+#endif
         mAudioSource = mAudioTrack;
     } else {
+#ifdef QCOM_ENHANCED_AUDIO
+        // For LPA Playback use the decoder without OMX layer
+        char *matchComponentName = NULL;
+        int64_t durationUs;
+        uint32_t flags = 0;
+        char lpaDecode[128];
+        property_get("lpa.decode",lpaDecode,"0");
+        if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
+            Mutex::Autolock autoLock(mMiscStateLock);
+            if (mDurationUs < 0 || durationUs > mDurationUs) {
+                mDurationUs = durationUs;
+            }
+        }
+        if ( mDurationUs > 60000000
+             && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC))
+             && LPAPlayer::objectsAlive == 0 && mVideoSource == NULL && (strcmp("true",lpaDecode) == 0)) {
+            char nonOMXDecoder[128];
+            if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+                ALOGD("matchComponentName is set to MP3Decoder %lld, mime %s",mDurationUs,mime);
+                property_get("use.non-omx.mp3.decoder",nonOMXDecoder,"0");
+                if((strcmp("true",nonOMXDecoder) == 0)) {
+                    matchComponentName = (char *) "MP3Decoder";
+                }
+            } else if((!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC))) {
+                ALOGD("matchComponentName is set to AACDecoder %lld, mime %s",mDurationUs,mime);
+                property_get("use.non-omx.aac.decoder",nonOMXDecoder,"0");
+                if((strcmp("true",nonOMXDecoder) == 0)) {
+                    matchComponentName = (char *) "AACDecoder";
+                } else {
+                    matchComponentName = (char *) "OMX.google.aac.decoder";
+                }
+            }
+            flags |= OMXCodec::kSoftwareCodecsOnly;
+        }
+        mAudioSource = OMXCodec::Create(
+                mClient.interface(), mAudioTrack->getFormat(),
+                false, // createEncoder
+                mAudioTrack, matchComponentName, flags,NULL);
+#else
         mAudioSource = OMXCodec::Create(
                 mClient.interface(), mAudioTrack->getFormat(),
                 false, // createEncoder
                 mAudioTrack);
+#endif
     }
 
     if (mAudioSource != NULL) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 9d0eea2..4ab602f 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -33,6 +33,9 @@
 #include "include/OggExtractor.h"
 #include "include/WAVExtractor.h"
 #include "include/WVMExtractor.h"
+#ifdef QCOM_HARDWARE
+#include "include/ExtendedExtractor.h"
+#endif
 
 #include "matroska/MatroskaExtractor.h"
 
@@ -122,6 +125,9 @@
     RegisterSniffer(SniffAAC);
     RegisterSniffer(SniffMPEG2PS);
     RegisterSniffer(SniffWVM);
+#ifdef QCOM_HARDWARE
+    RegisterSniffer(SniffExtendedExtractor);
+#endif
 
     char value[PROPERTY_VALUE_MAX];
     if (property_get("drm.service.enabled", value, NULL)
diff --git a/media/libstagefright/ExtendedExtractor.cpp b/media/libstagefright/ExtendedExtractor.cpp
new file mode 100644
index 0000000..8e0d5d7
--- /dev/null
+++ b/media/libstagefright/ExtendedExtractor.cpp
@@ -0,0 +1,110 @@
+/*Copyright (c) 2012, 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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ExtendedExtractor"
+#include <utils/Log.h>
+#include <dlfcn.h>  // for dlopen/dlclose
+
+#include "include/ExtendedExtractor.h"
+
+static const char* EXTENDED_PARSER_LIB = "libExtendedExtractor.so";
+
+namespace android {
+
+void* ExtendedParserLib() {
+    static void* extendedParserLib = NULL;
+    static bool alreadyTriedToOpenParsers = false;
+
+    if(!alreadyTriedToOpenParsers) {
+        alreadyTriedToOpenParsers = true;
+
+        extendedParserLib = ::dlopen(EXTENDED_PARSER_LIB, RTLD_LAZY);
+
+        if(extendedParserLib == NULL) {
+            ALOGV("Failed to open EXTENDED_PARSER_LIB, dlerror = %s \n", dlerror());
+        }
+    }
+
+    return extendedParserLib;
+}
+
+MediaExtractor* ExtendedExtractor::CreateExtractor(const sp<DataSource> &source, const char *mime) {
+    static MediaExtractorFactory mediaFactoryFunction = NULL;
+    static bool alreadyTriedToFindFactoryFunction = false;
+
+    MediaExtractor* extractor = NULL;
+
+    if(!alreadyTriedToFindFactoryFunction) {
+
+        void *extendedParserLib = ExtendedParserLib();
+        if (extendedParserLib != NULL) {
+
+            mediaFactoryFunction = (MediaExtractorFactory) dlsym(extendedParserLib, MEDIA_CREATE_EXTRACTOR);
+            alreadyTriedToFindFactoryFunction = true;
+        }
+    }
+
+    if(mediaFactoryFunction==NULL) {
+        ALOGE(" dlsym for ExtendedExtractor factory function failed, dlerror = %s \n", dlerror());
+        return NULL;
+    }
+
+    extractor = mediaFactoryFunction(source, mime);
+    if(extractor==NULL) {
+        ALOGE(" ExtendedExtractor failed to instantiate extractor \n");
+    }
+
+    return extractor;
+}
+
+bool SniffExtendedExtractor(const sp<DataSource> &source, String8 *mimeType,
+                            float *confidence,sp<AMessage> *meta) {
+    void *extendedParserLib = ExtendedParserLib();
+    bool retVal = false;
+    if (extendedParserLib != NULL) {
+       ExtendedExtractorSniffers extendedExtractorSniffers=
+           (ExtendedExtractorSniffers) dlsym(extendedParserLib, EXTENDED_EXTRACTOR_SNIFFERS);
+
+       if(extendedExtractorSniffers == NULL) {
+           ALOGE(" dlsym for extendedExtractorSniffers function failed, dlerror = %s \n", dlerror());
+           return retVal;
+       }
+
+       retVal = extendedExtractorSniffers(source, mimeType, confidence, meta);
+
+       if(!retVal) {
+           ALOGV("ExtendedExtractor:: ExtendedExtractorSniffers  Failed");
+       }
+    }
+    return retVal;
+}
+
+}  // namespace android
+
+
diff --git a/media/libstagefright/ExtendedWriter.cpp b/media/libstagefright/ExtendedWriter.cpp
new file mode 100644
index 0000000..7c8b08e
--- /dev/null
+++ b/media/libstagefright/ExtendedWriter.cpp
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+#include <media/stagefright/ExtendedWriter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/mediarecorder.h>
+#include <system/audio.h>
+
+#include <sys/prctl.h>
+#include <sys/resource.h>
+
+#include <arpa/inet.h>
+#include <QCMediaDefs.h>
+
+#undef LOG_TAG
+#define LOG_TAG "ExtendedWriter"
+
+namespace android {
+
+ExtendedWriter::ExtendedWriter(const char *filename)
+    : mFile(fopen(filename, "wb")),
+      mInitCheck(mFile != NULL ? OK : NO_INIT),
+      mStarted(false),
+      mPaused(false),
+      mResumed(false),
+      mOffset(0) {
+}
+
+ExtendedWriter::ExtendedWriter(int fd)
+    : mFile(fdopen(fd, "wb")),
+      mInitCheck(mFile != NULL ? OK : NO_INIT),
+      mStarted(false),
+      mPaused(false),
+      mResumed(false),
+      mOffset(0) {
+}
+
+ExtendedWriter::~ExtendedWriter() {
+    if (mStarted) {
+        stop();
+    }
+
+    if (mFile != NULL) {
+        fclose(mFile);
+        mFile = NULL;
+    }
+}
+
+status_t ExtendedWriter::initCheck() const {
+    return mInitCheck;
+}
+
+status_t ExtendedWriter::addSource(const sp<MediaSource> &source) {
+    if (mInitCheck != OK) {
+        ALOGE("Init Check not OK, return");
+        return mInitCheck;
+    }
+
+    if (mSource != NULL) {
+        ALOGE("A source already exists, return");
+        return UNKNOWN_ERROR;
+    }
+
+    sp<MetaData> meta = source->getFormat();
+
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    if ( !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
+        mFormat = AUDIO_FORMAT_QCELP;
+    } else if ( !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_EVRC)) {
+        mFormat = AUDIO_FORMAT_EVRC;
+    }
+    else {
+        return UNKNOWN_ERROR;
+    }
+
+    int32_t channelCount;
+    int32_t sampleRate;
+    CHECK(meta->findInt32(kKeyChannelCount, &channelCount));
+    CHECK_EQ(channelCount, 1);
+    CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+    CHECK_EQ(sampleRate, 8000);
+
+    mSource = source;
+
+    return OK;
+}
+
+status_t ExtendedWriter::start(MetaData *params) {
+    if (mInitCheck != OK) {
+        ALOGE("Init Check not OK, return");
+        return mInitCheck;
+    }
+
+    if (mSource == NULL) {
+        ALOGE("NULL Source");
+        return UNKNOWN_ERROR;
+    }
+
+    if (mStarted && mPaused) {
+        mPaused = false;
+        mResumed = true;
+        return OK;
+    } else if (mStarted) {
+        ALOGE("Already startd, return");
+        return OK;
+    }
+
+    //space for header;
+    size_t headerSize = sizeof( struct QCPEVRCHeader );
+    uint8_t * header = (uint8_t *)malloc(headerSize);
+    memset( header, '?', headerSize);
+    fwrite( header, 1, headerSize, mFile );
+    mOffset += headerSize;
+    delete header;
+
+    status_t err = mSource->start();
+
+    if (err != OK) {
+        return err;
+    }
+
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    mReachedEOS = false;
+    mDone = false;
+
+    pthread_create(&mThread, &attr, ThreadWrapper, this);
+    pthread_attr_destroy(&attr);
+
+    mStarted = true;
+
+    return OK;
+}
+
+status_t ExtendedWriter::pause() {
+    if (!mStarted) {
+        return OK;
+    }
+    mPaused = true;
+    return OK;
+}
+
+status_t ExtendedWriter::stop() {
+    if (!mStarted) {
+        return OK;
+    }
+
+    mDone = true;
+
+    void *dummy;
+    pthread_join(mThread, &dummy);
+
+    status_t err = (status_t) dummy;
+    {
+        status_t status = mSource->stop();
+        if (err == OK &&
+            (status != OK && status != ERROR_END_OF_STREAM)) {
+            err = status;
+        }
+    }
+
+    mStarted = false;
+    return err;
+}
+
+bool ExtendedWriter::exceedsFileSizeLimit() {
+    if (mMaxFileSizeLimitBytes == 0) {
+        return false;
+    }
+    return mEstimatedSizeBytes >= mMaxFileSizeLimitBytes;
+}
+
+bool ExtendedWriter::exceedsFileDurationLimit() {
+    if (mMaxFileDurationLimitUs == 0) {
+        return false;
+    }
+    return mEstimatedDurationUs >= mMaxFileDurationLimitUs;
+}
+
+// static
+void *ExtendedWriter::ThreadWrapper(void *me) {
+    return (void *) static_cast<ExtendedWriter *>(me)->threadFunc();
+}
+
+status_t ExtendedWriter::threadFunc() {
+    mEstimatedDurationUs = 0;
+    mEstimatedSizeBytes = 0;
+    bool stoppedPrematurely = true;
+    int64_t previousPausedDurationUs = 0;
+    int64_t maxTimestampUs = 0;
+    status_t err = OK;
+
+    pid_t tid  = gettid();
+    androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+    prctl(PR_SET_NAME, (unsigned long)"ExtendedWriter", 0, 0, 0);
+    while (!mDone) {
+        MediaBuffer *buffer;
+        err = mSource->read(&buffer);
+
+        if (err != OK) {
+            break;
+        }
+
+        if (mPaused) {
+            buffer->release();
+            buffer = NULL;
+            continue;
+        }
+
+        mEstimatedSizeBytes += buffer->range_length();
+        if (exceedsFileSizeLimit()) {
+            buffer->release();
+            buffer = NULL;
+            notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
+            break;
+        }
+
+        int64_t timestampUs;
+        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
+        if (timestampUs > mEstimatedDurationUs) {
+            mEstimatedDurationUs = timestampUs;
+        }
+        if (mResumed) {
+            previousPausedDurationUs += (timestampUs - maxTimestampUs - 20000);
+            mResumed = false;
+        }
+        timestampUs -= previousPausedDurationUs;
+        ALOGV("time stamp: %lld, previous paused duration: %lld",
+                timestampUs, previousPausedDurationUs);
+        if (timestampUs > maxTimestampUs) {
+            maxTimestampUs = timestampUs;
+        }
+
+        if (exceedsFileDurationLimit()) {
+            buffer->release();
+            buffer = NULL;
+            notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
+            break;
+        }
+        ssize_t n = fwrite(
+                (const uint8_t *)buffer->data() + buffer->range_offset(),
+                1,
+                buffer->range_length(),
+                mFile);
+        mOffset += n;
+
+        if (n < (ssize_t)buffer->range_length()) {
+            buffer->release();
+            buffer = NULL;
+
+            break;
+        }
+
+        // XXX: How to tell it is stopped prematurely?
+        if (stoppedPrematurely) {
+            stoppedPrematurely = false;
+        }
+
+        buffer->release();
+        buffer = NULL;
+    }
+
+    if (stoppedPrematurely) {
+        notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, UNKNOWN_ERROR);
+    }
+
+    if ( mFormat == AUDIO_FORMAT_QCELP ) {
+        writeQCPHeader( );
+    }
+    else if ( mFormat == AUDIO_FORMAT_EVRC ) {
+        writeEVRCHeader( );
+    }
+
+    fflush(mFile);
+    fclose(mFile);
+    mFile = NULL;
+    mReachedEOS = true;
+    if (err == ERROR_END_OF_STREAM || (err == -ETIMEDOUT)) {
+        return OK;
+    }
+    return err;
+}
+
+bool ExtendedWriter::reachedEOS() {
+    return mReachedEOS;
+}
+
+status_t ExtendedWriter::writeQCPHeader() {
+    /* Common part */
+    struct QCPEVRCHeader header = {
+        {'R', 'I', 'F', 'F'}, 0, {'Q', 'L', 'C', 'M'}, /* Riff */
+        {'f', 'm', 't', ' '}, 150, 1, 0, 0, 0, 0,{0}, 0, {0},0,0,160,8000,16,0,{0},{0},{0}, /* Fmt */
+        {'v','r','a','t'}, 0, 0, 0, /* Vrat */
+        {'d','a','t','a'},0 /* Data */
+    };
+
+    fseeko(mFile, 0, SEEK_SET);
+    header.s_riff = (mOffset - 8);
+    header.data1 = (0x5E7F6D41);
+    header.data2 = (0xB115);
+    header.data3 = (0x11D0);
+    header.data4[0] = 0xBA;
+    header.data4[1] = 0x91;
+    header.data4[2] = 0x00;
+    header.data4[3] = 0x80;
+    header.data4[4] = 0x5F;
+    header.data4[5] = 0xB4;
+    header.data4[6] = 0xB9;
+    header.data4[7] = 0x7E;
+    header.ver = (0x0002);
+    memcpy(header.name, "Qcelp 13K", 9);
+    header.abps = (13000);
+    header.bytes_per_pkt = (35);
+    header.vr_num_of_rates = 5;
+    header.vr_bytes_per_pkt[0] = (0x0422);
+    header.vr_bytes_per_pkt[1] = (0x0310);
+    header.vr_bytes_per_pkt[2] = (0x0207);
+    header.vr_bytes_per_pkt[3] = (0x0103);
+    header.s_vrat = (0x00000008);
+    header.v_rate = (0x00000001);
+    header.size_in_pkts = (mOffset - sizeof( struct QCPEVRCHeader ))/ header.bytes_per_pkt;
+    header.s_data = mOffset - sizeof( struct QCPEVRCHeader );
+    fwrite( &header, 1, sizeof( struct QCPEVRCHeader ), mFile );
+    return OK;
+}
+
+status_t ExtendedWriter::writeEVRCHeader() {
+    /* Common part */
+    struct QCPEVRCHeader header = {
+        {'R', 'I', 'F', 'F'}, 0, {'Q', 'L', 'C', 'M'}, /* Riff */
+        {'f', 'm', 't', ' '}, 150, 1, 0, 0, 0, 0,{0}, 0, {0},0,0,160,8000,16,0,{0},{0},{0}, /* Fmt */
+        {'v','r','a','t'}, 0, 0, 0, /* Vrat */
+        {'d','a','t','a'},0 /* Data */
+    };
+
+    fseeko(mFile, 0, SEEK_SET);
+    header.s_riff = (mOffset - 8);
+    header.data1 = (0xe689d48d);
+    header.data2 = (0x9076);
+    header.data3 = (0x46b5);
+    header.data4[0] = 0x91;
+    header.data4[1] = 0xef;
+    header.data4[2] = 0x73;
+    header.data4[3] = 0x6a;
+    header.data4[4] = 0x51;
+    header.data4[5] = 0x00;
+    header.data4[6] = 0xce;
+    header.data4[7] = 0xb4;
+    header.ver = (0x0001);
+    memcpy(header.name, "TIA IS-127 Enhanced Variable Rate Codec, Speech Service Option 3", 64);
+    header.abps = (9600);
+    header.bytes_per_pkt = (23);
+    header.vr_num_of_rates = 4;
+    header.vr_bytes_per_pkt[0] = (0x0416);
+    header.vr_bytes_per_pkt[1] = (0x030a);
+    header.vr_bytes_per_pkt[2] = (0x0200);
+    header.vr_bytes_per_pkt[3] = (0x0102);
+    header.s_vrat = (0x00000008);
+    header.v_rate = (0x00000001);
+    header.size_in_pkts = (mOffset - sizeof( struct QCPEVRCHeader )) / header.bytes_per_pkt;
+    header.s_data = mOffset - sizeof( struct QCPEVRCHeader );
+    fwrite( &header, 1, sizeof( struct QCPEVRCHeader ), mFile );
+    return OK;
+}
+
+
+}  // namespace android
diff --git a/media/libstagefright/LPAPlayerALSA.cpp b/media/libstagefright/LPAPlayerALSA.cpp
new file mode 100644
index 0000000..db3a022
--- /dev/null
+++ b/media/libstagefright/LPAPlayerALSA.cpp
@@ -0,0 +1,791 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2009-2012, 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_NDDEBUG 0
+#define LOG_NDEBUG 0
+#define LOG_TAG "LPAPlayerALSA"
+
+#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 262144
+#define MEM_BUFFER_COUNT 4
+
+#define PCM_FORMAT 2
+#define NUM_FDS 2
+namespace android {
+int LPAPlayer::objectsAlive = 0;
+
+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) {
+    ALOGV("LPAPlayer::LPAPlayer() ctor");
+    objectsAlive++;
+    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();
+
+    //mAudioFlinger->deregisterClient(AudioFlingerClient);
+    objectsAlive--;
+}
+
+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 &&
+         event != AudioSystem::EFFECT_CONFIG_CHANGED) {
+        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() {
+    //TODO: Implement
+}
+
+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;
+    }
+    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);
+    err = mAudioSink->open(
+        mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+        DEFAULT_AUDIOSINK_BUFFERCOUNT,
+        &LPAPlayer::AudioSinkCallback,
+        this,
+        (mA2DPEnabled ? AUDIO_OUTPUT_FLAG_NONE : flags));
+
+    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();
+    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;
+    mPauseTime = mSeekTimeUs;
+    ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);
+    mAudioSink->flush();
+    pthread_cond_signal(&decoder_cv);
+    return OK;
+}
+
+void LPAPlayer::pause(bool playPendingSamples) {
+    CHECK(mStarted);
+    if (mPaused) {
+        return;
+    }
+    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();
+    } 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();
+        }
+    }
+}
+
+void LPAPlayer::resume() {
+    ALOGV("resume: mPaused %d",mPaused);
+    Mutex::Autolock autoLock(mResumeLock);
+    if ( mPaused) {
+        CHECK(mStarted);
+        if (!mIsA2DPEnabled) {
+            if(mPauseEventPending) {
+                ALOGV("Resume(): Cancelling the puaseTimeout event");
+                mPauseEventPending = false;
+                mQueue.cancelEvent(mPauseEvent->eventID());
+            }
+
+        }
+
+        if (!mIsAudioRouted) {
+            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,
+                DEFAULT_AUDIOSINK_BUFFERCOUNT,
+                &LPAPlayer::AudioSinkCallback,
+                this,
+                (mA2DPEnabled ?  AUDIO_OUTPUT_FLAG_NONE : flags ));
+            if (err != NO_ERROR) {
+                ALOGE("Audio sink open failed.");
+            }
+            mIsAudioRouted = true;
+        }
+        mPaused = false;
+        mAudioSink->start();
+        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() {
+
+    ALOGV("Reset");
+    // Close the audiosink after all the threads exited to make sure
+    mReachedEOS = true;
+
+    // make sure Decoder thread has exited
+    ALOGV("Closing all the threads");
+    requestAndWaitForDecoderThreadExit();
+    requestAndWaitForA2DPNotificationThreadExit();
+
+    ALOGV("Close the Sink");
+    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) {
+
+        if (mReachedEOS || mPaused || !mIsAudioRouted) {
+            pthread_mutex_lock(&decoder_mutex);
+            pthread_cond_wait(&decoder_cv, &decoder_mutex);
+            pthread_mutex_unlock(&decoder_mutex);
+            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::A2DPNotificationThreadWrapper(void *me) {
+    static_cast<LPAPlayer *>(me)->A2DPNotificationThreadEntry();
+    return NULL;
+}
+
+void LPAPlayer::A2DPNotificationThreadEntry() {
+    while (1) {
+        pthread_mutex_lock(&a2dp_notification_mutex);
+        pthread_cond_wait(&a2dp_notification_cv, &a2dp_notification_mutex);
+        pthread_mutex_unlock(&a2dp_notification_mutex);
+        if (killA2DPNotificationThread) {
+            break;
+        }
+
+        ALOGV("A2DP notification has come mIsA2DPEnabled: %d", mIsA2DPEnabled);
+
+        if (mIsA2DPEnabled) {
+            //TODO:
+        }
+        else {
+        //TODO
+        }
+    }
+    a2dpNotificationThreadAlive = false;
+    ALOGV("A2DPNotificationThread is dying");
+
+}
+
+void LPAPlayer::createThreads() {
+
+    //Initialize all the Mutexes and Condition Variables
+    pthread_mutex_init(&decoder_mutex, NULL);
+    pthread_mutex_init(&a2dp_notification_mutex, NULL);
+    pthread_cond_init (&decoder_cv, NULL);
+    pthread_cond_init (&a2dp_notification_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;
+    a2dpNotificationThreadAlive = true;
+
+    ALOGV("Creating decoder Thread");
+    pthread_create(&decoderThread, &attr, decoderThreadWrapper, this);
+
+    ALOGV("Creating A2DP Notification Thread");
+    pthread_create(&A2DPNotificationThread, &attr, A2DPNotificationThreadWrapper, 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;
+                }
+
+                size_remaining = size;
+                size_done = 0;
+
+                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::getTimeStamp(A2DPState state) {
+    uint64_t timestamp = 0;
+    switch (state) {
+    case A2DP_ENABLED:
+    case A2DP_DISCONNECT:
+        ALOGV("Get timestamp for A2DP");
+        break;
+    case A2DP_DISABLED:
+    case A2DP_CONNECT: {
+        mAudioSink->getTimeStamp(&timestamp);
+        break;
+    }
+    default:
+        break;
+    }
+    ALOGV("timestamp %lld ", timestamp);
+    return timestamp;
+}
+
+int64_t LPAPlayer::getMediaTimeUs() {
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime);
+    if (mPaused) {
+        return mPauseTime;
+    } else {
+        A2DPState state = mIsA2DPEnabled ? A2DP_ENABLED : A2DP_DISABLED;
+        return (mSeekTimeUs + getTimeStamp(state));
+    }
+}
+
+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;
+
+    /* Flush the audio sink to unblock the decoder thread
+       if any write to audio HAL is blocked */
+    if (!mReachedOutputEOS && 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");
+    Mutex::Autolock autoLock(mResumeLock);
+    if (!mPauseEventPending) {
+        return;
+    }
+    mPauseEventPending = false;
+    if(!mIsA2DPEnabled) {
+        // 1.) Set seek flags
+        mReachedEOS = false;
+        mReachedOutputEOS = false;
+        if(mSeeking == false) {
+            mSeekTimeUs += getTimeStamp(A2DP_DISABLED);
+            mInternalSeeking = true;
+        } else {
+            //do not update seek time if user has already seeked
+            // to a new position
+            // also seek has to be posted back to player,
+            // so do not set mInternalSeeking flag
+            ALOGV("do not update seek time %lld ", mSeekTimeUs);
+        }
+        ALOGV("newseek time = %lld ", mSeekTimeUs);
+        // 2.) Close routing Session
+        mAudioSink->close();
+        mIsAudioRouted = false;
+    }
+
+}
+
+} //namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index dc8e4a3..62ba826 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -40,6 +40,9 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 #include <utils/String8.h>
+#ifdef QCOM_HARDWARE
+#include <QCMediaDefs.h>
+#endif
 
 namespace android {
 
@@ -257,6 +260,28 @@
         case FOURCC('a', 'v', 'c', '1'):
             return MEDIA_MIMETYPE_VIDEO_AVC;
 
+#ifdef QCOM_HARDWARE
+        case FOURCC('s', 'q', 'c', 'p'):
+            return MEDIA_MIMETYPE_AUDIO_QCELP;
+
+        case FOURCC('s', 'e', 'v', 'c'):
+            return MEDIA_MIMETYPE_AUDIO_EVRC;
+
+        case FOURCC('d', 't', 's', 'c'):
+        case FOURCC('d', 't', 's', 'h'):
+        case FOURCC('d', 't', 's', 'l'):
+            return MEDIA_MIMETYPE_AUDIO_DTS;
+
+        case FOURCC('d', 't', 's', 'e'):
+            return MEDIA_MIMETYPE_AUDIO_DTS_LBR;
+
+        case FOURCC('a', 'c', '-', '3'):
+            return MEDIA_MIMETYPE_AUDIO_AC3;
+
+        case FOURCC('e', 'c', '-', '3'):
+            return MEDIA_MIMETYPE_AUDIO_EAC3;
+#endif
+
         default:
             CHECK(!"should not be here.");
             return NULL;
@@ -921,6 +946,17 @@
         case FOURCC('m', 'p', '4', 'a'):
         case FOURCC('s', 'a', 'm', 'r'):
         case FOURCC('s', 'a', 'w', 'b'):
+#ifdef QCOM_HARDWARE
+        case FOURCC('.', 'm', 'p', '3'):
+        case FOURCC('s', 'e', 'v', 'c'):
+        case FOURCC('s', 'q', 'c', 'p'):
+        case FOURCC('d', 't', 's', 'c'):
+        case FOURCC('d', 't', 's', 'h'):
+        case FOURCC('d', 't', 's', 'l'):
+        case FOURCC('d', 't', 's', 'e'):
+        case FOURCC('a', 'c', '-', '3'):
+        case FOURCC('e', 'c', '-', '3'):
+#endif
         {
             uint8_t buffer[8 + 20];
             if (chunk_data_size < (ssize_t)sizeof(buffer)) {
@@ -961,7 +997,16 @@
             mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
 
             off64_t stop_offset = *offset + chunk_size;
-            *offset = data_offset + sizeof(buffer);
+#ifdef QCOM_HARDWARE
+            if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_MPEG, FourCC2MIME(chunk_type)) ||
+                !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, FourCC2MIME(chunk_type))) {
+                // ESD is not required in mp3
+                // amr wb with damr atom corrupted can cause the clip to not play
+               *offset = stop_offset;
+            } else
+#endif
+               *offset = data_offset + sizeof(buffer);
+
             while (*offset < stop_offset) {
                 status_t err = parseChunk(offset, depth + 1);
                 if (err != OK) {
@@ -1219,6 +1264,18 @@
             break;
         }
 
+#ifdef QCOM_HARDWARE
+        case FOURCC('d', 'd', 't', 's'):
+        case FOURCC('d', 'a', 'c', '3'):
+        case FOURCC('d', 'e', 'c', '3'):
+        {
+            //no information need to be passed here, just log and end
+            ALOGV("ddts/dac3/dec3 pass from mpeg4 extractor");
+            *offset += chunk_size;
+            break;
+        }
+#endif
+
         case FOURCC('a', 'v', 'c', 'C'):
         {
             char buffer[256];
@@ -1799,6 +1856,14 @@
         return ERROR_MALFORMED;
     }
 
+#ifdef QCOM_HARDWARE
+    if (objectTypeIndication == 0xA0) {
+        // This isn't MPEG4 audio at all, it's EVRC
+       mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_EVRC);
+       return OK;
+    }
+#endif
+
     if (objectTypeIndication == 0xe1) {
         // This isn't MPEG4 audio at all, it's QCELP 14k...
         mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_QCELP);
@@ -2313,6 +2378,9 @@
     }
 
     if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
+#ifdef QCOM_HARDWARE
+        || !memcmp(header, "ftyp3g2a", 8) || !memcmp(header, "ftyp3g2b", 8) || !memcmp(header, "ftyp3g2c", 8)
+#endif
         || !memcmp(header, "ftyp3gr6", 8) || !memcmp(header, "ftyp3gs6", 8)
         || !memcmp(header, "ftyp3ge6", 8) || !memcmp(header, "ftyp3gg6", 8)
         || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index b18c916..cca49fe 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -30,6 +30,9 @@
 #include "include/WVMExtractor.h"
 #include "include/FLACExtractor.h"
 #include "include/AACExtractor.h"
+#ifdef QCOM_HARDWARE
+#include "include/ExtendedExtractor.h"
+#endif
 
 #include "matroska/MatroskaExtractor.h"
 
@@ -132,6 +135,14 @@
        }
     }
 
+#ifdef QCOM_HARDWARE
+    if(ret == NULL) {
+        //Create Extended Extractor only if default extractor are not selected
+        ALOGV("Using ExtendedExtractor\n");
+        ret =  ExtendedExtractor::CreateExtractor(source, mime);
+    }
+#endif
+
     return ret;
 }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
old mode 100755
new mode 100644
index 560c1bb..4e6c395
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1,5 +1,9 @@
 /*
  * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2010 - 2012, 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.
@@ -42,6 +46,12 @@
 #include <OMX_Audio.h>
 #include <OMX_Component.h>
 
+#ifdef QCOM_HARDWARE
+#include <QCMediaDefs.h>
+#include <QCMetaData.h>
+#include <QOMX_AudioExtensions.h>
+#include <OMX_QCOMExtns.h>
+#endif
 #include "include/avc_utils.h"
 
 #ifdef USE_SAMSUNG_COLORFORMAT
@@ -271,6 +281,26 @@
                 index, "output-buffers-are-unreadable")) {
         quirks |= kOutputBuffersAreUnreadable;
     }
+#ifdef QCOM_HARDWARE
+    if (list->codecHasQuirk(
+                index, "requies-loaded-to-idle-after-allocation")) {
+      quirks |= kRequiresLoadedToIdleAfterAllocation;
+    }
+    if (list->codecHasQuirk(
+                index, "requires-global-flush")) {
+        quirks |= kRequiresGlobalFlush;
+    }
+    if (list->codecHasQuirk(
+                index, "requires-wma-pro-component")) {
+        quirks |= kRequiresWMAProComponent;
+    }
+    if (list->codecHasQuirk(
+                index, "defers-output-buffer-allocation")) {
+      quirks |= kDefersOutputBufferAllocation;
+    }
+
+    quirks |= QCOMXCodec::getQCComponentQuirks(list,index);
+#endif
 
     return quirks;
 }
@@ -352,7 +382,28 @@
                 return softwareCodec;
             }
         }
+#ifdef QCOM_HARDWARE
+        //quirks = getComponentQuirks(componentNameBase, createEncoder);
+        if(quirks & kRequiresWMAProComponent)
+        {
+           int32_t version;
+           CHECK(meta->findInt32(kKeyWMAVersion, &version));
+           if(version==kTypeWMA)
+           {
+              componentName = "OMX.qcom.audio.decoder.wma";
+           }
+           else if(version==kTypeWMAPro)
+           {
+              componentName= "OMX.qcom.audio.decoder.wma10Pro";
+           }
+           else if(version==kTypeWMALossLess)
+           {
+              componentName= "OMX.qcom.audio.decoder.wmaLossLess";
+           }
+        }
 
+        QCOMXCodec::setASFQuirks(quirks, meta, componentName);
+#endif
         ALOGV("Attempting to allocate OMX node '%s'", componentName);
 
         if (!createEncoder
@@ -515,9 +566,25 @@
 
             CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
             addCodecSpecificData(data, size);
+#ifdef QCOM_HARDWARE
+        } else if (meta->findData(kKeyRawCodecSpecificData, &type, &data, &size)) {
+            ALOGV("OMXCodec::configureCodec found kKeyRawCodecSpecificData of size %d\n", size);
+            addCodecSpecificData(data, size);
+        } else {
+            QCOMXCodec::checkAndAddRawFormat(this,meta);
+#endif
         }
     }
 
+#ifdef QCOM_HARDWARE
+    status_t errRetVal = QCOMXCodec::configureDIVXCodec( meta, mMIME, mOMX, mNode,
+                                                         (OMXCodec::mIsEncoder ?
+                                                         kPortIndexOutput : kPortIndexInput));
+    if(OK != errRetVal) {
+        return errRetVal;
+    }
+#endif
+
     int32_t bitRate = 0;
     if (mIsEncoder) {
         CHECK(meta->findInt32(kKeyBitRate, &bitRate));
@@ -545,6 +612,42 @@
             CODEC_LOGE("setAACFormat() failed (err = %d)", err);
             return err;
         }
+
+#ifdef QCOM_HARDWARE
+        uint32_t type;
+        const void *data;
+        size_t size;
+
+        if (meta->findData(kKeyAacCodecSpecificData, &type, &data, &size)) {
+            ALOGV("OMXCodec:: configureCodec found kKeyAacCodecSpecificData of size %d\n", size);
+            addCodecSpecificData(data, size);
+        }
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mMIME)) {
+        int32_t numChannels, sampleRate;
+        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+        setAC3Format(numChannels, sampleRate);
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_EAC3, mMIME)) {
+        int32_t numChannels, sampleRate;
+        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+        setAC3Format(numChannels, sampleRate); //since AC3 and EAC3 use same format at present
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_EVRC, mMIME)) {
+        int32_t numChannels, sampleRate;
+        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+        setEVRCFormat(numChannels, sampleRate, bitRate);
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_QCELP, mMIME)) {
+        int32_t numChannels, sampleRate;
+        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+        setQCELPFormat(numChannels, sampleRate, bitRate);
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_WMA, mMIME))  {
+        status_t err = setWMAFormat(meta);
+        if(err!=OK){
+           return err;
+        }
+#endif
     } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME)
             || !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) {
         // These are PCM-like formats with a fixed sample rate but
@@ -562,10 +665,37 @@
         CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
 
         setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+#ifdef QCOM_HARDWARE
+    } else {
+        status_t err = QCOMXCodec::setQCFormat(meta, mMIME, mOMX, mNode, this, mIsEncoder);
+
+        if(OK != err) {
+            return err;
+        }
+#endif
     }
 
     if (!strncasecmp(mMIME, "video/", 6)) {
+#ifdef QCOM_HARDWARE
+        if ((mFlags & kClientNeedsFramebuffer) && !strncmp(mComponentName, "OMX.qcom.", 9)) {
+            ALOGV("Enabling thumbnail mode.");
+            QOMX_ENABLETYPE enableType;
+            OMX_INDEXTYPE indexType;
 
+            status_t err = mOMX->getExtensionIndex(
+                mNode, OMX_QCOM_INDEX_PARAM_VIDEO_SYNCFRAMEDECODINGMODE, &indexType);
+
+            CHECK_EQ(err, (status_t)OK);
+
+            enableType.bEnable = OMX_TRUE;
+
+            err = mOMX->setParameter(
+                    mNode, indexType, &enableType, sizeof(enableType));
+            CHECK_EQ(err, (status_t)OK);
+
+            ALOGV("Thumbnail mode enabled.");
+        }
+#endif
         if (mIsEncoder) {
             setVideoInputFormat(mMIME, meta);
         } else {
@@ -833,8 +963,15 @@
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
         compressionFormat = OMX_VIDEO_CodingH263;
     } else {
-        ALOGE("Not a supported video mime type: %s", mime);
-        CHECK(!"Should not be here. Not a supported video mime type.");
+#ifdef QCOM_HARDWARE
+        status_t err = QCOMXCodec::setQCVideoInputFormat(mime, &compressionFormat);
+        if(err != OK) {
+#endif
+            ALOGE("Not a supported video mime type: %s", mime);
+            CHECK(!"Should not be here. Not a supported video mime type.");
+#ifdef QCOM_HARDWARE
+        }
+#endif
     }
 
     OMX_COLOR_FORMATTYPE colorFormat;
@@ -1230,8 +1367,16 @@
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) {
         compressionFormat = OMX_VIDEO_CodingMPEG2;
     } else {
-        ALOGE("Not a supported video mime type: %s", mime);
-        CHECK(!"Should not be here. Not a supported video mime type.");
+#ifdef QCOM_HARDWARE
+        status_t err = QCOMXCodec::setQCVideoOutputFormat(mime,&compressionFormat);
+
+        if(err != OK) {
+#endif
+            ALOGE("Not a supported video mime type: %s", mime);
+            CHECK(!"Should not be here. Not a supported video mime type.");
+#ifdef QCOM_HARDWARE
+        }
+#endif
     }
 
     status_t err = setVideoPortFormatType(
@@ -1389,6 +1534,9 @@
       mState(LOADED),
       mInitialBufferSubmit(true),
       mSignalledEOS(false),
+#ifdef QCOM_HARDWARE
+      mFinalStatus(OK),
+#endif
       mNoMoreOutputData(false),
       mOutputPortSettingsHaveChanged(false),
       mSeekTimeUs(-1),
@@ -1437,6 +1585,12 @@
             "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" },
         { MEDIA_MIMETYPE_AUDIO_G711_ALAW,
             "audio_decoder.g711alaw", "audio_encoder.g711alaw" },
+#ifdef QCOM_HARDWARE
+        { MEDIA_MIMETYPE_AUDIO_EVRC,
+            "audio_decoder.evrchw", "audio_encoder.evrc" },
+        { MEDIA_MIMETYPE_AUDIO_QCELP,
+            "audio_decoder,qcelp13Hw", "audio_encoder.qcelp13" },
+#endif
         { MEDIA_MIMETYPE_VIDEO_AVC,
             "video_decoder.avc", "video_encoder.avc" },
         { MEDIA_MIMETYPE_VIDEO_MPEG4,
@@ -1449,6 +1603,16 @@
             "audio_decoder.raw", "audio_encoder.raw" },
         { MEDIA_MIMETYPE_AUDIO_FLAC,
             "audio_decoder.flac", "audio_encoder.flac" },
+#ifdef QCOM_HARDWARE
+        { MEDIA_MIMETYPE_VIDEO_DIVX,
+            "video_decoder.divx", NULL },
+        { MEDIA_MIMETYPE_AUDIO_AC3,
+            "audio_decoder.ac3", NULL },
+        { MEDIA_MIMETYPE_AUDIO_EAC3,
+            "audio_decoder.eac3", NULL },
+        { MEDIA_MIMETYPE_VIDEO_DIVX311,
+            "video_decoder.divx", NULL },
+#endif
     };
 
     static const size_t kNumMimeToRole =
@@ -1462,6 +1626,9 @@
     }
 
     if (i == kNumMimeToRole) {
+#ifdef QCOM_HARDWARE
+        QCOMXCodec::checkQCRole(omx, node, isEncoder, mime);
+#endif
         return;
     }
 
@@ -2627,11 +2794,22 @@
 
             CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
 
-            CHECK_EQ((int)mPortStatus[portIndex], (int)SHUTTING_DOWN);
-            mPortStatus[portIndex] = ENABLED;
+#ifdef QCOM_HARDWARE
+            if (portIndex == (OMX_U32) -1) {
+                CHECK_EQ((int)mPortStatus[kPortIndexInput], (int)SHUTTING_DOWN);
+                mPortStatus[kPortIndexInput] = ENABLED;
+                CHECK_EQ((int)mPortStatus[kPortIndexOutput], (int)SHUTTING_DOWN);
+                mPortStatus[kPortIndexOutput] = ENABLED;
+            } else {
+#endif
+                CHECK_EQ((int)mPortStatus[portIndex], (int)SHUTTING_DOWN);
+                mPortStatus[portIndex] = ENABLED;
 
-            CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
-                     mPortBuffers[portIndex].size());
+                CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
+                         mPortBuffers[portIndex].size());
+#ifdef QCOM_HARDWARE
+            }
+#endif
 
             if (mSkipCutBuffer != NULL && mPortStatus[kPortIndexOutput] == ENABLED) {
                 mSkipCutBuffer->clear();
@@ -2896,21 +3074,30 @@
     CHECK(mState == EXECUTING || mState == RECONFIGURING
             || mState == EXECUTING_TO_IDLE);
 
-    CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
-         portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
-         mPortBuffers[portIndex].size());
+#ifdef QCOM_HARDWARE
+    if (portIndex == (OMX_U32) -1 ) {
+        mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
+        mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
+    } else {
+#endif
+        CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
+             portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
+             mPortBuffers[portIndex].size());
 
-    CHECK_EQ((int)mPortStatus[portIndex], (int)ENABLED);
-    mPortStatus[portIndex] = SHUTTING_DOWN;
+        CHECK_EQ((int)mPortStatus[portIndex], (int)ENABLED);
+        mPortStatus[portIndex] = SHUTTING_DOWN;
 
-    if ((mQuirks & kRequiresFlushCompleteEmulation)
-        && countBuffersWeOwn(mPortBuffers[portIndex])
-                == mPortBuffers[portIndex].size()) {
-        // No flush is necessary and this component fails to send a
-        // flush-complete event in this case.
+        if ((mQuirks & kRequiresFlushCompleteEmulation)
+            && countBuffersWeOwn(mPortBuffers[portIndex])
+                    == mPortBuffers[portIndex].size()) {
+            // No flush is necessary and this component fails to send a
+            // flush-complete event in this case.
 
-        return false;
+           return false;
+        }
+#ifdef QCOM_HARDWARE
     }
+#endif
 
     status_t err =
         mOMX->sendCommand(mNode, OMX_CommandFlush, portIndex);
@@ -2950,16 +3137,27 @@
     // end-of-output-stream. If we own all input buffers and also own
     // all output buffers and we already signalled end-of-input-stream,
     // the end-of-output-stream is implied.
-    if (mSignalledEOS
+
+#ifdef QCOM_HARDWARE
+    // NOTE: Thumbnail mode needs a call to fillOutputBuffer in order
+    // to get the decoded frame from the component. Currently,
+    // thumbnail mode calls emptyBuffer with an EOS flag on its first
+    // frame and sets mSignalledEOS to true, so without the check for
+    // !mThumbnailMode, fillOutputBuffer will never be called.
+    if (!((mFlags & kClientNeedsFramebuffer) && !strncmp(mComponentName, "OMX.qcom.", 9))){
+#endif
+        if (mSignalledEOS
             && countBuffersWeOwn(mPortBuffers[kPortIndexInput])
                 == mPortBuffers[kPortIndexInput].size()
             && countBuffersWeOwn(mPortBuffers[kPortIndexOutput])
                 == mPortBuffers[kPortIndexOutput].size()) {
-        mNoMoreOutputData = true;
-        mBufferFilled.signal();
-
-        return;
+            mNoMoreOutputData = true;
+            mBufferFilled.signal();
+            return;
+        }
+#ifdef QCOM_HARDWARE
     }
+#endif
 
     Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
     for (size_t i = 0; i < buffers->size(); ++i) {
@@ -3283,6 +3481,20 @@
 
     if (signalEOS) {
         flags |= OMX_BUFFERFLAG_EOS;
+#ifdef QCOM_HARDWARE
+    } else if ((mFlags & kClientNeedsFramebuffer) && !strncmp(mComponentName, "OMX.qcom.", 9)) {
+        // Because we don't get an EOS after getting the first frame, we
+        // need to notify the component with OMX_BUFFERFLAG_EOS, set
+        // mNoMoreOutputData to false so fillOutputBuffer gets called on
+        // the first output buffer (see comment in fillOutputBuffer), and
+        // mSignalledEOS must be true so drainInputBuffer is not executed
+        // on extra frames. Setting mFinalStatus to ERROR_END_OF_STREAM as
+        // we dont want to return OK and NULL buffer in read.
+        flags |= OMX_BUFFERFLAG_EOS;
+        mNoMoreOutputData = false;
+        mSignalledEOS = true;
+        mFinalStatus = ERROR_END_OF_STREAM;
+#endif
     } else {
         mNoMoreOutputData = false;
     }
@@ -3381,6 +3593,14 @@
         return mBufferFilled.wait(mLock);
     }
     status_t err = mBufferFilled.waitRelative(mLock, kBufferFilledEventTimeOutNs);
+#ifdef QCOM_HARDWARE
+    if ((err == -ETIMEDOUT) && (mPaused == true)){
+        // When the audio playback is paused, the fill buffer maybe timed out
+        // if input data is not available to decode. Hence, considering the
+        // timed out as a valid case.
+        err = OK;
+    }
+#endif
     if (err != OK) {
         CODEC_LOGE("Timed out waiting for output buffers: %d/%d",
             countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
@@ -3605,6 +3825,182 @@
     return OK;
 }
 
+#ifdef QCOM_HARDWARE
+void OMXCodec::setAC3Format(int32_t numChannels, int32_t sampleRate) {
+
+    QOMX_AUDIO_PARAM_AC3TYPE profileAC3;
+    QOMX_AUDIO_PARAM_AC3PP profileAC3PP;
+    OMX_INDEXTYPE indexTypeAC3;
+    OMX_INDEXTYPE indexTypeAC3PP;
+    OMX_PARAM_PORTDEFINITIONTYPE portParam;
+
+    //configure input port
+    CODEC_LOGV("setAC3Format samplerate %d, numChannels %d", sampleRate, numChannels);
+    InitOMXParams(&portParam);
+    portParam.nPortIndex = 0;
+    status_t err = mOMX->getParameter(
+       mNode, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+    CHECK_EQ(err, (status_t)OK);
+    err = mOMX->setParameter(
+       mNode, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+    CHECK_EQ(err, (status_t)OK);
+
+    //configure output port
+    portParam.nPortIndex = 1;
+    err = mOMX->getParameter(
+       mNode, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+    CHECK_EQ(err, (status_t)OK);
+    err = mOMX->setParameter(
+       mNode, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+    CHECK_EQ(err, (status_t)OK);
+
+    err = mOMX->getExtensionIndex(mNode, OMX_QCOM_INDEX_PARAM_AC3TYPE, &indexTypeAC3);
+
+    InitOMXParams(&profileAC3);
+    profileAC3.nPortIndex = kPortIndexInput;
+    err = mOMX->getParameter(mNode, indexTypeAC3, &profileAC3, sizeof(profileAC3));
+    CHECK_EQ(err,(status_t)OK);
+
+    profileAC3.nSamplingRate  =  sampleRate;
+    profileAC3.nChannels      =  2;
+    profileAC3.eChannelConfig =  OMX_AUDIO_AC3_CHANNEL_CONFIG_2_0;
+
+    CODEC_LOGE("numChannels = %d, profileAC3.nChannels = %d", numChannels, profileAC3.nChannels);
+
+    err = mOMX->setParameter(mNode, indexTypeAC3, &profileAC3, sizeof(profileAC3));
+    CHECK_EQ(err,(status_t)OK);
+
+    //for output port
+    OMX_AUDIO_PARAM_PCMMODETYPE profilePcm;
+    InitOMXParams(&profilePcm);
+    profilePcm.nPortIndex = kPortIndexOutput;
+    err = mOMX->getParameter(mNode, OMX_IndexParamAudioPcm, &profilePcm, sizeof(profilePcm));
+    CHECK_EQ(err, (status_t)OK);
+
+    profilePcm.nSamplingRate  =  sampleRate;
+    err = mOMX->setParameter(mNode, OMX_IndexParamAudioPcm, &profilePcm, sizeof(profilePcm));
+    CHECK_EQ(err, (status_t)OK);
+    mOMX->getExtensionIndex(mNode, OMX_QCOM_INDEX_PARAM_AC3PP, &indexTypeAC3PP);
+
+    InitOMXParams(&profileAC3PP);
+    profileAC3PP.nPortIndex = kPortIndexInput;
+    err = mOMX->getParameter(mNode, indexTypeAC3PP, &profileAC3PP, sizeof(profileAC3PP));
+    CHECK_EQ(err, (status_t)OK);
+
+    int i;
+    int channel_routing[6];
+
+    for (i=0; i<6; i++) {
+        channel_routing[i] = -1;
+    }
+    for (i=0; i<6; i++) {
+        profileAC3PP.eChannelRouting[i] =  (OMX_AUDIO_AC3_CHANNEL_ROUTING)channel_routing[i];
+    }
+
+    profileAC3PP.eChannelRouting[0] =  OMX_AUDIO_AC3_CHANNEL_LEFT;
+    profileAC3PP.eChannelRouting[1] =  OMX_AUDIO_AC3_CHANNEL_RIGHT;
+    err = mOMX->setParameter(mNode, indexTypeAC3PP, &profileAC3PP, sizeof(profileAC3PP));
+    CHECK_EQ(err, (status_t)OK);
+
+}
+
+
+status_t OMXCodec::setWMAFormat(const sp<MetaData> &meta)
+{
+   if (mIsEncoder) {
+        CODEC_LOGE("WMA encoding not supported");
+        return OK;
+    } else {
+        int32_t version;
+        OMX_AUDIO_PARAM_WMATYPE paramWMA;
+        QOMX_AUDIO_PARAM_WMA10PROTYPE paramWMA10;
+        CHECK(meta->findInt32(kKeyWMAVersion, &version));
+        int32_t numChannels;
+        int32_t bitRate;
+        int32_t sampleRate;
+        int32_t encodeOptions;
+        int32_t blockAlign;
+        int32_t bitspersample;
+        int32_t formattag;
+        int32_t advencopt1;
+        int32_t advencopt2;
+        int32_t VirtualPktSize;
+        if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+            CHECK(meta->findInt32(kKeyWMABitspersample, &bitspersample));
+            CHECK(meta->findInt32(kKeyWMAFormatTag, &formattag));
+            CHECK(meta->findInt32(kKeyWMAAdvEncOpt1,&advencopt1));
+            CHECK(meta->findInt32(kKeyWMAAdvEncOpt2,&advencopt2));
+            CHECK(meta->findInt32(kKeyWMAVirPktSize,&VirtualPktSize));
+        }
+        if(version==kTypeWMA) {
+            InitOMXParams(&paramWMA);
+            paramWMA.nPortIndex = kPortIndexInput;
+        } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+            InitOMXParams(&paramWMA10);
+            paramWMA10.nPortIndex = kPortIndexInput;
+        }
+        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+        CHECK(meta->findInt32(kKeyBitRate, &bitRate));
+        CHECK(meta->findInt32(kKeyWMAEncodeOpt, &encodeOptions));
+        CHECK(meta->findInt32(kKeyWMABlockAlign, &blockAlign));
+        CODEC_LOGV("Channels: %d, SampleRate: %d, BitRate; %d"
+                   "EncodeOptions: %d, blockAlign: %d", numChannels,
+                   sampleRate, bitRate, encodeOptions, blockAlign);
+        if(sampleRate>48000 || numChannels>2)
+        {
+            ALOGE("Unsupported samplerate/channels");
+            return ERROR_UNSUPPORTED;
+        }
+        if(version==kTypeWMAPro || version==kTypeWMALossLess)
+        {
+            CODEC_LOGV("Bitspersample: %d, wmaformattag: %d,"
+                       "advencopt1: %d, advencopt2: %d VirtualPktSize %d", bitspersample,
+                       formattag, advencopt1, advencopt2, VirtualPktSize);
+        }
+        status_t err = OK;
+        OMX_INDEXTYPE index;
+        if(version==kTypeWMA) {
+            err = mOMX->getParameter(
+                   mNode, OMX_IndexParamAudioWma, &paramWMA, sizeof(paramWMA));
+        } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+            mOMX->getExtensionIndex(mNode,"OMX.Qualcomm.index.audio.wma10Pro",&index);
+            err = mOMX->getParameter(
+                   mNode, index, &paramWMA10, sizeof(paramWMA10));
+        }
+        CHECK_EQ(err, (status_t)OK);
+        if(version==kTypeWMA) {
+            paramWMA.nChannels = numChannels;
+            paramWMA.nSamplingRate = sampleRate;
+            paramWMA.nEncodeOptions = encodeOptions;
+            paramWMA.nBitRate = bitRate;
+            paramWMA.nBlockAlign = blockAlign;
+        } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+            paramWMA10.nChannels = numChannels;
+            paramWMA10.nSamplingRate = sampleRate;
+            paramWMA10.nEncodeOptions = encodeOptions;
+            paramWMA10.nBitRate = bitRate;
+            paramWMA10.nBlockAlign = blockAlign;
+        }
+        if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+            paramWMA10.advancedEncodeOpt = advencopt1;
+            paramWMA10.advancedEncodeOpt2 = advencopt2;
+            paramWMA10.formatTag = formattag;
+            paramWMA10.validBitsPerSample = bitspersample;
+            paramWMA10.nVirtualPktSize = VirtualPktSize;
+        }
+        if(version==kTypeWMA) {
+            err = mOMX->setParameter(
+                  mNode, OMX_IndexParamAudioWma, &paramWMA, sizeof(paramWMA));
+        } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+           err = mOMX->setParameter(
+                 mNode, index, &paramWMA10, sizeof(paramWMA10));
+        }
+        return err;
+    }
+}
+#endif
+
 void OMXCodec::setG711Format(int32_t numChannels) {
     CHECK(!mIsEncoder);
     setRawAudioFormat(kPortIndexInput, 8000, numChannels);
@@ -3846,19 +4242,32 @@
                 CODEC_LOGV("This component requires a flush before transitioning "
                      "from EXECUTING to IDLE...");
 
-                bool emulateInputFlushCompletion =
-                    !flushPortAsync(kPortIndexInput);
+#ifdef QCOM_HARDWARE
+                //DSP supports flushing of ports simultaneously.
+                //Flushing individual port is not supported.
+                if(mQuirks & kRequiresGlobalFlush) {
+                    bool emulateFlushCompletion = !flushPortAsync(kPortIndexBoth);
+                    if (emulateFlushCompletion) {
+                        onCmdComplete(OMX_CommandFlush, kPortIndexBoth);
+                    }
+                } else {
+#endif
+                    bool emulateInputFlushCompletion =
+                        !flushPortAsync(kPortIndexInput);
 
-                bool emulateOutputFlushCompletion =
-                    !flushPortAsync(kPortIndexOutput);
+                    bool emulateOutputFlushCompletion =
+                        !flushPortAsync(kPortIndexOutput);
 
-                if (emulateInputFlushCompletion) {
-                    onCmdComplete(OMX_CommandFlush, kPortIndexInput);
+                    if (emulateInputFlushCompletion) {
+                        onCmdComplete(OMX_CommandFlush, kPortIndexInput);
+                    }
+
+                    if (emulateOutputFlushCompletion) {
+                        onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
+                    }
+#ifdef QCOM_HARDWARE
                 }
-
-                if (emulateOutputFlushCompletion) {
-                    onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
-                }
+#endif
             } else {
                 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
                 mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
@@ -3966,16 +4375,39 @@
 
         CHECK_EQ((int)mState, (int)EXECUTING);
 
-        bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
-        bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
+#ifdef QCOM_HARDWARE
+        //DSP supports flushing of ports simultaneously. Flushing individual port is not supported.
 
-        if (emulateInputFlushCompletion) {
-            onCmdComplete(OMX_CommandFlush, kPortIndexInput);
-        }
+        if(mQuirks & kRequiresGlobalFlush) {
+          bool emulateFlushCompletion = !flushPortAsync(kPortIndexBoth);
+          if (emulateFlushCompletion) {
+              onCmdComplete(OMX_CommandFlush, kPortIndexBoth);
+          }
+        } else {
 
-        if (emulateOutputFlushCompletion) {
-            onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
+        //DSP supports flushing of ports simultaneously.
+        //Flushing individual port is not supported.
+        if(mQuirks & kRequiresGlobalFlush) {
+            bool emulateFlushCompletion = !flushPortAsync(kPortIndexBoth);
+            if (emulateFlushCompletion) {
+                onCmdComplete(OMX_CommandFlush, kPortIndexBoth);
+            }
+        } else {
+#endif
+            bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
+            bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
+
+            if (emulateInputFlushCompletion) {
+                onCmdComplete(OMX_CommandFlush, kPortIndexInput);
+            }
+
+            if (emulateOutputFlushCompletion) {
+                onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
+            }
+#ifdef QCOM_HARDWARE
         }
+        }
+#endif
 
         while (mSeekTimeUs >= 0) {
             if ((err = waitForBufferFilled_l()) != OK) {
@@ -4553,9 +4985,46 @@
                 mOutputFormat->setInt32(kKeyChannelCount, numChannels);
                 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
                 mOutputFormat->setInt32(kKeyBitRate, bitRate);
+#ifdef QCOM_HARDWARE
+            } else if (audio_def->eEncoding == OMX_AUDIO_CodingQCELP13 ) {
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_QCELP);
+                int32_t numChannels, sampleRate, bitRate;
+                inputFormat->findInt32(kKeyChannelCount, &numChannels);
+                inputFormat->findInt32(kKeySampleRate, &sampleRate);
+                inputFormat->findInt32(kKeyBitRate, &bitRate);
+                mOutputFormat->setInt32(kKeyChannelCount, numChannels);
+                mOutputFormat->setInt32(kKeySampleRate, sampleRate);
+                mOutputFormat->setInt32(kKeyBitRate, bitRate);
+            } else if (audio_def->eEncoding == OMX_AUDIO_CodingEVRC ) {
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_EVRC);
+                int32_t numChannels, sampleRate, bitRate;
+                inputFormat->findInt32(kKeyChannelCount, &numChannels);
+                inputFormat->findInt32(kKeySampleRate, &sampleRate);
+                inputFormat->findInt32(kKeyBitRate, &bitRate);
+                mOutputFormat->setInt32(kKeyChannelCount, numChannels);
+                mOutputFormat->setInt32(kKeySampleRate, sampleRate);
+                mOutputFormat->setInt32(kKeyBitRate, bitRate);
             } else {
-                CHECK(!"Should not be here. Unknown audio encoding.");
+                AString mimeType;
+                if(OK == QCOMXCodec::checkQCFormats(audio_def->eEncoding, &mimeType)) {
+                    mOutputFormat->setCString(
+                            kKeyMIMEType, mimeType.c_str());
+                    int32_t numChannels, sampleRate, bitRate;
+                    inputFormat->findInt32(kKeyChannelCount, &numChannels);
+                    inputFormat->findInt32(kKeySampleRate, &sampleRate);
+                    inputFormat->findInt32(kKeyBitRate, &bitRate);
+                    mOutputFormat->setInt32(kKeyChannelCount, numChannels);
+                    mOutputFormat->setInt32(kKeySampleRate, sampleRate);
+                    mOutputFormat->setInt32(kKeyBitRate, bitRate);
+#endif
+                } else {
+                    CHECK(!"Should not be here. Unknown audio encoding.");
+                }
+#ifdef QCOM_HARDWARE
             }
+#endif
             break;
         }
 
@@ -4756,6 +5225,108 @@
     return QueryCodecs(omx, mimeType, queryDecoders, false /*hwCodecOnly*/, results);
 }
 
+#ifdef QCOM_HARDWARE
+void OMXCodec::setEVRCFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate) {
+    if (mIsEncoder) {
+      CHECK(numChannels == 1);
+        //////////////// input port ////////////////////
+        setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+        //////////////// output port ////////////////////
+        // format
+        OMX_AUDIO_PARAM_PORTFORMATTYPE format;
+        format.nPortIndex = kPortIndexOutput;
+        format.nIndex = 0;
+        status_t err = OMX_ErrorNone;
+        while (OMX_ErrorNone == err) {
+            CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioPortFormat,
+                    &format, sizeof(format)), (status_t)OK);
+            if (format.eEncoding == OMX_AUDIO_CodingEVRC) {
+                break;
+            }
+            format.nIndex++;
+        }
+        CHECK_EQ((status_t)OK, err);
+        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioPortFormat,
+                &format, sizeof(format)), (status_t)OK);
+
+        // port definition
+        OMX_PARAM_PORTDEFINITIONTYPE def;
+        InitOMXParams(&def);
+        def.nPortIndex = kPortIndexOutput;
+        def.format.audio.cMIMEType = NULL;
+        CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamPortDefinition,
+                &def, sizeof(def)), (status_t)OK);
+        def.format.audio.bFlagErrorConcealment = OMX_TRUE;
+        def.format.audio.eEncoding = OMX_AUDIO_CodingEVRC;
+        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition,
+                &def, sizeof(def)), (status_t)OK);
+
+        // profile
+        OMX_AUDIO_PARAM_EVRCTYPE profile;
+        InitOMXParams(&profile);
+        profile.nPortIndex = kPortIndexOutput;
+        CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioEvrc,
+                &profile, sizeof(profile)), (status_t)OK);
+        profile.nChannels = numChannels;
+        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioEvrc,
+                &profile, sizeof(profile)), (status_t)OK);
+    }
+    else{
+      ALOGI("EVRC decoder \n");
+    }
+}
+
+void OMXCodec::setQCELPFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate) {
+    if (mIsEncoder) {
+        CHECK(numChannels == 1);
+        //////////////// input port ////////////////////
+        setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+        //////////////// output port ////////////////////
+        // format
+        OMX_AUDIO_PARAM_PORTFORMATTYPE format;
+        format.nPortIndex = kPortIndexOutput;
+        format.nIndex = 0;
+        status_t err = OMX_ErrorNone;
+        while (OMX_ErrorNone == err) {
+            CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioPortFormat,
+                    &format, sizeof(format)), (status_t)OK);
+            if (format.eEncoding == OMX_AUDIO_CodingQCELP13) {
+                break;
+            }
+            format.nIndex++;
+        }
+        CHECK_EQ((status_t)OK, err);
+        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioPortFormat,
+                &format, sizeof(format)), (status_t)OK);
+
+        // port definition
+        OMX_PARAM_PORTDEFINITIONTYPE def;
+        InitOMXParams(&def);
+        def.nPortIndex = kPortIndexOutput;
+        def.format.audio.cMIMEType = NULL;
+        CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamPortDefinition,
+                &def, sizeof(def)), (status_t)OK);
+        def.format.audio.bFlagErrorConcealment = OMX_TRUE;
+        def.format.audio.eEncoding = OMX_AUDIO_CodingQCELP13;
+        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition,
+                &def, sizeof(def)), (status_t)OK);
+
+        // profile
+        OMX_AUDIO_PARAM_QCELP13TYPE profile;
+        InitOMXParams(&profile);
+        profile.nPortIndex = kPortIndexOutput;
+        CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioQcelp13,
+                &profile, sizeof(profile)), (status_t)OK);
+        profile.nChannels = numChannels;
+        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioQcelp13,
+                &profile, sizeof(profile)), (status_t)OK);
+    }
+    else{
+      ALOGI("QCELP decoder \n");
+    }
+}
+#endif
+
 // These are supposed be equivalent to the logic in
 // "audio_channel_out_mask_from_count".
 status_t getOMXChannelMapping(size_t numChannels, OMX_AUDIO_CHANNELTYPE map[]) {
diff --git a/media/libstagefright/QCMediaDefs.cpp b/media/libstagefright/QCMediaDefs.cpp
new file mode 100644
index 0000000..ec2d04e
--- /dev/null
+++ b/media/libstagefright/QCMediaDefs.cpp
@@ -0,0 +1,55 @@
+/*Copyright (c) 2012, 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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QCMediaDefs.h>
+
+namespace android {
+
+const char *MEDIA_MIMETYPE_AUDIO_EVRC = "audio/evrc";
+
+const char *MEDIA_MIMETYPE_VIDEO_WMV = "video/x-ms-wmv";
+const char *MEDIA_MIMETYPE_AUDIO_WMA = "audio/x-ms-wma";
+const char *MEDIA_MIMETYPE_CONTAINER_ASF = "video/x-ms-asf";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX = "video/divx";
+const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3";
+const char *MEDIA_MIMETYPE_CONTAINER_AAC = "audio/aac";
+const char *MEDIA_MIMETYPE_CONTAINER_QCP = "audio/vnd.qcelp";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX311 = "video/divx311";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX4 = "video/divx4";
+
+const char *MEDIA_MIMETYPE_CONTAINER_MPEG2 = "video/mp2";
+
+const char *MEDIA_MIMETYPE_CONTAINER_3G2 = "video/3g2";
+const char *MEDIA_MIMETYPE_AUDIO_DTS = "audio/dts";
+
+const char *MEDIA_MIMETYPE_AUDIO_DTS_LBR = "audio/dts-lbr";
+const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3";
+const char *MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS = "audio/amr-wb-plus";
+
+}  // namespace android
+
diff --git a/media/libstagefright/QCOMXCodec.cpp b/media/libstagefright/QCOMXCodec.cpp
new file mode 100644
index 0000000..1b24c8b
--- /dev/null
+++ b/media/libstagefright/QCOMXCodec.cpp
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2012, 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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "QCOMXCodec"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaCodecList.h>
+
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/QCOMXCodec.h>
+#include <media/stagefright/OMXCodec.h>
+#include <QCMetaData.h>
+#include <QCMediaDefs.h>
+#include <OMX_QCOMExtns.h>
+
+#include <OMX_Component.h>
+#include <QOMX_AudioExtensions.h>
+
+
+namespace android {
+
+uint32_t QCOMXCodec::getQCComponentQuirks(const MediaCodecList *list, size_t index) {
+    uint32_t quirks = 0;
+
+    if (list->codecHasQuirk(
+                index, "requires-wma-pro-component")) {
+        quirks |= kRequiresWMAProComponent;
+    }
+    return quirks;
+}
+
+void QCOMXCodec::setASFQuirks(uint32_t quirks, const sp<MetaData> &meta, const char* componentName) {
+    if(quirks & kRequiresWMAProComponent)
+    {
+       int32_t version;
+       CHECK(meta->findInt32(kKeyWMAVersion, &version));
+       if(version==kTypeWMA) {
+          componentName = "OMX.qcom.audio.decoder.wma";
+       } else if(version==kTypeWMAPro) {
+          componentName= "OMX.qcom.audio.decoder.wma10Pro";
+       } else if(version==kTypeWMALossLess) {
+          componentName= "OMX.qcom.audio.decoder.wmaLossLess";
+       }
+    }
+}
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+
+status_t QCOMXCodec::configureDIVXCodec(const sp<MetaData> &meta, char* mime, sp<IOMX> OMXhandle, IOMX::node_id nodeID, int port_index) {
+    status_t err = OK;
+    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime) ||
+        !strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime) ||
+        !strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)) {
+        ALOGV("Setting the QOMX_VIDEO_PARAM_DIVXTYPE params ");
+        QOMX_VIDEO_PARAM_DIVXTYPE paramDivX;
+        InitOMXParams(&paramDivX);
+        paramDivX.nPortIndex = port_index;
+        int32_t DivxVersion = 0;
+        CHECK(meta->findInt32(kKeyDivXVersion,&DivxVersion));
+        ALOGV("Divx Version Type %d\n",DivxVersion);
+
+        if(DivxVersion == kTypeDivXVer_4) {
+            paramDivX.eFormat = QOMX_VIDEO_DIVXFormat4;
+        } else if(DivxVersion == kTypeDivXVer_5) {
+            paramDivX.eFormat = QOMX_VIDEO_DIVXFormat5;
+        } else if(DivxVersion == kTypeDivXVer_6) {
+            paramDivX.eFormat = QOMX_VIDEO_DIVXFormat6;
+        } else if(DivxVersion == kTypeDivXVer_3_11 ) {
+            paramDivX.eFormat = QOMX_VIDEO_DIVXFormat311;
+        } else {
+            paramDivX.eFormat = QOMX_VIDEO_DIVXFormatUnused;
+        }
+        paramDivX.eProfile = (QOMX_VIDEO_DIVXPROFILETYPE)0;    //Not used for now.
+
+        err =  OMXhandle->setParameter(nodeID,
+                         (OMX_INDEXTYPE)OMX_QcomIndexParamVideoDivx,
+                         &paramDivX, sizeof(paramDivX));
+    }
+
+    return err;
+}
+
+void QCOMXCodec::checkAndAddRawFormat(OMXCodec *handle, const sp<MetaData> &meta){
+    uint32_t type;
+    const void *data;
+    size_t size;
+
+    if (meta->findData(kKeyRawCodecSpecificData, &type, &data, &size)) {
+        ALOGV("OMXCodec::configureCodec found kKeyRawCodecSpecificData of size %d\n", size);
+        handle->addCodecSpecificData(data, size);
+    }
+
+}
+
+status_t QCOMXCodec::setQCFormat(const sp<MetaData> &meta, char* mime, sp<IOMX> OMXhandle,
+                                     IOMX::node_id nodeID, OMXCodec *handle, bool isEncoder ) {
+    ALOGV("setQCFormat -- called ");
+    status_t err = OK;
+    if ((!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mime)) ||
+        (!strcasecmp(MEDIA_MIMETYPE_AUDIO_EAC3, mime))){
+        int32_t numChannels, sampleRate;
+        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+        setAC3Format(numChannels, sampleRate, OMXhandle, nodeID);
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_EVRC, mime)) {
+        int32_t numChannels, sampleRate;
+        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+        setEVRCFormat(numChannels, sampleRate, OMXhandle, nodeID, handle,isEncoder );
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_QCELP, mime)) {
+        int32_t numChannels, sampleRate;
+        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+        setQCELPFormat(numChannels, sampleRate, OMXhandle, nodeID, handle,isEncoder);
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_WMA, mime))  {
+        err = setWMAFormat(meta, OMXhandle, nodeID, isEncoder);
+    }
+    return err;
+}
+
+
+void QCOMXCodec::setEVRCFormat(int32_t numChannels, int32_t sampleRate, sp<IOMX> OMXhandle,
+                                    IOMX::node_id nodeID, OMXCodec *handle,  bool isEncoder ) {
+    ALOGV("setEVRCFormat -- called ");
+    if (isEncoder) {
+        CHECK(numChannels == 1);
+        //////////////// input port ////////////////////
+        handle->setRawAudioFormat(OMXCodec::kPortIndexInput, sampleRate, numChannels);
+        //////////////// output port ////////////////////
+        // format
+        OMX_AUDIO_PARAM_PORTFORMATTYPE format;
+        format.nPortIndex = OMXCodec::kPortIndexOutput;
+        format.nIndex = 0;
+        status_t err = OMX_ErrorNone;
+        while (OMX_ErrorNone == err) {
+            CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioPortFormat,
+                    &format, sizeof(format)), (status_t)OK);
+            if (format.eEncoding == OMX_AUDIO_CodingEVRC) {
+                break;
+            }
+            format.nIndex++;
+        }
+        CHECK_EQ((status_t)OK, err);
+        CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioPortFormat,
+                &format, sizeof(format)), (status_t)OK);
+
+        // port definition
+        OMX_PARAM_PORTDEFINITIONTYPE def;
+        InitOMXParams(&def);
+        def.nPortIndex = OMXCodec::kPortIndexOutput;
+        def.format.audio.cMIMEType = NULL;
+        CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamPortDefinition,
+                &def, sizeof(def)), (status_t)OK);
+        def.format.audio.bFlagErrorConcealment = OMX_TRUE;
+        def.format.audio.eEncoding = OMX_AUDIO_CodingEVRC;
+        CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamPortDefinition,
+                &def, sizeof(def)), (status_t)OK);
+
+        // profile
+        OMX_AUDIO_PARAM_EVRCTYPE profile;
+        InitOMXParams(&profile);
+        profile.nPortIndex = OMXCodec::kPortIndexOutput;
+        CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioEvrc,
+                &profile, sizeof(profile)), (status_t)OK);
+        profile.nChannels = numChannels;
+        CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioEvrc,
+                &profile, sizeof(profile)), (status_t)OK);
+    }
+    else{
+      ALOGI("EVRC decoder \n");
+    }
+}
+
+
+void QCOMXCodec::setQCELPFormat(int32_t numChannels, int32_t sampleRate, sp<IOMX> OMXhandle,
+                                     IOMX::node_id nodeID, OMXCodec *handle, bool isEncoder ) {
+    if (isEncoder) {
+        CHECK(numChannels == 1);
+        //////////////// input port ////////////////////
+        handle->setRawAudioFormat(OMXCodec::kPortIndexInput, sampleRate, numChannels);
+        //////////////// output port ////////////////////
+        // format
+        OMX_AUDIO_PARAM_PORTFORMATTYPE format;
+        format.nPortIndex = OMXCodec::kPortIndexOutput;
+        format.nIndex = 0;
+        status_t err = OMX_ErrorNone;
+        while (OMX_ErrorNone == err) {
+            CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioPortFormat,
+                    &format, sizeof(format)), (status_t)OK);
+            if (format.eEncoding == OMX_AUDIO_CodingQCELP13) {
+                break;
+            }
+            format.nIndex++;
+        }
+        CHECK_EQ((status_t)OK, err);
+        CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioPortFormat,
+                &format, sizeof(format)), (status_t)OK);
+
+        // port definition
+        OMX_PARAM_PORTDEFINITIONTYPE def;
+        InitOMXParams(&def);
+        def.nPortIndex = OMXCodec::kPortIndexOutput;
+        def.format.audio.cMIMEType = NULL;
+        CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamPortDefinition,
+                &def, sizeof(def)), (status_t)OK);
+        def.format.audio.bFlagErrorConcealment = OMX_TRUE;
+        def.format.audio.eEncoding = OMX_AUDIO_CodingQCELP13;
+        CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamPortDefinition,
+                &def, sizeof(def)), (status_t)OK);
+
+        // profile
+        OMX_AUDIO_PARAM_QCELP13TYPE profile;
+        InitOMXParams(&profile);
+        profile.nPortIndex = OMXCodec::kPortIndexOutput;
+        CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioQcelp13,
+                &profile, sizeof(profile)), (status_t)OK);
+        profile.nChannels = numChannels;
+        CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioQcelp13,
+                &profile, sizeof(profile)), (status_t)OK);
+    }
+    else {
+        ALOGI("QCELP decoder \n");
+    }
+}
+
+status_t QCOMXCodec::setWMAFormat(const sp<MetaData> &meta, sp<IOMX> OMXhandle,
+                                       IOMX::node_id nodeID, bool isEncoder ) {
+    ALOGV("setWMAFormat Called");
+    if (isEncoder) {
+        ALOGE("WMA encoding not supported");
+        return OK;
+    } else {
+        int32_t version;
+        OMX_AUDIO_PARAM_WMATYPE paramWMA;
+        QOMX_AUDIO_PARAM_WMA10PROTYPE paramWMA10;
+        CHECK(meta->findInt32(kKeyWMAVersion, &version));
+        int32_t numChannels;
+        int32_t bitRate;
+        int32_t sampleRate;
+        int32_t encodeOptions;
+        int32_t blockAlign;
+        int32_t bitspersample;
+        int32_t formattag;
+        int32_t advencopt1;
+        int32_t advencopt2;
+        int32_t VirtualPktSize;
+        if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+            CHECK(meta->findInt32(kKeyWMABitspersample, &bitspersample));
+            CHECK(meta->findInt32(kKeyWMAFormatTag, &formattag));
+            CHECK(meta->findInt32(kKeyWMAAdvEncOpt1,&advencopt1));
+            CHECK(meta->findInt32(kKeyWMAAdvEncOpt2,&advencopt2));
+            CHECK(meta->findInt32(kKeyWMAVirPktSize,&VirtualPktSize));
+        }
+        if(version==kTypeWMA) {
+            InitOMXParams(&paramWMA);
+            paramWMA.nPortIndex = OMXCodec::kPortIndexInput;
+        } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+            InitOMXParams(&paramWMA10);
+            paramWMA10.nPortIndex = OMXCodec::kPortIndexInput;
+        }
+        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+        CHECK(meta->findInt32(kKeyBitRate, &bitRate));
+        CHECK(meta->findInt32(kKeyWMAEncodeOpt, &encodeOptions));
+        CHECK(meta->findInt32(kKeyWMABlockAlign, &blockAlign));
+        ALOGV("Channels: %d, SampleRate: %d, BitRate; %d"
+                   "EncodeOptions: %d, blockAlign: %d", numChannels,
+                   sampleRate, bitRate, encodeOptions, blockAlign);
+        if(sampleRate>48000 || numChannels>2)
+        {
+            ALOGE("Unsupported samplerate/channels");
+            return ERROR_UNSUPPORTED;
+        }
+        if(version==kTypeWMAPro || version==kTypeWMALossLess)
+        {
+            ALOGV("Bitspersample: %d, wmaformattag: %d,"
+                       "advencopt1: %d, advencopt2: %d VirtualPktSize %d", bitspersample,
+                       formattag, advencopt1, advencopt2, VirtualPktSize);
+        }
+        status_t err = OK;
+        OMX_INDEXTYPE index;
+        if(version==kTypeWMA) {
+            err = OMXhandle->getParameter(
+                   nodeID, OMX_IndexParamAudioWma, &paramWMA, sizeof(paramWMA));
+        } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+            OMXhandle->getExtensionIndex(nodeID,"OMX.Qualcomm.index.audio.wma10Pro",&index);
+            err = OMXhandle->getParameter(
+                   nodeID, index, &paramWMA10, sizeof(paramWMA10));
+        }
+        CHECK_EQ(err, (status_t)OK);
+        if(version==kTypeWMA) {
+            paramWMA.nChannels = numChannels;
+            paramWMA.nSamplingRate = sampleRate;
+            paramWMA.nEncodeOptions = encodeOptions;
+            paramWMA.nBitRate = bitRate;
+            paramWMA.nBlockAlign = blockAlign;
+        } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+            paramWMA10.nChannels = numChannels;
+            paramWMA10.nSamplingRate = sampleRate;
+            paramWMA10.nEncodeOptions = encodeOptions;
+            paramWMA10.nBitRate = bitRate;
+            paramWMA10.nBlockAlign = blockAlign;
+        }
+        if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+            paramWMA10.advancedEncodeOpt = advencopt1;
+            paramWMA10.advancedEncodeOpt2 = advencopt2;
+            paramWMA10.formatTag = formattag;
+            paramWMA10.validBitsPerSample = bitspersample;
+            paramWMA10.nVirtualPktSize = VirtualPktSize;
+        }
+        if(version==kTypeWMA) {
+            err = OMXhandle->setParameter(
+                  nodeID, OMX_IndexParamAudioWma, &paramWMA, sizeof(paramWMA));
+        } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+           err = OMXhandle->setParameter(
+                 nodeID, index, &paramWMA10, sizeof(paramWMA10));
+        }
+        return err;
+    }
+    return OK;
+}
+
+
+void QCOMXCodec::setAC3Format(int32_t numChannels, int32_t sampleRate, sp<IOMX> OMXhandle,
+                                  IOMX::node_id nodeID) {
+    QOMX_AUDIO_PARAM_AC3TYPE profileAC3;
+    QOMX_AUDIO_PARAM_AC3PP profileAC3PP;
+    OMX_INDEXTYPE indexTypeAC3;
+    OMX_INDEXTYPE indexTypeAC3PP;
+    OMX_PARAM_PORTDEFINITIONTYPE portParam;
+
+    //configure input port
+    ALOGV("setAC3Format samplerate %d, numChannels %d", sampleRate, numChannels);
+    InitOMXParams(&portParam);
+    portParam.nPortIndex = 0;
+    status_t err = OMXhandle->getParameter(
+       nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+    CHECK_EQ(err, (status_t)OK);
+    err = OMXhandle->setParameter(
+       nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+    CHECK_EQ(err, (status_t)OK);
+
+    //configure output port
+    portParam.nPortIndex = 1;
+    err = OMXhandle->getParameter(
+       nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+    CHECK_EQ(err, (status_t)OK);
+    err = OMXhandle->setParameter(
+       nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+    CHECK_EQ(err, (status_t)OK);
+
+    err = OMXhandle->getExtensionIndex(nodeID, OMX_QCOM_INDEX_PARAM_AC3TYPE, &indexTypeAC3);
+
+    InitOMXParams(&profileAC3);
+    profileAC3.nPortIndex = OMXCodec::kPortIndexInput;
+    err = OMXhandle->getParameter(nodeID, indexTypeAC3, &profileAC3, sizeof(profileAC3));
+    CHECK_EQ(err,(status_t)OK);
+
+    profileAC3.nSamplingRate  =  sampleRate;
+    profileAC3.nChannels      =  2;
+    profileAC3.eChannelConfig =  OMX_AUDIO_AC3_CHANNEL_CONFIG_2_0;
+
+    ALOGV("numChannels = %d, profileAC3.nChannels = %d", numChannels, profileAC3.nChannels);
+
+    err = OMXhandle->setParameter(nodeID, indexTypeAC3, &profileAC3, sizeof(profileAC3));
+    CHECK_EQ(err,(status_t)OK);
+
+    //for output port
+    OMX_AUDIO_PARAM_PCMMODETYPE profilePcm;
+    InitOMXParams(&profilePcm);
+    profilePcm.nPortIndex = OMXCodec::kPortIndexOutput;
+    err = OMXhandle->getParameter(nodeID, OMX_IndexParamAudioPcm, &profilePcm, sizeof(profilePcm));
+    CHECK_EQ(err, (status_t)OK);
+
+    profilePcm.nSamplingRate  =  sampleRate;
+    err = OMXhandle->setParameter(nodeID, OMX_IndexParamAudioPcm, &profilePcm, sizeof(profilePcm));
+    CHECK_EQ(err, (status_t)OK);
+    OMXhandle->getExtensionIndex(nodeID, OMX_QCOM_INDEX_PARAM_AC3PP, &indexTypeAC3PP);
+
+    InitOMXParams(&profileAC3PP);
+    profileAC3PP.nPortIndex = OMXCodec::kPortIndexInput;
+    err = OMXhandle->getParameter(nodeID, indexTypeAC3PP, &profileAC3PP, sizeof(profileAC3PP));
+    CHECK_EQ(err, (status_t)OK);
+
+    int i;
+    int channel_routing[6];
+
+    for (i=0; i<6; i++) {
+        channel_routing[i] = -1;
+    }
+    for (i=0; i<6; i++) {
+        profileAC3PP.eChannelRouting[i] =  (OMX_AUDIO_AC3_CHANNEL_ROUTING)channel_routing[i];
+    }
+
+    profileAC3PP.eChannelRouting[0] =  OMX_AUDIO_AC3_CHANNEL_LEFT;
+    profileAC3PP.eChannelRouting[1] =  OMX_AUDIO_AC3_CHANNEL_RIGHT;
+    err = OMXhandle->setParameter(nodeID, indexTypeAC3PP, &profileAC3PP, sizeof(profileAC3PP));
+    CHECK_EQ(err, (status_t)OK);
+}
+
+
+status_t QCOMXCodec::setQCVideoInputFormat(const char *mime, OMX_VIDEO_CODINGTYPE *compressionFormat) {
+    status_t retVal = OK;
+    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime)){
+        *compressionFormat= (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime)){
+        *compressionFormat= (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)){
+        *compressionFormat= (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_WMV, mime)){
+        *compressionFormat = OMX_VIDEO_CodingWMV;
+    } else if (!strcasecmp(MEDIA_MIMETYPE_CONTAINER_MPEG2, mime)){
+        *compressionFormat = OMX_VIDEO_CodingMPEG2;
+    } else {
+        retVal = BAD_VALUE;
+    }
+
+    return retVal;
+}
+
+status_t QCOMXCodec::setQCVideoOutputFormat(const char *mime, OMX_VIDEO_CODINGTYPE *compressionFormat) {
+    status_t retVal = OK;
+    if(!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime)) {
+        *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+    } else if(!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)) {
+        *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+    } else if(!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime)) {
+        *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_WMV, mime)){
+        *compressionFormat = OMX_VIDEO_CodingWMV;
+    } else {
+        retVal = BAD_VALUE;
+    }
+    return retVal;
+}
+
+
+void QCOMXCodec::checkQCRole( const sp<IOMX> &omx, IOMX::node_id node,
+                                  bool isEncoder, const char *mime){
+    ALOGV("checkQCRole Called");
+    struct MimeToRole {
+        const char *mime;
+        const char *decoderRole;
+        const char *encoderRole;
+    };
+
+    static const MimeToRole kQCMimeToRole[] = {
+        { MEDIA_MIMETYPE_AUDIO_EVRC,
+          "audio_decoder.evrchw", "audio_encoder.evrc" },
+        { MEDIA_MIMETYPE_AUDIO_QCELP,
+          "audio_decoder,qcelp13Hw", "audio_encoder.qcelp13" },
+        { MEDIA_MIMETYPE_VIDEO_DIVX,
+          "video_decoder.divx", NULL },
+        { MEDIA_MIMETYPE_AUDIO_AC3,
+          "audio_decoder.ac3", NULL },
+        { MEDIA_MIMETYPE_VIDEO_DIVX311,
+          "video_decoder.divx", NULL },
+        };
+
+    static const size_t kNumMimeToRole =
+                     sizeof(kQCMimeToRole) / sizeof(kQCMimeToRole[0]);
+
+    size_t i;
+    for (i = 0; i < kNumMimeToRole; ++i) {
+        if (!strcasecmp(mime, kQCMimeToRole[i].mime)) {
+            break;
+        }
+    }
+
+    if (i == kNumMimeToRole) {
+        return;
+    }
+
+    const char *role =
+        isEncoder ? kQCMimeToRole[i].encoderRole
+                  : kQCMimeToRole[i].decoderRole;
+
+    if (role != NULL) {
+        OMX_PARAM_COMPONENTROLETYPE roleParams;
+        InitOMXParams(&roleParams);
+
+        strncpy((char *)roleParams.cRole,
+                role, OMX_MAX_STRINGNAME_SIZE - 1);
+
+        roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+        status_t err = omx->setParameter(
+                node, OMX_IndexParamStandardComponentRole,
+                &roleParams, sizeof(roleParams));
+
+        if (err != OK) {
+            ALOGW("Failed to set standard component role '%s'.", role);
+        }
+    }
+
+}
+
+status_t QCOMXCodec::checkQCFormats(int format, AString* meta){
+    ALOGV("checkQCFormats called");
+    status_t retVal = OK;
+    if (format == OMX_AUDIO_CodingQCELP13 ) {
+        *meta = MEDIA_MIMETYPE_AUDIO_QCELP;
+    } else if(format == OMX_AUDIO_CodingEVRC ) {
+        *meta = MEDIA_MIMETYPE_AUDIO_EVRC;
+    } else {
+        retVal = BAD_VALUE;
+    }
+    return retVal;
+}
+
+}
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index b7cf96e..510252a 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,7 +43,12 @@
         ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
         ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
         ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
-        ".avi", ".mpeg", ".mpg"
+        ".avi", ".mpg",
+#ifndef QCOM_HARDWARE
+       ".mpeg"
+#else
+        ".qcp", ".awb", ".ac3", ".dts", ".wmv"
+#endif
     };
     static const size_t kNumValidExtensions =
         sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/media/libstagefright/TunnelPlayer.cpp b/media/libstagefright/TunnelPlayer.cpp
new file mode 100644
index 0000000..34c260f
--- /dev/null
+++ b/media/libstagefright/TunnelPlayer.cpp
@@ -0,0 +1,782 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2009-2012, 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_NDDEBUG 0
+#define LOG_NDEBUG 0
+#define LOG_TAG "TunnelPlayer"
+#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/TunnelPlayer.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[] = "TunnelPlayer";
+#define MEM_METADATA_SIZE 64
+#define MEM_BUFFER_SIZE (600*1024 - MEM_METADATA_SIZE)
+#define MEM_BUFFER_COUNT 4
+
+namespace android {
+int TunnelPlayer::mTunnelObjectsAlive = 0;
+
+TunnelPlayer::TunnelPlayer(
+                    const sp<MediaPlayerBase::AudioSink> &audioSink, bool &initCheck,
+                    AwesomePlayer *observer, bool hasVideo)
+: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) {
+    ALOGD("TunnelPlayer::TunnelPlayer()");
+    mTunnelObjectsAlive++;
+    numChannels = 0;
+    mPaused = false;
+    mIsA2DPEnabled = false;
+    mAudioFlinger = NULL;
+    mAudioFlingerClient = NULL;
+    mFormat = AUDIO_FORMAT_MP3;
+    mQueue.start();
+    mQueueStarted      = true;
+    mPauseEvent        = new TunnelEvent(this, &TunnelPlayer::onPauseTimeOut);
+    mPauseEventPending = false;
+
+    //getAudioFlinger();
+    //ALOGD("Registering client with AudioFlinger");
+    //mAudioFlinger->registerClient(mAudioFlingerClient);
+
+    mSeekTimeUs = 0;
+
+    mHasVideo = hasVideo;
+    initCheck = true;
+
+    //mDeathRecipient = new PMDeathRecipient(this);
+}
+void TunnelPlayer::acquireWakeLock()
+{
+    /*Mutex::Autolock _l(pmLock);
+
+    if (mPowerManager == 0) {
+        // use checkService() to avoid blocking if power service is not up yet
+        sp<IBinder> binder =
+            defaultServiceManager()->checkService(String16("power"));
+        if (binder == 0) {
+            ALOGW("Thread %s cannot connect to the power manager service", mName);
+        } else {
+            mPowerManager = interface_cast<IPowerManager>(binder);
+            binder->linkToDeath(mDeathRecipient);
+        }
+    }
+    if (mPowerManager != 0 && mWakeLockToken == 0) {
+        sp<IBinder> binder = new BBinder();
+        status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
+                                                         binder,
+                                                         String16(mName));
+        if (status == NO_ERROR) {
+            mWakeLockToken = binder;
+        }
+        ALOGV("acquireWakeLock() %s status %d", mName, status);
+    }*/
+}
+
+void TunnelPlayer::releaseWakeLock()
+{
+    /*Mutex::Autolock _l(pmLock);
+
+    if (mWakeLockToken != 0) {
+        ALOGV("releaseWakeLock() %s", mName);
+        if (mPowerManager != 0) {
+            mPowerManager->releaseWakeLock(mWakeLockToken, 0);
+        }
+        mWakeLockToken.clear();
+    }*/
+}
+
+void TunnelPlayer::clearPowerManager()
+{
+    Mutex::Autolock _l(pmLock);
+    releaseWakeLock();
+    mPowerManager.clear();
+}
+
+void TunnelPlayer::PMDeathRecipient::binderDied(const wp<IBinder>& who)
+{
+    parentClass->clearPowerManager();
+    ALOGW("power manager service died !!!");
+}
+
+TunnelPlayer::~TunnelPlayer() {
+    ALOGD("TunnelPlayer::~TunnelPlayer()");
+    if (mQueueStarted) {
+        mQueue.stop();
+    }
+
+    reset();
+    //mAudioFlinger->deregisterClient(mAudioFlingerClient);
+    mTunnelObjectsAlive--;
+
+    releaseWakeLock();
+    if (mPowerManager != 0) {
+        sp<IBinder> binder = mPowerManager->asBinder();
+        binder->unlinkToDeath(mDeathRecipient);
+    }
+
+
+}
+
+void TunnelPlayer::getAudioFlinger() {
+/*    Mutex::Autolock _l(mAudioFlingerLock);
+
+    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 ( mAudioFlingerClient == NULL ) {
+            mAudioFlingerClient = new AudioFlingerTunnelDecodeClient(this);
+        }
+
+        binder->linkToDeath(mAudioFlingerClient);
+        mAudioFlinger = interface_cast<IAudioFlinger>(binder);
+    }
+    ALOGE_IF(mAudioFlinger==0, "no AudioFlinger!?");*/
+}
+
+/*TunnelPlayer::AudioFlingerTunnelDecodeClient::AudioFlingerTunnelDecodeClient(void *obj)
+{
+    ALOGD("TunnelPlayer::AudioFlingerTunnelDecodeClient - Constructor");
+    pBaseClass = (TunnelPlayer*)obj;
+}
+
+void TunnelPlayer::AudioFlingerTunnelDecodeClient::binderDied(const wp<IBinder>& who) {
+    Mutex::Autolock _l(pBaseClass->mAudioFlingerLock);
+
+    pBaseClass->mAudioFlinger.clear();
+    ALOGW("AudioFlinger server died!");
+}*/
+
+/*void TunnelPlayer::AudioFlingerTunnelDecodeClient::ioConfigChanged(int event, int ioHandle, void *param2) {
+    ALOGV("ioConfigChanged() event %d", event);
+
+
+    if (event != AudioSystem::A2DP_OUTPUT_STATE) {
+        return;
+    }
+
+    switch ( event ) {
+    case AudioSystem::A2DP_OUTPUT_STATE:
+        {
+            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;
+    default:
+        break;
+    }
+    ALOGV("ioConfigChanged Out");
+}*/
+
+/*void TunnelPlayer::handleA2DPSwitch() {
+    //TODO: Implement
+}
+*/
+
+void TunnelPlayer::setSource(const sp<MediaSource> &source) {
+    CHECK(mSource == NULL);
+    ALOGD("Setting source from Tunnel Player");
+    mSource = source;
+}
+
+status_t TunnelPlayer::start(bool sourceAlreadyStarted) {
+    CHECK(!mStarted);
+    CHECK(mSource != NULL);
+
+    ALOGD("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);
+    if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC)) {
+        mFormat = AUDIO_FORMAT_AAC;
+    }
+    if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
+        mFormat = AUDIO_FORMAT_AMR_WB;
+        ALOGV("TunnelPlayer::start AUDIO_FORMAT_AMR_WB");
+    }
+//    if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS)) {
+//        mFormat = AUDIO_FORMAT_AMR_WB_PLUS;
+//        ALOGV("TunnelPlayer::start AUDIO_FORMAT_AMR_WB_PLUS");
+//    }
+
+    CHECK(success);
+
+    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;
+    }
+    audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_TUNNEL |
+                                                         AUDIO_OUTPUT_FLAG_DIRECT);
+    ALOGV("mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",mSampleRate, numChannels, mChannelMask, flags);
+    err = mAudioSink->open(
+        mSampleRate, numChannels, mChannelMask, mFormat,
+        DEFAULT_AUDIOSINK_BUFFERCOUNT,
+        &TunnelPlayer::AudioSinkCallback,
+        this,
+        (mA2DPEnabled ? AUDIO_OUTPUT_FLAG_NONE : flags));
+
+    if (err != OK) {
+        if (mFirstBuffer != NULL) {
+            mFirstBuffer->release();
+            mFirstBuffer = NULL;
+        }
+
+        if (!sourceAlreadyStarted) {
+            mSource->stop();
+        }
+
+        ALOGE("Opening a routing session failed");
+        return err;
+    }
+
+    if (!mIsA2DPEnabled) {
+        acquireWakeLock();
+    }
+
+    mIsAudioRouted = true;
+    mStarted = true;
+    mAudioSink->start();
+    ALOGV("Waking up decoder thread");
+    pthread_cond_signal(&extractor_cv);
+
+    return OK;
+}
+
+status_t TunnelPlayer::seekTo(int64_t time_us) {
+
+    ALOGV("seekTo: time_us %lld", time_us);
+    if ( mReachedEOS ) {
+        mReachedEOS = false;
+        mReachedOutputEOS = false;
+    }
+    mSeeking = true;
+    mSeekTimeUs = time_us;
+    ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);
+    mAudioSink->flush();
+    pthread_cond_signal(&extractor_cv);
+    //TODO: Update the mPauseTime
+    return OK;
+}
+void TunnelPlayer::pause(bool playPendingSamples) {
+    CHECK(mStarted);
+    if (mPaused) {
+        return;
+    }
+    ALOGV("pause: playPendingSamples %d", playPendingSamples);
+    mPaused = true;
+    A2DPState state;
+    if(!mPauseEventPending) {
+        ALOGV("Posting an event for Pause timeout");
+        mQueue.postEventWithDelay(mPauseEvent, TUNNEL_PAUSE_TIMEOUT_USEC);
+        mPauseEventPending = true;
+    }
+    mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_DISABLED);
+    if (mAudioSink.get() != NULL) {
+        ALOGV("AudioSink pause");
+        mAudioSink->pause();
+    }
+}
+
+void TunnelPlayer::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());
+            }
+
+        }
+        audio_format_t format;
+
+        if (!mIsAudioRouted) {
+            audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_TUNNEL |
+                                                                AUDIO_OUTPUT_FLAG_DIRECT);
+            status_t err = mAudioSink->open(
+                mSampleRate, numChannels, mChannelMask, mFormat,
+                DEFAULT_AUDIOSINK_BUFFERCOUNT,
+                &TunnelPlayer::AudioSinkCallback,
+                this,
+                (mA2DPEnabled ?  AUDIO_OUTPUT_FLAG_NONE : flags ));
+            if (err != NO_ERROR) {
+                ALOGE("Audio sink open failed.");
+            }
+            mIsAudioRouted = true;
+        }
+        mPaused = false;
+        mAudioSink->start();
+        pthread_cond_signal(&extractor_cv);
+    }
+}
+
+//static
+size_t TunnelPlayer::AudioSinkCallback(
+        MediaPlayerBase::AudioSink *audioSink,
+        void *buffer, size_t size, void *cookie) {
+    if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
+        TunnelPlayer *me = (TunnelPlayer *)cookie;
+        me->mReachedEOS = true;
+        me->mReachedOutputEOS = true;
+        ALOGV("postAudioEOS");
+        me->mObserver->postAudioEOS(0);
+    }
+    return 1;
+}
+
+void TunnelPlayer::reset() {
+
+    mReachedEOS = true;
+
+    // make sure Decoder thread has exited
+    requestAndWaitForExtractorThreadExit();
+
+    // Close the audiosink after all the threads exited to make sure
+    mAudioSink->stop();
+    mAudioSink->close();
+    //TODO: Release Wake lock
+
+    // 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 TunnelPlayer::isSeeking() {
+    Mutex::Autolock autoLock(mLock);
+    return mSeeking;
+}
+
+bool TunnelPlayer::reachedEOS(status_t *finalStatus) {
+    *finalStatus = OK;
+    Mutex::Autolock autoLock(mLock);
+    *finalStatus = mFinalStatus;
+    return mReachedOutputEOS;
+}
+
+
+void *TunnelPlayer::extractorThreadWrapper(void *me) {
+    static_cast<TunnelPlayer *>(me)->extractorThreadEntry();
+    return NULL;
+}
+
+
+void TunnelPlayer::extractorThreadEntry() {
+
+    pthread_mutex_lock(&extractor_mutex);
+    uint32_t BufferSizeToUse = MEM_BUFFER_SIZE;
+
+    pid_t tid  = gettid();
+    androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+    prctl(PR_SET_NAME, (unsigned long)"Tunnel DecodeThread", 0, 0, 0);
+
+    ALOGV("extractorThreadEntry wait for signal \n");
+    if (!mStarted) {
+        pthread_cond_wait(&extractor_cv, &extractor_mutex);
+    }
+    ALOGV("extractorThreadEntry ready to work \n");
+    pthread_mutex_unlock(&extractor_mutex);
+    if (killExtractorThread) {
+        return;
+    }
+    if(mSource != NULL) {
+        sp<MetaData> format = mSource->getFormat();
+        const char *mime;
+        bool success = format->findCString(kKeyMIMEType, &mime);
+    }
+    void* local_buf = malloc(BufferSizeToUse);
+    int bytesWritten = 0;
+    while (!killExtractorThread) {
+
+        if (mReachedEOS || mPaused || !mIsAudioRouted) {
+            pthread_mutex_lock(&extractor_mutex);
+            pthread_cond_wait(&extractor_cv, &extractor_mutex);
+            pthread_mutex_unlock(&extractor_mutex);
+            continue;
+        }
+
+        if (!mIsA2DPEnabled) {
+            ALOGW("FillBuffer: MemBuffer size %d", BufferSizeToUse);
+            ALOGV("Fillbuffer started");
+            bytesWritten = fillBuffer(local_buf, BufferSizeToUse);
+            ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+            if(!killExtractorThread) {
+                mAudioSink->write(local_buf, bytesWritten);
+                if(mReachedEOS && bytesWritten)
+                    mAudioSink->write(local_buf, 0);
+            }
+        }
+    }
+
+    free(local_buf);
+
+    //TODO: Call fillbuffer with different size and write to mAudioSink()
+}
+void TunnelPlayer::createThreads() {
+
+    //Initialize all the Mutexes and Condition Variables
+    pthread_mutex_init(&extractor_mutex, NULL);
+    pthread_cond_init (&extractor_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);
+
+    killExtractorThread = false;
+
+    extractorThreadAlive = true;
+
+    ALOGV("Creating decoder Thread");
+    pthread_create(&extractorThread, &attr, extractorThreadWrapper, this);
+
+    pthread_attr_destroy(&attr);
+}
+size_t TunnelPlayer::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;
+                }
+
+                MediaSource::ReadOptions::SeekMode seekMode;
+                seekMode = MediaSource::ReadOptions::SEEK_CLOSEST_SYNC;
+                options.setSeekTo(mSeekTimeUs, seekMode );
+                if (mInputBuffer != NULL) {
+                    mInputBuffer->release();
+                    mInputBuffer = NULL;
+                }
+
+                // This is to ignore the data already filled in the output buffer
+                size_done = 0;
+                size_remaining = size;
+
+                mSeeking = false;
+                if (mObserver && !mInternalSeeking) {
+                    ALOGD("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) {
+                    ALOGD("fill buffer - reached eos true");
+                    mReachedEOS = true;
+                    mFinalStatus = err;
+                    break;
+                }
+            }
+
+        }
+        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(mReachedEOS)
+        memset((char *)data + size_done, 0x0, size_remaining);
+    ALOGV("fill buffer size_done = %d",size_done);
+
+    if (postSeekComplete) {
+        mObserver->postAudioSeekComplete();
+    }
+
+    return size_done;
+}
+
+int64_t TunnelPlayer::getRealTimeUs() {
+    Mutex::Autolock autoLock(mLock);
+    return getRealTimeUsLocked();
+}
+
+
+int64_t TunnelPlayer::getRealTimeUsLocked(){
+    //Used for AV sync: irrelevant API for Tunnel.
+    return 0;
+}
+
+int64_t TunnelPlayer::getTimeStamp(A2DPState state) {
+    uint64_t timestamp = 0;
+    switch (state) {
+    case A2DP_ENABLED:
+    case A2DP_DISCONNECT:
+        ALOGV("Get timestamp for A2DP");
+        break;
+    case A2DP_DISABLED:
+    case A2DP_CONNECT: {
+        mAudioSink->getTimeStamp(&timestamp);
+        break;
+    }
+    default:
+        break;
+    }
+    ALOGV("timestamp %lld ", timestamp);
+    return timestamp;
+}
+
+int64_t TunnelPlayer::getMediaTimeUs() {
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime);
+    if (mPaused) {
+        return mPauseTime;
+    } else {
+        A2DPState state = mIsA2DPEnabled ? A2DP_ENABLED : A2DP_DISABLED;
+        return (mSeekTimeUs + getTimeStamp(state));
+    }
+}
+
+bool TunnelPlayer::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 TunnelPlayer::requestAndWaitForExtractorThreadExit() {
+
+    if (!extractorThreadAlive)
+        return;
+    mAudioSink->flush();
+    killExtractorThread = true;
+    pthread_cond_signal(&extractor_cv);
+    pthread_join(extractorThread,NULL);
+    ALOGD("Extractor thread killed");
+}
+
+void TunnelPlayer::onPauseTimeOut() {
+    ALOGV("onPauseTimeOut");
+    if (!mPauseEventPending) {
+        return;
+    }
+    mPauseEventPending = false;
+    if(!mIsA2DPEnabled) {
+        // 1.) Set seek flags
+        mReachedEOS = false;
+        mReachedOutputEOS = false;
+        mSeekTimeUs += getTimeStamp(A2DP_DISABLED);
+        mInternalSeeking = true;
+
+        // 2.) Close routing Session
+        mAudioSink->close();
+        mIsAudioRouted = false;
+
+        // 3.) Release Wake Lock
+        releaseWakeLock();
+    }
+
+}
+
+} //namespace android
diff --git a/media/libstagefright/WAVEWriter.cpp b/media/libstagefright/WAVEWriter.cpp
new file mode 100644
index 0000000..9700fa7
--- /dev/null
+++ b/media/libstagefright/WAVEWriter.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2012, 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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "WAVEWriter"
+#include <utils/Log.h>
+
+#include <media/stagefright/WAVEWriter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/mediarecorder.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android {
+
+static struct wav_header hdr;
+
+
+WAVEWriter::WAVEWriter(const char *filename)
+    : mFd(-1),
+      mInitCheck(NO_INIT),
+      mStarted(false),
+      mPaused(false),
+      mResumed(false) {
+
+    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+    if (mFd >= 0) {
+        mInitCheck = OK;
+    }
+}
+
+WAVEWriter::WAVEWriter(int fd)
+    : mFd(dup(fd)),
+      mInitCheck(mFd < 0? NO_INIT: OK),
+      mStarted(false),
+      mPaused(false),
+      mResumed(false) {
+}
+
+WAVEWriter::~WAVEWriter() {
+    if (mStarted) {
+        stop();
+    }
+
+    if (mFd != -1) {
+        close(mFd);
+        mFd = -1;
+    }
+}
+
+status_t WAVEWriter::initCheck() const {
+    return mInitCheck;
+}
+
+status_t WAVEWriter::addSource(const sp<MediaSource> &source) {
+    uint32_t count;
+    if (mInitCheck != OK) {
+        ALOGE("Init Check not OK, return");
+        return mInitCheck;
+    }
+
+    if (mSource != NULL) {
+        ALOGE("A source already exists, return");
+        return UNKNOWN_ERROR;
+    }
+
+    sp<MetaData> meta = source->getFormat();
+
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    int32_t channelCount;
+    int32_t sampleRate;
+    CHECK(meta->findInt32(kKeyChannelCount, &channelCount));
+    CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+
+    memset(&hdr, 0, sizeof(struct wav_header));
+    hdr.riff_id = ID_RIFF;
+    hdr.riff_fmt = ID_WAVE;
+    hdr.fmt_id = ID_FMT;
+    hdr.fmt_sz = 16;
+    hdr.audio_format = FORMAT_PCM;
+    hdr.num_channels = channelCount;
+    hdr.sample_rate = sampleRate;
+    hdr.bits_per_sample = 16;
+    hdr.byte_rate = (sampleRate * channelCount * hdr.bits_per_sample) / 8;
+    hdr.block_align = ( hdr.bits_per_sample * channelCount ) / 8;
+    hdr.data_id = ID_DATA;
+    hdr.data_sz = 0;
+    hdr.riff_sz = hdr.data_sz + 44 - 8;
+
+    if (write(mFd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+        ALOGE("Write header error, return ERROR_IO");
+        return -ERROR_IO;
+    }
+
+    mSource = source;
+
+    return OK;
+}
+
+status_t WAVEWriter::start(MetaData *params) {
+    if (mInitCheck != OK) {
+        ALOGE("Init Check not OK, return");
+        return mInitCheck;
+    }
+
+    if (mSource == NULL) {
+        ALOGE("NULL Source");
+        return UNKNOWN_ERROR;
+    }
+
+    if (mStarted && mPaused) {
+        mPaused = false;
+        mResumed = true;
+        return OK;
+    } else if (mStarted) {
+        ALOGE("Already startd, return");
+        return OK;
+    }
+
+    status_t err = mSource->start();
+
+    if (err != OK) {
+        return err;
+    }
+
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    mReachedEOS = false;
+    mDone = false;
+
+    pthread_create(&mThread, &attr, ThreadWrapper, this);
+    pthread_attr_destroy(&attr);
+
+    mStarted = true;
+
+    return OK;
+}
+
+status_t WAVEWriter::pause() {
+    if (!mStarted) {
+        return OK;
+    }
+    mPaused = true;
+    return OK;
+}
+
+status_t WAVEWriter::stop() {
+    if (!mStarted) {
+        return OK;
+    }
+
+    mDone = true;
+
+    void *dummy;
+    pthread_join(mThread, &dummy);
+
+    status_t err = (status_t) dummy;
+    {
+        status_t status = mSource->stop();
+        if (err == OK &&
+            (status != OK && status != ERROR_END_OF_STREAM)) {
+            err = status;
+        }
+    }
+
+    mStarted = false;
+    return err;
+}
+
+bool WAVEWriter::exceedsFileSizeLimit() {
+    if (mMaxFileSizeLimitBytes == 0) {
+        return false;
+    }
+    return mEstimatedSizeBytes >= mMaxFileSizeLimitBytes;
+}
+
+bool WAVEWriter::exceedsFileDurationLimit() {
+    if (mMaxFileDurationLimitUs == 0) {
+        return false;
+    }
+    return mEstimatedDurationUs >= mMaxFileDurationLimitUs;
+}
+
+// static
+void *WAVEWriter::ThreadWrapper(void *me) {
+    return (void *) static_cast<WAVEWriter *>(me)->threadFunc();
+}
+
+status_t WAVEWriter::threadFunc() {
+    mEstimatedDurationUs = 0;
+    mEstimatedSizeBytes = 0;
+    bool stoppedPrematurely = true;
+    int64_t previousPausedDurationUs = 0;
+    int64_t maxTimestampUs = 0;
+    status_t err = OK;
+
+    prctl(PR_SET_NAME, (unsigned long)"WAVEWriter", 0, 0, 0);
+    hdr.data_sz = 0;
+    while (!mDone) {
+        MediaBuffer *buffer;
+        err = mSource->read(&buffer);
+
+        if (err != OK) {
+            break;
+        }
+
+        if (mPaused) {
+            buffer->release();
+            buffer = NULL;
+            continue;
+        }
+
+        mEstimatedSizeBytes += buffer->range_length();
+        if (exceedsFileSizeLimit()) {
+            buffer->release();
+            buffer = NULL;
+            notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
+            break;
+        }
+
+        int64_t timestampUs;
+        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
+        if (timestampUs > mEstimatedDurationUs) {
+            mEstimatedDurationUs = timestampUs;
+        }
+        if (mResumed) {
+            previousPausedDurationUs += (timestampUs - maxTimestampUs - 20000);
+            mResumed = false;
+        }
+        timestampUs -= previousPausedDurationUs;
+        ALOGV("time stamp: %lld, previous paused duration: %lld",
+                timestampUs, previousPausedDurationUs);
+        if (timestampUs > maxTimestampUs) {
+            maxTimestampUs = timestampUs;
+        }
+
+        if (exceedsFileDurationLimit()) {
+            buffer->release();
+            buffer = NULL;
+            notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
+            break;
+        }
+        ssize_t n = write(mFd,
+                        (const uint8_t *)buffer->data() + buffer->range_offset(),
+                        buffer->range_length());
+
+        hdr.data_sz += (ssize_t)buffer->range_length();
+        hdr.riff_sz = hdr.data_sz + 44 - 8;
+
+        if (n < (ssize_t)buffer->range_length()) {
+            buffer->release();
+            buffer = NULL;
+
+            break;
+        }
+
+        if (stoppedPrematurely) {
+            stoppedPrematurely = false;
+        }
+
+        buffer->release();
+        buffer = NULL;
+    }
+
+    if (stoppedPrematurely) {
+        notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, UNKNOWN_ERROR);
+    }
+
+    lseek(mFd, 0, SEEK_SET);
+    write(mFd, &hdr, sizeof(hdr));
+    lseek(mFd, 0, SEEK_END);
+
+    close(mFd);
+    mFd = -1;
+    mReachedEOS = true;
+    if (err == ERROR_END_OF_STREAM) {
+        return OK;
+    }
+    return err;
+}
+
+bool WAVEWriter::reachedEOS() {
+    return mReachedEOS;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 1422687..107c5da 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -200,6 +200,9 @@
 
     bool mWatchForAudioSeekComplete;
     bool mWatchForAudioEOS;
+#ifdef QCOM_ENHANCED_AUDIO
+    static int mTunnelAliveAP;
+#endif
 
     sp<TimedEventQueue::Event> mVideoEvent;
     bool mVideoEventPending;
@@ -339,6 +342,11 @@
 
     size_t countTracks() const;
 
+#ifdef QCOM_ENHANCED_AUDIO
+    //Flag to check if tunnel mode audio is enabled
+    bool mIsTunnelAudio;
+#endif
+
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
 };
diff --git a/media/libstagefright/include/ExtendedExtractor.h b/media/libstagefright/include/ExtendedExtractor.h
new file mode 100644
index 0000000..e7d8704
--- /dev/null
+++ b/media/libstagefright/include/ExtendedExtractor.h
@@ -0,0 +1,58 @@
+/*Copyright (c) 2012, 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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef EXTENDED_EXTRACTOR_
+#define EXTENDED_EXTRACTOR_
+
+#include <media/stagefright/DataSource.h>
+
+namespace android {
+
+class MediaExtractor;
+
+typedef MediaExtractor* (*MediaExtractorFactory)(const sp<DataSource> &source, const char* mime);
+
+static const char* MEDIA_CREATE_EXTRACTOR = "CreateExtractor";
+
+typedef bool (*ExtendedExtractorSniffers)(const sp<DataSource> &source, String8 *mimeType,
+                                          float *confidence,sp<AMessage> *meta);
+
+static const char* EXTENDED_EXTRACTOR_SNIFFERS = "SniffExtendedExtractor";
+
+class ExtendedExtractor
+{
+public:
+    static MediaExtractor* CreateExtractor(const sp<DataSource> &source, const char *mime);
+};
+
+bool SniffExtendedExtractor(const sp<DataSource> &source, String8 *mimeType,
+                               float *confidence,sp<AMessage> *meta);
+
+}  // namespace android
+
+#endif //EXTENDED_EXTRACTOR_