frameworks/av: Squashed commit of media features from CAF

 * Completely synced with kk_2.7_rb1.9 branch, as of:

       libmedia: Add QC enhancements to MediaProfiles.

 * Following patch reverted for now, because it doesn't compile:

       frameworks/av: Enable subsystem re-start for LPA/Tunnel

---
MediaProfiles: Add support for camcorder video resolutions.

Added video resolutions to support camcorder recording.
(cherry picked from commit I2291de43ae2be7338c673f2f0417ec5c1581391e)

Change-Id: I309fa41cfa36ee0551a8a7c53072089858a2c66a
(cherry picked from commit 805cb98f40acfb242206b7db71c50bc56ea77d2a)
(cherry picked from commit 68c1f41295f4be54ed13af20ebd1041890d2f3ca)
(cherry picked from commit 5a74f7e0e0fbec707333a1f7481d85961aff3908)

frameworks/av: Add support for FM feature

Add FM handle key and volume key to AudioParamater
class which is used to initimate Audio HAL to
that FM device is connected and apply correct
volume to FM stream

Change-Id: If5fa14faf7946ab27eb42b89546dc2274b24f754
(cherry picked from commit 165f20759433d0137a292b457aa783f801f13277)
(cherry picked from commit c98b484de0877e159f00b3b01d622b6539f0b2bc)
(cherry picked from commit f752d489bb85a94b81d38c72333409b4384d860a)

libstagefright:add enhancements for extended format support

Extended-extractor to support extended container format.
 - Introduce an Extended Extractor to facilitate plugging-in
   of parsers extensions.

Extended-codec to configure codec specific configurations.
 - configures omx component with extensions to augment
   container/codec format-suppor

Extended-utility to add utility methods and shell extensions.
 - Utility methods for supporting following features
  - High Frame Rate (HFR) recording
  - Support for B frame encoding

Change-Id: I77a40af701916f1803fa9c6af3c43a312a8d2c98
(cherry picked from commit ab6a474cd9acc7bc54c54a7c235f6eab032349ca)
(cherry picked from commit fe07c231dbecd255aedbf7aac597260831eb98cf)
(cherry picked from commit df7b013ceeeb4697f448a2d150ae75b86c325013)

libstagefright:enable extended codec/format support

Configure omx component with extended extensions and
register exended-extractor to augment container/codec
support.

Change-Id: I0bfa4bd6c4dfed93a96e1af431018de54d6fb57b
(cherry picked from commit 318c38f40b53e1987473b29a359e586615bf3c02)
(cherry picked from commit 4a0e6d65c200604a9618e2fc90326031153e6f08)
(cherry picked from commit f9b65059fabc1c24ae5107b54f96a017e8fc7376)

libstagefright: For interlace, set decoder in arbitrary mode

In arbitrary mode, frame parsers sends individual fields
to core. Once both the field is decoded, output done (FBD)
is sent back to client.
Default frame by frame mode will send both the fields in
a single buffer to core, which might decode only one field
or will throw up error.

CRs-Fixed: 531034
Change-Id: I31844093b6a93d3a62577fc8d799353d30573c17
(cherry picked from commit cb45f5a702992242538fab6d9e2c36b7b8e55c7f)
(cherry picked from commit 214938ef4f9997233a33a24e9e9e9751a1fa1882)
(cherry picked from commit 646e3bdce1c8241fb46802e7eba3c4f8a528517d)

audio: add support for MSM audio formats

- Add support for EVRC, QCELP, AMRWB+, and WMA formats
- Refernece change If110058284c8b3e18c2f242f560fc7748f62081c form jb-mr2

Change-Id: Ie20f2d61f79d2ba41d552718187b7098141e7b8c
(cherry picked from commit bca561e38853351c0bae15c5d201dbca7f5a027e)
(cherry picked from commit a11972f505000be397ee3a377ec42bf9e5fef420)
(cherry picked from commit 7465e6129b291c66dc7741325a90e3725e40e941)

libstagefright: fix metadata key sizes

 - some wma metadata keys should be treated as 32 bit keys instead
   of 64 bits.
 - fixes wma lossless from failing

Change-Id: Ic6af8392aea6a1bd8810dac59e1d1c27c21c4059
(cherry picked from commit 1fae0bcb8ef9244e1f28d21c36e388ab365e3c0f)
(cherry picked from commit 97be73e3004a838227060f026f38c7231dd7e2f7)
(cherry picked from commit 4d24c91e49c89eadb7b48e47e38a9b7b6df8f1cf)

frameworks/av: Add support for LPA and Tunnel Playback

-Add DirectTrack and DirectTrackClient
-DirectTrack enables client to create a direct
 output
-DirectTrackClient allows notifications to be sent to the
 client from DirectTrack.
-DirectTrack is being used for Low Power Audio
 playback and Tunnel Audio playback
Change-Id: I265ae1fa32c6fdd8be0382cc2b28605bc756a2f3
(cherry picked from commit b255c1963bb3af6f547b68d646737a7c92739555)
(cherry picked from commit 7cb21f77ae28f58da1cb8ba8f684b2968dcd4122)
(cherry picked from commit d4fa9e74c1ee1c2f7f7262c245da0b94dc0ac05b)

frameworks/av: port fixes in LPA and Tunnel mode playback

No History was maintained during porting. Updating the Description
and CR's of all the fixes.
Reference point: AU_LINUX_ANDROID_JB_MR1.04.02.02.049.366
LPA Mode:
LPAPlayer synchronization fixes.
Fixes for seek, pause/resume, EOS handling
Fixes for synchronization b/w the decoder thread, TimedEventQueue and player thread.
Convert mono to stereo for LPA clips - CRs-Fixed: 421639
Add support to change clip duration to enable LPA
Set correct device while creating effects - CRs-Fixed: 496866
Fix the LPA-AudioEffects dead lock issue - CRs-Fixed: 477511
fix volume not updated in pause state of direct track - CRs-Fixed: 490592
Tunnel Mode:
Use tunnel player only for music stream
Exceptions in using Tunnel mode decode - CRs-Fixed: 432080
Enable Tunnel Decode for select formats - CRs-Fixed:437651
Use software decoder for ADTS content. - CRs-fixed: 431096
Skip tunnel mode for playback through AudioCache - CRs-Fixed: 437539
Fix stability crash on tunnel playback. - CRs-Fixed: 498386
support multiple tunnel instances - CRs-Fixed: 483603
Fix ANR repeated next with tunnel clips on BT/AOA - CRs-Fixed: 482966
Update condition to ignore a seek request - CRs-Fixed: 461908
Return seek position until seek has been processed - CRs-Fixed: 454825
TunnelPlayer performance tweaks for audio video playback - CRs-Fixed: 444041
Stability fixes for Tunnel Player (part 2) - CRs-Fixed: 449122
Adjustment for TunnelPlayer buffer size - CRs-Fixed: 447274, 442365
Remove unnecessary code from TunnelPlayer - CRs-Fixed: 442365
update condition to send SEEK_COMPLETE - CRs-Fixed: 441411
Stop extractor source after start in TunnelPlayer - CRs-Fixed: 440239
Handling of EOS, and triggering EOS was wrong in TunnelPlayer.
EOS should not be posted till seek is complete
Disable tunnel mode playback for streaming use cases to avoid jittery playback
CRs-Fixed: 433346 432233 429868
APIs for returning correct timestamps were implemented
Check whether sink is open before flushing or closing it.
Check for mIsAudioRouted is good to know if we are closing it
Seekbar freezes after seek and pause
Check pause status before writing

Change-Id: Iea150f8d75aa9aa6d14da078695e920a3742dd81
(cherry picked from commit f7c9bafa439c5d52d945b966ba08cb16dfc34818)
(cherry picked from commit 68dee8112bbac7e0a70003175ed71b4e6a0376f4)
(cherry picked from commit 19c7fd3e330be551d477e8388b536294b1166a22)

frameworks/av: port fixes in LPA and Tunnel mode playback draft -2

 -LPAPlayer: Update condition to ignore seek CRs-Fixed: 453067
 -libstagefright: TunnelPlayer: update condition to send SEEK_COMPLETE
  CRs-Fixed: 441411
 -libstagefright: Fix ANR with rigorous rewind of 3gp LPA clips
  CRs-Fixed: 491077 490992
 -frameworks/av: Add  metadata mode changes to LPAPlayer
  CRs-Fixed: 458904 491077 490992

Change-Id: Ia89d7d6ac63b1267422a9138df9f98ef59b0ccb7
(cherry picked from commit 72f3bd4cddd3d93812692bffbfc19e2534477938)
(cherry picked from commit db6330d01d91d466d18c7714bd024a10fb009f57)
(cherry picked from commit 416e9ef0eed0ffa7b6e2c9d5a107d1ed2a94a624)

frameworks/av: port fixes in LPA effects

 -audio: fix for deadlock issue during LPA playback.
 -frameworks/av: Fix the LPA-AudioEffects dead lock issue CRs-Fixed: 477511
 -audioflinger: Fix pops in LPA while effects are applied CRs-Fixed: 526799
 -audioflinger: Fix delay in enabling effect for LPA CRs-Fixed: 525510

Change-Id: I92118b5cba17f5337608007052e7dc891d2d6b5b
(cherry picked from commit b24a38903f3fc2fd2bf7cc8fb71d50e1ff38162d)
(cherry picked from commit e8a1d6f80e64822d83f04f4f0704890644048189)
(cherry picked from commit 571f36890abe9f6b8bfe7341776cb5b3975bf952)

frameworks/av: Use the correct macro for AV enhancement

- Use correct macro for AV enhancement
- Add HW aac encoder entry in codec list

Change-Id: I2933ee92ff15875144acec17d3dd8ef61d6b37f9
(cherry picked from commit 5bb728d3bb84f2f24ddfbaa99fa133c87ff66298)
(cherry picked from commit dbc1e5bde1564e80052086a7ee301173515c8d64)
(cherry picked from commit 941f87a69f87dbeab0068f3e9a98c97981ff2700)

libstagefright: Add support for H/W AAC decoder

- Currently, only software AAC decoding is supported.
- Add support for H/W AAC decoding by including it in the
  list of available decoders and use it for decoding only
  if the property 'media.aaccodectype' is set to 0.

Change-Id: I35caba6fb694d17b51a0a9983a5fc5f28cb375ec
CRs-Fixed: 449145
(cherry picked from commit a87c3159a34da86e62c029a06e8e39bef66ae2db)
(cherry picked from commit 6a47c5cb0fe741f31b36bee7e74bd953a3ad3bcc)
(cherry picked from commit 8f6bacb4427d3c84af00b06a8ceb1bb324550acc)

frameworks/av: Compile AudioParameter as shared library

- AudioParameter as shared lib is needed by BT,
  support in WFD source, SRS TruMedia

Change-Id: I30ee584ba7f45f5cafbdf07c45aa7429a84b1b49
(cherry picked from commit 30b89b3bfdafa2f3b877644400efbaefd6572f1e)
(cherry picked from commit 84c3b42f25a28d14426dba29276aae8c5ab795ce)
(cherry picked from commit 53c42631eeb1e13b786d9f4f616f38fe59690e4e)

frameworks/av: Define MSM Audio parameters

- Define MSM audio paramters for FM, VOIP,
  fluence, SSR, and etc.

Change-Id: Iec6f146a0dde3095e3380da439a883b1bbb7d462
(cherry picked from commit 8e943f5bd88bda87f1aa9230487a69372ad49cf7)
(cherry picked from commit 85f4743d12c13aab39ac712a9005632f427c1c43)
(cherry picked from commit 333ba54561c59049f695b07479afe1d5ed734d31)

frameworsk/av: SSR bring-up

- Initial bring up for Surround Sound recording
- 5.1 channel AAC recording and LPCM 5.1 channel
  recording supported

Change-Id: I0d237dc91b74ce6e6550243c9e48cf358734634b
(cherry picked from commit 9f5c9b8eb2f34a0431621b0b54b1b0ea4914224a)
(cherry picked from commit d551917f9e65a0468bd838d4ffbf21006426b4c5)
(cherry picked from commit 236c0861d24eab95f2f6e8941394b38cdd2e15c8)

libmediaplayerservice: Add support for DashPlayer

Add support for DashPlayer in MedaPlayerFactor

Change-Id: I3e1fd871340117cb11975f6819d4bf0e6630607a
(cherry picked from commit f0dcae2a6bf22c8c5846b235f3ae900b8b824f79)
(cherry picked from commit d73fd11ce138f661770e809b959a17dac975b284)
(cherry picked from commit 8d3b0b273ddd2ff08707d33b647d8ee6db3c7598)

frameworks/av: Enable subsystem re-start for LPA/Tunnel

-Audio Daemon in Audio HAL intimates AudioFlinger
 of ADSP status (online/offline) using set_paramaters.
-AudioFlinger send set_parameters to its clients
 which is DirectTrack used for LPA/Tunnel playback.
-In case of ADSP crash during LPA/Tunnel playback,
 clean up of DirectTrack is initiated.

Change-Id: I87f720f305765e00e12032eed3e018aeff952390
(cherry picked from commit 02861e0f092c46640576bb8c700418ed82c266c3)
(cherry picked from commit 5abe97aa9e103420813b87e7abb2b676ffe8d097)
(cherry picked from commit 9a27f1e6c449585095e518f0d2f44e621ef18f52)

frameworks/av: Add support for Quality Of Experience (QOE) events in MediaPlayer

- Add MEDIA_QOE event type
- Allow MEDIA_QOE event to be passed to Application after reset
  is completed, similar to MEDIA_ERROR

Change-Id: I71e3d9e1f5f934c5844d80c65c653b2702a22ca1
(cherry picked from commit a3320b6e617d1143bf2135abfaaff28365513de4)
(cherry picked from commit 3ca9bdff130c204678def4578fc7a06fd8b3a03a)
(cherry picked from commit d13bd4be1a5418cb806029ba65854c13608cbb0c)

frameworks/av: fix for testAACEncoder CTS testcase

- testAACEncoders CTS testcase is failing for
  Hardware aac encoder use case
- hardware encoder has bitrate limitation
  due to which  CTS testcase is failing
- Removed hardware AAC encoder component from MediaCodec list
- Updated the macro for av enhancements in OMXCodec

Change-Id: I3140898f466a600a4488306701aa16e194df8cc6
(cherry picked from commit a084948269982c868916833546c4b56acdeb1de9)
(cherry picked from commit b5cff08f65b0811efec6b739c98b3aa42d1dd3f7)
(cherry picked from commit 96b425ed8125a7f535572276c2efd09ec81a6a59)

audio : init rc to avoid effect's fault state

Effect command doesn't necessarily fill cmd return code into &cmdStatus,
so we should initialize cmdStatus to avoid uninitialized value propagates
to upper stack caller.

Change-Id: I2a2985e3010f0d7b8aedf9244a6faabdf05740ac
CRs-Fixed: 517766

Conflicts:
	services/audioflinger/Effects.cpp
(cherry picked from commit 708dd6e07fc363c76ee9d26a4bc6bb6d7cd3815e)
(cherry picked from commit 0f864db4f4c30c0f31a6998301dd4ec0098a5b24)
(cherry picked from commit 70047618259f68ce74349ed33edffd0ab5a467cc)

audio: Add pause support for hardware omx component

-ADSP doesn't enter sleep state after wma playback is paused
and power suspended.
-No support for NT session pause in case of hardware component.
NT session need to be paused to put ADSP into power collapse.
-Add support of pause in stagefright to ensure device enters
suspend mode. Also add intermediate states to avoid concurrency
issues between read and pause.

Change-Id: Ia0d77a3a0a344b8caad4f4d395641fd6a82f80b9
CRs-Fixed: 496256
(cherry picked from commit 369536f28349e7d1e3033c9d6205c692e32d0751)
(cherry picked from commit 1dcd1d7eba1d82c14961b05dab4e854ed2a979b3)
(cherry picked from commit 0a1b5cbced55d0718d96eccab9e2fe06aa68b199)

audio: Fix for race conditions in direct audio track

-Issue: Mediaserver crash is observed in direct track functions.
-Rootcause: Between write and flush functions, write and destructor
effectpool buffers are accessed without any synchronization that
might lead to operations on null buffers and cause crash.
-Fix: Use mEffectLock to synchronize access of effectpool buffers.

Change-Id: I5982e31fd6d292a9fe28dfee4cf75ebfe0ade5e6
CRs-Fixed: 515107
(cherry picked from commit b14c28f0d3b51ee989640aa46f3addcfabccb6be)
(cherry picked from commit 782f8512023facb1b655fb636bdcbd19af21b493)
(cherry picked from commit 1601287d6a06e11d782a821791bf1f5a9dcbd188)

audio: Correct the condition that checks for wma version

-Few wma clips fail to play when tried to play from music app.
-In overrideComponentName(), a wrong condition is added due to which
component name is always returned null. Due to this all wma clips use
wma component irrespective of the version. This causes playback
failure for other version clips.
-Correct this condition to ensure that all wma clips play fine.

Change-Id: I3a724755fb254bedfc0d3a6dba46c019bc3535bb
CRs-Fixed: 548188
(cherry picked from commit a716cf363b4c7e89fba11547732bbdd9ceff185b)
(cherry picked from commit b7e09e104afb3eda1f2ce95f5ac25fca6483fa28)
(cherry picked from commit bb37a77adbfc6eabbb2c15ea9c7fcae113b6fa9d)

audio: Fix to prevent deadlock in AudioEffects

-Write is blocked waiting for effect chain lock and this causes
decoder thread to wait indefintely.
-Sometimes it is observed that effectschain is locked before
mLPAEffectChain is initialized and but unlocking is skipped if
mLPAEffectChain is initialized in between.Due to this LPA
silence and framework reboot issues are observed as
applyEffectsOn() cannot acquire lock to progress further.
-Use flag to check if all effects have been locked and unlock
accordingly to prevent the deadlock scenario.
CRs-Fixed: 524759

Change-Id: I8ea0b1fc97de157b8254688b5471fd21bc9b565d
(cherry picked from commit 64dda9be5640f02c923cb7d5a08036ebb49ce86f)
(cherry picked from commit 9056fa50895243fbb1672eb117d60004757e7deb)
(cherry picked from commit b43e3b9859ddd90f512c80b637186f2a6e54a835)

audio: check for divide by zero possibilities

When output stream is not available to audioflinger
due to any reason, sampleRate and frameCount have
zero values when trying to create new Audiotrack.
This might result in divide by 0 situation.

Change-Id: If7fbcb6eb4cfcdba6d6bb3b4f758e46e4a57e37b
(cherry picked from commit d1576c1648a78354535fc9cd7130412f300864e5)
(cherry picked from commit 15b951bfcb2180f728669ab23ef0d6791fd790c2)
(cherry picked from commit c980dbea39f984a3c28e2694174e87b311e77308)

audio: Fix crash in flinger during monkey runs

The trackrefptr in DirectTrack descriptor can be invalid and
this can result in a crash is stability runs. Add check for
validity of the trackrefptr before accessing it

Change-Id: I4c7fbff022f381f9d2cdbf0fc04ade8defbb2195
(cherry picked from commit 66917496a28241bf38f117cb05b5810021a185a0)
(cherry picked from commit e1c916bb324f4f6f7923b8e4b2a9c436a65534ff)
(cherry picked from commit dc983d3efd2a5ec3435246d4d2a2e1b4265b5f22)

audio: Use High Quality resampler

Use very high quality resampler to upsample to 48KHz sample
rate.
CRs-fixed: 416730

Change-Id: I30420cbaa8f6d34e2bce408494cc08cb00b175a3
(cherry picked from commit 2904e01dd4a3921b7bc0bec71f63f4757204408b)
(cherry picked from commit 0302cfba74b948e5fb3b2adbcb9330b5dcc36595)
(cherry picked from commit 955a6569ab9d28fbfd6e1e234f06016fcbe5fb6b)

libstagefright: Add interlaced video support

- Adds call to set output buffer size on the native window

Change-Id: I4754e1f1d4d0bba375f719240499ef58c9e87ca2
(cherry picked from commit 63452051ea03bc48af85bd58767fd2a9b0ae13b6)
(cherry picked from commit 856b08a0c452a5d1e0b02487bcbebc44e55fd3e7)
(cherry picked from commit 8f445b519a7c3d107f4180ead01c9722b12b0adf)

ExtendedCodec: Enable timestamp reordering for MPEG4 codec type clips

MPEG4 codec type video clips can contain B frames. This change will
enable timestamp reordering for all MPEG4 codec type clips

CRs-Fixed: 539036

Change-Id: I7682a3781e6aa1b8e73418e4e73ee266c6338770
(cherry picked from commit 8d52ec137be60676c310bda168e8ce18d22dc534)
(cherry picked from commit 3b47eeb2cb5d595f2e755dcaa9e564eac8cbf33d)
(cherry picked from commit 9b47486f507fe834e4c5ab51524be8aa91df875b)

libstagefright: Use proper ctts offset

Calculate ctts offset as difference between composition
time and decoding time, and avoid adding kMaxCttsOffsetTimeUs
as it increases the sample timestamp by the same amount
which leads to av sync loss.

CRs-Fixed: 524739
Change-Id: I75a1bb594536623e3a445af2ee1ceb0cf0926a6e
(cherry picked from commit 863cb2bae6015b32c9ad12f074394c9a54c7bc47)
(cherry picked from commit 8e0e1a4330babf3c38152d48db1f2edf4db7a659)
(cherry picked from commit 87b09615f9473e369883142009d4035e37a2a806)

libvideoeditor: use vWidth and vHeight for buffer allocation

Change-Id: I2ab01b8ef79a3ad9b1eb737b2e9f1211a6e668c2
 - video editor detects crop information from decoder, crop
   width and height will override metadata width and height.
 - decoder is capable of sending crop information where
   crop width and height are smaller than actual resolution.
 - use actual metadata width and height for calculating
   buffer size.
CRs-Fixed: 452511
(cherry picked from commit 93432b8b1c29b2dd62fad923ffa622b002311fa8)
(cherry picked from commit de34cceeb13eead49daf4a47f28bf49286917101)
(cherry picked from commit 865f7b2e0f034b0aea09ef5b13f401c776585bf2)

libstagefright: post video events dynamically - calculate amount of time to delay video event after renderusing the formula: delay = (us between frames)-(us taken by event)-(lateness)

Change-Id: I136ee19520200b26058099f88c8979d1e4e34e23
(cherry picked from commit 61ef39e403f708b014ca434eec35056815558deb)
(cherry picked from commit eb7422fb58a6f95f385574c4d845754db8da6b1f)
(cherry picked from commit 427260792cfa7a53fb27808ac24600a3ebfa7ca2)

libstagefright: Reset the decoder while performing seek

-Observed noise when seeking to beginning of file for the recorded
AMR clip.
-While performing seek, the AMR decoder states are not being reset.
In AMR decoder, the current frame output is predicted using the states
from previous frame. If these states are not cleared, it might cause
noise when seek is performed.
-Fixed by resetting the decoder when seek is issued and port flush
completion is notified to the decoder.

CRs-Fixed: 500851
Change-Id: Ia8480b88521abc09c8b01d6052df4730a0359518
(cherry picked from commit df2b77618d69ac10f1c41ffd5eedb92dd43e161d)
(cherry picked from commit 654f3ad1192bd210b27dbfe29f3cf75a4a3774d8)
(cherry picked from commit 6374b1a4bbf6e853d7214eee6c7177251d246c58)

libstagefright: notify updated stride to NativeWindow for DRC  -Notify updated stride after resolution switch to NativeWindow  to re-interpret the buffer layout  -CRs-fixed: 534910

Change-Id: I4c1427a4826c8d29f93064c34eb3e2eaeef434d7
(cherry picked from commit f93a1ed7561a3a29b73466054e8c43dcbb4c9a1e)
(cherry picked from commit fc948d949de674c4d978b9ca87dea039f4aa86bd)
(cherry picked from commit e5954f19fc67414620ce582a361dd09f5444a01c)

libstagefright: Fix crash in media server mpeg2 playback. -There is a check in dequeueAccessUnitMPEGAudio function inESQueue that  time stamp returned by fetchTimeStamp is alwaysgreater than 0 -In the current scenario, valid time stamp set on the firstframe is  getting replaced in the sub sequent code by -1. -Fix is to reset the flag after first frame is identified CRs-Fixed: 512218

Change-Id: I1be136fb8c8c3a88f46b88f42a1f200582fd1086
(cherry picked from commit 275b8f8d4047346fea7450b97a004c4e43e9a72b)
(cherry picked from commit 2a2bc3622413ac1d0304cffaec9603de77d5228d)
(cherry picked from commit 7836a4a64b3afb56689bc7384cb3dcdaa5a454c0)

frameworks/av: Fix for failure in CTS MediaRecorderTest cases

 -Issue: MediaRecorder CTS test cases are failing.

 -Root Cause: Running the CTS test "testRecorderRandomAction" at beginning
  sets the huge file size and stargeFrightRecorder set the 64 bit file
  offset.
  In MPEG4 writer estimateMoovBoxSize depends on a static const
  variable which uses this file offset info.
  As the variable to calculate estimateMoovBoxSize is static const it
  remains same for next media recording session even if file size is small.

 -Fix: Don't use static const variable which is used to calculate
  estimateMoovBoxSize as its value may change depending on file offsets.

Change-Id: I6bd859fcd7951a4e78abc50bc99dab38e8284877
(cherry picked from commit 0542e6f3af9e17559542764856f430ceaa255cac)
(cherry picked from commit 48fda261ceba7ed1c38c09e3282e9f9147bc03a0)
(cherry picked from commit 70af301150f7a5829f490b44da5caa596da76fa6)

audioflinger: Fix monkey crash in audioflinger set parameter.

-Track ref ptr is initialized to direct track pointer only in create
 Direct Track although the descriptor is created in open Output
-If there is a set parameter coming in during this time it could
 result in a crash as track ref ptr is not initialized.
-Initialize track ref ptr to NULL when descriptor is created.

Change-Id: Iee887baee45a9e7b381f6e2ea2ab523a23689f6b
(cherry picked from commit 10d4ae79b727f7191484f3adda13f9bba9d62c09)
(cherry picked from commit 7d130a825ad58e44b04cce4a4e3f4e4919337a7b)
(cherry picked from commit 0b72bac19b8f8988e385b06ede234ca80e2e2e07)

audio: Adding support for SRS effects

-Add support for SRS Trumedia post processing effects

Change-Id: I41b8983e1a59f5a84e10a21418d7731e6d8ec430
(cherry picked from commit 5b7c47861ce5e4afee2a3ce8e956e0cfec10cf29)
(cherry picked from commit e0ff892f774310e921f9926748ed9a3fe9784af3)
(cherry picked from commit 6d92096966d3dd16f5d08556e3b1273041d1cf58)

audio: Do not apply effect on multichannel content

-Do not apply effect on multichannel content.
-Effects are applied only for mono or stereo.
CRs-Fixed: 484078

Change-Id: I623d40f926d5dd80e74f9aa2f98448158518047e
(cherry picked from commit b11bb5ec8184b0880a37b13033b22e255dbfccac)
(cherry picked from commit af7c6323538ad5b0e5a9f3efd2458cd44744c397)
(cherry picked from commit b984891aaade017a7fc9aad0c0d9f9398653cf71)

audioflinger:Set correct device while creating effects

 -Issue: Effectmodule is created with stale output device
  -Rootcause: While creating effects the output device set is
   output device of mixer thread, which is stale and
   not updated, so effects use the wrong/old device as
   the output device and leads to issue such as difference
   in volume level after setting correct device etc.
  -Fix: Cache the latest device value for direct track
   in a flinger member variable when setparameter of
   flinger is called with new device and
   audioflinger::openoutput is called.
   Use this cached value while creating effects

CRs-Fixed: 496866

Change-Id: I66f08b968c75e8a3b812aad7d91b20fd4557ba24
(cherry picked from commit 20d090b0a481722eede1ca01d38fddcd0977c633)
(cherry picked from commit b39d113f2bac7ca1df8ef144d81bdb28c32975d0)
(cherry picked from commit baf45ef7b6c12a1916d56ce37965de3d366b9f84)

frameworks/av: Initial bringup of voip and vocoders

-Add support for voip and vocoders.

Change-Id: Ibe6dfa100e564e057deebe1613cafd282ee2344e
(cherry picked from commit 96043bb0b5e93099bbbdd2a64c2b6039911c0ac3)
(cherry picked from commit 1682b8eb630c22b7ef0aa7a29746c6ce06118d95)
(cherry picked from commit bf72f4c502777df4703c345d1269057c57d11615)

stagefright: Enable HFR feature during recording video.

- Enable HFR related calls to set HFR mode in stagefright and
  libmediaplayerservice.
CRs-fixed: 557371

Change-Id: I8cf0856b608c5a76a4ac0ad128f05eab43ca4d49
(cherry picked from commit 94a175141e61b8fa20b687ea054a05d15b7746b5)
(cherry picked from commit c57bfc012bd9004ea1ab79d617d55418412bbaaf)
(cherry picked from commit b19127db20c99a23f26adafe105928bca38c4749)

libstagefright: In thumbnail mode set EOS on first frame

- 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
behandled
- Required for thumbnail generation for some interlaced
videos

Change-Id: I896dec4c58f688a76c29a5d72fb8b61cb04bbfcc
(cherry picked from commit a124c3b722b251f148141b503ba9614cf33af43a)
(cherry picked from commit 44ee9348a2743bf39c2e517612b7e75d7be797ad)
(cherry picked from commit cb113596724882fcd2ce2ee52d1e447698d79865)

audio: Fix a/v sync issue for playback over BT

-Audio and video are out of sync when a video is played/streamed
with a BT headset connected to the target.
-AudioTrack does not consider the BT latency.
-Latency of the BT stream added to the existing latency.

-query for tunnel mode latency
-During tunnel playback, we need to offset latency for audio plaback
 on BT devices by querying BT HAL.

Change-Id: I01a132687aec09cd2897039622daa35cff7ec409
(cherry picked from commit 9096501e28ecb56dc3a5a4d36d474b99804315cd)
(cherry picked from commit 29cb9299834d73a916b7a68617a32fb615c95d95)
(cherry picked from commit ca1f9dd47ca4299797e68029f3c260a5f291d3bd)

audio: AudioTrack constructor initialization

- Initialized few  member variables to null

Change-Id: I36fe9fd2f9e4c2b1967b8d9562ffcad635c6f686
(cherry picked from commit 673fd8919e310f3b2ecea082cfb9c2b08d00ad44)
(cherry picked from commit 75a64de910334e8cb12cfa0079910269e3f4e0e3)

audio: enable tunnel mode based on flags

- Enable tunnel mode playback based on flags defined
  in target board config file instead of checking
  target name.

Change-Id: I78c39b2653e7bae6a6eae8de36fbcacbeb1e6686

Conflicts:
	media/libstagefright/Android.mk
(cherry picked from commit 55a727f33978d374ffbdf612dd4a8560c3bffe3f)
(cherry picked from commit bb7234c9bb0505f3d6df998f84b9a062b206e097)

libstagefright: adjust AV sync late margin based on property

- Current AV late margin is 40 ms
- Read system property media.sf.set.late.margin and if
new AV sync late margin is set then use the same
- Max AV sync late margin allowed is 250 ms
- Min AV sync late margin is default 40 ms

Change-Id: Ie99a4b85264d4a07c983a3f116c18bee3b0acfc7
(cherry picked from commit 0931561dafecce2a0b9148822e77c5f526f31934)
(cherry picked from commit a7fbe5b8ff05c52c902f4f550b812169c8ed456b)

Camcoder: Add missing timelapse recording resolutions to map variable.

VGA and WVGA resolutions were missing in a map variable.
Because of this parsing media profiles xml for these
profiles was crashing.

Change-Id: I5494436f8a3cde9c8a5f0d26b066ca5b37dbd585
CRs-fixed: 564722
(cherry picked from commit 4ac681161652d6dcf6b3313853769b19905010f2)
(cherry picked from commit 668759a8ba976b18932773ad002b7964b9cc071c)

libstagefright: For interlace, set decoder in arbitrary mode

In arbitrary mode, frame parsers sends individual fields
to core. Once both the field is decoded, output done (FBD)
is sent back to client.
Default frame by frame mode will send both the fields in
a single buffer to core, which might decode only one field
or will throw up error.

Change-Id: Ia35d754e685f28f0df9f2c6ef2180b8a3dae1f28
CRs-Fixed: 531034
(cherry picked from commit 0428493caa128cfcb7b3df9082427cb6872a029e)
(cherry picked from commit f0ca79d0509d278a4a322121dc113e173c33534c)

framework\av: libstagefright: Update NOTICE file.

- Update NOTICE file with the correct information.

Change-Id: I04384d4cc12d05db768a41c4580f39050e99441f
CRs-Fixed: 534648
(cherry picked from commit 7edaaf1230953115325b4b2701160d0edd8d63f9)

frameworks/av: rendering statistics for Stagefright.

- this adds extra fps statisticis
- report via dumpsys
- prints statistics before reset at the end of playback ontologcat
- add resume latency, from play_l to render
- add seek latency, from seek_l to render
- enabled using persist.debug.sf.statistics 1
- print all statistics when seek or resume is issued.

Change-Id: I90e215bf3139c38731b9db2b07f6d6f5a916b11e
(cherry picked from commit ecc5a30e06abcf87c941068b44023227e0eb8266)

libmedia: Add QC enhancements to MediaProfiles.

Add entries for:
- 4K resolution support for camcorder
- Timelapse for some resolution

Change-Id: I2bbeec06ac457eb9a6fb92e3aa8fc5ead3372809
(cherry picked from commit 90b4f7c00008b7d1afe4bcc503680e807a935db9)

Revert "frameworks/av: Enable subsystem re-start for LPA/Tunnel"

This reverts commit 9fd40491ae10c99b35c5592e96cc9246b2a8c4ae.

Change-Id: Ia7faba22db4134c36875fec90f98cf23e019288b
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 2bd8475..fb12e08 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -11,11 +11,22 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_SRC_FILES:= AudioParameter.cpp
+LOCAL_MODULE:= libaudioparameter
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libutils libcutils
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
 LOCAL_SRC_FILES:= \
     AudioTrack.cpp \
     AudioTrackShared.cpp \
     IAudioFlinger.cpp \
     IAudioFlingerClient.cpp \
+    IDirectTrack.cpp \
+    IDirectTrackClient.cpp \
     IAudioTrack.cpp \
     IAudioRecord.cpp \
     ICrypto.cpp \
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index e3fea77..cf4d8c3 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -1,4 +1,7 @@
 /*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
  * Copyright (C) 2006-2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,6 +35,16 @@
 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_FM_ENABLED
+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;
+const char * const AudioParameter::keyADSPStatus = AUDIO_PARAMETER_KEY_ADSP_STATUS;
+const char * const AudioParameter::keyCanOpenProxy = AUDIO_CAN_OPEN_PROXY;
+const char * const AudioParameter::keyFmVolume = AUDIO_PARAMETER_KEY_FM_VOLUME;
+#endif
 
 AudioParameter::AudioParameter(const String8& keyValuePairs)
 {
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 666fafa..0e33805 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -60,9 +60,10 @@
     // We double the size of input buffer for ping pong use of record buffer.
     size <<= 1;
 
-    // Assumes audio_is_linear_pcm(format)
+    if (audio_is_linear_pcm(format) || format == AUDIO_FORMAT_AMR_WB) {
     uint32_t channelCount = popcount(channelMask);
     size /= channelCount * audio_bytes_per_sample(format);
+    }
 
     *frameCount = size;
     return NO_ERROR;
@@ -194,11 +195,6 @@
         ALOGE("Invalid format %d", format);
         return BAD_VALUE;
     }
-    // Temporary restriction: AudioFlinger currently supports 16-bit PCM only
-    if (format != AUDIO_FORMAT_PCM_16_BIT) {
-        ALOGE("Format %d is not supported", format);
-        return BAD_VALUE;
-    }
     mFormat = format;
 
     if (!audio_is_input_channel(channelMask)) {
@@ -206,20 +202,27 @@
         return BAD_VALUE;
     }
     mChannelMask = channelMask;
-    uint32_t channelCount = popcount(channelMask);
+    uint32_t channelCount = popcount(channelMask
+        &(AUDIO_CHANNEL_IN_STEREO|AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_5POINT1));
     mChannelCount = channelCount;
 
-    // Assumes audio_is_linear_pcm(format), else sizeof(uint8_t)
-    mFrameSize = channelCount * audio_bytes_per_sample(format);
+    mFrameSize = frameSize();
 
-    // validate framecount
-    size_t minFrameCount = 0;
-    status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
-            sampleRate, format, channelMask);
+    size_t inputBuffSizeInBytes = -1;
+    status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &inputBuffSizeInBytes);
     if (status != NO_ERROR) {
-        ALOGE("getMinFrameCount() failed; status %d", status);
-        return status;
+        ALOGE("AudioSystem could not query the input buffer size; status %d", status);
+        return NO_INIT;
     }
+
+    if (inputBuffSizeInBytes == 0) {
+        ALOGE("Unsupported configuration: sampleRate %u, format %d, channelMask %#x",
+            sampleRate, format, channelMask);
+        return BAD_VALUE;
+    }
+
+    int minFrameCount = (inputBuffSizeInBytes * 2)/mFrameSize;
+
     ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
 
     if (frameCount == 0) {
@@ -276,6 +279,11 @@
     return NO_ERROR;
 }
 
+audio_source_t AudioRecord::inputSource() const
+{
+    return mInputSource;
+}
+
 // -------------------------------------------------------------------------
 
 status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession)
@@ -463,6 +471,10 @@
     }
 
     int originalSessionId = mSessionId;
+    if (inputSource() == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+        ALOGV("Notify use of Voice Communication");
+        trackFlags |= IAudioFlinger::TRACK_VOICE_COMMUNICATION;
+    }
     sp<IAudioRecord> record = audioFlinger->openRecord(input,
                                                        mSampleRate, mFormat,
                                                        mChannelMask,
@@ -952,6 +964,36 @@
     return result;
 }
 
+size_t AudioRecord::frameSize() const
+{
+    if (inputSource() == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+        if (audio_is_linear_pcm(mFormat)) {
+            return channelCount()*audio_bytes_per_sample(mFormat);
+        } else {
+            return channelCount()*sizeof(int16_t);
+        }
+    } else {
+        if (format() ==AUDIO_FORMAT_AMR_NB) {
+            return channelCount() * AMR_FRAMESIZE; // Full rate framesize
+        } else if (format() == AUDIO_FORMAT_EVRC) {
+            return channelCount() * EVRC_FRAMESIZE; // Full rate framesize
+        } else if (format() == AUDIO_FORMAT_QCELP) {
+           return channelCount() * QCELP_FRAMESIZE; // Full rate framesize
+        } else if (format() == AUDIO_FORMAT_AAC) {
+            // Not actual framsize but for variable frame rate AAC encoding,
+            // buffer size is treated as a frame size
+            return AAC_FRAMESIZE;
+        } else if(format() == AUDIO_FORMAT_AMR_WB) {
+            return channelCount() * AMR_WB_FRAMESIZE;
+        }
+        if (audio_is_linear_pcm(mFormat)) {
+            return channelCount()*audio_bytes_per_sample(mFormat);
+        } else {
+            return sizeof(uint8_t);
+        }
+   }
+}
+
 // =========================================================================
 
 void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who)
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index fffd4a5..234ec71 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -316,19 +316,9 @@
                                  audio_stream_type_t streamType,
                                  uint32_t* latency)
 {
-    OutputDescriptor *outputDesc;
-
-    gLock.lock();
-    outputDesc = AudioSystem::gOutputs.valueFor(output);
-    if (outputDesc == NULL) {
-        gLock.unlock();
-        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
-        if (af == 0) return PERMISSION_DENIED;
-        *latency = af->latency(output);
-    } else {
-        *latency = outputDesc->latency;
-        gLock.unlock();
-    }
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    *latency = af->latency(output);
 
     ALOGV("getLatency() streamType %d, output %d, latency %d", streamType, output, *latency);
 
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index fe5cd9e..f626f6f 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1,5 +1,6 @@
 /*
-**
+** Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
 ** Copyright 2007, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -53,19 +54,22 @@
     //          audio_format_t format
     //          audio_channel_mask_t channelMask
     //          audio_output_flags_t flags
-    uint32_t afSampleRate;
+    uint32_t afSampleRate = 0;
     if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
         return NO_INIT;
     }
-    size_t afFrameCount;
+    size_t afFrameCount = 0;
     if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
         return NO_INIT;
     }
-    uint32_t afLatency;
+    uint32_t afLatency = 0;
     if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
         return NO_INIT;
     }
-
+    if(!afSampleRate || !afFrameCount) {
+        ALOGW("samplerate or framecount 0");
+        return NO_INIT;
+    }
     // Ensure that buffer depth covers at least audio hardware latency
     uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
     if (minBufCount < 2) {
@@ -85,7 +89,10 @@
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
-      mPreviousSchedulingGroup(SP_DEFAULT)
+      mPreviousSchedulingGroup(SP_DEFAULT),
+      mAudioFlinger(NULL),
+      mObserver(NULL),
+      mCblk(NULL)
 {
 }
 
@@ -105,7 +112,10 @@
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
-      mPreviousSchedulingGroup(SP_DEFAULT)
+      mPreviousSchedulingGroup(SP_DEFAULT),
+      mAudioFlinger(NULL),
+      mObserver(NULL),
+      mCblk(NULL)
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
@@ -128,7 +138,11 @@
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
-      mPreviousSchedulingGroup(SP_DEFAULT)
+      mPreviousSchedulingGroup(SP_DEFAULT),
+      mProxy(NULL),
+      mAudioFlinger(NULL),
+      mObserver(NULL),
+      mCblk(NULL)
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             0 /*frameCount*/, flags, cbf, user, notificationFrames,
@@ -148,10 +162,16 @@
             mAudioTrackThread->requestExitAndWait();
             mAudioTrackThread.clear();
         }
-        mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
-        mAudioTrack.clear();
+        if (mAudioTrack != 0) {
+            mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
+            mAudioTrack.clear();
+            AudioSystem::releaseAudioSessionId(mSessionId);
+        }
+
+        if (mDirectTrack != 0) {
+            mDirectTrack.clear();
+        }
         IPCThreadState::self()->flushCommands();
-        AudioSystem::releaseAudioSessionId(mSessionId);
     }
 }
 
@@ -286,12 +306,30 @@
     uint32_t channelCount = popcount(channelMask);
     mChannelCount = channelCount;
 
-    if (audio_is_linear_pcm(format)) {
-        mFrameSize = channelCount * audio_bytes_per_sample(format);
-        mFrameSizeAF = channelCount * sizeof(int16_t);
+    if ((streamType == AUDIO_STREAM_VOICE_CALL)
+         && (channelCount == 1)
+         && ((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);
+    }
+
+    if ((audio_stream_type_t)streamType == AUDIO_STREAM_VOICE_CALL) {
+        if (audio_is_linear_pcm(format)) {
+            mFrameSize = channelCount * audio_bytes_per_sample(format);
+            mFrameSizeAF = channelCount * sizeof(int16_t);
+        } else {
+            mFrameSize = sizeof(uint16_t);
+            mFrameSizeAF = sizeof(uint16_t);
+        }
     } else {
-        mFrameSize = sizeof(uint8_t);
-        mFrameSizeAF = sizeof(uint8_t);
+        if (audio_is_linear_pcm(format)) {
+            mFrameSize = channelCount * audio_bytes_per_sample(format);
+            mFrameSizeAF = channelCount * sizeof(int16_t);
+        } else {
+            mFrameSize = sizeof(uint8_t);
+            mFrameSizeAF = sizeof(uint8_t);
+        }
     }
 
     audio_io_handle_t output = AudioSystem::getOutput(
@@ -316,39 +354,70 @@
     mAuxEffectId = 0;
     mFlags = flags;
     mCbf = cbf;
+    mSampleRate = sampleRate;
 
-    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,
-                                  frameCount,
-                                  flags,
-                                  sharedBuffer,
-                                  output,
-                                  0 /*epoch*/);
-
-    if (status != NO_ERROR) {
-        if (mAudioTrackThread != 0) {
-            mAudioTrackThread->requestExit();   // see comment in AudioTrack.h
-            mAudioTrackThread->requestExitAndWait();
-            mAudioTrackThread.clear();
+    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;
         }
-        //Use of direct and offloaded output streams is ref counted by audio policy manager.
-        // As getOutput was called above and resulted in an output stream to be opened,
-        // we need to release it.
-        AudioSystem::releaseOutput(output);
-        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 {
+        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,
+                                      frameCount,
+                                      flags,
+                                      sharedBuffer,
+                                      output,
+                                      0 /*epoch*/);
+
+        if (status != NO_ERROR) {
+            if (mAudioTrackThread != 0) {
+                mAudioTrackThread->requestExit();   // see comment in AudioTrack.h
+                mAudioTrackThread->requestExitAndWait();
+                mAudioTrackThread.clear();
+            }
+            //Use of direct and offloaded output streams is ref counted by audio policy manager.
+            // As getOutput was called above and resulted in an output stream to be opened,
+            // we need to release it.
+            AudioSystem::releaseOutput(output);
+            return status;
+        }
+        AudioSystem::acquireAudioSessionId(mSessionId);
+        mAudioDirectOutput = -1;
+        mDirectTrack = NULL;
+        mSharedBuffer = sharedBuffer;
+    }
+    mUserData = user;
     mStatus = NO_ERROR;
     mStreamType = streamType;
     mFormat = format;
-    mSharedBuffer = sharedBuffer;
     mState = STATE_STOPPED;
     mUserData = user;
     mLoopPeriod = 0;
@@ -356,7 +425,6 @@
     mMarkerReached = false;
     mNewPosition = 0;
     mUpdatePeriod = 0;
-    AudioSystem::acquireAudioSessionId(mSessionId);
     mSequence = 1;
     mObservedSequence = mSequence;
     mInUnderrun = false;
@@ -367,10 +435,27 @@
 
 // -------------------------------------------------------------------------
 
+uint32_t AudioTrack::latency() const
+{
+    if (mAudioDirectOutput != -1) {
+        return mAudioFlinger->latency(mAudioDirectOutput);
+    } else if (mOutput != 0) {
+        uint32_t afLatency = 0;
+        uint32_t newLatency = 0;
+        AudioSystem::getLatency(mOutput, mStreamType, &afLatency);
+        if (0 != mSampleRate){
+            newLatency = afLatency + (1000*mCblk->frameCount_) / mSampleRate;
+        }
+        ALOGD("latency() mLatency = %d, newLatency = %d", mLatency, newLatency);
+        return newLatency;
+    }
+    return mLatency;
+}
+
 status_t AudioTrack::start()
 {
+    status_t status = NO_ERROR;
     AutoMutex lock(mLock);
-
     if (mState == STATE_ACTIVE) {
         return INVALID_OPERATION;
     }
@@ -383,6 +468,10 @@
     } else {
         mState = STATE_ACTIVE;
     }
+    if (mDirectTrack != NULL) {
+        mDirectTrack->start();
+        return status;
+    }
     if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
         // reset current position as seen by client to 0
         mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
@@ -406,7 +495,6 @@
         androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
     }
 
-    status_t status = NO_ERROR;
     if (!(flags & CBLK_INVALID)) {
         status = mAudioTrack->start();
         if (status == DEAD_OBJECT) {
@@ -447,28 +535,32 @@
         mState = STATE_STOPPED;
     }
 
-    mProxy->interrupt();
-    mAudioTrack->stop();
-    // the playback head position will reset to 0, so if a marker is set, we need
-    // to activate it again
-    mMarkerReached = false;
+    if(mDirectTrack != NULL) {
+        mDirectTrack->stop();
+    } else if (mAudioTrack != NULL) {
+        mProxy->interrupt();
+        mAudioTrack->stop();
+        // the playback head position will reset to 0, so if a marker is set, we need
+        // to activate it again
+        mMarkerReached = false;
 #if 0
-    // Force flush if a shared buffer is used otherwise audioflinger
-    // will not stop before end of buffer is reached.
-    // It may be needed to make sure that we stop playback, likely in case looping is on.
-    if (mSharedBuffer != 0) {
-        flush_l();
-    }
+        // Force flush if a shared buffer is used otherwise audioflinger
+        // will not stop before end of buffer is reached.
+        // It may be needed to make sure that we stop playback, likely in case looping is on.
+        if (mSharedBuffer != 0) {
+            flush_l();
+        }
 #endif
 
-    sp<AudioTrackThread> t = mAudioTrackThread;
-    if (t != 0) {
-        if (!isOffloaded()) {
-            t->pause();
+        sp<AudioTrackThread> t = mAudioTrackThread;
+        if (t != 0) {
+            if (!isOffloaded()) {
+                t->pause();
+            }
+        } else {
+            setpriority(PRIO_PROCESS, 0, mPreviousPriority);
+            set_sched_policy(0, mPreviousSchedulingGroup);
         }
-    } else {
-        setpriority(PRIO_PROCESS, 0, mPreviousPriority);
-        set_sched_policy(0, mPreviousSchedulingGroup);
     }
 }
 
@@ -480,10 +572,11 @@
 
 void AudioTrack::flush()
 {
-    if (mSharedBuffer != 0) {
-        return;
+    if(mDirectTrack != NULL) {
+        ALOGE("mdirect track flush");
+        mDirectTrack->flush();
+        return ;
     }
-    AutoMutex lock(mLock);
     if (mState == STATE_ACTIVE || mState == STATE_FLUSHED) {
         return;
     }
@@ -518,8 +611,13 @@
     } else {
         return;
     }
-    mProxy->interrupt();
-    mAudioTrack->pause();
+    if(mDirectTrack != NULL) {
+        ALOGV("mDirectTrack pause");
+        mDirectTrack->pause();
+    } else {
+        mProxy->interrupt();
+        mAudioTrack->pause();
+    }
 }
 
 status_t AudioTrack::setVolume(float left, float right)
@@ -531,8 +629,12 @@
     AutoMutex lock(mLock);
     mVolume[LEFT] = left;
     mVolume[RIGHT] = right;
-
-    mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
+    if(mDirectTrack != NULL) {
+        ALOGV("mDirectTrack->setVolume(left = %f , right = %f)", left,right);
+        mDirectTrack->setVolume(left, right);
+    } else {
+       mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
+    }
 
     if (isOffloaded()) {
         mAudioTrack->signal();
@@ -547,6 +649,9 @@
 
 status_t AudioTrack::setAuxEffectSendLevel(float level)
 {
+    if (mDirectTrack != NULL) {
+        return NO_ERROR;
+    }
     if (level < 0.0f || level > 1.0f) {
         return BAD_VALUE;
     }
@@ -594,6 +699,9 @@
     }
 
     AutoMutex lock(mLock);
+    if(mAudioDirectOutput != -1) {
+        return mAudioFlinger->sampleRate(mAudioDirectOutput);
+    }
     return mSampleRate;
 }
 
@@ -820,21 +928,21 @@
 
     // Not all of these values are needed under all conditions, but it is easier to get them all
 
-    uint32_t afLatency;
+    uint32_t afLatency = 0;
     status = AudioSystem::getLatency(output, streamType, &afLatency);
     if (status != NO_ERROR) {
         ALOGE("getLatency(%d) failed status %d", output, status);
         return NO_INIT;
     }
 
-    size_t afFrameCount;
+    size_t afFrameCount = 0;
     status = AudioSystem::getFrameCount(output, streamType, &afFrameCount);
     if (status != NO_ERROR) {
         ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, streamType, status);
         return NO_INIT;
     }
 
-    uint32_t afSampleRate;
+    uint32_t afSampleRate = 0;
     status = AudioSystem::getSamplingRate(output, streamType, &afSampleRate);
     if (status != NO_ERROR) {
         ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, streamType, status);
@@ -903,6 +1011,10 @@
         // FIXME move these calculations and associated checks to server
 
         // Ensure that buffer depth covers at least audio hardware latency
+        if(!afSampleRate && !afFrameCount) {
+            ALOGW("samplerate or framecount zero");
+            return NO_INIT;
+        }
         uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
         ALOGV("afFrameCount=%d, minBufCount=%d, afSampleRate=%u, afLatency=%d",
                 afFrameCount, minBufCount, afSampleRate, afLatency);
@@ -1039,7 +1151,11 @@
 
     mAudioTrack->attachAuxEffect(mAuxEffectId);
     // FIXME don't believe this lie
-    mLatency = afLatency + (1000*frameCount) / sampleRate;
+    if(sampleRate){
+        mLatency = afLatency + (1000*frameCount) / sampleRate;
+    }else{
+        mLatency = afLatency;
+    }
     mFrameCount = frameCount;
     // If IAudioTrack is re-created, don't let the requested frameCount
     // decrease.  This can confuse clients that cache frameCount().
@@ -1192,7 +1308,8 @@
     // restart track if it was disabled by audioflinger due to previous underrun
     if (mState == STATE_ACTIVE) {
         audio_track_cblk_t* cblk = mCblk;
-        if (android_atomic_and(~CBLK_DISABLED, &cblk->mFlags) & CBLK_DISABLED) {
+        if (cblk->mFlags & CBLK_DISABLED) {
+            android_atomic_and(~CBLK_DISABLED, &cblk->mFlags);
             ALOGW("releaseBuffer() track %p name=%s disabled due to previous underrun, restarting",
                     this, mName.string());
             // FIXME ignoring status
@@ -1205,6 +1322,11 @@
 
 ssize_t AudioTrack::write(const void* buffer, size_t userSize)
 {
+    if (mDirectTrack != NULL) {
+        ssize_t written = 0;
+        written = mDirectTrack->write(buffer,userSize);
+        return written;
+    }
     if (mTransfer != TRANSFER_SYNC || mIsTimed) {
         return INVALID_OPERATION;
     }
@@ -1761,7 +1883,9 @@
     result.append(buffer);
     snprintf(buffer, 255, "  sample rate(%u), status(%d)\n", mSampleRate, mStatus);
     result.append(buffer);
-    snprintf(buffer, 255, "  state(%d), latency (%d)\n", mState, mLatency);
+    uint32_t afLatency = 0;
+    AudioSystem::getLatency(mOutput, mStreamType, &afLatency);
+    snprintf(buffer, 255, "  state(%d), latency (%d)\n", mState, afLatency + (1000*mCblk->frameCount_) / mSampleRate);
     result.append(buffer);
     ::write(fd, result.string(), result.size());
     return NO_ERROR;
@@ -1784,6 +1908,25 @@
     }
 }
 
+void AudioTrack::notify(int msg) {
+    if (msg == EVENT_UNDERRUN) {
+        ALOGV("Posting event underrun to Audio Sink.");
+        mCbf(EVENT_UNDERRUN, mUserData, 0);
+    }
+    if (msg == EVENT_HW_FAIL) {
+        ALOGV("Posting event HW fail to Audio Sink.");
+        mCbf(EVENT_HW_FAIL, mUserData, 0);
+    }
+}
+
+status_t AudioTrack::getTimeStamp(uint64_t *tstamp) {
+    if (mDirectTrack != NULL) {
+        *tstamp = mDirectTrack->getTimeStamp();
+        ALOGE("Timestamp %lld ", *tstamp);
+    }
+    return NO_ERROR;
+}
+
 // =========================================================================
 
 AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 448a82e..d248d19 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -1,5 +1,6 @@
 /*
-**
+** Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
 ** Copyright 2007, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -74,6 +75,7 @@
     GET_PRIMARY_OUTPUT_SAMPLING_RATE,
     GET_PRIMARY_OUTPUT_FRAME_COUNT,
     SET_LOW_RAM_DEVICE,
+    CREATE_DIRECT_TRACK,
 };
 
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -143,6 +145,47 @@
         return track;
     }
 
+    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;
+    }
+
     virtual sp<IAudioRecord> openRecord(
                                 audio_io_handle_t input,
                                 uint32_t sampleRate,
@@ -782,6 +825,24 @@
             reply->writeStrongBinder(track->asBinder());
             return NO_ERROR;
         } break;
+        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;
         case OPEN_RECORD: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             audio_io_handle_t input = (audio_io_handle_t) data.readInt32();
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index 3c0d4cf..5e4da5d 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -1,4 +1,7 @@
 /*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
  * Copyright (C) 2009 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -49,9 +52,9 @@
             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) {
-            const AudioSystem::OutputDescriptor *desc =
-                    (const AudioSystem::OutputDescriptor *)param2;
+        } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED &&
+                   event != AudioSystem::EFFECT_CONFIG_CHANGED) {
+            const AudioSystem::OutputDescriptor *desc = (const AudioSystem::OutputDescriptor *)param2;
             data.writeInt32(desc->samplingRate);
             data.writeInt32(desc->format);
             data.writeInt32(desc->channelMask);
diff --git a/media/libmedia/IDirectTrack.cpp b/media/libmedia/IDirectTrack.cpp
new file mode 100644
index 0000000..e12cd74
--- /dev/null
+++ b/media/libmedia/IDirectTrack.cpp
@@ -0,0 +1,177 @@
+/*
+** Copyright (c) 2012, The Linux Foundation. All rights reserved.
+** Not a Contribution
+**
+** 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..f837a14
--- /dev/null
+++ b/media/libmedia/IDirectTrackClient.cpp
@@ -0,0 +1,68 @@
+/*
+** Copyright (c) 2012, The Linux Foundation. All rights reserved.
+** Not a Contribution.
+**
+** 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..50ff5d0 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -45,7 +45,8 @@
     {"amrwb",  AUDIO_ENCODER_AMR_WB},
     {"aac",    AUDIO_ENCODER_AAC},
     {"heaac",  AUDIO_ENCODER_HE_AAC},
-    {"aaceld", AUDIO_ENCODER_AAC_ELD}
+    {"aaceld", AUDIO_ENCODER_AAC_ELD},
+    {"lpcm",  AUDIO_ENCODER_LPCM}
 };
 
 const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
@@ -74,6 +75,8 @@
     {"wvga", CAMCORDER_QUALITY_WVGA},
     {"vga", CAMCORDER_QUALITY_VGA},
     {"wqvga", CAMCORDER_QUALITY_WQVGA},
+    {"4kuhd", CAMCORDER_QUALITY_4kUHD},
+    {"4kdci", CAMCORDER_QUALITY_4kDCI},
 
     {"timelapselow",  CAMCORDER_QUALITY_TIME_LAPSE_LOW},
     {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
@@ -83,6 +86,10 @@
     {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
     {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
     {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
+    {"timelapsevga", CAMCORDER_QUALITY_TIME_LAPSE_VGA},
+    {"timelapsewvga", CAMCORDER_QUALITY_TIME_LAPSE_WVGA},
+    {"timelapsefwvga", CAMCORDER_QUALITY_TIME_LAPSE_FWVGA},
+    {"timelapsewqvga", CAMCORDER_QUALITY_TIME_LAPSE_WQVGA},
 };
 
 /*static*/ void
@@ -804,6 +811,8 @@
 MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
 {
     profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
+    profiles->mAudioEncoders.add(createDefaultAacEncoderCap());
+    profiles->mAudioEncoders.add(createDefaultLpcmEncoderCap());
 }
 
 /*static*/ void
@@ -837,6 +846,18 @@
     return new MediaProfiles::AudioEncoderCap(
         AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
 }
+/*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);
+}
 
 /*static*/ void
 MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 7e0881c..6297061 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -683,7 +683,7 @@
     }
 
     // Allows calls from JNI in idle state to notify errors
-    if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
+    if (!((msg == MEDIA_ERROR || msg == MEDIA_QOE) && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
         ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
         if (locked) mLock.unlock();   // release the lock when done.
         return;
@@ -758,6 +758,8 @@
         break;
     case MEDIA_SUBTITLE_DATA:
         ALOGV("Received subtitle data message");
+    case MEDIA_QOE:
+        ALOGV("Received QOE Message for event : %d",ext2);
         break;
     default:
         ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index b47a785..badb84c 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -65,6 +65,18 @@
 
 LOCAL_MODULE:= libmediaplayerservice
 
+ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS),true)
+    LOCAL_CFLAGS += -DENABLE_AV_ENHANCEMENTS
+    LOCAL_C_INCLUDES += $(TOP)/frameworks/av/include/media
+    ifneq ($(TARGET_QCOM_MEDIA_VARIANT),)
+        LOCAL_C_INCLUDES += \
+            $(TOP)/hardware/qcom/media-$(TARGET_QCOM_MEDIA_VARIANT)/mm-core/inc
+    else
+        LOCAL_C_INCLUDES += \
+            $(TOP)/hardware/qcom/media/mm-core/inc
+    endif
+endif #TARGET_ENABLE_QC_AV_ENHANCEMENTS
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index b1685b9..29e1edd 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -346,21 +346,25 @@
     MediaPlayerFactory::IFactory* pFactory  = NULL;
     void* pFactoryLib = NULL;
     typedef MediaPlayerFactory::IFactory* (*CreateDASHDriverFn)();
-
+    ALOGE("calling dlopen on FACTORY_LIB");
     pFactoryLib = ::dlopen(FACTORY_LIB, RTLD_LAZY);
-    if (pFactoryLib != NULL) {
-        CreateDASHDriverFn pCreateFnPtr;
-        pCreateFnPtr = (CreateDASHDriverFn) dlsym(pFactoryLib, FACTORY_CREATE_FN);
-        if (pCreateFnPtr == NULL) {
-            ALOGE("Could not locate pCreateFnPtr");
+    if (pFactoryLib == NULL) {
+      ALOGE("Failed to open FACTORY_LIB Error : %s ",::dlerror());
+    } else {
+      CreateDASHDriverFn pCreateFnPtr;
+      ALOGE("calling dlsym on pFactoryLib for FACTORY_CREATE_FN ");
+      pCreateFnPtr = (CreateDASHDriverFn) dlsym(pFactoryLib, FACTORY_CREATE_FN);
+      if (pCreateFnPtr == NULL) {
+          ALOGE("Could not locate pCreateFnPtr");
+      } else {
+        pFactory = pCreateFnPtr();
+        if(pFactory == NULL) {
+          ALOGE("Failed to invoke CreateDASHDriverFn...");
         } else {
-            pFactory = pCreateFnPtr();
-            if(pFactory == NULL) {
-                ALOGE("Failed to invoke CreateDASHDriverFn...");
-            } else {
-                registerFactory_l(pFactory,DASH_PLAYER);
-            }
+          ALOGE("registering DASH Player factory...");
+          registerFactory_l(pFactory,DASH_PLAYER);
         }
+      }
     }
     sInitComplete = true;
 }
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9553458..951ca97 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1,5 +1,8 @@
 /*
 **
+** Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
+**
 ** Copyright 2008, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -78,6 +81,7 @@
 #include "HDCP.h"
 #include "HTTPBase.h"
 #include "RemoteDisplay.h"
+#define DEFAULT_SAMPLE_RATE 44100
 
 namespace {
 using android::media::Metadata;
@@ -1372,6 +1376,11 @@
     return mTrack->latency();
 }
 
+audio_stream_type_t MediaPlayerService::AudioOutput::streamType () const
+{
+    return mStreamType;
+}
+
 float MediaPlayerService::AudioOutput::msecsPerFrame() const
 {
     return mMsecsPerFrame;
@@ -1383,6 +1392,20 @@
     return mTrack->getPosition(position);
 }
 
+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;
+}
+
 status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
 {
     if (mTrack == 0) return NO_INIT;
@@ -1438,7 +1461,48 @@
 {
     mCallback = cb;
     mCallbackCookie = cookie;
+    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;
+        }
+        deleteRecycledTrack();
 
+        ALOGV("setVolume");
+        mCallbackData = newcbd;
+        audioTrack->setVolume(mLeftVolume, mRightVolume);
+        mSampleRateHz = sampleRate;
+        mFlags = flags;
+        mTrack = audioTrack;
+        return NO_ERROR;
+    }
     // Check argument "bufferCount" against the mininum buffer count
     if (bufferCount < mMinBufferCount) {
         ALOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
@@ -1667,7 +1731,6 @@
 
 ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
 {
-    LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
 
     //ALOGV("write(%p, %u)", buffer, size);
     if (mTrack != 0) {
@@ -1699,7 +1762,7 @@
 void MediaPlayerService::AudioOutput::close()
 {
     ALOGV("close");
-    mTrack.clear();
+    if (mTrack != 0) mTrack.clear();
 }
 
 void MediaPlayerService::AudioOutput::setVolume(float left, float right)
@@ -1752,55 +1815,97 @@
 void MediaPlayerService::AudioOutput::CallbackWrapper(
         int event, void *cookie, void *info) {
     //ALOGV("callbackwrapper");
-    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.
+    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, CB_EVENT_UNDERRUN);
         data->unlock();
-        if (buffer != NULL) {
-            buffer->size = 0;
+        return;
+    }
+    if (event == AudioTrack::EVENT_HW_FAIL) {
+        ALOGW("Event hardware failure");
+        CallbackData *data = (CallbackData*)cookie;
+        if (data != NULL) {
+            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;
+            }
+            ALOGV("Callback!!!");
+            (*me->mCallback)(me, NULL, (size_t)AudioTrack::EVENT_HW_FAIL,
+                             me->mCallbackCookie, CB_EVENT_HW_FAIL);
+            data->unlock();
         }
         return;
     }
-
-    switch(event) {
-    case AudioTrack::EVENT_MORE_DATA: {
-        size_t actualSize = (*me->mCallback)(
-                me, buffer->raw, buffer->size, me->mCallbackCookie,
-                CB_EVENT_FILL_BUFFER);
-
-        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;
+    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();
+            if (buffer != NULL) {
+                buffer->size = 0;
+            }
+            return;
         }
 
-        buffer->size = actualSize;
-        } break;
+        switch(event) {
+        case AudioTrack::EVENT_MORE_DATA: {
+            size_t actualSize = (*me->mCallback)(
+                    me, buffer->raw, buffer->size, me->mCallbackCookie,
+                    CB_EVENT_FILL_BUFFER);
+
+            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;
+            }
+
+            buffer->size = actualSize;
+            } break;
 
 
-    case AudioTrack::EVENT_STREAM_END:
-        ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
-        (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
-                me->mCallbackCookie, CB_EVENT_STREAM_END);
-        break;
+        case AudioTrack::EVENT_STREAM_END:
+            ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
+            (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
+                    me->mCallbackCookie, CB_EVENT_STREAM_END);
+            break;
 
-    case AudioTrack::EVENT_NEW_IAUDIOTRACK :
-        ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
-        (*me->mCallback)(me,  NULL /* buffer */, 0 /* size */,
-                me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
-        break;
+        case AudioTrack::EVENT_NEW_IAUDIOTRACK :
+            ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
+            (*me->mCallback)(me,  NULL /* buffer */, 0 /* size */,
+                    me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
+            break;
 
-    default:
-        ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
+        default:
+            ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
+        }
+
+        data->unlock();
     }
 
-    data->unlock();
+    return;
 }
 
 int MediaPlayerService::AudioOutput::getSessionId() const
@@ -1833,6 +1938,11 @@
     return NO_ERROR;
 }
 
+ssize_t MediaPlayerService::AudioCache::sampleRate() const
+{
+    return mSampleRate;
+}
+
 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 21f4117..1df311c 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -1,5 +1,8 @@
 /*
 **
+** Copyright (c) 2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
+**
 ** Copyright 2008, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -82,6 +85,7 @@
         virtual ssize_t         channelCount() const;
         virtual ssize_t         frameSize() const;
         virtual uint32_t        latency() const;
+        virtual audio_stream_type_t streamType() const;
         virtual float           msecsPerFrame() const;
         virtual status_t        getPosition(uint32_t *position) const;
         virtual status_t        getFramesWritten(uint32_t *frameswritten) const;
@@ -112,9 +116,13 @@
                 void            setNextOutput(const sp<AudioOutput>& nextOutput);
                 void            switchToNextOutput();
         virtual bool            needsTrailingPadding() { return mNextOutput == NULL; }
+
         virtual status_t        setParameters(const String8& keyValuePairs);
         virtual String8         getParameters(const String8& keys);
 
+        virtual ssize_t         sampleRate() const;
+        virtual status_t        getTimeStamp(uint64_t *tstamp);
+
     private:
         static void             setMinBufferCount();
         static void             CallbackWrapper(
@@ -208,7 +216,6 @@
                 void            setAudioStreamType(audio_stream_type_t streamType) {}
                 void            setVolume(float left, float right) {}
         virtual status_t        setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; }
-                uint32_t        sampleRate() const { return mSampleRate; }
                 audio_format_t  format() const { return mFormat; }
                 size_t          size() const { return mSize; }
                 status_t        wait();
@@ -218,6 +225,7 @@
         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;
+        virtual ssize_t         sampleRate() const;
 
     private:
                                 AudioCache();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 4fc38da..c1c6e4a 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -17,7 +17,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "StagefrightRecorder"
 #include <utils/Log.h>
-
+#include <media/AudioParameter.h>
 #include "StagefrightRecorder.h"
 
 #include <binder/IPCThreadState.h>
@@ -29,6 +29,8 @@
 #include <media/stagefright/AudioSource.h>
 #include <media/stagefright/AMRWriter.h>
 #include <media/stagefright/AACWriter.h>
+#include <media/stagefright/ExtendedWriter.h>
+#include <media/stagefright/WAVEWriter.h>
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/CameraSourceTimeLapse.h>
 #include <media/stagefright/MPEG2TSWriter.h>
@@ -42,13 +44,18 @@
 #include <camera/ICamera.h>
 #include <camera/CameraParameters.h>
 #include <gui/Surface.h>
+#include <utils/String8.h>
 
 #include <utils/Errors.h>
 #include <sys/types.h>
 #include <ctype.h>
 #include <unistd.h>
 
+#include "ExtendedUtils.h"
 #include <system/audio.h>
+#ifdef ENABLE_AV_ENHANCEMENTS
+#include <QCMediaDefs.h>
+#endif
 
 #include "ARTPWriter.h"
 #include <cutils/properties.h>
@@ -103,6 +110,9 @@
         ALOGE("Invalid audio source: %d", as);
         return BAD_VALUE;
     }
+    if (ExtendedUtils::ShellProp::isAudioDisabled()) {
+        return OK;
+    }
 
     if (as == AUDIO_SOURCE_DEFAULT) {
         mAudioSource = AUDIO_SOURCE_MIC;
@@ -155,12 +165,32 @@
         return BAD_VALUE;
     }
 
+    if (ExtendedUtils::ShellProp::isAudioDisabled()) {
+        return OK;
+    }
     if (ae == AUDIO_ENCODER_DEFAULT) {
         mAudioEncoder = AUDIO_ENCODER_AMR_NB;
     } else {
         mAudioEncoder = ae;
     }
 
+    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 = mAudioBitRate ? mAudioBitRate : 23850;
+    } else {
+        mSampleRate = mSampleRate ? mSampleRate : 8000;
+        mAudioChannels = mAudioChannels ? mAudioChannels : 1;
+        mAudioBitRate = mAudioBitRate ? mAudioBitRate : 12200;
+    }
     return OK;
 }
 
@@ -329,7 +359,7 @@
 
 status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
     ALOGV("setParamAudioNumberOfChannels: %d", channels);
-    if (channels <= 0 || channels >= 3) {
+    if (channels != 1 && channels != 2 && channels != 6) {
         ALOGE("Invalid number of audio channels: %d", channels);
         return BAD_VALUE;
     }
@@ -795,6 +825,14 @@
             status = startMPEG2TSRecording();
             break;
 
+#ifdef ENABLE_AV_ENHANCEMENTS
+        case OUTPUT_FORMAT_QCP:
+            status = startExtendedRecording( );
+            break;
+#endif
+        case OUTPUT_FORMAT_WAVE:
+            status = startWAVERecording( );
+            break;
         default:
             ALOGE("Unsupported output file format: %d", mOutputFormat);
             status = UNKNOWN_ERROR;
@@ -819,6 +857,52 @@
 }
 
 sp<MediaSource> StagefrightRecorder::createAudioSource() {
+    bool tunneledSource = false;
+    const char *tunnelMime;
+    {
+        AudioParameter param;
+        String8 key("tunneled-input-formats");
+        param.add( key, String8("get") );
+        String8 valueStr = AudioSystem::getParameters( 0, param.toString());
+        AudioParameter result(valueStr);
+        int value;
+        if ( mAudioEncoder == AUDIO_ENCODER_AMR_NB &&
+            result.getInt(String8("AMR"),value) == NO_ERROR ) {
+            tunneledSource = true;
+            tunnelMime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+        }
+#ifdef ENABLE_AV_ENHANCEMENTS
+        else if ( mAudioEncoder == AUDIO_ENCODER_QCELP &&
+            result.getInt(String8("QCELP"),value) == NO_ERROR ) {
+            tunneledSource = true;
+            tunnelMime = MEDIA_MIMETYPE_AUDIO_QCELP;
+        }
+        else if ( mAudioEncoder == AUDIO_ENCODER_EVRC &&
+            result.getInt(String8("EVRC"),value) == NO_ERROR ) {
+            tunneledSource = true;
+            tunnelMime = MEDIA_MIMETYPE_AUDIO_EVRC;
+        }
+#endif
+        else if ( mAudioEncoder == AUDIO_ENCODER_AMR_WB &&
+            result.getInt(String8("AWB"),value) == NO_ERROR ) {
+            tunneledSource = true;
+            tunnelMime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
+        }
+    }
+    if ( tunneledSource ) {
+        ALOGD("tunnel recording");
+        sp<AudioSource> audioSource = NULL;
+        sp<MetaData> meta = new MetaData;
+        meta->setInt32(kKeyChannelCount, mAudioChannels);
+        meta->setInt32(kKeySampleRate, mSampleRate);
+        meta->setInt32(kKeyBitRate, mAudioBitRate);
+        if (mAudioTimeScale > 0) {
+            meta->setInt32(kKeyTimeScale, mAudioTimeScale);
+        }
+        meta->setCString( kKeyMIMEType, tunnelMime );
+        audioSource = new AudioSource( mAudioSource, meta);
+        return audioSource->initCheck( ) == OK ? audioSource : NULL;
+    }
     sp<AudioSource> audioSource =
         new AudioSource(
                 mAudioSource,
@@ -835,6 +919,9 @@
     sp<MetaData> encMeta = new MetaData;
     const char *mime;
     switch (mAudioEncoder) {
+        case AUDIO_ENCODER_LPCM:
+            mime = MEDIA_MIMETYPE_AUDIO_RAW;
+            break;
         case AUDIO_ENCODER_AMR_NB:
         case AUDIO_ENCODER_DEFAULT:
             mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
@@ -854,6 +941,14 @@
             mime = MEDIA_MIMETYPE_AUDIO_AAC;
             encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD);
             break;
+#ifdef ENABLE_AV_ENHANCEMENTS
+        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);
@@ -875,9 +970,28 @@
 
     OMXClient client;
     CHECK_EQ(client.connect(), (status_t)OK);
+#ifdef ENABLE_AV_ENHANCEMENTS
+    sp<MediaSource> audioEncoder;
+    if (ExtendedUtils::UseQCHWAACEncoder(mAudioEncoder,mAudioChannels,mAudioBitRate,mSampleRate)) {
+        ALOGV("use QCOM HW AAC encoder");
+        audioEncoder = OMXCodec::Create(client.interface(), encMeta,
+            true /* createEncoder */, audioSource,"OMX.qcom.audio.encoder.aac",OMXCodec::kHardwareCodecsOnly );
+    } else {
+        audioEncoder = OMXCodec::Create(client.interface(), encMeta,
+            true /* createEncoder */, audioSource);
+    }
+#else
     sp<MediaSource> audioEncoder =
         OMXCodec::Create(client.interface(), encMeta,
                          true /* createEncoder */, audioSource);
+#endif
+    if (audioEncoder == NULL) {
+        ALOGD("No encoder is needed, use the AudioSource directly as the MediaSource for LPCM format");
+        audioEncoder = audioSource;
+    }
+    if (mAudioSourceNode != NULL) {
+        mAudioSourceNode.clear();
+    }
     mAudioSourceNode = audioSource;
 
     return audioEncoder;
@@ -914,14 +1028,29 @@
                     mAudioEncoder);
             return BAD_VALUE;
         }
+        if (mSampleRate != 8000) {
+            ALOGE("Invalid sampling rate %d used for AMRNB recording",
+                    mSampleRate);
+            return BAD_VALUE;
+        }
     } 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;
         }
+        if (mSampleRate != 16000) {
+            ALOGE("Invalid sample rate %d used for AMRWB recording",
+                    mSampleRate);
+            return BAD_VALUE;
+        }
     }
 
+    if (mAudioChannels != 1) {
+        ALOGE("Invalid number of audio channels %d used for amr recording",
+                mAudioChannels);
+        return BAD_VALUE;
+    }
     mWriter = new AMRWriter(mOutputFd);
     status_t status = startRawAudioRecording();
     if (status != OK) {
@@ -930,6 +1059,18 @@
     }
     return status;
 }
+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;
+}
 
 status_t StagefrightRecorder::startRawAudioRecording() {
     if (mAudioSource >= AUDIO_SOURCE_CNT) {
@@ -1433,6 +1574,15 @@
     if (mVideoTimeScale > 0) {
         enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
     }
+
+    status_t retVal = ExtendedUtils::HFR::reCalculateFileDuration(
+            meta, enc_meta, mMaxFileDurationUs, mFrameRate, mVideoEncoder);
+    if(retVal != OK) {
+        return retVal;
+    }
+
+    ExtendedUtils::ShellProp::setEncoderProfile(mVideoEncoder, mVideoEncoderProfile);
+
     if (mVideoEncoderProfile != -1) {
         enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
     }
@@ -1485,6 +1635,7 @@
         case AUDIO_ENCODER_AAC:
         case AUDIO_ENCODER_HE_AAC:
         case AUDIO_ENCODER_AAC_ELD:
+        case AUDIO_ENCODER_LPCM:
             break;
 
         default:
@@ -1646,6 +1797,10 @@
         ::close(mOutputFd);
         mOutputFd = -1;
     }
+    if (mAudioSourceNode != NULL) {
+        mAudioSourceNode.clear();
+        mAudioSourceNode = NULL;
+    }
 
     if (mStarted) {
         mStarted = false;
@@ -1688,9 +1843,9 @@
     mVideoHeight   = 144;
     mFrameRate     = -1;
     mVideoBitRate  = 192000;
-    mSampleRate    = 8000;
-    mAudioChannels = 1;
-    mAudioBitRate  = 12200;
+    mSampleRate    = 0;
+    mAudioChannels = 0;
+    mAudioBitRate  = 0;
     mInterleaveDurationUs = 0;
     mIFramesIntervalSec = 1;
     mAudioSourceNode = 0;
@@ -1802,4 +1957,39 @@
     ::write(fd, result.string(), result.size());
     return OK;
 }
+#ifdef ENABLE_AV_ENHANCEMENTS
+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 c864207..04724fe 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -135,6 +135,7 @@
     status_t startMPEG4Recording();
     status_t startAMRRecording();
     status_t startAACRecording();
+    status_t startWAVERecording();
     status_t startRawAudioRecording();
     status_t startRTPRecording();
     status_t startMPEG2TSRecording();
@@ -190,6 +191,9 @@
 
     StagefrightRecorder(const StagefrightRecorder &);
     StagefrightRecorder &operator=(const StagefrightRecorder &);
+#ifdef ENABLE_AV_ENHANCEMENTS
+    status_t startExtendedRecording();
+#endif
 };
 
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 22f699e..6b27e52 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -25,6 +25,7 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/ACodec.h>
 #include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/ExtendedCodec.h>
 
 namespace android {
 
@@ -57,6 +58,18 @@
         mCSD.push(csd);
     }
 
+    sp<ABuffer> extendedCSD = ExtendedCodec::getRawCodecSpecificData(format);
+    if (extendedCSD != NULL) {
+        ALOGV("pushing extended CSD of size %d", extendedCSD->size());
+        mCSD.push(extendedCSD);
+    }
+
+    sp<ABuffer> aacCSD = ExtendedCodec::getAacCodecSpecificData(format);
+    if (aacCSD != NULL) {
+        ALOGV("pushing AAC CSD of size %d", aacCSD->size());
+        mCSD.push(aacCSD);
+    }
+
     if (mNativeWindow != NULL) {
         format->setObject("native-window", mNativeWindow);
     }
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
old mode 100644
new mode 100755
index f315d04..1732620
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -32,6 +32,7 @@
 #include <media/stagefright/NativeWindowWrapper.h>
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/ExtendedCodec.h>
 
 #include <media/hardware/HardwareAPI.h>
 
@@ -46,6 +47,7 @@
 #endif
 
 #include "include/avc_utils.h"
+#include "include/ExtendedUtils.h"
 
 namespace android {
 
@@ -378,7 +380,8 @@
       mDequeueCounter(0),
       mStoreMetaDataInOutputBuffers(false),
       mMetaDataBuffersToSubmit(0),
-      mRepeatFrameDelayUs(-1ll) {
+      mRepeatFrameDelayUs(-1ll),
+      mInSmoothStreamingMode(false) {
     mUninitializedState = new UninitializedState(this);
     mLoadedState = new LoadedState(this);
     mLoadedToIdleState = new LoadedToIdleState(this);
@@ -979,6 +982,10 @@
             "audio_decoder.amrnb", "audio_encoder.amrnb" },
         { MEDIA_MIMETYPE_AUDIO_AMR_WB,
             "audio_decoder.amrwb", "audio_encoder.amrwb" },
+#ifdef ENABLE_QC_AV_ENHANCEMENTS
+        { MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
+            "audio_decoder.amrwbplus", "audio_encoder.amrwbplus" },
+#endif
         { MEDIA_MIMETYPE_AUDIO_AAC,
             "audio_decoder.aac", "audio_encoder.aac" },
         { MEDIA_MIMETYPE_AUDIO_VORBIS,
@@ -1016,7 +1023,7 @@
     }
 
     if (i == kNumMimeToRole) {
-        return ERROR_UNSUPPORTED;
+        return ExtendedCodec::setSupportedRole(mOMX, mNode, isEncoder, mime);
     }
 
     const char *role =
@@ -1212,6 +1219,10 @@
                 err = setupVideoDecoder(mime, width, height);
             }
         }
+        if (err == OK) {
+            const char* componentName = mComponentName.c_str();
+            ExtendedCodec::configureVideoDecoder(msg, mime, mOMX, 0, mNode, componentName);
+        }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
         int32_t numChannels, sampleRate;
         if (!msg->findInt32("channel-count", &numChannels)
@@ -1294,6 +1305,19 @@
         } else {
             err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
         }
+    } else {
+        if (encoder) {
+            int32_t numChannels, sampleRate;
+            if (msg->findInt32("channel-count", &numChannels)
+                  && msg->findInt32("sample-rate", &sampleRate)) {
+                setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+            }
+       }
+       err = ExtendedCodec::setAudioFormat(
+                 msg, mime, mOMX, mNode, mIsEncoder);
+       if(err != OK) {
+           return err;
+       }
     }
 
     if (err != OK) {
@@ -1772,7 +1796,9 @@
     status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat);
 
     if (err != OK) {
-        return err;
+        err = ExtendedCodec::setVideoOutputFormat(mime, &compressionFormat);
+        if (err != OK)
+            return err;
     }
 
     err = setVideoPortFormatType(
@@ -1802,6 +1828,9 @@
         return err;
     }
 
+    ExtendedCodec::enableSmoothStreaming(
+            mOMX, mNode, &mInSmoothStreamingMode, mComponentName.c_str());
+
     return OK;
 }
 
@@ -1895,7 +1924,11 @@
     err = GetVideoCodingTypeFromMime(mime, &compressionFormat);
 
     if (err != OK) {
-        return err;
+        err = ExtendedCodec::setVideoInputFormat(mime, &compressionFormat);
+        if (err != OK) {
+            ALOGE("Not a supported video mime type: %s", mime);
+            return err;
+        }
     }
 
     err = setVideoPortFormatType(
@@ -2559,6 +2592,9 @@
                             rect.nTop,
                             rect.nLeft + rect.nWidth,
                             rect.nTop + rect.nHeight);
+                    reply->setInt32(
+                            "color-format",
+                            (int)(videoDef->eColorFormat));
                 }
             }
             break;
@@ -2675,7 +2711,24 @@
                 }
 
                 default:
+                {
+                    AString mimeType;
+                    status_t err = ExtendedCodec::handleSupportedAudioFormats(
+                        audioDef->eEncoding, &mimeType);
+                    if (err == OK) {
+                        int channelCount;
+                        err = ExtendedCodec::getSupportedAudioFormatInfo(
+                                      &mimeType,
+                                      mOMX,
+                                      mNode,
+                                      kPortIndexOutput,
+                                      &channelCount);
+                        notify->setString("mime", mimeType.c_str());
+                        notify->setInt32("channel-count", channelCount);
+                        break;
+                    }
                     TRESPASS();
+                }
             }
             break;
         }
@@ -3425,6 +3478,13 @@
     android_native_rect_t crop;
     if (msg->findRect("crop",
             &crop.left, &crop.top, &crop.right, &crop.bottom)) {
+        if (mCodec->mInSmoothStreamingMode) {
+            OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused;
+            CHECK(msg->findInt32("color-format", (int32_t*)&eColorFormat));
+            ExtendedUtils::updateNativeWindowBufferGeometry(
+                    mCodec->mNativeWindow.get(), crop.right,
+                    crop.bottom, eColorFormat);
+        }
         CHECK_EQ(0, native_window_set_crop(
                 mCodec->mNativeWindow.get(), &crop));
     }
@@ -3637,6 +3697,7 @@
             ++matchIndex) {
         componentName = matchingCodecs.itemAt(matchIndex).mName.string();
         quirks = matchingCodecs.itemAt(matchIndex).mQuirks;
+        ExtendedCodec::overrideComponentName(quirks, msg, &componentName);
 
         pid_t tid = androidGetTid();
         int prevPriority = androidGetThreadPriority(tid);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 3d5e06d..9373e33 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -1,6 +1,15 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+ifeq ($(BOARD_USES_ALSA_AUDIO),true)
+   ifeq ($(USE_TUNNEL_MODE),true)
+        LOCAL_CFLAGS += -DUSE_TUNNEL_MODE
+   endif
+   ifeq ($(NO_TUNNEL_MODE_FOR_MULTICHANNEL),true)
+        LOCAL_CFLAGS += -DNO_TUNNEL_MODE_FOR_MULTICHANNEL
+   endif
+endif
+
 include frameworks/av/media/libstagefright/codecs/common/Config.mk
 
 ifeq ($(BOARD_HTC_3D_SUPPORT),true)
@@ -25,6 +34,7 @@
         FLACExtractor.cpp                 \
         HTTPBase.cpp                      \
         JPEGSource.cpp                    \
+        LPAPlayerALSA.cpp                 \
         MP3Extractor.cpp                  \
         MPEG2TSWriter.cpp                 \
         MPEG4Extractor.cpp                \
@@ -43,6 +53,7 @@
         NuMediaExtractor.cpp              \
         OMXClient.cpp                     \
         OMXCodec.cpp                      \
+        ExtendedCodec.cpp                 \
         OggExtractor.cpp                  \
         SampleIterator.cpp                \
         SampleTable.cpp                   \
@@ -53,14 +64,18 @@
         ThrottledSource.cpp               \
         TimeSource.cpp                    \
         TimedEventQueue.cpp               \
+        TunnelPlayer.cpp                  \
         Utils.cpp                         \
         VBRISeeker.cpp                    \
         WAVExtractor.cpp                  \
+        WAVEWriter.cpp                    \
         WVMExtractor.cpp                  \
         XINGSeeker.cpp                    \
         avc_utils.cpp                     \
         mp4/FragmentedMP4Parser.cpp       \
         mp4/TrackFragment.cpp             \
+        ExtendedExtractor.cpp             \
+        ExtendedUtils.cpp                 \
 
 LOCAL_C_INCLUDES:= \
         $(TOP)/frameworks/av/include/media/stagefright/timedtext \
@@ -111,6 +126,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_color_conversion \
+        libstagefright_mp3dec \
         libstagefright_aacenc \
         libstagefright_matroska \
         libstagefright_timedtext \
@@ -121,6 +137,13 @@
         libFLAC \
         libmedia_helper
 
+ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS),true)
+       LOCAL_CFLAGS     += -DENABLE_AV_ENHANCEMENTS
+       LOCAL_C_INCLUDES += $(TOP)/hardware/qcom/media/mm-core/inc
+       LOCAL_SRC_FILES  += ExtendedMediaDefs.cpp
+       LOCAL_SRC_FILES  += ExtendedWriter.cpp
+endif #TARGET_ENABLE_AV_ENHANCEMENTS
+
 LOCAL_SRC_FILES += \
         chromium_http_stub.cpp
 LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
@@ -150,6 +173,12 @@
 LOCAL_CFLAGS += -DUSE_TI_DUCATI_H264_PROFILE
 endif
 
+ifdef DOLBY_UDC
+  LOCAL_CFLAGS += -DDOLBY_UDC
+endif #DOLBY_UDC
+ifdef DOLBY_UDC_MULTICHANNEL
+  LOCAL_CFLAGS += -DDOLBY_UDC_MULTICHANNEL
+endif #DOLBY_UDC_MULTICHANNEL
 LOCAL_MODULE:= libstagefright
 
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 18bebd8..ffa3475 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -1,4 +1,6 @@
 /*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
  * Copyright (C) 2009 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -36,8 +38,7 @@
 
 AudioPlayer::AudioPlayer(
         const sp<MediaPlayerBase::AudioSink> &audioSink,
-        uint32_t flags,
-        AwesomePlayer *observer)
+        uint32_t flags, AwesomePlayer *observer)
     : mInputBuffer(NULL),
       mSampleRate(0),
       mLatencyUs(0),
@@ -51,6 +52,7 @@
       mFinalStatus(OK),
       mSeekTimeUs(0),
       mStarted(false),
+      mSourcePaused(false),
       mIsFirstBuffer(false),
       mFirstBufferResult(OK),
       mFirstBuffer(NULL),
@@ -79,6 +81,7 @@
 
     status_t err;
     if (!sourceAlreadyStarted) {
+        mSourcePaused = false;
         err = mSource->start();
 
         if (err != OK) {
@@ -253,7 +256,6 @@
 
 void AudioPlayer::pause(bool playPendingSamples) {
     CHECK(mStarted);
-
     if (playPendingSamples) {
         if (mAudioSink.get() != NULL) {
             mAudioSink->stop();
@@ -274,10 +276,19 @@
     }
 
     mPlaying = false;
+    CHECK(mSource != NULL);
+    if (mSource->pause() == OK) {
+        mSourcePaused = true;
+    }
 }
 
 status_t AudioPlayer::resume() {
     CHECK(mStarted);
+    CHECK(mSource != NULL);
+    if (mSourcePaused == true) {
+        mSourcePaused = false;
+        mSource->start();
+    }
     status_t err;
 
     if (mAudioSink.get() != NULL) {
@@ -339,7 +350,7 @@
         mInputBuffer->release();
         mInputBuffer = NULL;
     }
-
+    mSourcePaused = false;
     mSource->stop();
 
     // The following hack is necessary to ensure that the OMX
@@ -415,6 +426,11 @@
         MediaPlayerBase::AudioSink::cb_event_t event) {
     AudioPlayer *me = (AudioPlayer *)cookie;
 
+    if (buffer == NULL) {
+        //Not applicable for AudioPlayer
+        ALOGE("This indicates the event underrun case for LPA/Tunnel");
+        return 0;
+    }
     switch(event) {
     case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
         return me->fillBuffer(buffer, size);
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 5396c14..4e9699e 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -27,10 +27,14 @@
 #include <media/stagefright/foundation/ALooper.h>
 #include <cutils/properties.h>
 #include <stdlib.h>
+#ifdef ENABLE_QC_AV_ENHANCEMENTS
+#include <QCMediaDefs.h>
+#endif
+#include <system/audio.h>
+#define DEFAULT_TUNNEL_BUFFER_COUNT 4
 
 namespace android {
-// Treat time out as an error if we have not received any output
-// buffers after 1 seconds
+
 const static int64_t WaitLockEventTimeOutNs = 1000000000LL;
 static void AudioRecordCallbackFunction(int event, void *user, void *info) {
     AudioSource *source = (AudioSource *) user;
@@ -51,23 +55,31 @@
 
 AudioSource::AudioSource(
         audio_source_t inputSource, uint32_t sampleRate, uint32_t channelCount)
-    : mStarted(false),
+    : mRecord(NULL),
+      mStarted(false),
       mSampleRate(sampleRate),
       mPrevSampleTimeUs(0),
       mNumFramesReceived(0),
-      mNumClientOwnedBuffers(0) {
+      mNumClientOwnedBuffers(0),
+      mFormat(AUDIO_FORMAT_PCM_16_BIT),
+      mMime(MEDIA_MIMETYPE_AUDIO_RAW) {
     ALOGV("sampleRate: %d, channelCount: %d", sampleRate, channelCount);
-    CHECK(channelCount == 1 || channelCount == 2);
+    CHECK(channelCount == 1 || channelCount == 2 || channelCount == 6);
 
     size_t minFrameCount;
     status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
                                            sampleRate,
                                            AUDIO_FORMAT_PCM_16_BIT,
                                            audio_channel_in_mask_from_count(channelCount));
+    if ( NO_ERROR != AudioSystem::getInputBufferSize(
+        sampleRate, mFormat, channelCount, (size_t*)&mMaxBufferSize) ) {
+        mMaxBufferSize = kMaxBufferSize;
+        ALOGV("mMaxBufferSize = %d", mMaxBufferSize);
+    }
     if (status == OK) {
         // make sure that the AudioRecord callback never returns more than the maximum
         // buffer size
-        int frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount;
+        int frameCount = mMaxBufferSize / sizeof(int16_t) / channelCount;
 
         // make sure that the AudioRecord total buffer size is large enough
         int bufCount = 2;
@@ -78,13 +90,11 @@
         mRecord = new AudioRecord(
                     inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
                     audio_channel_in_mask_from_count(channelCount),
-                    bufCount * frameCount,
+                    DEFAULT_TUNNEL_BUFFER_COUNT * mMaxBufferSize / sizeof(int16_t), /* Enable ping-pong buffers */
                     AudioRecordCallbackFunction,
                     this,
                     frameCount);
         mInitCheck = mRecord->initCheck();
-
-        //configure the auto ramp start duration
         mAutoRampStartUs = kAutoRampStartUs;
         uint32_t playbackLatencyMs = 0;
         if (AudioSystem::getOutputLatency(&playbackLatencyMs,
@@ -99,6 +109,59 @@
     }
 }
 
+AudioSource::AudioSource( audio_source_t inputSource, const sp<MetaData>& meta )
+    : mStarted(false),
+      mPrevSampleTimeUs(0),
+      mNumFramesReceived(0),
+      mNumClientOwnedBuffers(0),
+      mFormat(AUDIO_FORMAT_PCM_16_BIT),
+      mMime(MEDIA_MIMETYPE_AUDIO_RAW) {
+    const char * mime;
+    ALOGE("SK: in AudioSource : inputSource: %d", inputSource);
+    CHECK( meta->findCString( kKeyMIMEType, &mime ) );
+    mMime = mime;
+    int32_t sampleRate = 0; //these are the only supported values
+    int32_t channels = 0;      //for the below tunnel formats
+    CHECK( meta->findInt32( kKeyChannelCount, &channels ) );
+    CHECK( meta->findInt32( kKeySampleRate, &sampleRate ) );
+    int32_t frameSize = -1;
+    mSampleRate = sampleRate;
+    if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_AMR_NB ) ) {
+        mFormat = AUDIO_FORMAT_AMR_NB;
+        frameSize = AMR_FRAMESIZE;
+        mMaxBufferSize = AMR_FRAMESIZE*10;
+    }
+#ifdef ENABLE_QC_AV_ENHANCEMENTS
+    else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_QCELP ) ) {
+        mFormat = AUDIO_FORMAT_QCELP;
+        frameSize = QCELP_FRAMESIZE;
+        mMaxBufferSize = QCELP_FRAMESIZE*10;
+    }
+    else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_EVRC ) ) {
+        mFormat = AUDIO_FORMAT_EVRC;
+        frameSize = EVRC_FRAMESIZE;
+        mMaxBufferSize = EVRC_FRAMESIZE*10;
+    }
+#endif
+    else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_AMR_WB ) ) {
+        mFormat = AUDIO_FORMAT_AMR_WB;
+        frameSize = AMR_WB_FRAMESIZE;
+        mMaxBufferSize = AMR_WB_FRAMESIZE*10;
+    }
+    else {
+        CHECK(0);
+    }
+    mAutoRampStartUs = 0;
+    CHECK(channels == 1 || channels == 2);
+    mRecord = new AudioRecord(
+                inputSource, sampleRate, mFormat,
+                channels > 1? AUDIO_CHANNEL_IN_STEREO:
+                AUDIO_CHANNEL_IN_MONO,
+                4*mMaxBufferSize/channels/frameSize,
+                AudioRecordCallbackFunction,
+                this);
+    mInitCheck = mRecord->initCheck();
+}
 AudioSource::~AudioSource() {
     if (mStarted) {
         reset();
@@ -180,10 +243,10 @@
     }
 
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-    meta->setInt32(kKeySampleRate, mSampleRate);
+    meta->setCString(kKeyMIMEType, mMime);
+    meta->setInt32(kKeySampleRate, mRecord->getSampleRate());
     meta->setInt32(kKeyChannelCount, mRecord->channelCount());
-    meta->setInt32(kKeyMaxInputSize, kMaxBufferSize);
+    meta->setInt32(kKeyMaxInputSize, mMaxBufferSize);
 
     return meta;
 }
@@ -247,22 +310,24 @@
     int64_t timeUs;
     CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
     int64_t elapsedTimeUs = timeUs - mStartTimeUs;
-    if (elapsedTimeUs < mAutoRampStartUs) {
+    if ( mFormat == AUDIO_FORMAT_PCM_16_BIT ) {
+        if (elapsedTimeUs < mAutoRampStartUs) {
         memset((uint8_t *) buffer->data(), 0, buffer->range_length());
-    } else if (elapsedTimeUs < mAutoRampStartUs + kAutoRampDurationUs) {
+        } else if (elapsedTimeUs < mAutoRampStartUs + kAutoRampDurationUs) {
         int32_t autoRampDurationFrames =
                     (kAutoRampDurationUs * mSampleRate + 500000LL) / 1000000LL;
 
         int32_t autoRampStartFrames =
-                    (mAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL;
+                        (mAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL;
 
         int32_t nFrames = mNumFramesReceived - autoRampStartFrames;
         rampVolume(nFrames, autoRampDurationFrames,
                 (uint8_t *) buffer->data(), buffer->range_length());
+        }
     }
 
     // Track the max recording signal amplitude.
-    if (mTrackMaxAmplitude) {
+    if (mTrackMaxAmplitude && ( mFormat == AUDIO_FORMAT_PCM_16_BIT)) {
         trackMaxAmplitude(
             (int16_t *) buffer->data(), buffer->range_length() >> 1);
     }
@@ -319,6 +384,7 @@
     }
 
     CHECK_EQ(numLostBytes & 1, 0u);
+    if ( mFormat == AUDIO_FORMAT_PCM_16_BIT )
     CHECK_EQ(audioBuffer.size & 1, 0u);
     if (numLostBytes > 0) {
         // Loss of audio frames should happen rarely; thus the LOGW should
@@ -357,19 +423,30 @@
 void AudioSource::queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs) {
     const size_t bufferSize = buffer->range_length();
     const size_t frameSize = mRecord->frameSize();
-    const int64_t timestampUs =
-                mPrevSampleTimeUs +
-                    ((1000000LL * (bufferSize / frameSize)) +
+    int64_t timestampUs = mPrevSampleTimeUs;
+    int64_t recordDurationUs = 0;
+    if ( mFormat == AUDIO_FORMAT_PCM_16_BIT && mSampleRate){
+        recordDurationUs = ((1000000LL * (bufferSize / (2 * mRecord->channelCount()))) +
                         (mSampleRate >> 1)) / mSampleRate;
+    } else {
+       recordDurationUs = bufferDurationUs(bufferSize);
+    }
+    timestampUs += recordDurationUs;
 
     if (mNumFramesReceived == 0) {
         buffer->meta_data()->setInt64(kKeyAnchorTime, mStartTimeUs);
     }
 
     buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs);
+    if (mFormat == AUDIO_FORMAT_PCM_16_BIT) {
     buffer->meta_data()->setInt64(kKeyDriftTime, timeUs - mInitialReadTimeUs);
+    } else {
+        int64_t wallClockTimeUs = timeUs - mInitialReadTimeUs;
+        int64_t mediaTimeUs = mStartTimeUs + mPrevSampleTimeUs;
+        buffer->meta_data()->setInt64(kKeyDriftTime, mediaTimeUs - wallClockTimeUs);
+    }
     mPrevSampleTimeUs = timestampUs;
-    mNumFramesReceived += bufferSize / frameSize;
+    mNumFramesReceived += buffer->range_length() / sizeof(int16_t);
     mBuffersReceived.push_back(buffer);
     mFrameAvailableCondition.signal();
 }
@@ -397,4 +474,22 @@
     return value;
 }
 
+int64_t AudioSource::bufferDurationUs( ssize_t n ) {
+    int64_t dataDurationMs = 0;
+    if (mFormat == AUDIO_FORMAT_AMR_NB) {
+        dataDurationMs = (n/AMR_FRAMESIZE) * 20; //ms
+    }
+    else if (mFormat == AUDIO_FORMAT_EVRC) {
+       dataDurationMs = (n/EVRC_FRAMESIZE) * 20; //ms
+    }
+    else if (mFormat == AUDIO_FORMAT_QCELP) {
+        dataDurationMs = (n/QCELP_FRAMESIZE) * 20; //ms
+    }
+    else if (mFormat == AUDIO_FORMAT_AMR_WB) {
+        dataDurationMs = (n/AMR_WB_FRAMESIZE) * 20; //ms
+    }
+    else
+        CHECK(0);
+    return dataDurationMs*1000LL;
+}
 }  // namespace android
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b817a35..1ea742a 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1,4 +1,6 @@
 /*
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
  * Copyright (C) 2009 The Android Open Source Project
  * Copyright (c) 2012, The Linux Foundation. All rights reserved.
  *
@@ -40,6 +42,10 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/timedtext/TimedTextDriver.h>
 #include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/LPAPlayer.h>
+#ifdef USE_TUNNEL_MODE
+#include <media/stagefright/TunnelPlayer.h>
+#endif
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBuffer.h>
@@ -48,6 +54,7 @@
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXCodec.h>
+#include "include/ExtendedUtils.h"
 #include <media/stagefright/Utils.h>
 
 #include <gui/IGraphicBufferProducer.h>
@@ -59,6 +66,8 @@
 
 #define USE_SURFACE_ALLOC 1
 #define FRAME_DROP_FREQ 0
+#define LPA_MIN_DURATION_USEC_ALLOWED 30000000
+#define LPA_MIN_DURATION_USEC_DEFAULT 60000000
 
 namespace android {
 
@@ -66,6 +75,10 @@
 static int64_t kHighWaterMarkUs = 5000000ll;  // 5secs
 static const size_t kLowWaterMarkBytes = 40000;
 static const size_t kHighWaterMarkBytes = 200000;
+static const int64_t kInitFrameDurationUs = 16000;
+static const int64_t kScheduleLagGapUs = 1000;
+static const int64_t kDefaultEventDelayUs = 10000;
+int AwesomePlayer::mTunnelAliveAP = 0;
 
 // maximum time in paused state when offloading audio decompression. When elapsed, the AudioPlayer
 // is destroyed to allow the audio DSP to power down.
@@ -203,6 +216,7 @@
       mVideoBuffer(NULL),
       mDecryptHandle(NULL),
       mLastVideoTimeUs(-1),
+      mFrameDurationUs(kInitFrameDurationUs),
       mTextDriver(NULL),
       mOffloadAudio(false),
       mAudioTearDown(false) {
@@ -229,6 +243,8 @@
     mAudioTearDownEventPending = false;
 
     reset();
+    mIsTunnelAudio = false;
+    mLateAVSyncMargin = ExtendedUtils::ShellProp::getMaxAVSyncLateMargin();
 }
 
 AwesomePlayer::~AwesomePlayer() {
@@ -238,9 +254,57 @@
 
     reset();
 
+    // Disable Tunnel Mode Audio
+    if (mIsTunnelAudio) {
+        if (mTunnelAliveAP > 0) {
+            mTunnelAliveAP--;
+            ALOGV("mTunnelAliveAP = %d", mTunnelAliveAP);
+        }
+    }
+    mIsTunnelAudio = false;
     mClient.disconnect();
 }
 
+void AwesomePlayer::printStats() {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("persist.debug.sf.statistics", value, "0");
+    if (atoi(value) && mVideoSource != NULL) {
+        ALOGE("===========================\n"
+            "   videoDimensions(%d x %d)\n"
+            "   Total Video Frames Decoded(%lld)\n"
+            "   Total Video Frames Rendered(%lld)\n"
+            "   Total Playback Duration(%lld ms)\n"
+            "   numVideoFramesDropped(%lld)\n"
+            "   Average Frames Per Second(%.4f)\n"
+            "   Last Seek To Time(%lld ms)\n"
+            "   Last Paused Time(%lld ms)\n"
+            "   First Frame Latency (%lld ms)\n"
+            "   Number of times AV Sync Lost(%u)\n"
+            "   Max Video Ahead Time Delta(%u)\n"
+            "   Max Video Behind Time Delta(%u)\n"
+            "   Max Time Sync Loss(%u)\n"
+            "   EOS(%d)\n"
+            "   PLAYING(%d)\n"
+            "===========================\n\n",
+            mStats.mVideoWidth,
+            mStats.mVideoHeight,
+            mStats.mNumVideoFramesDecoded,
+            mStats.mTotalFrames,
+            mStats.mTotalTimeUs/1000,
+            mStats.mNumVideoFramesDropped,
+            mStats.mTotalTimeUs > 0 ? ((double)(mStats.mTotalFrames)*1E6)/((double)mStats.mTotalTimeUs) : 0,
+            mStats.mLastSeekToTimeMs,
+            mStats.mLastPausedTimeMs,
+            mStats.mFirstFrameLatencyUs/1000,
+            mStats.mNumTimesSyncLoss,
+            -mStats.mMaxEarlyDelta/1000,
+            mStats.mMaxLateDelta/1000,
+            mStats.mMaxTimeSyncLoss/1000,
+            (mFlags & VIDEO_AT_EOS) > 0,
+            (mFlags & PLAYING) > 0);
+    }
+}
+
 void AwesomePlayer::cancelPlayerEvents(bool keepNotifications) {
     mQueue.cancelEvent(mVideoEvent->eventID());
     mVideoEventPending = false;
@@ -317,12 +381,28 @@
     return OK;
 }
 
+void AwesomePlayer::printFileName(int fd) {
+
+    char symName[40] = {0};
+    char fileName[256] = {0};
+
+    snprintf(symName, sizeof(symName), "/proc/%d/fd/%d", getpid(), fd);
+
+    if (readlink( symName, fileName, (sizeof(fileName) - 1)) != -1 ) {
+        ALOGD("printFileName fd(%d) -> %s", fd, fileName);
+    }
+}
+
 status_t AwesomePlayer::setDataSource(
         int fd, int64_t offset, int64_t length) {
     Mutex::Autolock autoLock(mLock);
 
+    ALOGD("Before reset_l");
     reset_l();
 
+    if(fd)
+        printFileName(fd);
+
     sp<DataSource> dataSource = new FileSource(fd, offset, length);
 
     status_t err = dataSource->initCheck();
@@ -568,6 +648,8 @@
 
     mVideoRenderer.clear();
 
+    modifyFlags(PLAYING, CLEAR);
+    printStats();
     if (mVideoSource != NULL) {
         shutdownVideoDecoder_l();
     }
@@ -589,7 +671,7 @@
 
     mBitrate = -1;
     mLastVideoTimeUs = -1;
-
+    mFrameDurationUs = kInitFrameDurationUs;
     {
         Mutex::Autolock autoLock(mStatsLock);
         mStats.mFd = -1;
@@ -603,6 +685,21 @@
         mStats.mVideoHeight = -1;
         mStats.mFlags = 0;
         mStats.mTracks.clear();
+        mStats.mConsecutiveFramesDropped = 0;
+        mStats.mCatchupTimeStart = 0;
+        mStats.mNumTimesSyncLoss = 0;
+        mStats.mMaxEarlyDelta = 0;
+        mStats.mMaxLateDelta = 0;
+        mStats.mMaxTimeSyncLoss = 0;
+        mStats.mTotalFrames = 0;
+        mStats.mLastFrameUs = 0;
+        mStats.mTotalTimeUs = 0;
+        mStats.mVeryFirstFrame = true;
+        mStats.mFirstFrameLatencyUs = 0;
+        mStats.mLastPausedTimeMs = 0;
+        mStats.mLastSeekToTimeMs = 0;
+        mStats.mResumeDelayStartUs = -1;
+        mStats.mSeekDelayStartUs = -1;
     }
 
     mWatchForAudioSeekComplete = false;
@@ -925,9 +1022,12 @@
 
             // 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;
+            if(mIsTunnelAudio) {
+                // For tunnel Audio error has to be posted to the client
+                sendErrorNotification = true;
+            }
+            status_t err = startAudioPlayer_l(sendErrorNotification);
 
             if ((err != OK) && mOffloadAudio) {
                 ALOGI("play_l() cannot create offload output, fallback to sw decode");
@@ -979,6 +1079,15 @@
         mTimeSource = &mSystemTimeSource;
     }
 
+    {
+        Mutex::Autolock autoLock(mStatsLock);
+        if (mStats.mVeryFirstFrame) {
+            mStats.mFirstFrameLatencyStartUs = getTimeOfDayUs();
+        } else {
+            mStats.mResumeDelayStartUs = getTimeOfDayUs();
+        }
+    }
+
     if (mVideoSource != NULL) {
         // Kick off video playback
         postVideoEvent_l();
@@ -1016,7 +1125,11 @@
     uint32_t flags = 0;
     int64_t cachedDurationUs;
     bool eos;
-
+    sp<MetaData> format = mAudioTrack->getFormat();
+    const char *mime;
+    bool success = format->findCString(kKeyMIMEType, &mime);
+    int tunnelObjectsAlive = 0;
+    CHECK(success);
     if (mOffloadAudio) {
         flags |= AudioPlayer::USE_OFFLOAD;
     } else if (mVideoSource == NULL
@@ -1031,8 +1144,85 @@
     if (mVideoSource != NULL) {
         flags |= AudioPlayer::HAS_VIDEO;
     }
+#ifdef USE_TUNNEL_MODE
+    // Create tunnel player if tunnel mode is enabled
+    ALOGW("Trying to create tunnel player mIsTunnelAudio %d, \
+            LPAPlayer::mObjectsAlive %d, \
+            TunnelPlayer::mTunnelObjectsAlive = %d,\
+            (mAudioPlayer == NULL) %d",
+            mIsTunnelAudio, TunnelPlayer::mTunnelObjectsAlive,
+            LPAPlayer::mObjectsAlive,(mAudioPlayer == NULL));
 
-    mAudioPlayer = new AudioPlayer(mAudioSink, flags, this);
+    if(mIsTunnelAudio && (mAudioPlayer == NULL) &&
+            (LPAPlayer::mObjectsAlive == 0) &&
+            (TunnelPlayer::mTunnelObjectsAlive < TunnelPlayer::getTunnelObjectsAliveMax())) {
+        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
+            ALOGD("Tunnel for video");
+            mAudioPlayer = new TunnelPlayer(mAudioSink, initCheck,
+                    this, true);
+        }
+        else {
+            ALOGD("Tunnel for audio");
+            mAudioPlayer = new TunnelPlayer(mAudioSink, initCheck,
+                    this);
+        }
+        if(!initCheck) {
+            ALOGE("deleting Tunnel Player - initCheck failed");
+            delete mAudioPlayer;
+            mAudioPlayer = NULL;
+        }
+    }
+    tunnelObjectsAlive = (TunnelPlayer::mTunnelObjectsAlive);
+#endif
+    int32_t nchannels = 0;
+    if(mAudioTrack != NULL) {
+        sp<MetaData> format = mAudioTrack->getFormat();
+        if(format != NULL) {
+            format->findInt32( kKeyChannelCount, &nchannels );
+            ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0",nchannels);
+        }
+    }
+    char lpaDecode[PROPERTY_VALUE_MAX];
+    uint32_t minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+    char minUserDefDuration[PROPERTY_VALUE_MAX];
+    property_get("lpa.decode",lpaDecode,"0");
+    property_get("lpa.min_duration",minUserDefDuration,"LPA_MIN_DURATION_USEC_DEFAULT");
+    minDurationForLPA = atoi(minUserDefDuration);
+    if(minDurationForLPA < LPA_MIN_DURATION_USEC_ALLOWED) {
+        if(mAudioPlayer == NULL) {
+            ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
+            minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+        }
+    }
+    if((strcmp("true",lpaDecode) == 0) && (mAudioPlayer == NULL) &&
+#ifdef USE_TUNNEL_MODE
+       (tunnelObjectsAlive < TunnelPlayer::getTunnelObjectsAliveMax()) &&
+#endif
+       (nchannels && (nchannels <= 2)))
+    {
+        ALOGV("LPAPlayer::getObjectsAlive() %d",LPAPlayer::mObjectsAlive);
+        if ( mDurationUs > minDurationForLPA
+             && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC))
+             && LPAPlayer::mObjectsAlive == 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) {
+                 ALOGE("deleting Tunnel Player - initCheck failed");
+                 delete mAudioPlayer;
+                 mAudioPlayer = NULL;
+            }
+        }
+    }
+    if(mAudioPlayer == NULL) {
+        ALOGV("AudioPlayer created, Non-LPA mode mime %s duration %lld\n", mime, mDurationUs);
+        mAudioPlayer = new AudioPlayer(mAudioSink, flags, this);
+    }
     mAudioPlayer->setSource(mAudioSource);
 
     mTimeSource = mAudioPlayer;
@@ -1073,6 +1263,7 @@
                 true /* sourceAlreadyStarted */);
 
         if (err != OK) {
+            ALOGE("AudioPlayer start error");
             if (sendErrorNotification) {
                 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
             }
@@ -1264,6 +1455,12 @@
                 Playback::PAUSE, 0);
     }
 
+    if(!(mFlags & VIDEO_AT_EOS)){
+        Mutex::Autolock autoLock(mStatsLock);
+        mStats.mLastPausedTimeMs = mVideoTimeUs/1000;
+        printStats();
+    }
+
     uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
     if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
         params |= IMediaPlayerService::kBatteryDataTrackAudio;
@@ -1423,6 +1620,11 @@
     }
 
     mSeeking = SEEK;
+
+    {
+        Mutex::Autolock autoLock(mStatsLock);
+        mStats.mSeekDelayStartUs = getTimeOfDayUs();
+    }
     mSeekNotificationSent = false;
     mSeekTimeUs = timeUs;
     modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
@@ -1499,22 +1701,121 @@
     // stream to hardware that doesn't have the necessary codec
     mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL), isStreamingHTTP());
 
-    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
-        ALOGV("createAudioPlayer: bypass OMX (raw)");
+    int32_t nchannels = 0;
+    int32_t isADTS = 0;
+    meta->findInt32( kKeyChannelCount, &nchannels );
+    meta->findInt32(kKeyIsADTS, &isADTS);
+    if (isADTS == 1) {
+        ALOGV("Widevine content\n");
+    }
+
+    ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0",
+           nchannels);
+
+#ifdef USE_TUNNEL_MODE
+    char tunnelDecode[PROPERTY_VALUE_MAX];
+    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);
+
+    bool sys_prop_enabled = !strcmp("true",tunnelDecode) || atoi(tunnelDecode);
+    ALOGD("maxPossible tunnels = %d", TunnelPlayer::getTunnelObjectsAliveMax());
+    //widevine will fallback to software decoder
+    if (sys_prop_enabled && (TunnelPlayer::mTunnelObjectsAlive < TunnelPlayer::getTunnelObjectsAliveMax()) &&
+       (mTunnelAliveAP < TunnelPlayer::getTunnelObjectsAliveMax()) && (isADTS == 0) &&
+        mAudioSink->realtime() &&
+        inSupportedTunnelFormats(mime)) {
+
+        if (mVideoSource != NULL) {
+           char tunnelAVDecode[PROPERTY_VALUE_MAX];
+           property_get("tunnel.audiovideo.decode",tunnelAVDecode,"0");
+           sys_prop_enabled = !strncmp("true", tunnelAVDecode, 4) || atoi(tunnelAVDecode);
+           if (sys_prop_enabled) {
+               ALOGD("Enable Tunnel Mode for A-V playback");
+               mIsTunnelAudio = true;
+           }
+        }
+        else {
+            ALOGI("Tunnel Mode Audio Enabled");
+            mIsTunnelAudio = true;
+        }
+#ifdef NO_TUNNEL_MODE_FOR_MULTICHANNEL
+        if (nchannels > 2 || nchannels <= 0) {
+            ALOGD("Use tunnel mode only for mono and stereo channels");
+            mIsTunnelAudio = false;
+        }
+#endif
+    }
+    else
+       ALOGD("Normal Audio Playback");
+#endif
+
+    checkTunnelExceptions();
+
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW) ||
+             (mIsTunnelAudio
+#ifdef USE_TUNNEL_MODE
+             && (mTunnelAliveAP < TunnelPlayer::getTunnelObjectsAliveMax())
+#endif
+    )) {
+        ALOGD("Set Audio Track as Audio Source");
+        if(mIsTunnelAudio) {
+            mTunnelAliveAP++;
+        }
         mAudioSource = mAudioTrack;
     } else {
-        // If offloading we still create a OMX decoder as a fall-back
-        // but we don't start it
-        mOmxSource = OMXCodec::Create(
+        // For LPA Playback use the decoder without OMX layer
+        char *matchComponentName = NULL;
+        int64_t durationUs;
+        uint32_t flags = 0;
+        char lpaDecode[128];
+        uint32_t minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+        char minUserDefDuration[PROPERTY_VALUE_MAX];
+        property_get("lpa.decode",lpaDecode,"0");
+        property_get("lpa.min_duration",minUserDefDuration,"LPA_MIN_DURATION_USEC_DEFAULT");
+        minDurationForLPA = atoi(minUserDefDuration);
+        if(minDurationForLPA < LPA_MIN_DURATION_USEC_ALLOWED) {
+            ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
+            minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+        }
+        if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
+            Mutex::Autolock autoLock(mMiscStateLock);
+            if (mDurationUs < 0 || durationUs > mDurationUs) {
+                mDurationUs = durationUs;
+            }
+        }
+        if ( mDurationUs > minDurationForLPA
+             && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC))
+             && LPAPlayer::mObjectsAlive == 0 && mVideoSource == NULL && (strcmp("true",lpaDecode) == 0)
+             && (nchannels && (nchannels <= 2)) ) {
+            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);
+                mAudioTrack, matchComponentName, flags,NULL);
 
         if (mOffloadAudio) {
             ALOGV("createAudioPlayer: bypass OMX (offload)");
             mAudioSource = mAudioTrack;
-        } else {
-            mAudioSource = mOmxSource;
         }
     }
 
@@ -1710,10 +2011,18 @@
         mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
                 Playback::START, videoTimeUs / 1000);
     }
+
+    {
+        Mutex::Autolock autoLock(mStatsLock);
+        mStats.mLastSeekToTimeMs = mSeekTimeUs/1000;
+        printStats();
+    }
 }
 
 void AwesomePlayer::onVideoEvent() {
     ATRACE_CALL();
+    int64_t eventStartTimeUs = mSystemTimeSource.getRealTimeUs();
+    int64_t earlyGapUs = kScheduleLagGapUs; // gap for in case of event scheduling lag
     Mutex::Autolock autoLock(mLock);
     if (!mVideoEventPending) {
         // The event has been cancelled in reset_l() but had already
@@ -1722,6 +2031,14 @@
     }
     mVideoEventPending = false;
 
+    {
+        Mutex::Autolock autoLock(mStatsLock);
+        if(!mStats.mVeryFirstFrame && mSeeking == NO_SEEK){
+            mStats.mTotalTimeUs += getTimeOfDayUs() - mStats.mLastFrameUs;
+        }
+        mStats.mLastFrameUs = getTimeOfDayUs();
+    }
+
     if (mSeeking != NO_SEEK) {
         if (mVideoBuffer) {
             mVideoBuffer->release();
@@ -1815,7 +2132,11 @@
 
     int64_t timeUs;
     CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
+    if ((mLastVideoTimeUs != timeUs)
+          && (mLastVideoTimeUs > 0)
+          && (mSeeking == NO_SEEK)) {
+        mFrameDurationUs = timeUs - mLastVideoTimeUs;
+    }
     mLastVideoTimeUs = timeUs;
 
     if (mSeeking == SEEK_VIDEO_ONLY) {
@@ -1855,18 +2176,27 @@
         modifyFlags(FIRST_FRAME, CLEAR);
         mSinceLastDropped = 0;
         mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
+
+        {
+            Mutex::Autolock autoLock(mStatsLock);
+            if(mStats.mVeryFirstFrame){
+                logFirstFrame();
+                printStats();
+                mStats.mLastFrameUs = getTimeOfDayUs();
+            }
+        }
     }
 
-    int64_t realTimeUs, mediaTimeUs;
+    int64_t realTimeUs, mediaTimeUs, nowUs = 0, latenessUs = 0;
     if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
         && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
         mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
     }
 
     if (wasSeeking == SEEK_VIDEO_ONLY) {
-        int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
+        nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
 
-        int64_t latenessUs = nowUs - timeUs;
+        latenessUs = nowUs - timeUs;
 
         ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
 
@@ -1878,9 +2208,9 @@
     if (wasSeeking == NO_SEEK) {
         // Let's display the first frame after seeking right away.
 
-        int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
+        nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
 
-        int64_t latenessUs = nowUs - timeUs;
+        latenessUs = nowUs - timeUs;
 
         ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
 
@@ -1908,7 +2238,7 @@
             }
         }
 
-        if (latenessUs > 40000) {
+        if (latenessUs > mLateAVSyncMargin) {
             // We're more than 40ms late.
             ALOGV("we're late by %lld us (%.2f secs)",
                  latenessUs, latenessUs / 1E6);
@@ -1927,15 +2257,28 @@
                 {
                     Mutex::Autolock autoLock(mStatsLock);
                     ++mStats.mNumVideoFramesDropped;
+                    mStats.mConsecutiveFramesDropped++;
+                    if (mStats.mConsecutiveFramesDropped == 1){
+                        mStats.mCatchupTimeStart = mTimeSource->getRealTimeUs();
+                    }
+                    if(!(mFlags & AT_EOS)) logLate(timeUs,nowUs,latenessUs);
                 }
 
-                postVideoEvent_l();
+                int64_t eventDurationUs = mSystemTimeSource.getRealTimeUs() - eventStartTimeUs;
+                int64_t delayUs = mFrameDurationUs - eventDurationUs - latenessUs - earlyGapUs;
+                delayUs = delayUs > kDefaultEventDelayUs ? kDefaultEventDelayUs : delayUs;
+                postVideoEvent_l(delayUs > 0 ? delayUs : 0);
                 return;
             }
         }
 
         if (latenessUs < -10000) {
             // We're more than 10ms early.
+            logOnTime(timeUs,nowUs,latenessUs);
+            {
+                Mutex::Autolock autoLock(mStatsLock);
+                mStats.mConsecutiveFramesDropped = 0;
+            }
             postVideoEvent_l(10000);
             return;
         }
@@ -1959,6 +2302,26 @@
         if (mFlags & PLAYING) {
             notifyIfMediaStarted_l();
         }
+        {
+            Mutex::Autolock autoLock(mStatsLock);
+            logOnTime(timeUs,nowUs,latenessUs);
+            mStats.mTotalFrames++;
+            mStats.mConsecutiveFramesDropped = 0;
+            char value[PROPERTY_VALUE_MAX];
+            property_get("persist.debug.sf.statistics", value, "0");
+            if (atoi(value) && mVideoSource != NULL) {
+                if (mStats.mResumeDelayStartUs > 0) {
+                    printStats();
+                    ALOGE("Resume Latency = %lld us", getTimeOfDayUs() - mStats.mResumeDelayStartUs);
+                    mStats.mResumeDelayStartUs = -1;
+                }
+                if (mStats.mSeekDelayStartUs > 0) {
+                    printStats();
+                    ALOGE("Seek Latency = %lld us", getTimeOfDayUs() - mStats.mSeekDelayStartUs);
+                    mStats.mSeekDelayStartUs = -1;
+                }
+            }
+        }
     }
 
     mVideoBuffer->release();
@@ -1968,8 +2331,10 @@
         modifyFlags(SEEK_PREVIEW, CLEAR);
         return;
     }
-
-    postVideoEvent_l();
+    int64_t eventDurationUs = mSystemTimeSource.getRealTimeUs() - eventStartTimeUs;
+    int64_t delayUs = mFrameDurationUs - eventDurationUs - latenessUs - earlyGapUs;
+    delayUs = delayUs > kDefaultEventDelayUs ? kDefaultEventDelayUs : delayUs;
+    postVideoEvent_l(delayUs > 0 ? delayUs : 0);
 }
 
 void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
@@ -2803,13 +3168,33 @@
 
         if ((ssize_t)i == mStats.mVideoTrackIndex) {
             fprintf(out,
-                    "   videoDimensions(%d x %d), "
-                    "numVideoFramesDecoded(%lld), "
-                    "numVideoFramesDropped(%lld)\n",
+                    "   videoDimensions(%d x %d)\n"
+                    "   Total Video Frames Decoded(%lld)\n"
+                    "   Total Video Frames Rendered(%lld)\n"
+                    "   Total Playback Duration(%lld ms)\n"
+                    "   numVideoFramesDropped(%lld)\n"
+                    "   Average Frames Per Second(%.4f)\n"
+                    "   First Frame Latency (%lld ms)\n"
+                    "   Number of times AV Sync Lost(%u)\n"
+                    "   Max Video Ahead Time Delta(%u)\n"
+                    "   Max Video Behind Time Delta(%u)\n"
+                    "   Max Time Sync Loss(%u)\n"
+                    "   EOS(%d)\n"
+                    "   PLAYING(%d)\n",
                     mStats.mVideoWidth,
                     mStats.mVideoHeight,
                     mStats.mNumVideoFramesDecoded,
-                    mStats.mNumVideoFramesDropped);
+                    mStats.mTotalFrames,
+                    mStats.mTotalTimeUs/1000,
+                    mStats.mNumVideoFramesDropped,
+                    ((double)(mStats.mTotalFrames)*1E6)/((double)mStats.mTotalTimeUs),
+                    mStats.mFirstFrameLatencyUs/1000,
+                    mStats.mNumTimesSyncLoss,
+                    -mStats.mMaxEarlyDelta/1000,
+                    mStats.mMaxLateDelta/1000,
+                    mStats.mMaxTimeSyncLoss/1000,
+                    (mFlags & AT_EOS) > 0,
+                    (mFlags & PLAYING) > 0);
         }
     }
 
@@ -2891,4 +3276,137 @@
     beginPrepareAsync_l();
 }
 
+bool AwesomePlayer::inSupportedTunnelFormats(const char * mime) {
+    const char * tunnelFormats [ ] = {
+        MEDIA_MIMETYPE_AUDIO_MPEG,
+        MEDIA_MIMETYPE_AUDIO_AAC,
+#ifdef TUNNEL_MODE_SUPPORTS_AMRWB
+        MEDIA_MIMETYPE_AUDIO_AMR_WB,
+    #ifdef ENABLE_QC_AV_ENHANCEMENTS
+        MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS
+    #endif
+#endif
+    };
+
+    if (!mime) {
+        return false;
+    }
+
+    size_t len = sizeof(tunnelFormats)/sizeof(const char *);
+    for (size_t i = 0; i < len; i++) {
+        const char * tf = tunnelFormats[i];
+        if (!strncasecmp(mime, tf, strlen(tf))) {
+            if (strlen(mime) == strlen(tf)) { //to prevent a substring match
+                ALOGD("Tunnel playback supported for %s", tf);
+                return true;
+            }
+        }
+    }
+
+    ALOGW("Tunnel playback unsupported for %s", mime);
+    return false;
+}
+
+void AwesomePlayer::checkTunnelExceptions()
+{
+    /* exception 1: No streaming */
+    if (isStreamingHTTP()) {
+        ALOGV("Streaming, force disable tunnel mode playback");
+        mIsTunnelAudio = false;
+        return;
+    }
+
+    CHECK(mAudioTrack != NULL);
+
+    /*
+     * exception 2: No AAC-LD content,
+     * hint given by setting kKeyTunnelException in the track meta
+     */
+    int32_t exception = 0;
+    if (mAudioTrack->getFormat()->findInt32(kKeyTunnelException, &exception) &&
+        exception) {
+        ALOGV("kKeyTunnelException set, disable tunnel mode");
+        mIsTunnelAudio = false;
+        return;
+    }
+
+    /* exception 3: use tunnel player only for AUDIO_STREAM_MUSIC */
+    if (mAudioSink->streamType() != AUDIO_STREAM_MUSIC ) {
+        ALOGV("Use tunnel player only for AUDIO_STREAM_MUSIC");
+        mIsTunnelAudio = false;
+        return;
+    }
+
+    /* below exceptions are only for av content */
+    if (mVideoTrack == NULL) return;
+
+    /* exception 3: No avi having video + mp3 */
+    if (mExtractor == NULL) return;
+
+    sp<MetaData> metaData = mExtractor->getMetaData();
+    const char * container;
+
+    /*only proceed for avi content.*/
+    if (!metaData->findCString(kKeyMIMEType, &container) ||
+        strcmp(container, MEDIA_MIMETYPE_CONTAINER_AVI)) {
+        return;
+    }
+
+    const char * mime;
+    metaData = mAudioTrack->getFormat();
+    /*disable for av content having mp3*/
+    if (metaData->findCString(kKeyMIMEType, &mime) &&
+        !strcmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+        ALOGV("Clip has AVI extractor and mp3 content, disable tunnel mode");
+        mIsTunnelAudio = false;
+        return;
+    }
+
+    return;
+}
+
+inline void AwesomePlayer::logFirstFrame() {
+    mStats.mFirstFrameLatencyUs = getTimeOfDayUs()-mStats.mFirstFrameLatencyStartUs;
+    mStats.mVeryFirstFrame = false;
+}
+
+inline void AwesomePlayer::logCatchUp(int64_t ts, int64_t clock, int64_t delta)
+{
+    if (mStats.mConsecutiveFramesDropped > 0) {
+        mStats.mNumTimesSyncLoss++;
+        if (mStats.mMaxTimeSyncLoss < (clock - mStats.mCatchupTimeStart) && clock > 0 && ts > 0) {
+            mStats.mMaxTimeSyncLoss = clock - mStats.mCatchupTimeStart;
+        }
+    }
+}
+
+inline void AwesomePlayer::logLate(int64_t ts, int64_t clock, int64_t delta)
+{
+    if (mStats.mMaxLateDelta < delta && clock > 0 && ts > 0) {
+        mStats.mMaxLateDelta = delta;
+    }
+}
+
+inline void AwesomePlayer::logOnTime(int64_t ts, int64_t clock, int64_t delta)
+{
+    bool needLogLate = false;
+    logCatchUp(ts, clock, delta);
+    if (delta <= 0) {
+        if ((-delta) > (-mStats.mMaxEarlyDelta) && clock > 0 && ts > 0) {
+            mStats.mMaxEarlyDelta = delta;
+        }
+    }
+    else {
+        needLogLate = true;
+    }
+
+    if(needLogLate) logLate(ts, clock, delta);
+}
+
+inline int64_t AwesomePlayer::getTimeOfDayUs() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+
+    return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
 }  // namespace android
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index f139637..2067420 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -30,6 +30,7 @@
 #include <gui/Surface.h>
 #include <utils/String8.h>
 #include <cutils/properties.h>
+#include "include/ExtendedUtils.h"
 
 #ifdef USE_TI_CUSTOM_DOMX
 #include <OMX_TI_IVCommon.h>
@@ -580,6 +581,9 @@
     mMeta->setInt32(kKeyStride,      mVideoSize.width);
     mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
     mMeta->setInt32(kKeyFrameRate,   mVideoFrameRate);
+
+    ExtendedUtils::HFR::setHFRIfEnabled(params, mMeta);
+
     return OK;
 }
 
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
old mode 100644
new mode 100755
index fc6fd9c..ed5b67e
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -32,6 +32,7 @@
 #include "include/OggExtractor.h"
 #include "include/WAVExtractor.h"
 #include "include/WVMExtractor.h"
+#include "include/ExtendedExtractor.h"
 
 #include "matroska/MatroskaExtractor.h"
 
@@ -159,6 +160,7 @@
     RegisterSniffer(SniffAAC);
     RegisterSniffer(SniffMPEG2PS);
     RegisterSniffer(SniffWVM);
+    RegisterSniffer(ExtendedExtractor::Sniff);
 
     char value[PROPERTY_VALUE_MAX];
     if (property_get("drm.service.enabled", value, NULL)
diff --git a/media/libstagefright/ExtendedCodec.cpp b/media/libstagefright/ExtendedCodec.cpp
new file mode 100644
index 0000000..ab2d839
--- /dev/null
+++ b/media/libstagefright/ExtendedCodec.cpp
@@ -0,0 +1,1078 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * 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 "ExtendedCodec"
+#include <utils/Log.h>
+#include <cutils/properties.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaCodecList.h>
+
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/ExtendedCodec.h>
+#include <media/stagefright/OMXCodec.h>
+
+#ifdef ENABLE_AV_ENHANCEMENTS
+
+#include <QCMetaData.h>
+#include <QCMediaDefs.h>
+#include <OMX_QCOMExtns.h>
+#include <OMX_Component.h>
+#include <QOMX_AudioExtensions.h>
+#include "include/ExtendedUtils.h"
+
+namespace android {
+enum MetaKeyType{
+    INT32, INT64, STRING, DATA, CSD
+};
+
+struct MetaKeyEntry{
+    int MetaKey;
+    const char* MsgKey;
+    MetaKeyType KeyType;
+};
+
+static const MetaKeyEntry MetaKeyTable[] {
+   {kKeyBitRate              , "bitrate"                , INT32},
+   {kKeyAacCodecSpecificData , "aac-codec-specific-data", CSD},
+   {kKeyRawCodecSpecificData , "raw-codec-specific-data", CSD},
+   {kKeyDivXVersion          , "divx-version"           , INT32},  // int32_t
+   {kKeyDivXDrm              , "divx-drm"               , DATA},  // void *
+   {kKeyWMAEncodeOpt         , "wma-encode-opt"         , INT32},  // int32_t
+   {kKeyWMABlockAlign        , "wma-block-align"        , INT32},  // int32_t
+   {kKeyWMAVersion           , "wma-version"            , INT32},  // int32_t
+   {kKeyWMAAdvEncOpt1        , "wma-adv-enc-opt1"       , INT32},  // int16_t
+   {kKeyWMAAdvEncOpt2        , "wma-adv-enc-opt2"       , INT32},  // int32_t
+   {kKeyWMAFormatTag         , "wma-format-tag"         , INT32},  // int32_t
+   {kKeyWMABitspersample     , "wma-bits-per-sample"    , INT32},  // int32_t
+   {kKeyWMAVirPktSize        , "wma-vir-pkt-size"       , INT32},  // int32_t
+   {kKeyWMAChannelMask       , "wma-channel-mask"       , INT32},  // int32_t
+
+   {kKeyFileFormat           , "file-format"            , STRING},  // cstring
+
+   {kkeyAacFormatAdif        , "aac-format-adif"        , INT32},  // bool (int32_t)
+   {kkeyAacFormatLtp         , "aac-format-ltp"         , INT32},
+
+   //DTS subtype
+   {kKeyDTSSubtype           , "dts-subtype"            , INT32},  //int32_t
+
+   //Extractor sets this
+   {kKeyUseArbitraryMode     , "use-arbitrary-mode"     , INT32},  //bool (int32_t)
+   {kKeySmoothStreaming      , "smooth-streaming"       , INT32},  //bool (int32_t)
+   {kKeyHFR                  , "hfr"                    , INT32},  // int32_t
+
+   {kKeySampleRate           , "sample-rate"            , INT32},
+   {kKeyChannelCount         , "channel-count"          , INT32},
+};
+
+const char* ExtendedCodec::getMsgKey(int key) {
+    static const size_t numMetaKeys =
+                     sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]);
+    size_t i;
+    for (i = 0; i < numMetaKeys; ++i) {
+        if (key == MetaKeyTable[i].MetaKey) {
+            return MetaKeyTable[i].MsgKey;
+        }
+    }
+    return "unknown";
+}
+
+status_t ExtendedCodec::convertMetaDataToMessage(
+        const sp<MetaData> &meta, sp<AMessage> *format) {
+    const char * str_val;
+    int32_t int32_val;
+    int64_t int64_val;
+    uint32_t data_type;
+    const void * data;
+    size_t size;
+    static const size_t numMetaKeys =
+                     sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]);
+    size_t i;
+    for (i = 0; i < numMetaKeys; ++i) {
+        if (MetaKeyTable[i].KeyType == INT32 &&
+            meta->findInt32(MetaKeyTable[i].MetaKey, &int32_val)) {
+            ALOGV("found metakey %s of type int32", MetaKeyTable[i].MsgKey);
+            format->get()->setInt32(MetaKeyTable[i].MsgKey, int32_val);
+        }
+        else if (MetaKeyTable[i].KeyType == INT64 &&
+                 meta->findInt64(MetaKeyTable[i].MetaKey, &int64_val)) {
+            ALOGV("found metakey %s of type int64", MetaKeyTable[i].MsgKey);
+            format->get()->setInt64(MetaKeyTable[i].MsgKey, int64_val);
+        }
+        else if (MetaKeyTable[i].KeyType == STRING &&
+                 meta->findCString(MetaKeyTable[i].MetaKey, &str_val)) {
+            ALOGV("found metakey %s of type string", MetaKeyTable[i].MsgKey);
+            format->get()->setString(MetaKeyTable[i].MsgKey, str_val);
+        }
+        else if ( (MetaKeyTable[i].KeyType == DATA ||
+                   MetaKeyTable[i].KeyType == CSD) &&
+                   meta->findData(MetaKeyTable[i].MetaKey, &data_type, &data, &size)) {
+            ALOGV("found metakey %s of type data", MetaKeyTable[i].MsgKey);
+            sp<ABuffer> buffer = new ABuffer(size);
+            memcpy(buffer->data(), data, size);
+            if (MetaKeyTable[i].KeyType == CSD) {
+                buffer->meta()->setInt32("csd", true);
+                buffer->meta()->setInt64("timeUs", 0);
+            }
+            format->get()->setBuffer(MetaKeyTable[i].MsgKey, buffer);
+        }
+    }
+    return OK;
+}
+
+uint32_t ExtendedCodec::getComponentQuirks(
+        const MediaCodecList *list, size_t index) {
+    uint32_t quirks = 0;
+
+    if (list->codecHasQuirk(
+                index, "requires-wma-pro-component")) {
+        quirks |= kRequiresWMAProComponent;
+    }
+    return quirks;
+}
+
+const char* ExtendedCodec::overrideComponentName(
+        uint32_t quirks, const sp<MetaData> &meta) {
+    const char* componentName = NULL;
+    if(quirks & kRequiresWMAProComponent)
+    {
+       int32_t version = 0;
+       if (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";
+           }
+       }
+    }
+    return componentName;
+}
+
+void ExtendedCodec::overrideComponentName(
+        uint32_t quirks, const sp<AMessage> &msg, AString* componentName) {
+    if(quirks & kRequiresWMAProComponent)
+    {
+       int32_t version = 0;
+       if (msg->findInt32(getMsgKey(kKeyWMAVersion), &version)) {
+           if(version==kTypeWMA) {
+              componentName->setTo("OMX.qcom.audio.decoder.wma");
+           } else if(version==kTypeWMAPro) {
+              componentName->setTo("OMX.qcom.audio.decoder.wma10Pro");
+           } else if(version==kTypeWMALossLess) {
+              componentName->setTo("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 ExtendedCodec::setDIVXFormat(
+        const sp<AMessage> &msg, const 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(msg->findInt32(getMsgKey(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 ExtendedCodec::getRawCodecSpecificData(
+        const sp<MetaData> &meta, const void* &data, size_t &size) {
+    uint32_t type = 0;
+    size = 0;
+    if (meta->findData(kKeyRawCodecSpecificData, &type, &data, &size)) {
+        ALOGV("OMXCodec::configureCodec found kKeyRawCodecSpecificData of size %d\n", size);
+    }
+}
+
+sp<ABuffer> ExtendedCodec::getRawCodecSpecificData(
+        const sp<AMessage> &msg) {
+    sp<ABuffer> buffer;
+    if (msg->findBuffer(getMsgKey(kKeyRawCodecSpecificData), &buffer)) {
+        ALOGV("ACodec found kKeyRawCodecSpecificData of size %d\n", buffer->size());
+        return buffer;
+    }
+    return NULL;
+}
+
+void ExtendedCodec::getAacCodecSpecificData(
+        const sp<MetaData> &meta, const void* &data, size_t &size) {
+    uint32_t type = 0;
+    size = 0;
+    if (meta->findData(kKeyAacCodecSpecificData, &type, &data, &size)) {
+        ALOGV("OMXCodec::configureCodec found kKeyAacCodecSpecificData of size %d\n", size);
+    }
+}
+
+sp<ABuffer> ExtendedCodec::getAacCodecSpecificData(
+        const sp<AMessage> &msg) {
+    sp<ABuffer> buffer;
+    if (msg->findBuffer(getMsgKey(kKeyAacCodecSpecificData), &buffer)) {
+        ALOGV("ACodec found kKeyAacCodecSpecificData of size %d\n", buffer->size());
+        return buffer;
+    }
+    return NULL;
+}
+
+status_t ExtendedCodec::setAudioFormat(
+        const sp<MetaData> &meta, const char* mime, sp<IOMX> OMXhandle,
+        IOMX::node_id nodeID, bool isEncoder ) {
+    sp<AMessage> msg = new AMessage();
+    msg->clear();
+    convertMetaDataToMessage(meta, &msg);
+    return setAudioFormat(msg, mime, OMXhandle, nodeID, isEncoder);
+}
+
+status_t ExtendedCodec::setAudioFormat(
+        const sp<AMessage> &msg, const char* mime, sp<IOMX> OMXhandle,
+        IOMX::node_id nodeID, bool isEncoder ) {
+    ALOGV("setAudioFormat called");
+    status_t err = OK;
+
+    if ((!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mime)) ||
+        (!strcasecmp(MEDIA_MIMETYPE_AUDIO_EAC3, mime))){
+        int32_t numChannels, sampleRate;
+        /* Commenting follwoing call as AC3 soft decoder does not
+         need it and it causes issue with playback*/
+        //setAC3Format(numChannels, sampleRate, OMXhandle, nodeID);
+        CHECK(msg->findInt32("channel-count", &numChannels));
+        CHECK(msg->findInt32("sample-rate", &sampleRate));
+        setAC3Format(numChannels, sampleRate, OMXhandle, nodeID);
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_EVRC, mime)) {
+        int32_t numChannels, sampleRate;
+        CHECK(msg->findInt32("channel-count", &numChannels));
+        CHECK(msg->findInt32("sample-rate", &sampleRate));
+        setEVRCFormat(numChannels, sampleRate, OMXhandle, nodeID, isEncoder );
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_QCELP, mime)) {
+        int32_t numChannels, sampleRate;
+        CHECK(msg->findInt32("channel-count", &numChannels));
+        CHECK(msg->findInt32("sample-rate", &sampleRate));
+        setQCELPFormat(numChannels, sampleRate, OMXhandle, nodeID, isEncoder);
+    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_WMA, mime))  {
+        err = setWMAFormat(msg, OMXhandle, nodeID, isEncoder);
+    }
+    return err;
+}
+
+status_t ExtendedCodec::setVideoInputFormat(
+        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 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)){
+        *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc;
+    } else {
+        retVal = BAD_VALUE;
+    }
+
+    return retVal;
+}
+
+status_t ExtendedCodec::setVideoOutputFormat(
+        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 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)){
+        *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc;
+    } else {
+        retVal = BAD_VALUE;
+    }
+    return retVal;
+}
+
+status_t ExtendedCodec::setSupportedRole(
+        const sp<IOMX> &omx, IOMX::node_id node,
+        bool isEncoder, const char *mime){
+    ALOGV("setSupportedRole Called %s", mime);
+    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_VIDEO_DIVX4,
+          "video_decoder.divx", NULL },
+        { MEDIA_MIMETYPE_VIDEO_DIVX311,
+          "video_decoder.divx", NULL },
+        { MEDIA_MIMETYPE_VIDEO_WMV,
+          "video_decoder.vc1",  NULL },
+        { MEDIA_MIMETYPE_AUDIO_AC3,
+          "audio_decoder.ac3", NULL },
+        { MEDIA_MIMETYPE_AUDIO_WMA,
+          "audio_decoder.wma" , 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 ERROR_UNSUPPORTED;
+    }
+
+    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);
+            return err;
+        }
+    }
+    return OK;
+}
+
+status_t ExtendedCodec::getSupportedAudioFormatInfo(
+        const AString* mime,
+        sp<IOMX> OMXhandle,
+        IOMX::node_id nodeID,
+        int portIndex,
+        int* channelCount) {
+    status_t retVal = OK;
+    if (!strcmp(mime->c_str(),MEDIA_MIMETYPE_AUDIO_QCELP)) {
+        OMX_AUDIO_PARAM_QCELP13TYPE params;
+        InitOMXParams(&params);
+        params.nPortIndex = portIndex;
+        CHECK_EQ(OMXhandle->getParameter(
+                   nodeID, OMX_IndexParamAudioQcelp13, &params, sizeof(params)), (status_t)OK);
+        *channelCount = params.nChannels;
+    } else if(!strcmp(mime->c_str(), MEDIA_MIMETYPE_AUDIO_EVRC)) {
+        OMX_AUDIO_PARAM_EVRCTYPE params;
+        InitOMXParams(&params);
+        params.nPortIndex = portIndex;
+        CHECK_EQ(OMXhandle->getParameter(
+                   nodeID, OMX_IndexParamAudioEvrc, &params, sizeof(params)), (status_t)OK);
+        *channelCount = params.nChannels;
+    } else {
+        retVal = BAD_VALUE;
+    }
+    return retVal;
+}
+
+status_t ExtendedCodec::handleSupportedAudioFormats(int format, AString* mime) {
+    ALOGV("checkQCFormats called");
+    status_t retVal = OK;
+    if (format == OMX_AUDIO_CodingQCELP13 ) {
+        *mime = MEDIA_MIMETYPE_AUDIO_QCELP;
+    } else if(format == OMX_AUDIO_CodingEVRC ) {
+        *mime = MEDIA_MIMETYPE_AUDIO_EVRC;
+    } else {
+        retVal = BAD_VALUE;
+    }
+    return retVal;
+}
+
+void ExtendedCodec::configureFramePackingFormat(
+        const sp<AMessage> &msg, sp<IOMX> OMXhandle, IOMX::node_id nodeID,
+        const char* componentName) {
+    //ignore non QC components
+    if (strncmp(componentName, "OMX.qcom.", 9)) {
+        return;
+    }
+
+    int32_t arbitraryMode = 0;
+    bool success = msg->findInt32(getMsgKey(kKeyUseArbitraryMode), &arbitraryMode);
+    bool useFrameByFrameMode = true; //default option
+    if (success && arbitraryMode) {
+        useFrameByFrameMode = false;
+    }
+
+    if (useFrameByFrameMode) {
+        ALOGI("Enable frame by frame mode");
+        OMX_QCOM_PARAM_PORTDEFINITIONTYPE portFmt;
+        portFmt.nPortIndex = kPortIndexInput;
+        portFmt.nFramePackingFormat = OMX_QCOM_FramePacking_OnlyOneCompleteFrame;
+        status_t err = OMXhandle->setParameter(
+        nodeID, (OMX_INDEXTYPE)OMX_QcomIndexPortDefn, (void *)&portFmt, sizeof(portFmt));
+        if(err != OK) {
+            ALOGW("Failed to set frame packing format on component");
+        }
+    } else {
+        ALOGI("Decoder should be in arbitrary mode");
+    }
+}
+
+void ExtendedCodec::configureFramePackingFormat(
+        const sp<MetaData> &meta, sp<IOMX> OMXhandle, IOMX::node_id nodeID,
+        const char* componentName) {
+    sp<AMessage> msg = new AMessage();
+    msg->clear();
+    convertMetaDataToMessage(meta, &msg);
+    configureFramePackingFormat(msg, OMXhandle, nodeID, componentName);
+}
+
+void ExtendedCodec::configureVideoDecoder(
+        const sp<AMessage> &msg, const char* mime, sp<IOMX> OMXhandle,
+        const uint32_t flags, IOMX::node_id nodeID, const char* componentName ) {
+    if (strncmp(componentName, "OMX.qcom.", 9)) {
+        //do nothing for non QC component
+        return;
+    }
+
+    setDIVXFormat(msg, mime, OMXhandle, nodeID, kPortIndexOutput);
+    AString fileFormat;
+    const char *fileFormatCStr = NULL;
+    bool success = msg->findString(getMsgKey(kKeyFileFormat), &fileFormat);
+    if (success) {
+        fileFormatCStr = fileFormat.c_str();
+    }
+
+    // Enable timestamp reordering for AVI file type, mpeg4 and vc1 codec types
+    if (!strcmp(componentName, "OMX.qcom.video.decoder.vc1") ||
+        !strcmp(componentName, "OMX.qcom.video.decoder.mpeg4") ||
+        (fileFormatCStr!= NULL && !strncmp(fileFormatCStr, "video/avi", 9))) {
+        ALOGI("Enabling timestamp reordering");
+        QOMX_INDEXTIMESTAMPREORDER reorder;
+        InitOMXParams(&reorder);
+        reorder.nPortIndex = kPortIndexOutput;
+        reorder.bEnable = OMX_TRUE;
+        status_t err = OMXhandle->setParameter(nodeID,
+                       (OMX_INDEXTYPE)OMX_QcomIndexParamEnableTimeStampReorder,
+                       (void *)&reorder, sizeof(reorder));
+
+        if(err != OK) {
+            ALOGW("Failed to enable timestamp reordering");
+        }
+    }
+
+    // Enable Sync-frame decode mode for thumbnails
+    if (flags & OMXCodec::kClientNeedsFramebuffer) {
+        ALOGV("Enabling thumbnail mode.");
+        QOMX_ENABLETYPE enableType;
+        OMX_INDEXTYPE indexType;
+
+        status_t err = OMXhandle->getExtensionIndex(
+                nodeID, OMX_QCOM_INDEX_PARAM_VIDEO_SYNCFRAMEDECODINGMODE,
+                &indexType);
+        if(err != OK) {
+            ALOGW("Failed to get extension for SYNCFRAMEDECODINGMODE");
+            return;
+        }
+
+        enableType.bEnable = OMX_TRUE;
+        err = OMXhandle->setParameter(nodeID,indexType,
+                   (void *)&enableType, sizeof(enableType));
+        if(err != OK) {
+            ALOGW("Failed to get extension for SYNCFRAMEDECODINGMODE");
+            return;
+        }
+        ALOGI("Thumbnail mode enabled.");
+    }
+
+}
+
+void ExtendedCodec::configureVideoDecoder(
+        const sp<MetaData> &meta, const char* mime, sp<IOMX> OMXhandle,
+        const uint32_t flags, IOMX::node_id nodeID, const char* componentName ) {
+    sp<AMessage> msg = new AMessage();
+    msg->clear();
+    convertMetaDataToMessage(meta, &msg);
+    configureVideoDecoder(msg, mime, OMXhandle, flags, nodeID, componentName);
+}
+
+void ExtendedCodec::enableSmoothStreaming(
+        const sp<IOMX> &omx, IOMX::node_id nodeID, bool* isEnabled,
+        const char* componentName) {
+    *isEnabled = false;
+
+    if (!ExtendedUtils::ShellProp::isSmoothStreamingEnabled()) {
+        return;
+    }
+
+    //ignore non QC components
+    if (strncmp(componentName, "OMX.qcom.", 9)) {
+        return;
+    }
+    status_t err = omx->setParameter(
+            nodeID,
+            (OMX_INDEXTYPE)OMX_QcomIndexParamEnableSmoothStreaming,
+            &err, sizeof(status_t));
+    if (err != OK) {
+        ALOGE("Failed to enable Smoothstreaming!");
+        return;
+    }
+    *isEnabled = true;
+    ALOGI("Smoothstreaming Enabled");
+    return;
+}
+
+//private methods
+void ExtendedCodec::setEVRCFormat(
+        int32_t numChannels, int32_t sampleRate, sp<IOMX> OMXhandle,
+        IOMX::node_id nodeID, bool isEncoder ) {
+    ALOGV("setEVRCFormat called");
+
+    if (isEncoder) {
+        CHECK(numChannels == 1);
+        //////////////// input port ////////////////////
+        //handle->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(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 = 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 = 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 ExtendedCodec::setQCELPFormat(
+        int32_t numChannels, int32_t sampleRate, sp<IOMX> OMXhandle,
+        IOMX::node_id nodeID, bool isEncoder ) {
+
+    if (isEncoder) {
+        CHECK(numChannels == 1);
+        //////////////// input port ////////////////////
+        //handle->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(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 = 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 = 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 ExtendedCodec::setWMAFormat(
+        const sp<MetaData> &meta, sp<IOMX> OMXhandle,
+        IOMX::node_id nodeID, bool isEncoder ) {
+    sp<AMessage> msg = new AMessage();
+    msg->clear();
+    convertMetaDataToMessage(meta, &msg);
+    return setWMAFormat(msg, OMXhandle, nodeID, isEncoder);
+}
+
+status_t ExtendedCodec::setWMAFormat(
+        const sp<AMessage> &msg, 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(msg->findInt32(getMsgKey(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(msg->findInt32(getMsgKey(kKeyWMABitspersample), &bitspersample));
+            CHECK(msg->findInt32(getMsgKey(kKeyWMAFormatTag), &formattag));
+            CHECK(msg->findInt32(getMsgKey(kKeyWMAAdvEncOpt1), &advencopt1));
+            CHECK(msg->findInt32(getMsgKey(kKeyWMAAdvEncOpt2), &advencopt2));
+            CHECK(msg->findInt32(getMsgKey(kKeyWMAVirPktSize), &VirtualPktSize));
+        }
+        if(version==kTypeWMA) {
+            InitOMXParams(&paramWMA);
+            paramWMA.nPortIndex = kPortIndexInput;
+        } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+            InitOMXParams(&paramWMA10);
+            paramWMA10.nPortIndex = kPortIndexInput;
+        }
+        CHECK(msg->findInt32("channel-count", &numChannels));
+        CHECK(msg->findInt32("sample-rate", &sampleRate));
+        CHECK(msg->findInt32(getMsgKey(kKeyBitRate), &bitRate));
+        CHECK(msg->findInt32(getMsgKey(kKeyWMAEncodeOpt), &encodeOptions));
+        CHECK(msg->findInt32(getMsgKey(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 ExtendedCodec::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 = 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 = 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 = kPortIndexInput;
+    err = OMXhandle->getParameter(
+            nodeID, indexTypeAC3PP, &profileAC3PP, sizeof(profileAC3PP));
+    CHECK_EQ(err, (status_t)OK);
+
+    int i;
+    int channel_routing[6] = {0};
+
+    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);
+}
+
+bool ExtendedCodec::useHWAACDecoder(const char *mime) {
+    char value[PROPERTY_VALUE_MAX] = {0};
+    int aaccodectype = 0;
+    aaccodectype = property_get("media.aaccodectype", value, NULL);
+    if (aaccodectype && !strncmp("0", value, 1) &&
+        !strncmp(mime, MEDIA_MIMETYPE_AUDIO_AAC,sizeof(MEDIA_MIMETYPE_AUDIO_AAC))) {
+        ALOGI("Using Hardware AAC Decoder");
+        return true;
+    }
+    return false;
+}
+
+} //namespace android
+
+#else //ENABLE_AV_ENHANCEMENTS
+
+namespace android {
+    status_t ExtendedCodec::convertMetaDataToMessage(
+            const sp<MetaData> &meta, sp<AMessage> *format) {
+        return OK;
+    }
+
+    uint32_t ExtendedCodec::getComponentQuirks (
+            const MediaCodecList *list, size_t index) {
+        return 0;
+    }
+
+    status_t ExtendedCodec::setDIVXFormat(
+            const sp<AMessage> &msg, const char* mime,
+            sp<IOMX> OMXhandle,IOMX::node_id nodeID, int port_index) {
+        return OK;
+    }
+
+    status_t ExtendedCodec::setAudioFormat(
+            const sp<MetaData> &meta, const char* mime,
+            sp<IOMX> OMXhandle,IOMX::node_id nodeID,
+            bool isEncoder) {
+        return OK;
+    }
+
+    status_t ExtendedCodec::setAudioFormat(
+            const sp<AMessage> &msg, const char* mime,
+            sp<IOMX> OMXhandle,IOMX::node_id nodeID,
+            bool isEncoder) {
+        return OK;
+    }
+
+    status_t ExtendedCodec::setVideoInputFormat(
+            const char *mime,
+            OMX_VIDEO_CODINGTYPE *compressionFormat) {
+        return OK;
+    }
+
+    status_t ExtendedCodec::setVideoOutputFormat(
+            const char *mime,
+            OMX_VIDEO_CODINGTYPE *compressionFormat) {
+        return OK;
+    }
+
+    status_t ExtendedCodec::getSupportedAudioFormatInfo(
+            const AString* mime,
+            sp<IOMX> OMXhandle,
+            IOMX::node_id nodeID,
+            int portIndex,
+            int* channelCount) {
+        return OK;
+    }
+
+    status_t ExtendedCodec::handleSupportedAudioFormats(
+            int format, AString* meta) {
+        return UNKNOWN_ERROR;
+    }
+
+    const char* ExtendedCodec::overrideComponentName (
+            uint32_t quirks, const sp<MetaData> &meta) {
+        return NULL;
+    }
+
+    void ExtendedCodec::overrideComponentName(
+            uint32_t quirks, const sp<AMessage> &msg,
+            AString* componentName){
+    }
+
+    void ExtendedCodec::getRawCodecSpecificData(
+        const sp<MetaData> &meta, const void* &data, size_t &size) {
+            size = 0;
+    }
+
+    sp<ABuffer> ExtendedCodec::getRawCodecSpecificData(
+            const sp<AMessage> &msg){
+        return NULL;
+    }
+
+    void ExtendedCodec::getAacCodecSpecificData(
+            const sp<MetaData> &meta,
+            const void* &data,
+            size_t& size){
+        return;
+    }
+
+    sp<ABuffer> ExtendedCodec::getAacCodecSpecificData(
+            const sp<AMessage> &msg){
+        return NULL;
+    }
+
+
+    status_t ExtendedCodec::setSupportedRole(
+            const sp<IOMX> &omx, IOMX::node_id node,
+            bool isEncoder, const char *mime) {
+        return OK;
+    }
+
+    status_t ExtendedCodec::setWMAFormat(
+            const sp<MetaData> &meta, sp<IOMX> OMXhandle,
+            IOMX::node_id nodeID, bool isEncoder) {
+        return OK;
+    }
+
+    status_t ExtendedCodec::setWMAFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            IOMX::node_id nodeID, bool isEncoder) {
+        return OK;
+    }
+
+    void ExtendedCodec::setEVRCFormat(
+            int32_t numChannels, int32_t sampleRate,
+            sp<IOMX> OMXhandle, IOMX::node_id nodeID,
+            bool isEncoder) {
+    }
+
+    void ExtendedCodec::setQCELPFormat(
+            int32_t numChannels, int32_t sampleRate,
+            sp<IOMX> OMXhandle, IOMX::node_id nodeID,
+            bool isEncoder) {
+    }
+
+    void ExtendedCodec::setAC3Format(
+            int32_t numChannels, int32_t sampleRate,
+            sp<IOMX> OMXhandle, IOMX::node_id nodeID) {
+    }
+
+    void ExtendedCodec::configureFramePackingFormat(
+            const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+            IOMX::node_id nodeID, const char* componentName){
+    }
+
+    void ExtendedCodec::configureFramePackingFormat(
+            const sp<MetaData> &meta, sp<IOMX> OMXhandle,
+            IOMX::node_id nodeID, const char* componentName) {
+    }
+
+    void ExtendedCodec::configureVideoDecoder(
+        const sp<MetaData> &meta, const char* mime, sp<IOMX> OMXhandle,
+        const uint32_t flags, IOMX::node_id nodeID, const char* componentName) {
+    }
+
+    void ExtendedCodec::configureVideoDecoder(
+        const sp<AMessage> &msg, const char* mime,  sp<IOMX> OMXhandle,
+        const uint32_t flags, IOMX::node_id nodeID, const char* componentName) {
+    }
+
+    bool ExtendedCodec::useHWAACDecoder(const char *mime) {
+        return false;
+    }
+
+    void ExtendedCodec::enableSmoothStreaming(
+            const sp<IOMX> &omx, IOMX::node_id nodeID, bool* isEnabled,
+            const char* componentName) {
+        *isEnabled = false;
+        return;
+    }
+
+} //namespace android
+
+#endif //ENABLE_AV_ENHANCEMENTS
diff --git a/media/libstagefright/ExtendedExtractor.cpp b/media/libstagefright/ExtendedExtractor.cpp
new file mode 100644
index 0000000..952f542
--- /dev/null
+++ b/media/libstagefright/ExtendedExtractor.cpp
@@ -0,0 +1,143 @@
+/*Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * 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"
+
+#ifdef ENABLE_AV_ENHANCEMENTS
+
+namespace android {
+
+static const char* EXTENDED_EXTRACTOR_LIB = "libExtendedExtractor.so";
+static const char* EXTENDED_EXTRACTOR_CREATE = "CreateExtractor";
+static const char* EXTENDED_EXTRACTOR_SNIFF = "SniffExtendedExtractor";
+
+typedef MediaExtractor* (*ExtendedExtractorCreate)
+                            (const sp<DataSource> &source, const char* mime);
+
+typedef bool (*ExtendedExtractorSniff)
+                 (const sp<DataSource> &source, String8 *mimeType,
+                 float *confidence,sp<AMessage> *meta);
+
+static void* loadExtendedExtractorLib() {
+    static void* extendedExtractorLib = NULL;
+    static bool alreadyTriedToLoadLib = false;
+
+    if(!alreadyTriedToLoadLib) {
+        alreadyTriedToLoadLib = true;
+
+        extendedExtractorLib = ::dlopen(EXTENDED_EXTRACTOR_LIB, RTLD_LAZY);
+
+        if(extendedExtractorLib == NULL) {
+            ALOGV("Failed to load %s, dlerror = %s \n",
+                EXTENDED_EXTRACTOR_LIB, dlerror());
+        }
+    }
+
+    return extendedExtractorLib;
+}
+
+MediaExtractor* ExtendedExtractor::Create (
+        const sp<DataSource> &source, const char *mime) {
+    static ExtendedExtractorCreate create = NULL;
+    static bool alreadyTriedToFindCreateFunction = false;
+    MediaExtractor* extractor = NULL;
+
+    if (!alreadyTriedToFindCreateFunction) {
+        void *extendedExtractorLib = loadExtendedExtractorLib();
+
+        if (extendedExtractorLib != NULL) {
+            create = (ExtendedExtractorCreate) dlsym (
+                    extendedExtractorLib, EXTENDED_EXTRACTOR_CREATE);
+            alreadyTriedToFindCreateFunction = true;
+        }
+    }
+
+    if (create == NULL) {
+        ALOGE ("Failed to find symbol : %s, dlerror = %s",
+            EXTENDED_EXTRACTOR_CREATE, dlerror());
+        return NULL;
+    }
+
+    extractor = create (source, mime);
+    if (extractor == NULL) {
+        ALOGE("Failed to instantiate extractor \n");
+    }
+
+    return extractor;
+}
+
+bool ExtendedExtractor::Sniff (
+        const sp<DataSource> &source, String8 *mimeType,
+        float *confidence,sp<AMessage> *meta) {
+    void *extendedExtractorLib = loadExtendedExtractorLib();
+    bool retVal = false;
+
+    if (extendedExtractorLib != NULL) {
+       ExtendedExtractorSniff sniff = (ExtendedExtractorSniff) dlsym (
+               extendedExtractorLib, EXTENDED_EXTRACTOR_SNIFF);
+
+        if (sniff == NULL) {
+            ALOGE ("Failed to find symbol : %s, dlerror = %s",
+                EXTENDED_EXTRACTOR_SNIFF, dlerror());
+            return retVal;
+        }
+
+       retVal = sniff (source, mimeType, confidence, meta);
+
+       if(!retVal) {
+           ALOGV("Sniff Failed");
+       }
+    }
+    return retVal;
+}
+
+}  // namespace android
+
+#else //ENABLE_AV_ENHANCEMENTS
+
+namespace android {
+
+MediaExtractor* ExtendedExtractor::Create (
+        const sp<DataSource> &source, const char *mime) {
+    return NULL;
+}
+bool ExtendedExtractor::Sniff (
+        const sp<DataSource> &source, String8 *mimeType,
+        float *confidence,sp<AMessage> *meta) {
+    *confidence = 0.0;
+    return false;
+}
+
+}  // namespace android
+
+#endif //ENABLE_AV_ENHANCEMENTS
+
diff --git a/media/libstagefright/ExtendedMediaDefs.cpp b/media/libstagefright/ExtendedMediaDefs.cpp
new file mode 100644
index 0000000..209db2b
--- /dev/null
+++ b/media/libstagefright/ExtendedMediaDefs.cpp
@@ -0,0 +1,66 @@
+/*Copyright (c) 2012 - 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * 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";
+const char *MEDIA_MIMETYPE_VIDEO_HEVC = "video/hevc";
+const char *MEDIA_MIMETYPE_CONTAINER_QCAMR_NB = "audio/qc-amr";
+const char *MEDIA_MIMETYPE_CONTAINER_QCAMR_WB = "audio/qc-amr-wb";
+const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG = "audio/qc-mpeg";
+const char *MEDIA_MIMETYPE_CONTAINER_QCWAV = "audio/qc-wav";
+const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG2TS = "video/qc-mp2ts";
+const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG2PS = "video/qc-mp2ps";
+const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG4 = "video/qc-mp4";
+const char *MEDIA_MIMETYPE_CONTAINER_QCMATROSKA = "video/qc-matroska";
+const char *MEDIA_MIMETYPE_CONTAINER_QCOGG = "video/qc-ogg";
+const char *MEDIA_MIMETYPE_CONTAINER_QCFLV = "video/qc-flv";
+const char *MEDIA_MIMETYPE_VIDEO_VPX = "video/x-vnd.on2.vp8"; //backward compatibility
+
+}  // namespace android
diff --git a/media/libstagefright/ExtendedUtils.cpp b/media/libstagefright/ExtendedUtils.cpp
new file mode 100644
index 0000000..1da6c9d
--- /dev/null
+++ b/media/libstagefright/ExtendedUtils.cpp
@@ -0,0 +1,649 @@
+/*Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * 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 "ExtendedUtils"
+#include <utils/Log.h>
+
+#include <utils/Errors.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/OMXCodec.h>
+#include <cutils/properties.h>
+#include <media/stagefright/MediaExtractor.h>
+
+#include "include/ExtendedUtils.h"
+
+static const int64_t kDefaultAVSyncLateMargin =  40000;
+static const int64_t kMaxAVSyncLateMargin     = 250000;
+
+#ifdef ENABLE_AV_ENHANCEMENTS
+
+#include <QCMetaData.h>
+#include <QCMediaDefs.h>
+
+#include "include/ExtendedExtractor.h"
+#include "include/avc_utils.h"
+
+namespace android {
+
+void ExtendedUtils::HFR::setHFRIfEnabled(
+        const CameraParameters& params,
+        sp<MetaData> &meta) {
+    const char *hfr_str = params.get("video-hfr");
+    int32_t hfr = -1;
+    if ( hfr_str != NULL ) {
+        hfr = atoi(hfr_str);
+    }
+    if (hfr < 0) {
+        ALOGW("Invalid hfr value(%d) set from app. Disabling HFR.", hfr);
+        hfr = 0;
+    }
+
+    meta->setInt32(kKeyHFR, hfr);
+}
+
+status_t ExtendedUtils::HFR::reCalculateFileDuration(
+        sp<MetaData> &meta, sp<MetaData> &enc_meta,
+        int64_t &maxFileDurationUs, int32_t frameRate,
+        video_encoder videoEncoder) {
+    status_t retVal = OK;
+    int32_t hfr = 0;
+
+    if (!meta->findInt32(kKeyHFR, &hfr)) {
+        ALOGW("hfr not found, default to 0");
+    }
+
+    if (hfr && frameRate) {
+        maxFileDurationUs = maxFileDurationUs * (hfr/frameRate);
+    }
+
+    enc_meta->setInt32(kKeyHFR, hfr);
+    int32_t width = 0, height = 0;
+
+    CHECK(meta->findInt32(kKeyWidth, &width));
+    CHECK(meta->findInt32(kKeyHeight, &height));
+
+    char mDeviceName[100];
+    property_get("ro.board.platform",mDeviceName,"0");
+    if (!strncmp(mDeviceName, "msm7627a", 8)) {
+        if (hfr && (width * height > 432*240)) {
+            ALOGE("HFR mode is supported only upto WQVGA resolution");
+            return INVALID_OPERATION;
+        }
+    } else if (!strncmp(mDeviceName, "msm8974", 7) ||
+               !strncmp(mDeviceName, "msm8610", 7)) {
+        if (hfr && (width * height > 1920*1088)) {
+            ALOGE("HFR mode is supported only upto 1080p resolution");
+            return INVALID_OPERATION;
+        }
+    } else {
+        if (hfr && ((videoEncoder != VIDEO_ENCODER_H264) || (width * height > 800*480))) {
+            ALOGE("HFR mode is supported only upto WVGA and H264 codec.");
+            return INVALID_OPERATION;
+        }
+    }
+    return retVal;
+}
+
+void ExtendedUtils::HFR::reCalculateTimeStamp(
+        sp<MetaData> &meta, int64_t &timestampUs) {
+    int32_t frameRate = 0, hfr = 0;
+    if (!(meta->findInt32(kKeyFrameRate, &frameRate))) {
+        return;
+    }
+
+    if (!(meta->findInt32(kKeyHFR, &hfr))) {
+        return;
+    }
+
+    if (hfr && frameRate) {
+        timestampUs = (hfr * timestampUs) / frameRate;
+    }
+}
+
+void ExtendedUtils::HFR::reCalculateHFRParams(
+        const sp<MetaData> &meta, int32_t &frameRate,
+        int32_t &bitRate) {
+    int32_t hfr = 0;
+    if (!(meta->findInt32(kKeyHFR, &hfr))) {
+        return;
+    }
+
+    if (hfr && frameRate) {
+        bitRate = (hfr * bitRate) / frameRate;
+        frameRate = hfr;
+    }
+}
+
+void ExtendedUtils::HFR::copyHFRParams(
+        const sp<MetaData> &inputFormat,
+        sp<MetaData> &outputFormat) {
+    int32_t frameRate = 0, hfr = 0;
+    inputFormat->findInt32(kKeyHFR, &hfr);
+    inputFormat->findInt32(kKeyFrameRate, &frameRate);
+    outputFormat->setInt32(kKeyHFR, hfr);
+    outputFormat->setInt32(kKeyFrameRate, frameRate);
+}
+
+bool ExtendedUtils::ShellProp::isAudioDisabled() {
+    bool retVal = false;
+    char disableAudio[PROPERTY_VALUE_MAX];
+    property_get("persist.debug.sf.noaudio", disableAudio, "0");
+    if (atoi(disableAudio) == 1) {
+        retVal = true;
+    }
+    return retVal;
+}
+
+void ExtendedUtils::ShellProp::setEncoderProfile(
+        video_encoder &videoEncoder, int32_t &videoEncoderProfile) {
+    char value[PROPERTY_VALUE_MAX];
+    bool customProfile = false;
+    if (!property_get("encoder.video.profile", value, NULL) > 0) {
+        return;
+    }
+
+    switch (videoEncoder) {
+        case VIDEO_ENCODER_H264:
+            if (strncmp("base", value, 4) == 0) {
+                videoEncoderProfile = OMX_VIDEO_AVCProfileBaseline;
+                ALOGI("H264 Baseline Profile");
+            } else if (strncmp("main", value, 4) == 0) {
+                videoEncoderProfile = OMX_VIDEO_AVCProfileMain;
+                ALOGI("H264 Main Profile");
+            } else if (strncmp("high", value, 4) == 0) {
+                videoEncoderProfile = OMX_VIDEO_AVCProfileHigh;
+                ALOGI("H264 High Profile");
+            } else {
+                ALOGW("Unsupported H264 Profile");
+            }
+            break;
+        case VIDEO_ENCODER_MPEG_4_SP:
+            if (strncmp("simple", value, 5) == 0 ) {
+                videoEncoderProfile = OMX_VIDEO_MPEG4ProfileSimple;
+                ALOGI("MPEG4 Simple profile");
+            } else if (strncmp("asp", value, 3) == 0 ) {
+                videoEncoderProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple;
+                ALOGI("MPEG4 Advanced Simple Profile");
+            } else {
+                ALOGW("Unsupported MPEG4 Profile");
+            }
+            break;
+        default:
+            ALOGW("No custom profile support for other codecs");
+            break;
+    }
+}
+
+int64_t ExtendedUtils::ShellProp::getMaxAVSyncLateMargin() {
+    char lateMarginMs[PROPERTY_VALUE_MAX] = {0};
+    property_get("media.sf.set.late.margin", lateMarginMs, "0");
+    int64_t newLateMarginUs = atoi(lateMarginMs)*1000;
+    int64_t maxLateMarginUs = newLateMarginUs;
+
+    if (newLateMarginUs > kDefaultAVSyncLateMargin
+            || newLateMarginUs < kDefaultAVSyncLateMargin) {
+        maxLateMarginUs = kDefaultAVSyncLateMargin;
+    }
+
+    ALOGI("AV Sync late margin : Intended=%lldms Using=%lldms",
+            maxLateMarginUs/1000, newLateMarginUs/1000);
+    return maxLateMarginUs;
+}
+
+bool ExtendedUtils::ShellProp::isSmoothStreamingEnabled() {
+    char prop[PROPERTY_VALUE_MAX] = {0};
+    property_get("mm.enable.smoothstreaming", prop, "0");
+    if (!strncmp(prop, "true", 4) || atoi(prop)) {
+        return true;
+    }
+    return false;
+}
+
+void ExtendedUtils::setBFrames(
+        OMX_VIDEO_PARAM_MPEG4TYPE &mpeg4type, int32_t &numBFrames,
+        const char* componentName) {
+    //ignore non QC components
+    if (strncmp(componentName, "OMX.qcom.", 9)) {
+        return;
+    }
+    if (mpeg4type.eProfile > OMX_VIDEO_MPEG4ProfileSimple) {
+        mpeg4type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
+        mpeg4type.nBFrames = 1;
+        mpeg4type.nPFrames /= (mpeg4type.nBFrames + 1);
+        numBFrames = mpeg4type.nBFrames;
+    }
+    return;
+}
+
+void ExtendedUtils::setBFrames(
+        OMX_VIDEO_PARAM_AVCTYPE &h264type, int32_t &numBFrames,
+        int32_t iFramesInterval, int32_t frameRate, const char* componentName) {
+    //ignore non QC components
+    if (strncmp(componentName, "OMX.qcom.", 9)) {
+        return;
+    }
+    OMX_U32 val = 0;
+    if (iFramesInterval < 0) {
+        val =  0xFFFFFFFF;
+    } else if (iFramesInterval == 0) {
+        val = 0;
+    } else {
+        val  = frameRate * iFramesInterval - 1;
+        CHECK(val > 1);
+    }
+
+    h264type.nPFrames = val;
+
+    if (h264type.nPFrames == 0) {
+        h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
+    }
+
+    if (h264type.eProfile > OMX_VIDEO_AVCProfileBaseline) {
+        h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
+        h264type.nBFrames = 1;
+        h264type.nPFrames /= (h264type.nBFrames + 1);
+        //enable CABAC as default entropy mode for Hihg/Main profiles
+        h264type.bEntropyCodingCABAC = OMX_TRUE;
+        h264type.nCabacInitIdc = 0;
+        numBFrames = h264type.nBFrames;
+    }
+    return;
+}
+
+/*
+QCOM HW AAC encoder allowed bitrates
+------------------------------------------------------------------------------------------------------------------
+Bitrate limit |AAC-LC(Mono)           | AAC-LC(Stereo)        |AAC+(Mono)            | AAC+(Stereo)            | eAAC+                      |
+Minimum     |Min(24000,0.5 * f_s)   |Min(24000,f_s)           | 24000                      |24000                        |  24000                       |
+Maximum    |Min(192000,6 * f_s)    |Min(192000,12 * f_s)  | Min(192000,6 * f_s)  | Min(192000,12 * f_s)  |  Min(192000,12 * f_s) |
+------------------------------------------------------------------------------------------------------------------
+*/
+bool ExtendedUtils::UseQCHWAACEncoder(audio_encoder Encoder,int32_t Channel,int32_t BitRate,int32_t SampleRate)
+{
+    bool ret = false;
+    int minBiteRate = -1;
+    int maxBiteRate = -1;
+    char propValue[PROPERTY_VALUE_MAX] = {0};
+
+    property_get("qcom.hw.aac.encoder",propValue,NULL);
+    if (!strncmp(propValue,"true",sizeof("true"))) {
+        //check for QCOM's HW AAC encoder only when qcom.aac.encoder =  true;
+        ALOGV("qcom.aac.encoder enabled, check AAC encoder(%d) allowed bitrates",Encoder);
+        switch (Encoder) {
+        case AUDIO_ENCODER_AAC:// for AAC-LC format
+            if (Channel == 1) {//mono
+                minBiteRate = MIN_BITERATE_AAC<(SampleRate/2)?MIN_BITERATE_AAC:(SampleRate/2);
+                maxBiteRate = MAX_BITERATE_AAC<(SampleRate*6)?MAX_BITERATE_AAC:(SampleRate*6);
+            } else if (Channel == 2) {//stereo
+                minBiteRate = MIN_BITERATE_AAC<SampleRate?MIN_BITERATE_AAC:SampleRate;
+                maxBiteRate = MAX_BITERATE_AAC<(SampleRate*12)?MAX_BITERATE_AAC:(SampleRate*12);
+            }
+            break;
+        case AUDIO_ENCODER_HE_AAC:// for AAC+ format
+            if (Channel == 1) {//mono
+                minBiteRate = MIN_BITERATE_AAC;
+                maxBiteRate = MAX_BITERATE_AAC<(SampleRate*6)?MAX_BITERATE_AAC:(SampleRate*6);
+            } else if (Channel == 2) {//stereo
+                minBiteRate = MIN_BITERATE_AAC;
+                maxBiteRate = MAX_BITERATE_AAC<(SampleRate*12)?MAX_BITERATE_AAC:(SampleRate*12);
+            }
+            break;
+        default:
+            ALOGV("encoder:%d not supported by QCOM HW AAC encoder",Encoder);
+
+        }
+
+        //return true only when 1. minBiteRate and maxBiteRate are updated(not -1) 2. minBiteRate <= SampleRate <= maxBiteRate
+        if (SampleRate >= minBiteRate && SampleRate <= maxBiteRate) {
+            ret = true;
+        }
+    }
+
+    return ret;
+}
+
+
+//- returns NULL if we dont really need a new extractor (or cannot),
+//  valid extractor is returned otherwise
+//- caller needs to check for NULL
+//  ----------------------------------------
+//  defaultExt - the existing extractor
+//  source - file source
+//  mime - container mime
+//  ----------------------------------------
+//  Note: defaultExt will be deleted in this function if the new parser is selected
+
+sp<MediaExtractor> ExtendedUtils::MediaExtractor_CreateIfNeeded(sp<MediaExtractor> defaultExt,
+                                                            const sp<DataSource> &source,
+                                                            const char *mime) {
+    bool bCheckExtendedExtractor = false;
+    bool videoTrackFound         = false;
+    bool audioTrackFound         = false;
+    bool amrwbAudio              = false;
+    int  numOfTrack              = 0;
+
+    if (defaultExt != NULL) {
+        for (size_t trackItt = 0; trackItt < defaultExt->countTracks(); ++trackItt) {
+            ++numOfTrack;
+            sp<MetaData> meta = defaultExt->getTrackMetaData(trackItt);
+            const char *_mime;
+            CHECK(meta->findCString(kKeyMIMEType, &_mime));
+
+            String8 mime = String8(_mime);
+
+            if (!strncasecmp(mime.string(), "audio/", 6)) {
+                audioTrackFound = true;
+
+                amrwbAudio = !strncasecmp(mime.string(),
+                                          MEDIA_MIMETYPE_AUDIO_AMR_WB,
+                                          strlen(MEDIA_MIMETYPE_AUDIO_AMR_WB));
+                if (amrwbAudio) {
+                    break;
+                }
+            }else if(!strncasecmp(mime.string(), "video/", 6)) {
+                videoTrackFound = true;
+            }
+        }
+
+        if(amrwbAudio) {
+            bCheckExtendedExtractor = true;
+        }else if (numOfTrack  == 0) {
+            bCheckExtendedExtractor = true;
+        } else if(numOfTrack == 1) {
+            if((videoTrackFound) ||
+                (!videoTrackFound && !audioTrackFound)){
+                bCheckExtendedExtractor = true;
+            }
+        } else if (numOfTrack >= 2){
+            if(videoTrackFound && audioTrackFound) {
+                if(amrwbAudio) {
+                    bCheckExtendedExtractor = true;
+                }
+            } else {
+                bCheckExtendedExtractor = true;
+            }
+        }
+    } else {
+        bCheckExtendedExtractor = true;
+    }
+
+    if (!bCheckExtendedExtractor) {
+        ALOGD("extended extractor not needed, return default");
+        return defaultExt;
+    }
+
+    //Create Extended Extractor only if default extractor is not selected
+    ALOGD("Try creating ExtendedExtractor");
+    sp<MediaExtractor>  retExtExtractor = ExtendedExtractor::Create(source, mime);
+
+    if (retExtExtractor == NULL) {
+        ALOGD("Couldn't create the extended extractor, return default one");
+        return defaultExt;
+    }
+
+    if (defaultExt == NULL) {
+        ALOGD("default extractor is NULL, return extended extractor");
+        return retExtExtractor;
+    }
+
+    //bCheckExtendedExtractor is true which means default extractor was found
+    //but we want to give preference to extended extractor based on certain
+    //conditions.
+
+    //needed to prevent a leak in case both extractors are valid
+    //but we still dont want to use the extended one. we need
+    //to delete the new one
+    bool bUseDefaultExtractor = true;
+
+    for (size_t trackItt = 0; (trackItt < retExtExtractor->countTracks()); ++trackItt) {
+        sp<MetaData> meta = retExtExtractor->getTrackMetaData(trackItt);
+        const char *mime;
+        bool success = meta->findCString(kKeyMIMEType, &mime);
+        if ((success == true) &&
+            (!strncasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
+                                strlen(MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS)) ||
+             !strncasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC,
+                                strlen(MEDIA_MIMETYPE_VIDEO_HEVC)) )) {
+
+            ALOGD("Discarding default extractor and using the extended one");
+            bUseDefaultExtractor = false;
+            break;
+        }
+    }
+
+    if (bUseDefaultExtractor) {
+        ALOGD("using default extractor inspite of having a new extractor");
+        retExtExtractor.clear();
+        return defaultExt;
+    } else {
+        defaultExt.clear();
+        return retExtExtractor;
+    }
+
+}
+
+
+void ExtendedUtils::helper_addMediaCodec(Vector<MediaCodecList::CodecInfo> &mCodecInfos,
+                                          KeyedVector<AString, size_t> &mTypes,
+                                          bool encoder, const char *name,
+                                          const char *type, uint32_t quirks) {
+    mCodecInfos.push();
+    MediaCodecList::CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1);
+    info->mName = name;
+    info->mIsEncoder = encoder;
+    ssize_t index = mTypes.indexOfKey(type);
+    uint32_t bit = mTypes.valueAt(index);
+    info->mTypes |= 1ul << bit;
+    info->mQuirks = quirks;
+}
+
+uint32_t ExtendedUtils::helper_getCodecSpecificQuirks(KeyedVector<AString, size_t> &mCodecQuirks,
+                                                       Vector<AString> quirks) {
+    size_t i = 0, numQuirks = quirks.size();
+    uint32_t bit = 0, value = 0;
+    for (i = 0; i < numQuirks; i++)
+    {
+        ssize_t index = mCodecQuirks.indexOfKey(quirks.itemAt(i));
+        bit = mCodecQuirks.valueAt(index);
+        value |= 1ul << bit;
+    }
+    return value;
+}
+
+bool ExtendedUtils::isAVCProfileSupported(int32_t  profile){
+   if(profile == OMX_VIDEO_AVCProfileMain || profile == OMX_VIDEO_AVCProfileHigh || profile == OMX_VIDEO_AVCProfileBaseline){
+      return true;
+   } else {
+      return false;
+   }
+}
+
+void ExtendedUtils::updateNativeWindowBufferGeometry(ANativeWindow* anw,
+        OMX_U32 width, OMX_U32 height, OMX_COLOR_FORMATTYPE colorFormat) {
+#if UPDATE_BUFFER_GEOMETRY_AVAILABLE
+    if (anw != NULL) {
+        ALOGI("Calling native window update buffer geometry [%lu x %lu]",
+                width, height);
+        status_t err = anw->perform(
+                anw, NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY,
+                width, height, colorFormat);
+        if (err != OK) {
+            ALOGE("UPDATE_BUFFER_GEOMETRY failed %d", err);
+        }
+    }
+#endif
+}
+
+bool ExtendedUtils::checkIsThumbNailMode(const uint32_t flags, char* componentName) {
+    bool isInThumbnailMode = false;
+    if ((flags & OMXCodec::kClientNeedsFramebuffer) && !strncmp(componentName, "OMX.qcom.", 9)) {
+        isInThumbnailMode = true;
+    }
+    return isInThumbnailMode;
+}
+
+void ExtendedUtils::setArbitraryModeIfInterlaced(
+        const uint8_t *ptr, const sp<MetaData> &meta) {
+
+    if (ptr == NULL) {
+        return;
+    }
+    uint16_t spsSize = (((uint16_t)ptr[6]) << 8) + (uint16_t)(ptr[7]);
+    int32_t width = 0, height = 0, isInterlaced = 0;
+    const uint8_t *spsStart = &ptr[8];
+
+    sp<ABuffer> seqParamSet = new ABuffer(spsSize);
+    memcpy(seqParamSet->data(), spsStart, spsSize);
+    FindAVCDimensions(seqParamSet, &width, &height, NULL, NULL, &isInterlaced);
+
+    ALOGV("height is %d, width is %d, isInterlaced is %d\n", height, width, isInterlaced);
+    if (isInterlaced) {
+        meta->setInt32(kKeyUseArbitraryMode, 1);
+        meta->setInt32(kKeyInterlace, 1);
+    }
+    return;
+}
+
+int32_t ExtendedUtils::checkIsInterlace(sp<MetaData> &meta) {
+    int32_t isInterlaceFormat = 0;
+
+    if(meta->findInt32(kKeyInterlace, &isInterlaceFormat)) {
+        ALOGI("interlace format detected");
+    }
+
+    return isInterlaceFormat;
+}
+
+}
+#else //ENABLE_AV_ENHANCEMENTS
+
+namespace android {
+
+void ExtendedUtils::HFR::setHFRIfEnabled(
+        const CameraParameters& params, sp<MetaData> &meta) {
+}
+
+status_t ExtendedUtils::HFR::reCalculateFileDuration(
+        sp<MetaData> &meta, sp<MetaData> &enc_meta,
+        int64_t &maxFileDurationUs, int32_t frameRate,
+        video_encoder videoEncoder) {
+    return OK;
+}
+
+void ExtendedUtils::HFR::reCalculateTimeStamp(
+        sp<MetaData> &meta, int64_t &timestampUs) {
+}
+
+void ExtendedUtils::HFR::reCalculateHFRParams(
+        const sp<MetaData> &meta, int32_t &frameRate,
+        int32_t &bitrate) {
+}
+
+void ExtendedUtils::HFR::copyHFRParams(
+        const sp<MetaData> &inputFormat,
+        sp<MetaData> &outputFormat) {
+}
+
+bool ExtendedUtils::ShellProp::isAudioDisabled() {
+    return false;
+}
+
+void ExtendedUtils::ShellProp::setEncoderProfile(
+        video_encoder &videoEncoder, int32_t &videoEncoderProfile) {
+}
+
+int64_t ExtendedUtils::ShellProp::getMaxAVSyncLateMargin() {
+     return kDefaultAVSyncLateMargin;
+}
+
+bool ExtendedUtils::ShellProp::isSmoothStreamingEnabled() {
+    return false;
+}
+
+void ExtendedUtils::setBFrames(
+        OMX_VIDEO_PARAM_MPEG4TYPE &mpeg4type, int32_t &numBFrames,
+        const char* componentName) {
+}
+
+void ExtendedUtils::setBFrames(
+        OMX_VIDEO_PARAM_AVCTYPE &h264type, int32_t &numBFrames,
+        int32_t iFramesInterval, int32_t frameRate,
+        const char* componentName) {
+}
+
+bool ExtendedUtils::UseQCHWAACEncoder(audio_encoder Encoder,int32_t Channel,
+    int32_t BitRate,int32_t SampleRate) {
+    return false;
+}
+
+sp<MediaExtractor> ExtendedUtils::MediaExtractor_CreateIfNeeded(sp<MediaExtractor> defaultExt,
+                                                            const sp<DataSource> &source,
+                                                            const char *mime) {
+                   return defaultExt;
+}
+
+void QCUtils::helper_addMediaCodec(Vector<MediaCodecList::CodecInfo> &mCodecInfos,
+                                          KeyedVector<AString, size_t> &mTypes,
+                                          bool encoder, const char *name,
+                                          const char *type, uint32_t quirks) {
+}
+
+uint32_t QCUtils::helper_getCodecSpecificQuirks(KeyedVector<AString, size_t> &mCodecQuirks,
+                                                       Vector<AString> quirks) {
+    return 0;
+}
+
+bool ExtendedUtils::isAVCProfileSupported(int32_t  profile){
+     return false;
+}
+
+void ExtendedUtils::updateNativeWindowBufferGeometry(ANativeWindow* anw,
+        OMX_U32 width, OMX_U32 height, OMX_COLOR_FORMATTYPE colorFormat) {
+}
+
+bool ExtendedUtils::checkIsThumbNailMode(const uint32_t flags, char* componentName) {
+    return false;
+}
+
+void ExtendedUtils::setArbitraryModeIfInterlaced(
+        const uint8_t *ptr, const sp<MetaData> &meta) {
+}
+
+int32_t ExtendedUtils::checkIsInterlace(sp<MetaData> &meta) {
+    return false;
+}
+
+}
+#endif //ENABLE_AV_ENHANCEMENTS
diff --git a/media/libstagefright/ExtendedWriter.cpp b/media/libstagefright/ExtendedWriter.cpp
new file mode 100644
index 0000000..db5bb4a
--- /dev/null
+++ b/media/libstagefright/ExtendedWriter.cpp
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2012 - 2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution.
+ *
+ * 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..c7b490f
--- /dev/null
+++ b/media/libstagefright/LPAPlayerALSA.cpp
@@ -0,0 +1,750 @@
+/*
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ * Copyright (C) 2009 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_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 <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 "include/AwesomePlayer.h"
+
+static const char   mName[] = "LPAPlayer";
+
+#define MEM_METADATA_SIZE 64
+#define MEM_BUFFER_SIZE ((256*1024) - MEM_METADATA_SIZE)
+#define MEM_BUFFER_COUNT 4
+#define LPA_BUFFER_TIME 1500000
+
+namespace android {
+int LPAPlayer::mObjectsAlive = 0;
+
+LPAPlayer::LPAPlayer(
+                    const sp<MediaPlayerBase::AudioSink> &audioSink, bool &initCheck,
+                    AwesomePlayer *observer)
+:AudioPlayer(audioSink, 0, observer),
+mPositionTimeMediaUs(-1),
+mPositionTimeRealUs(-1),
+mInternalSeeking(false),
+mStarted(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");
+    mObjectsAlive++;
+    mNumOutputChannels =0;
+    mNumInputChannels = 0;
+    mPaused = false;
+    /* Initialize Suspend/Resume related variables */
+    mQueue.start();
+    mQueueStarted      = true;
+    mPauseEvent        = new TimedEvent(this, &LPAPlayer::onPauseTimeOut);
+    mPauseEventPending = false;
+    ALOGV("Registering client with AudioFlinger");
+
+    mIsAudioRouted = false;
+
+    initCheck = true;
+
+}
+
+LPAPlayer::~LPAPlayer() {
+    ALOGV("LPAPlayer::~LPAPlayer()");
+    if (mQueueStarted) {
+        mQueue.stop();
+    }
+
+    reset();
+
+    mObjectsAlive--;
+}
+
+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 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, &mNumInputChannels);
+    CHECK(success);
+
+    // Always produce stereo output
+    mNumOutputChannels = 2;
+
+    if(!format->findInt32(kKeyChannelMask, &mChannelMask)) {
+        // log only when there's a risk of ambiguity of channel mask selection
+        ALOGI_IF(mNumInputChannels > 2,
+                "source format didn't specify channel mask, using (%d) channel order", mNumInputChannels);
+        mChannelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
+    }
+    audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA |
+                                                         AUDIO_OUTPUT_FLAG_DIRECT);
+    ALOGV("mAudiosink->open() mSampleRate %d, numOutputChannels %d, mChannelMask %d, flags %d",mSampleRate,
+          mNumOutputChannels, mChannelMask, flags);
+    err = mAudioSink->open(
+        mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+        DEFAULT_AUDIOSINK_BUFFERCOUNT,
+        &LPAPlayer::AudioSinkCallback,
+        this,
+        flags,
+        NULL);
+
+    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");
+    mLock.lock();
+    mDecoderCv.signal();
+    mLock.unlock();
+
+    return OK;
+}
+
+status_t LPAPlayer::seekTo(int64_t time_us) {
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("seekTo: time_us %lld", time_us);
+
+    if (seekTooClose(time_us)) {
+        mLock.unlock();
+        mObserver->postAudioSeekComplete();
+        mLock.lock();
+        return OK;
+    }
+
+    mSeeking = true;
+    mSeekTimeUs = time_us;
+    mPauseTime = mSeekTimeUs;
+    ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);
+
+    if (mIsAudioRouted) {
+        mAudioSink->flush();
+    }
+
+    if (mReachedEOS) {
+        mReachedEOS = false;
+        mReachedOutputEOS = false;
+        if(mPaused == false) {
+            ALOGV("Going to signal decoder thread since playback is already going on ");
+            mDecoderCv.signal();
+            ALOGV("Signalled extractor thread.");
+        }
+    }
+    ALOGV("seek done.");
+    return OK;
+}
+
+void LPAPlayer::pause(bool playPendingSamples) {
+    CHECK(mStarted);
+    if (mPaused) {
+        return;
+    }
+    ALOGV("pause: playPendingSamples %d", playPendingSamples);
+    mPaused = true;
+    if (!mPauseEventPending) {
+        ALOGV("Posting an event for Pause timeout");
+        mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
+        mPauseEventPending = true;
+    }
+    mPauseTime = mSeekTimeUs + getTimeStamp();
+
+    if (mAudioSink.get() != NULL) {
+        ALOGV("AudioSink pause");
+        mAudioSink->pause();
+    }
+}
+
+status_t LPAPlayer::resume() {
+    ALOGV("resume: mPaused %d",mPaused);
+    status_t err = NO_ERROR;
+    Mutex::Autolock autoLock(mLock);
+    if ( mPaused) {
+        CHECK(mStarted);
+        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);
+            err = mAudioSink->open(
+                mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+                DEFAULT_AUDIOSINK_BUFFERCOUNT,
+                &LPAPlayer::AudioSinkCallback,
+                this,
+                flags,
+                NULL);
+            if (err != NO_ERROR) {
+                ALOGE("Audio sink open failed.");
+            }
+            mIsAudioRouted = true;
+        }
+        mPaused = false;
+        mAudioSink->start();
+        mDecoderCv.signal();
+
+    }
+    return err;
+}
+
+//static
+size_t LPAPlayer::AudioSinkCallback(
+        MediaPlayerBase::AudioSink *audioSink,
+        void *buffer, size_t size, void *cookie,
+        MediaPlayerBase::AudioSink::cb_event_t event) {
+    if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
+        LPAPlayer *me = (LPAPlayer *)cookie;
+        if(me->mReachedEOS == true) {
+            //in the case of seek all these flags will be reset
+            me->mReachedOutputEOS = true;
+            ALOGV("postAudioEOS mSeeking %d", me->mSeeking);
+            me->mObserver->postAudioEOS(0);
+        }else {
+            ALOGV("postAudioEOS ignored since %d", me->mSeeking);
+        }
+    }
+    return 1;
+}
+
+void LPAPlayer::reset() {
+    ALOGD("Reset");
+
+    Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
+
+    //cancel any pending onpause timeout events
+    //doesnt matter if the event is really present or not
+    mPauseEventPending = false;
+    mQueue.cancelEvent(mPauseEvent->eventID());
+
+    // Close the audiosink after all the threads exited to make sure
+    mReachedEOS = true;
+
+    // make sure Decoder thread has exited
+    ALOGD("Closing all the threads");
+    requestAndWaitForDecoderThreadExit_l();
+
+    ALOGD("Close the Sink");
+    if (mIsAudioRouted) {
+        mAudioSink->stop();
+        mAudioSink->close();
+        mAudioSink.clear();
+        mIsAudioRouted = false;
+    }
+    // Make sure to release any buffer we hold onto so that the
+    // source is able to stop().
+    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() {
+
+    mLock.lock();
+    pid_t tid  = gettid();
+    androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+    prctl(PR_SET_NAME, (unsigned long)"LPA DecodeThread", 0, 0, 0);
+
+    ALOGV("mDecoderThreadEntry wait for signal \n");
+    if (!mStarted) {
+        mDecoderCv.wait(mLock);
+    }
+    ALOGV("decoderThreadEntry ready to work \n");
+    mLock.unlock();
+    if (mKillDecoderThread) {
+        return;
+    }
+    void* local_buf = malloc(MEM_BUFFER_SIZE);
+    if(local_buf == (void*) NULL) {
+        mKillDecoderThread = true;
+        ALOGE("Malloc failed");
+        return;
+    }
+    int *lptr = ((int*)local_buf);
+    int bytesWritten = 0;
+
+    if (!local_buf) {
+      ALOGE("Failed to allocate temporary buffer for mDecoderThread");
+      return;
+    }
+
+    bool lSeeking = false;
+    bool lPaused = false;
+
+    while (!mKillDecoderThread) {
+
+        if (mReachedEOS || mPaused || !mIsAudioRouted) {
+            ALOGV("Going to sleep before write since "
+                  "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+                  mReachedEOS, mPaused, mIsAudioRouted);
+            mDecoderMutex.lock();
+            mDecoderCv.wait(mDecoderMutex);
+            mDecoderMutex.unlock();
+            ALOGV("Woke up from sleep before write since "
+                  "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+                  mReachedEOS, mPaused, mIsAudioRouted);
+            continue;
+        }
+
+        ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE);
+        ALOGV("Fillbuffer started");
+        if (mNumInputChannels == 1) {
+            bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE/2);
+            CHECK(bytesWritten <= MEM_BUFFER_SIZE/2);
+
+            convertMonoToStereo((int16_t*)local_buf, bytesWritten);
+            bytesWritten *= 2;
+        } else {
+            bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE);
+            CHECK(bytesWritten <= MEM_BUFFER_SIZE);
+        }
+
+        ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+        if(!mKillDecoderThread) {
+            mLock.lock();
+            lPaused = mPaused;
+            mLock.unlock();
+
+            if(lPaused == true) {
+                //write only if player is not in paused state. Sleep on lock
+                // resume is called
+                ALOGV("Going to sleep in decodethreadiwrite since sink is paused");
+                mDecoderMutex.lock();
+                mDecoderCv.wait(mDecoderMutex);
+                ALOGV("Going to unlock n decodethreadwrite since sink "
+                      "resumed mPaused %d, mIsAudioRouted %d, mReachedEOS %d",
+                      mPaused, mIsAudioRouted, mReachedEOS);
+                mDecoderMutex.unlock();
+            }
+            mLock.lock();
+            lSeeking = mSeeking||mInternalSeeking;
+            mLock.unlock();
+
+            if(lSeeking == false && (mKillDecoderThread == false)){
+                //if we are seeking, ignore write, otherwise write
+                ALOGV("Fillbuffer before seeling flag %d", mSeeking);
+                int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten);
+                ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking);
+            } else {
+                ALOGV("Fillbuffer ignored since we seeked after fillBuffer was set %d", mSeeking);
+            }
+        }
+    }
+
+    free(local_buf);
+
+    //TODO: Call fillbuffer with different size and write to mAudioSink()
+}
+
+void LPAPlayer::createThreads() {
+
+    // Create 4 threads Effect, decoder, event and A2dp
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    mKillDecoderThread = false;
+
+    mDecoderThreadAlive = true;
+
+    ALOGV("Creating decoder Thread");
+    pthread_create(&mDecoderThread, &attr, decoderThreadWrapper, this);
+
+    pthread_attr_destroy(&attr);
+}
+
+size_t LPAPlayer::fillBuffer(void *data, size_t size) {
+
+    if (mReachedEOS) {
+        return 0;
+    }
+
+    if ((data == (void*) NULL) || size > MEM_BUFFER_SIZE) {
+        ALOGE("fillBuffer given wrong buffer");
+        return 0;
+    }
+
+    bool postSeekComplete = false;
+
+    size_t size_done = 0;
+    size_t size_remaining = size;
+    ALOGV("fillBuffer: Clearing seek flag in fill buffer");
+
+    while (size_remaining > 0) {
+        MediaSource::ReadOptions options;
+
+        {
+            Mutex::Autolock autoLock(mLock);
+
+            if(mSeeking) {
+                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;
+                }
+
+                // This is to ignore the data already filled in the output buffer
+                size_done = 0;
+                size_remaining = size;
+
+                mSeeking = false;
+                if (mObserver && !mInternalSeeking) {
+                    ALOGV("fillBuffer: Posting audio seek complete event");
+                    postSeekComplete = true;
+                }
+                mInternalSeeking = false;
+                ALOGV("fillBuffer: Setting seek flag in fill buffer");
+            }
+        }
+
+        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;
+                }
+            }
+
+            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();
+        } //is size_remaining < range_length impossible?
+
+        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() {
+    uint64_t timestamp = 0;
+    mAudioSink->getTimeStamp(&timestamp);
+    ALOGV("timestamp %lld ", timestamp);
+    return timestamp;
+}
+
+int64_t LPAPlayer::getMediaTimeUs_l() {
+    if (mPaused) {
+        return mPauseTime;
+    } else {
+        return (mSeekTimeUs + getTimeStamp());
+    }
+}
+
+int64_t LPAPlayer::getMediaTimeUs() {
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime);
+    return getMediaTimeUs_l();
+}
+
+bool LPAPlayer::getMediaTimeMapping(
+                                   int64_t *realtime_us, int64_t *mediatime_us) {
+    ALOGE("getMediaTimeMapping is invalid for LPA Player");
+    *realtime_us = -1;
+    *mediatime_us = -1;
+    return false;
+}
+
+bool LPAPlayer::seekTooClose(int64_t time_us) {
+    int64_t t1 = getMediaTimeUs_l();
+    /*
+     * empirical
+     * -----------
+     * This constant signifies how much data (in Us) has been rendered by the
+     * DSP in the interval between the moment flush is issued on AudioSink to
+     * after ioctl(PAUSE) returns in Audio HAL. (flush triggers an implicit
+     * pause in audio HAL)
+     *
+     */
+     const int64_t kDeltaUs = 60000LL; /* 60-70ms on msm8974, must be measured for other targets */
+     t1 += kDeltaUs;
+     return (time_us > t1) && ((time_us - t1) <= LPA_BUFFER_TIME);
+}
+
+//lock taken in reset()
+void LPAPlayer::requestAndWaitForDecoderThreadExit_l() {
+
+    if (!mDecoderThreadAlive)
+        return;
+    mKillDecoderThread = true;
+
+    /* Flush the audio sink to unblock the decoder thread
+       if any write to audio HAL is blocked */
+    if (!mReachedOutputEOS && mIsAudioRouted)
+        mAudioSink->flush();
+
+    mDecoderCv.signal();
+    mLock.unlock();
+    pthread_join(mDecoderThread,NULL);
+    mLock.lock();
+    ALOGD("decoder thread killed");
+
+}
+
+void LPAPlayer::onPauseTimeOut() {
+    ALOGV("onPauseTimeOut");
+    Mutex::Autolock autoLock(mLock);
+    if (!mPauseEventPending) {
+        return;
+    }
+    mPauseEventPending = false;
+    // 1.) Set seek flags
+    mReachedEOS = false;
+    mReachedOutputEOS = false;
+    if(mSeeking == false) {
+        mSeekTimeUs += getTimeStamp();
+        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->flush();
+    mAudioSink->stop();
+    mAudioSink->close();
+    mIsAudioRouted = false;
+}
+
+//dup each mono frame
+void LPAPlayer::convertMonoToStereo(int16_t *data, size_t size)
+{
+    int i =0;
+    int16_t *start_pointer = data;
+    int monoFrameCount = (size) / (sizeof(int16_t));
+
+    for (i = monoFrameCount; i > 0 ; i--) {
+      int16_t temp_sample = *(start_pointer + i - 1);
+      *(start_pointer + (i*2) - 1) = temp_sample;
+      *(start_pointer + (i*2) - 2) = temp_sample;
+    }
+}
+
+} //namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 8cd8830..fcb47d1 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -37,6 +37,10 @@
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
+#ifdef ENABLE_QC_AV_ENHANCEMENTS
+#include <QCMediaDefs.h>
+#include "include/ExtendedUtils.h"
+#endif
 
 namespace android {
 
@@ -186,6 +190,11 @@
       mCachedOffset(0),
       mCachedSize(0),
       mCache(NULL) {
+      #ifdef DOLBY_UDC
+      #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+      ALOGE("@DDP MPEG4DataSource::MPEG4DataSource");
+      #endif
+      #endif //DOLBY_UDC
 }
 
 MPEG4DataSource::~MPEG4DataSource() {
@@ -293,9 +302,16 @@
 }
 
 static const char *FourCC2MIME(uint32_t fourcc) {
+    #ifdef DOLBY_UDC
+    #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+    ALOGE("@DDP FourCC2MIME");
+    #endif
+    #endif //DOLBY_UDC
     switch (fourcc) {
         case FOURCC('m', 'p', '4', 'a'):
             return MEDIA_MIMETYPE_AUDIO_AAC;
+        case FOURCC('.', 'm', 'p', '3'):
+            return MEDIA_MIMETYPE_AUDIO_MPEG;
 
         case FOURCC('s', 'a', 'm', 'r'):
             return MEDIA_MIMETYPE_AUDIO_AMR_NB;
@@ -314,8 +330,29 @@
         case FOURCC('a', 'v', 'c', '1'):
             return MEDIA_MIMETYPE_VIDEO_AVC;
 
+#ifdef ENABLE_QC_AV_ENHANCEMENTS
+        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.");
+            #ifdef DOLBY_UDC
+            #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+            ALOGE("@DDP FourCC2Mime default (not found)");
+            #endif
+            #endif //DOLBY_UDC
             return NULL;
     }
 }
@@ -347,6 +384,11 @@
       mFileMetaData(new MetaData),
       mFirstSINF(NULL),
       mIsDrm(false) {
+      #ifdef DOLBY_UDC
+      #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+      ALOGE("@DDP MPEG4Extractor::MPEG4Extractor");
+      #endif
+      #endif //DOLBY_UDC
 }
 
 MPEG4Extractor::~MPEG4Extractor() {
@@ -1220,8 +1262,17 @@
 
         case FOURCC('m', 'p', '4', 'a'):
         case FOURCC('e', 'n', 'c', 'a'):
+        case FOURCC('.', 'm', 'p', '3'):
         case FOURCC('s', 'a', 'm', 'r'):
         case FOURCC('s', 'a', 'w', 'b'):
+        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'):
         {
             uint8_t buffer[8 + 20];
             if (chunk_data_size < (ssize_t)sizeof(buffer)) {
@@ -1245,13 +1296,23 @@
                 mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
                 AdjustChannelsAndRate(chunk_type, &num_channels, &sample_rate);
             }
+            #ifdef DOLBY_UDC
+            #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+            ALOGE("@DDP FourCC:'%s'", FourCC2MIME(chunk_type));
+            #endif
+            #endif //DOLBY_UDC
             ALOGV("*** coding='%s' %d channels, size %d, rate %d\n",
                    chunk, num_channels, sample_size, sample_rate);
             mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
             mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
 
             off64_t stop_offset = *offset + chunk_size;
+            if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_MPEG, FourCC2MIME(chunk_type)) ||
+                !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, FourCC2MIME(chunk_type))) {
+               *offset = stop_offset;
+            } else {
             *offset = data_offset + sizeof(buffer);
+            }
             while (*offset < stop_offset) {
                 status_t err = parseChunk(offset, depth + 1);
                 if (err != OK) {
@@ -1525,6 +1586,14 @@
             break;
         }
 
+        case FOURCC('d', 'd', 't', 's'):
+        case FOURCC('d', 'a', 'c', '3'):
+        case FOURCC('d', 'e', 'c', '3'):
+        {
+            ALOGV("ddts/dac3/dec3 pass from mpeg4 extractor");
+            *offset += chunk_size;
+            break;
+        }
         case FOURCC('a', 'v', 'c', 'C'):
         {
             sp<ABuffer> buffer = new ABuffer(chunk_data_size);
@@ -2233,18 +2302,24 @@
         return ERROR_MALFORMED;
     }
 
+#ifdef ENABLE_QC_AV_ENHANCEMENTS
+    if (objectTypeIndication == 0xA0) {
+       mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_EVRC);
+       return OK;
+    }
     if (objectTypeIndication == 0xe1) {
         // This isn't MPEG4 audio at all, it's QCELP 14k...
         mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_QCELP);
         return OK;
     }
+#endif
 
-    if (objectTypeIndication  == 0x6b) {
-        // The media subtype is MP3 audio
+    if (objectTypeIndication  == 0x6b
+         || objectTypeIndication  == 0x69) {
         // Our software MP3 audio decoder may not be able to handle
-        // packetized MP3 audio; for now, lets just return ERROR_UNSUPPORTED
-        ALOGE("MP3 track in MP4/3GPP file is not supported");
-        return ERROR_UNSUPPORTED;
+         mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+         ALOGD("objectTypeIndication:0x%x, set mimetype to mpeg ",objectTypeIndication);
+         return OK;
     }
 
     const uint8_t *csd;
@@ -2372,6 +2447,11 @@
       mBuffer(NULL),
       mWantsNALFragments(false),
       mSrcBuffer(NULL) {
+      #ifdef DOLBY_UDC
+      #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+      ALOGE("@DDP MPEG4Source::MPEG4Source");
+      #endif
+      #endif //DOLBY_UDC
 
     mFormat->findInt32(kKeyCryptoMode, &mCryptoMode);
     mDefaultIVSize = 0;
@@ -3150,7 +3230,9 @@
 
                 return ERROR_IO;
             }
-
+#ifdef ENABLE_QC_AV_ENHANCEMENTS
+            ExtendedUtils::helper_mpeg4extractor_checkAC3EAC3(mBuffer, mFormat, size);
+#endif
             CHECK(mBuffer != NULL);
             mBuffer->set_range(0, size);
             mBuffer->meta_data()->clear();
@@ -3582,7 +3664,8 @@
         return false;
     }
 
-    if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
+    if (!memcmp(header, "ftyp3g2a", 8) || !memcmp(header, "ftyp3g2b", 8) || !memcmp(header, "ftyp3g2c", 8)
+        || !memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
         || !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/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 9569fc1..2b1227c 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -40,6 +40,8 @@
 
 #include "include/ESDS.h"
 
+#include "include/ExtendedUtils.h"
+
 namespace android {
 
 static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
@@ -510,10 +512,10 @@
 
     // If the estimation is wrong, we will pay the price of wasting
     // some reserved space. This should not happen so often statistically.
+    int32_t factor = mUse32BitOffset? 1: 2;
     static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024;  // 3 KB
     static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
     int64_t size = MIN_MOOV_BOX_SIZE;
-    int32_t factor = mUse32BitOffset? 1: 2;
 
     // Max file size limit is set
     if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
@@ -2264,6 +2266,10 @@
         meta_data->findInt32(kKeyIsSyncFrame, &isSync);
         CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
 
+        if (!mIsAudio) {
+            ExtendedUtils::HFR::reCalculateTimeStamp(mMeta, timestampUs);
+        }
+
 ////////////////////////////////////////////////////////////////////////////////
         if (mStszTableEntries->count() == 0) {
             mFirstSampleTimeRealUs = systemTime() / 1000;
@@ -2293,10 +2299,12 @@
              */
             int64_t decodingTimeUs;
             CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
+            ExtendedUtils::HFR::reCalculateTimeStamp(mMeta, decodingTimeUs);
+
             decodingTimeUs -= previousPausedDurationUs;
             cttsOffsetTimeUs =
-                    timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
-            CHECK_GE(cttsOffsetTimeUs, 0ll);
+                    timestampUs - decodingTimeUs;
+            CHECK_GE(kMaxCttsOffsetTimeUs, decodingTimeUs - timestampUs);
             timestampUs = decodingTimeUs;
             ALOGV("decoding time: %lld and ctts offset time: %lld",
                 timestampUs, cttsOffsetTimeUs);
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
old mode 100644
new mode 100755
index e0686be..5a1d341
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -35,6 +35,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/ExtendedCodec.h>
 #include <media/stagefright/NativeWindowWrapper.h>
 
 #include "include/avc_utils.h"
@@ -1415,6 +1416,19 @@
         ++i;
     }
 
+    sp<ABuffer> extendedCSD = ExtendedCodec::getRawCodecSpecificData(format);
+    if (extendedCSD != NULL) {
+        ALOGV("pushing extended CSD of size %d", extendedCSD->size());
+        mCSD.push_back(extendedCSD);
+    }
+
+    sp<ABuffer> aacCSD = ExtendedCodec::getAacCodecSpecificData(format);
+    if (aacCSD != NULL) {
+        ALOGV("pushing AAC CSD of size %d", aacCSD->size());
+        mCSD.push_back(aacCSD);
+    }
+
+
     ALOGV("Found %u pieces of codec specific data.", mCSD.size());
 }
 
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 6248e90..b8499f9 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -27,6 +27,7 @@
 #include <utils/threads.h>
 
 #include <libexpat/expat.h>
+#include "include/ExtendedUtils.h"
 
 namespace android {
 
@@ -62,8 +63,15 @@
 
         addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm");
 
+
         addMediaCodec(
-                false /* encoder */, "OMX.google.raw.decoder", "audio/raw");
+                     false /* encoder */, "OMX.google.raw.decoder", "audio/raw");
+
+        Vector<AString> QcomAACQuirks;
+        QcomAACQuirks.push(AString("requires-allocate-on-input-ports"));
+        QcomAACQuirks.push(AString("requires-allocate-on-output-ports"));
+        ExtendedUtils::helper_addMediaCodec(mCodecInfos, mTypes, false, "OMX.qcom.audio.decoder.multiaac",
+            "audio/mp4a-latm", ExtendedUtils::helper_getCodecSpecificQuirks(mCodecQuirks, QcomAACQuirks));
     }
 
 #if 0
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
old mode 100644
new mode 100755
index 9ab6611..7c66429
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -39,6 +39,8 @@
 #include <media/stagefright/MetaData.h>
 #include <utils/String8.h>
 
+#include "include/ExtendedUtils.h"
+
 namespace android {
 
 sp<MetaData> MediaExtractor::getMetaData() {
@@ -126,7 +128,7 @@
        }
     }
 
-    return ret;
+    return ExtendedUtils::MediaExtractor_CreateIfNeeded(ret, source, mime);
 }
 
 }  // namespace android
diff --git a/media/libstagefright/NOTICE b/media/libstagefright/NOTICE
index c5b1efa..1c3f344 100644
--- a/media/libstagefright/NOTICE
+++ b/media/libstagefright/NOTICE
@@ -188,3 +188,31 @@
 
    END OF TERMS AND CONDITIONS
 
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+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.
+
+
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 9aa77fc..fd20b6b 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1,5 +1,8 @@
 /*
  * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2010 - 2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +22,7 @@
 #include <utils/Log.h>
 
 #include "include/AACEncoder.h"
+#include "include/MP3Decoder.h"
 
 #include "include/ESDS.h"
 
@@ -41,9 +45,17 @@
 
 #include <OMX_Audio.h>
 #include <OMX_Component.h>
-
+#include <media/stagefright/ExtendedCodec.h>
+#include "include/ExtendedUtils.h"
 #include "include/avc_utils.h"
 
+#ifdef ENABLE_AV_ENHANCEMENTS
+#include <QCMediaDefs.h>
+#include <QCMetaData.h>
+#include <QOMX_AudioExtensions.h>
+#endif
+#include "include/ExtendedUtils.h"
+
 #ifdef USE_SAMSUNG_COLORFORMAT
 #include <sec_format.h>
 #endif
@@ -87,6 +99,11 @@
 // component in question is buggy or not.
 const static uint32_t kMaxColorFormatSupported = 1000;
 
+#define FACTORY_CREATE(name) \
+static sp<MediaSource> Make##name(const sp<MediaSource> &source) { \
+    return new name(source); \
+}
+
 #define FACTORY_CREATE_ENCODER(name) \
 static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaData> &meta) { \
     return new name(source, meta); \
@@ -94,6 +111,7 @@
 
 #define FACTORY_REF(name) { #name, Make##name },
 
+FACTORY_CREATE(MP3Decoder)
 FACTORY_CREATE_ENCODER(AACEncoder)
 
 static sp<MediaSource> InstantiateSoftwareEncoder(
@@ -117,8 +135,26 @@
     return NULL;
 }
 
+static sp<MediaSource> InstantiateSoftwareDecoder(
+        const char *name, const sp<MediaSource> &source) {
+    struct FactoryInfo {
+        const char *name;
+        sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &);
+    };
+    static const FactoryInfo kFactoryInfo[] = {
+        FACTORY_REF(MP3Decoder)
+    };
+    for (size_t i = 0;
+         i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
+        if (!strcmp(name, kFactoryInfo[i].name)) {
+            return (*kFactoryInfo[i].CreateFunc)(source);
+        }
+    }
+    return NULL;
+}
 #undef FACTORY_CREATE_ENCODER
 #undef FACTORY_REF
+#undef FACTORY_CREATE
 
 #define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
 #define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
@@ -163,7 +199,13 @@
 }
 
 static bool IsSoftwareCodec(const char *componentName) {
-    if (!strncmp("OMX.google.", componentName, 11)) {
+#ifdef DOLBY_UDC
+    if (!strncmp("OMX.dolby.", componentName, 10)) {
+        return true;
+    }
+#endif // DOLBY_UDC
+    if (!strncmp("OMX.google.", componentName, 11)
+        || !strncmp("OMX.PV.", componentName, 7)) {
         return true;
     }
 
@@ -223,19 +265,15 @@
 
     size_t index = 0;
 
-#ifdef ENABLE_QC_AV_ENHANCEMENTS
-    //Check if application specially reuqested for  aac hardware encoder
-    //This is not a part of  mediacodec list
+#ifdef ENABLE_AV_ENHANCEMENTS
     if (matchComponentName && !strcmp("OMX.qcom.audio.encoder.aac", matchComponentName)) {
         matchingCodecs->add();
-
         CodecNameAndQuirks *entry = &matchingCodecs->editItemAt(index);
         entry->mName = String8("OMX.qcom.audio.encoder.aac");
         entry->mQuirks = 0;
         return;
     }
 #endif
-
     for (;;) {
         ssize_t matchIndex =
             list->findCodecByType(mime, createEncoder, index);
@@ -249,6 +287,7 @@
         const char *componentName = list->getCodecName(matchIndex);
 
         // If a specific codec is requested, skip the non-matching ones.
+        ALOGV("matchComponentName %s ",matchComponentName);
         if (matchComponentName && strcmp(componentName, matchComponentName)) {
             continue;
         }
@@ -313,6 +352,28 @@
                 index, "output-buffers-are-unreadable")) {
         quirks |= kOutputBuffersAreUnreadable;
     }
+    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, "defers-output-buffer-allocation")) {
+        quirks |= kDefersOutputBufferAllocation;
+    }
+#ifdef DOLBY_UDC
+    if (list->codecHasQuirk(
+                index, "needs-flush-before-disable")) {
+        quirks |= kNeedsFlushBeforeDisable;
+    }
+    if (list->codecHasQuirk(
+                index, "requires-flush-complete-emulation")) {
+        quirks |= kRequiresFlushCompleteEmulation;
+    }
+#endif // DOLBY_UDC
 #ifdef OMAP_ENHANCEMENT
     if (list->codecHasQuirk(
                 index, "avoid-memcopy-input-recording-frames")) {
@@ -324,6 +385,8 @@
     }
 #endif
 
+    quirks |= ExtendedCodec::getComponentQuirks(list,index);
+
     return quirks;
 }
 
@@ -334,9 +397,7 @@
     if (list == NULL) {
         return false;
     }
-#ifdef ENABLE_QC_AV_ENHANCEMENTS
-    //Check for aac hardware encoder
-    //This is not a part of  mediacodec list
+#ifdef ENABLE_AV_ENHANCEMENTS
     if (componentName && !strcmp("OMX.qcom.audio.encoder.aac", componentName)) {
         *quirks = 0;
         return true;
@@ -376,8 +437,14 @@
     CHECK(success);
 
     Vector<CodecNameAndQuirks> matchingCodecs;
-    findMatchingCodecs(
+
+    if (ExtendedCodec::useHWAACDecoder(mime)) {
+        findMatchingCodecs(mime, createEncoder,
+            "OMX.qcom.audio.decoder.multiaac", flags, &matchingCodecs);
+    } else {
+        findMatchingCodecs(
             mime, createEncoder, matchComponentName, flags, &matchingCodecs);
+    }
 
     if (matchingCodecs.isEmpty()) {
         ALOGV("No matching codecs! (mime: %s, createEncoder: %s, "
@@ -402,15 +469,21 @@
             componentName = tmp.c_str();
         }
 
+        sp<MediaSource> softwareCodec;
         if (createEncoder) {
-            sp<MediaSource> softwareCodec =
-                InstantiateSoftwareEncoder(componentName, source, meta);
-
+            softwareCodec = InstantiateSoftwareEncoder(componentName, source, meta);
+        } else {
+            softwareCodec = InstantiateSoftwareDecoder(componentName, source);
+        }
             if (softwareCodec != NULL) {
                 ALOGV("Successfully allocated software codec '%s'", componentName);
 
                 return softwareCodec;
             }
+
+        const char* ext_componentName = ExtendedCodec::overrideComponentName(quirks, meta);
+        if(ext_componentName != NULL) {
+          componentName = ext_componentName;
         }
 
         ALOGV("Attempting to allocate OMX node '%s'", componentName);
@@ -554,8 +627,14 @@
             esds.getCodecSpecificInfo(
                     &codec_specific_data, &codec_specific_data_size);
 
+            const char * mime_type;
+            meta->findCString(kKeyMIMEType, &mime_type);
+            if (strncmp(mime_type,
+                        MEDIA_MIMETYPE_AUDIO_MPEG,
+                        strlen(MEDIA_MIMETYPE_AUDIO_MPEG))) {
             addCodecSpecificData(
                     codec_specific_data, codec_specific_data_size);
+            }
         } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
             // Parse the AVCDecoderConfigurationRecord
 
@@ -567,6 +646,8 @@
                 return err;
             }
 
+            ExtendedUtils::setArbitraryModeIfInterlaced((const uint8_t *)data, meta);
+
             CODEC_LOGI(
                     "AVC profile = %u (%s), level = %u",
                     profile, AVCProfileToString(profile), level);
@@ -575,6 +656,16 @@
 
             CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
             addCodecSpecificData(data, size);
+#ifdef ENABLE_AV_ENHANCEMENTS
+        } else if (meta->findData(kKeyRawCodecSpecificData, &type, &data, &size)) {
+            ALOGV("OMXCodec::configureCodec found kKeyRawCodecSpecificData of size %d\n", size);
+            addCodecSpecificData(data, size);
+#endif
+        } else {
+            ExtendedCodec::getRawCodecSpecificData(meta, data, size);
+            if (size) {
+                addCodecSpecificData(data, size);
+            }
         }
     }
 
@@ -605,6 +696,15 @@
             CODEC_LOGE("setAACFormat() failed (err = %d)", err);
             return err;
         }
+#ifdef ENABLE_AV_ENHANCEMENTS
+        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);
+        }
+#endif
     } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_MPEG, mMIME)) {
         int32_t numChannels, sampleRate;
         if (meta->findInt32(kKeyChannelCount, &numChannels)
@@ -633,6 +733,18 @@
         CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
 
         setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+    } else {
+        if (mIsEncoder && !mIsVideo) {
+            int32_t numChannels, sampleRate;
+            CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+            CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+            setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+        }
+        status_t err = ExtendedCodec::setAudioFormat(
+                meta, mMIME, mOMX, mNode, mIsEncoder);
+        if(OK != err) {
+            return err;
+        }
     }
 
     if (!strncasecmp(mMIME, "video/", 6)) {
@@ -649,6 +761,13 @@
             if (err != OK) {
                 return err;
             }
+
+            ExtendedCodec::configureVideoDecoder(
+                    meta, mMIME, mOMX, mFlags, mNode, mComponentName);
+            ExtendedCodec::configureFramePackingFormat(
+                    meta, mOMX, mNode, mComponentName);
+            ExtendedCodec::enableSmoothStreaming(
+                    mOMX, mNode, &mInSmoothStreamingMode, mComponentName);
         }
     }
 
@@ -915,6 +1034,8 @@
     CHECK(success);
     CHECK(stride != 0);
 
+    ExtendedUtils::HFR::reCalculateHFRParams(meta, frameRate, bitRate);
+
     OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
     if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
         compressionFormat = OMX_VIDEO_CodingAVC;
@@ -923,9 +1044,12 @@
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
         compressionFormat = OMX_VIDEO_CodingH263;
     } else {
+        status_t err = ExtendedCodec::setVideoInputFormat(mime, &compressionFormat);
+        if(err != OK) {
         ALOGE("Not a supported video mime type: %s", mime);
         CHECK(!"Should not be here. Not a supported video mime type.");
     }
+    }
 
     OMX_COLOR_FORMATTYPE colorFormat;
     CHECK_EQ((status_t)OK, findTargetColorFormat(meta, &colorFormat));
@@ -1168,6 +1292,8 @@
     h263type.nAllowedPictureTypes =
         OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
 
+    ExtendedUtils::HFR::reCalculateHFRParams(meta, frameRate, bitRate);
+
     h263type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
     if (h263type.nPFrames == 0) {
         h263type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
@@ -1219,6 +1345,8 @@
     mpeg4type.nAllowedPictureTypes =
         OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
 
+    ExtendedUtils::HFR::reCalculateHFRParams(meta, frameRate, bitRate);
+
     mpeg4type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
     if (mpeg4type.nPFrames == 0) {
         mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
@@ -1240,6 +1368,7 @@
     mpeg4type.eProfile = static_cast<OMX_VIDEO_MPEG4PROFILETYPE>(profileLevel.mProfile);
     mpeg4type.eLevel = static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(profileLevel.mLevel);
 
+    ExtendedUtils::setBFrames(mpeg4type, mNumBFrames, mComponentName);
     err = mOMX->setParameter(
             mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
     CHECK_EQ(err, (status_t)OK);
@@ -1277,12 +1406,16 @@
     h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profileLevel.mProfile);
     h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(profileLevel.mLevel);
 
+    ExtendedUtils::HFR::reCalculateHFRParams(meta, frameRate, bitRate);
+
     // XXX
 #ifdef USE_TI_DUCATI_H264_PROFILE
     if ((strncmp(mComponentName, "OMX.TI.DUCATI1", 14) != 0)
             && (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline)) {
 #else
-    if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) {
+    if (ExtendedUtils::isAVCProfileSupported(h264type.eProfile)){
+        ALOGI("Profile type is  %d ",h264type.eProfile);
+    } else if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) {
 #endif
         ALOGW("Use baseline profile instead of %d for AVC recording",
             h264type.eProfile);
@@ -1308,6 +1441,8 @@
         h264type.nCabacInitIdc = 0;
     }
 
+    ExtendedUtils::setBFrames(
+            h264type, mNumBFrames, iFramesInterval, frameRate, mComponentName);
     if (h264type.nBFrames != 0) {
         h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
     }
@@ -1353,9 +1488,13 @@
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) {
         compressionFormat = OMX_VIDEO_CodingMPEG2;
     } else {
+        status_t err = ExtendedCodec::setVideoOutputFormat(mime,&compressionFormat);
+
+        if(err != OK) {
         ALOGE("Not a supported video mime type: %s", mime);
         CHECK(!"Should not be here. Not a supported video mime type.");
     }
+    }
 
     status_t err = setVideoPortFormatType(
             kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
@@ -1515,6 +1654,7 @@
       mState(LOADED),
       mInitialBufferSubmit(true),
       mSignalledEOS(false),
+      mFinalStatus(OK),
       mNoMoreOutputData(false),
       mOutputPortSettingsHaveChanged(false),
       mSeekTimeUs(-1),
@@ -1527,7 +1667,9 @@
       mNativeWindow(
               (!strncmp(componentName, "OMX.google.", 11)
               || !strcmp(componentName, "OMX.Nvidia.mpeg2v.decode"))
-                        ? NULL : nativeWindow) {
+                        ? NULL : nativeWindow),
+      mNumBFrames(0),
+      mInSmoothStreamingMode(false) {
     mPortStatus[kPortIndexInput] = ENABLED;
     mPortStatus[kPortIndexOutput] = ENABLED;
 
@@ -1555,6 +1697,10 @@
             "audio_decoder.amrnb", "audio_encoder.amrnb" },
         { MEDIA_MIMETYPE_AUDIO_AMR_WB,
             "audio_decoder.amrwb", "audio_encoder.amrwb" },
+#ifdef ENABLE_AV_ENHANCEMENTS
+        { MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
+            "audio_decoder.amrwbplus", "audio_encoder.amrwbplus" },
+#endif
         { MEDIA_MIMETYPE_AUDIO_AAC,
             "audio_decoder.aac", "audio_encoder.aac" },
         { MEDIA_MIMETYPE_AUDIO_VORBIS,
@@ -1563,6 +1709,12 @@
             "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" },
         { MEDIA_MIMETYPE_AUDIO_G711_ALAW,
             "audio_decoder.g711alaw", "audio_encoder.g711alaw" },
+#ifdef ENABLE_AV_ENHANCEMENTS
+        { 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,
@@ -1579,6 +1731,16 @@
             "audio_decoder.flac", "audio_encoder.flac" },
         { MEDIA_MIMETYPE_AUDIO_MSGSM,
             "audio_decoder.gsm", "audio_encoder.gsm" },
+#ifdef ENABLE_AV_ENHANCEMENTS
+        { 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 =
@@ -1592,6 +1754,7 @@
     }
 
     if (i == kNumMimeToRole) {
+        ExtendedCodec::setSupportedRole(omx, node, isEncoder, mime);
         return;
     }
 
@@ -1678,6 +1841,8 @@
     return state == LOADED_TO_IDLE
         || state == IDLE_TO_EXECUTING
         || state == EXECUTING_TO_IDLE
+        || state == PAUSING
+        || state == FLUSHING
         || state == IDLE_TO_LOADED
         || state == RECONFIGURING;
 }
@@ -2011,6 +2176,13 @@
         return err;
     }
 
+    err = mNativeWindow.get()->perform(mNativeWindow.get(),
+                             NATIVE_WINDOW_SET_BUFFERS_SIZE, def.nBufferSize);
+    if (err != 0) {
+        ALOGE("native_window_set_buffers_size failed: %s (%d)", strerror(-err),
+                -err);
+        return err;
+    }
     CODEC_LOGV("allocating %lu buffers from a native window of size %lu on "
             "output port", def.nBufferCountActual, def.nBufferSize);
 
@@ -2771,11 +2943,18 @@
 
             CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
 
+            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 {
             CHECK_EQ((int)mPortStatus[portIndex], (int)SHUTTING_DOWN);
             mPortStatus[portIndex] = ENABLED;
 
             CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
                      mPortBuffers[portIndex].size());
+            }
 
             if (mSkipCutBuffer != NULL && mPortStatus[kPortIndexOutput] == ENABLED) {
                 mSkipCutBuffer->clear();
@@ -2882,13 +3061,29 @@
                 mPortStatus[kPortIndexInput] = ENABLED;
                 mPortStatus[kPortIndexOutput] = ENABLED;
 
-                if ((mFlags & kEnableGrallocUsageProtected) &&
-                        mNativeWindow != NULL) {
-                    // We push enough 1x1 blank buffers to ensure that one of
-                    // them has made it to the display.  This allows the OMX
-                    // component teardown to zero out any protected buffers
-                    // without the risk of scanning out one of those buffers.
-                    pushBlankBuffersToNativeWindow();
+                if (mNativeWindow != NULL) {
+                    /*
+                     * reset buffer size field with SurfaceTexture
+                     * back to 0. This will ensure proper size
+                     * buffers are allocated if the same SurfaceTexture
+                     * is re-used in a different decode session
+                     */
+                    int err =
+                        mNativeWindow.get()->perform(mNativeWindow.get(),
+                                                     NATIVE_WINDOW_SET_BUFFERS_SIZE,
+                                                     0);
+                    if (err != 0) {
+                        ALOGE("set_buffers_size failed: %s (%d)", strerror(-err),
+                             -err);
+                    }
+
+                    if (mFlags & kEnableGrallocUsageProtected) {
+                        // We push enough 1x1 blank buffers to ensure that one of
+                        // them has made it to the display.  This allows the OMX
+                        // component teardown to zero out any protected buffers
+                        // without the risk of scanning out one of those buffers.
+                        pushBlankBuffersToNativeWindow();
+                    }
                 }
 
                 setState(IDLE_TO_LOADED);
@@ -2924,6 +3119,14 @@
             break;
         }
 
+        case OMX_StatePause:
+        {
+            CODEC_LOGV("Now paused.");
+            CHECK_EQ((int)mState, (int)PAUSING);
+            setState(PAUSED);
+            break;
+        }
+
         case OMX_StateInvalid:
         {
             setState(ERROR);
@@ -3038,8 +3241,12 @@
 
 bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
     CHECK(mState == EXECUTING || mState == RECONFIGURING
-            || mState == EXECUTING_TO_IDLE);
+            || mState == EXECUTING_TO_IDLE || mState == FLUSHING);
 
+    if (portIndex == (OMX_U32) -1 ) {
+        mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
+        mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
+    } else {
     CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
          portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
          mPortBuffers[portIndex].size());
@@ -3054,6 +3261,7 @@
         // flush-complete event in this case.
 
         return false;
+        }
     }
 
     status_t err =
@@ -3088,13 +3296,20 @@
 }
 
 void OMXCodec::fillOutputBuffers() {
-    CHECK_EQ((int)mState, (int)EXECUTING);
+    CHECK(mState == EXECUTING || mState == FLUSHING);
 
     // This is a workaround for some decoders not properly reporting
     // 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
+
+    // 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(!ExtendedUtils::checkIsThumbNailMode(mFlags, mComponentName)) {
+        if (mSignalledEOS
             && countBuffersWeOwn(mPortBuffers[kPortIndexInput])
                 == mPortBuffers[kPortIndexInput].size()
             && countBuffersWeOwn(mPortBuffers[kPortIndexOutput])
@@ -3102,7 +3317,8 @@
         mNoMoreOutputData = true;
         mBufferFilled.signal();
 
-        return;
+            return;
+        }
     }
 
     Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
@@ -3115,7 +3331,7 @@
 }
 
 void OMXCodec::drainInputBuffers() {
-    CHECK(mState == EXECUTING || mState == RECONFIGURING);
+    CHECK(mState == EXECUTING || mState == RECONFIGURING || mState == FLUSHING);
 
     if (mFlags & kUseSecureInputBuffers) {
         Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
@@ -3138,7 +3354,8 @@
                 break;
             }
 
-            if (mFlags & kOnlySubmitOneInputBufferAtOneTime) {
+            if ((mFlags & kOnlySubmitOneInputBufferAtOneTime)
+                    && (i == mNumBFrames)) {
                 break;
             }
         }
@@ -3241,6 +3458,8 @@
 
     size_t offset = 0;
     int32_t n = 0;
+    int32_t InterlaceFormatDetected = false;
+    int32_t InterlaceFrameCount = 0;
 
 
     for (;;) {
@@ -3288,6 +3507,9 @@
             break;
         }
 
+        sp<MetaData> metaData = mSource->getFormat();
+        InterlaceFormatDetected = ExtendedUtils::checkIsInterlace(metaData);
+
         if (mFlags & kUseSecureInputBuffers) {
             info = findInputBufferByDataPointer(srcBuffer->data());
             CHECK(info != NULL);
@@ -3446,8 +3668,25 @@
 
     OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
 
+    if(InterlaceFormatDetected) {
+        InterlaceFrameCount++;
+    }
+
     if (signalEOS) {
         flags |= OMX_BUFFERFLAG_EOS;
+    } else if(ExtendedUtils::checkIsThumbNailMode(mFlags, mComponentName)
+                   && (!InterlaceFormatDetected || InterlaceFrameCount>= 2)) {
+        // 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;
     } else {
         mNoMoreOutputData = false;
     }
@@ -3554,6 +3793,9 @@
         return mBufferFilled.wait(mLock);
     }
     status_t err = mBufferFilled.waitRelative(mLock, kBufferFilledEventTimeOutNs);
+    if ((err == -ETIMEDOUT) && (mPaused == true)){
+        err = OK;
+    }
     if (err != OK) {
         CODEC_LOGE("Timed out waiting for output buffers: %d/%d",
             countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
@@ -3569,6 +3811,7 @@
     OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
     def.nPortIndex = portIndex;
+    def.format.audio.cMIMEType = NULL;
     status_t err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, (status_t)OK);
@@ -3901,6 +4144,27 @@
 status_t OMXCodec::start(MetaData *meta) {
     Mutex::Autolock autoLock(mLock);
 
+    if (mPaused) {
+        if (!strncmp(mComponentName, "OMX.qcom.", 9)) {
+            while (isIntermediateState(mState)) {
+                mAsyncCompletion.wait(mLock);
+            }
+            CHECK_EQ(mState, (status_t)PAUSED);
+            status_t err = mOMX->sendCommand(mNode,OMX_CommandStateSet, OMX_StateExecuting);
+            CHECK_EQ(err, (status_t)OK);
+            setState(IDLE_TO_EXECUTING);
+            mPaused = false;
+            while (mState != EXECUTING && mState != ERROR) {
+                mAsyncCompletion.wait(mLock);
+            }
+            drainInputBuffers();
+            return mState == ERROR ? UNKNOWN_ERROR : OK;
+        } else {   // SW Codec
+            mPaused = false;
+            return OK;
+        }
+    }
+
     if (mState != LOADED) {
         CODEC_LOGE("called start in the unexpected state: %d", mState);
         return UNKNOWN_ERROR;
@@ -4011,6 +4275,7 @@
             isError = true;
         }
 
+        case PAUSED:
         case EXECUTING:
         {
             setState(EXECUTING_TO_IDLE);
@@ -4019,6 +4284,14 @@
                 CODEC_LOGV("This component requires a flush before transitioning "
                      "from EXECUTING to IDLE...");
 
+                //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 {
                 bool emulateInputFlushCompletion =
                     !flushPortAsync(kPortIndexInput);
 
@@ -4031,6 +4304,7 @@
 
                 if (emulateOutputFlushCompletion) {
                     onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
+                    }
                 }
             } else {
                 mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
@@ -4138,7 +4412,22 @@
         mFilledBuffers.clear();
 
         CHECK_EQ((int)mState, (int)EXECUTING);
+        setState(FLUSHING);
 
+        if(mQuirks & kRequiresGlobalFlush) {
+            bool emulateFlushCompletion = !flushPortAsync(kPortIndexBoth);
+            if (emulateFlushCompletion) {
+                onCmdComplete(OMX_CommandFlush, kPortIndexBoth);
+            }
+        } else {
+        //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 {
         bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
         bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
 
@@ -4149,6 +4438,8 @@
         if (emulateOutputFlushCompletion) {
             onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
         }
+            }
+        }
 
         while (mSeekTimeUs >= 0) {
             if ((err = waitForBufferFilled_l()) != OK) {
@@ -4159,6 +4450,13 @@
 
     while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
         if ((err = waitForBufferFilled_l()) != OK) {
+            if ((err == -ETIMEDOUT) && (mPaused == true) && !mIsVideo) {
+                // 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.
+                ALOGV("returned OK instead of timedout from read() as mPaused is true");
+                err = OK;
+            }
             return err;
         }
     }
@@ -4167,6 +4465,11 @@
         return UNKNOWN_ERROR;
     }
 
+    if (seeking) {
+        CHECK_EQ((int)mState, (int)FLUSHING);
+        setState(EXECUTING);
+    }
+
     if (mFilledBuffers.empty()) {
         return mSignalledEOS ? mFinalStatus : ERROR_END_OF_STREAM;
     }
@@ -4390,6 +4693,9 @@
         "OMX_AUDIO_CodingWMA",
         "OMX_AUDIO_CodingRA",
         "OMX_AUDIO_CodingMIDI",
+#ifdef DOLBY_UDC
+        "OMX_AUDIO_CodingDDP",
+#endif // DOLBY_UDC
     };
 
     size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
@@ -4727,7 +5033,21 @@
                 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
                 mOutputFormat->setInt32(kKeyBitRate, bitRate);
             } else {
+                AString mimeType;
+                if (OK == ExtendedCodec::handleSupportedAudioFormats(
+                        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);
+                } else {
                 CHECK(!"Should not be here. Unknown audio encoding.");
+                }
             }
             break;
         }
@@ -4796,8 +5116,15 @@
                 }
 
                 if (mNativeWindow != NULL) {
-                     initNativeWindowCrop();
+                    if (mInSmoothStreamingMode) {
+                        ExtendedUtils::updateNativeWindowBufferGeometry(
+                                mNativeWindow.get(), video_def->nFrameWidth,
+                                video_def->nFrameHeight, video_def->eColorFormat);
+                    }
+                    initNativeWindowCrop();
                 }
+            } else {
+                ExtendedUtils::HFR::copyHFRParams(inputFormat, mOutputFormat);
             }
             break;
         }
@@ -4819,11 +5146,29 @@
 }
 
 status_t OMXCodec::pause() {
+    CODEC_LOGV("pause mState=%d", mState);
+
     Mutex::Autolock autoLock(mLock);
-
-    mPaused = true;
-
-    return OK;
+    if (mState != EXECUTING) {
+        return UNKNOWN_ERROR;
+    }
+    while (isIntermediateState(mState)) {
+        mAsyncCompletion.wait(mLock);
+    }
+    if (!strncmp(mComponentName, "OMX.qcom.", 9)) {
+        status_t err = mOMX->sendCommand(mNode,
+            OMX_CommandStateSet, OMX_StatePause);
+        CHECK_EQ(err, (status_t)OK);
+        setState(PAUSING);
+        mPaused = true;
+        while (mState != PAUSED && mState != ERROR) {
+            mAsyncCompletion.wait(mLock);
+        }
+        return mState == ERROR ? UNKNOWN_ERROR : OK;
+    } else {
+        mPaused = true;
+        return OK;
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 3981290..9d86a0f 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -360,8 +360,9 @@
         return ERROR_IO;
     }
 
-    if (U32_AT(header) != 0) {
-        // Expected version = 0, flags = 0.
+    if (U32_AT(header) != 0 &&
+        U32_AT(header) != 0x01000000) {
+        // Expected version = 0/1, flags = 0.
         return ERROR_MALFORMED;
     }
 
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index af8186c..98ba1a4 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -43,6 +43,9 @@
         ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
         ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
         ".avi", ".mpeg", ".mpg", ".awb", ".mpga"
+#ifdef ENABLE_AV_ENHANCEMENTS
+        ,".qcp", ".ac3", ".dts", ".wmv", ".ec3"
+#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..9aacbb6
--- /dev/null
+++ b/media/libstagefright/TunnelPlayer.cpp
@@ -0,0 +1,798 @@
+/*
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ * Copyright (C) 2009 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_NDEBUG 0
+//#define LOG_NDDEBUG 0
+#define LOG_TAG "TunnelPlayer"
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <signal.h>
+#include <sys/prctl.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 "include/AwesomePlayer.h"
+#include <cutils/properties.h>
+
+static const char   mName[] = "TunnelPlayer";
+#define MEM_METADATA_SIZE 64
+/*
+ * We need to reserve some space in the
+ * ion buffer (used in HAL) to save the
+ * metadata. so read from the extractor
+ * a somewhat smaller number of bytes.
+ * ideally this number should be bufer_size - sizeof(struct output_metadata_t)
+ */
+#define MEM_BUFFER_SIZE (240*1024 - MEM_METADATA_SIZE)
+#define MEM_BUFFER_COUNT 4
+#define TUNNEL_BUFFER_TIME 1500000
+
+namespace android {
+int TunnelPlayer::mTunnelObjectsAlive = 0;
+
+TunnelPlayer::TunnelPlayer(
+                    const sp<MediaPlayerBase::AudioSink> &audioSink, bool &initCheck,
+                    AwesomePlayer *observer, bool hasVideo)
+:AudioPlayer(audioSink, 0, observer),
+mPositionTimeMediaUs(-1),
+mPositionTimeRealUs(-1),
+mInternalSeeking(false),
+mStarted(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;
+    mFormat = AUDIO_FORMAT_MP3;
+    mQueue.start();
+    mQueueStarted      = true;
+    mPauseEvent        = new TunnelEvent(this, &TunnelPlayer::onPauseTimeOut);
+    mPauseEventPending = false;
+
+    mSeekTimeUs = 0;
+    mIsAudioRouted = false;
+    mExtractorThreadAlive = false;
+
+    mHasVideo = hasVideo;
+    initCheck = true;
+
+}
+const int TunnelPlayer::getTunnelObjectsAliveMax() {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("tunnel.multiple", value, "0");
+    if (strcmp("true",value) == 0) {
+        return 4;
+    }
+    return 1;
+}
+
+TunnelPlayer::~TunnelPlayer() {
+    ALOGD("TunnelPlayer::~TunnelPlayer()");
+    if (mQueueStarted) {
+        mQueue.stop();
+    }
+
+    reset();
+    mTunnelObjectsAlive--;
+
+}
+
+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);
+
+    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 extractor thread, read and initialize all the
+    //mutexes and coditional variables
+    createThreads();
+    ALOGV("Thread 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;
+    }
+    else if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_MPEG)) {
+        mFormat = AUDIO_FORMAT_MP3;
+        ALOGD("TunnelPlayer::start AUDIO_FORMAT_MP3");
+    } else {
+        ALOGE("TunnelPlayer::UNSUPPORTED");
+    }
+
+
+    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,
+        flags,
+        NULL);
+
+    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();
+    mLock.lock();
+    ALOGV("Waking up extractor thread");
+    mExtractorCv.signal();
+    mLock.unlock();
+    return OK;
+}
+
+status_t TunnelPlayer::seekTo(int64_t time_us) {
+
+    ALOGD("seekTo: time_us %lld", time_us);
+
+    Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
+
+    if (seekTooClose(time_us)) {
+      ALOGV("seek time is too close to current playback position");
+      mLock.unlock(); //unlock and post
+      mObserver->postAudioSeekComplete();
+      mLock.lock();
+      return OK;
+    }
+
+    mSeeking = true;
+    mSeekTimeUs = time_us;
+    mPauseTime = mSeekTimeUs;
+    ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);
+
+    if (mIsAudioRouted) {
+        mAudioSink->flush();
+    }
+
+    if (mReachedEOS) {
+        mReachedEOS = false;
+        mReachedOutputEOS = false;
+        if(mPaused == false) {
+            ALOGV("Going to signal extractor thread since playback is already going on ");
+            mExtractorCv.signal();
+            ALOGV("Signalled extractor thread.");
+        }
+    }
+    ALOGV("seek done.");
+    return OK;
+}
+void TunnelPlayer::pause(bool playPendingSamples) {
+    CHECK(mStarted);
+    if (mPaused) {
+        return;
+    }
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("pause: playPendingSamples %d", playPendingSamples);
+    mPaused = true;
+    int64_t playedTime = 0;
+    if(!mPauseEventPending) {
+        ALOGV("Posting an event for Pause timeout");
+        mQueue.postEventWithDelay(mPauseEvent, TUNNEL_PAUSE_TIMEOUT_USEC);
+        mPauseEventPending = true;
+    }
+    getPlayedTimeFromDSP_l(&playedTime);
+    mPauseTime = mSeekTimeUs + playedTime;
+    if (mAudioSink.get() != NULL) {
+        ALOGV("AudioSink pause");
+        mAudioSink->pause();
+    }
+}
+
+status_t TunnelPlayer::resume() {
+    status_t err = NO_ERROR;
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("resume: mPaused %d",mPaused);
+    if ( mPaused) {
+        CHECK(mStarted);
+        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);
+            err = mAudioSink->open(
+                mSampleRate, numChannels, mChannelMask, mFormat,
+                DEFAULT_AUDIOSINK_BUFFERCOUNT,
+                &TunnelPlayer::AudioSinkCallback,
+                this,
+                flags,
+                NULL);
+            if (err != NO_ERROR) {
+                ALOGE("Audio sink open failed.");
+            }
+            mIsAudioRouted = true;
+        }
+        mPaused = false;
+        ALOGV("Audio sink open succeeded.");
+        mAudioSink->start();
+        ALOGV("Audio sink start succeeded.");
+        mExtractorCv.signal();
+        ALOGV("Audio signalling extractor thread.");
+    }
+    return err;
+}
+
+//static
+size_t TunnelPlayer::AudioSinkCallback(
+        MediaPlayerBase::AudioSink *audioSink,
+        void *buffer, size_t size, void *cookie,
+        MediaPlayerBase::AudioSink::cb_event_t event) {
+    TunnelPlayer *me = (TunnelPlayer *)cookie;
+    if(me != NULL) {
+        ALOGV("postAudioEOS mSeeking %d", me->mSeeking);
+        if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
+            if(me->mReachedEOS == true) {
+                //in the case of seek all these flags will be reset
+                me->mReachedOutputEOS = true;
+                ALOGV("postAudioEOS mSeeking %d", me->mSeeking);
+                me->mObserver->postAudioEOS(0);
+            }else {
+                ALOGV("postAudioEOS ignored since %d", me->mSeeking);
+            }
+        } else if (size == AudioTrack::EVENT_HW_FAIL) {
+            ALOGV("postAudioEOS in SSR " );
+            me->mReachedOutputEOS = true;
+            me->mReachedEOS = true;
+            me->mKillExtractorThread = true;
+            me->mObserver->postAudioEOS(0);
+       }
+    }
+    return 1;
+}
+
+void TunnelPlayer::reset() {
+    ALOGV("Reset");
+
+    Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
+
+    //cancel any pending onpause timeout events
+    //doesnt matter if the event is really present or not
+    mPauseEventPending = false;
+    mQueue.cancelEvent(mPauseEvent->eventID());
+
+    mReachedEOS = true;
+
+    // make sure Decoder thread has exited
+    requestAndWaitForExtractorThreadExit_l();
+
+    // Close the audiosink after all the threads exited to make sure
+    if (mIsAudioRouted) {
+        mAudioSink->stop();
+        mAudioSink->close();
+        mIsAudioRouted = false;
+    }
+    //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;
+    }
+
+    if (mStarted)
+        mSource->stop();
+
+    mSource.clear();
+
+    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() {
+
+    mLock.lock();
+    uint32_t BufferSizeToUse = MEM_BUFFER_SIZE;
+
+    pid_t tid  = gettid();
+    androidSetThreadPriority(tid, mHasVideo ? ANDROID_PRIORITY_NORMAL :
+                                              ANDROID_PRIORITY_AUDIO);
+    prctl(PR_SET_NAME, (unsigned long)"Extractor Thread", 0, 0, 0);
+
+    ALOGV("extractorThreadEntry wait for signal \n");
+    if (!mStarted && !mKillExtractorThread) {
+        mExtractorCv.wait(mLock);
+    }
+    ALOGV("extractorThreadEntry ready to work \n");
+    mLock.unlock();
+    if (mKillExtractorThread) {
+        return;
+    }
+    if(mSource != NULL) {
+        sp<MetaData> format = mSource->getFormat();
+        const char *mime;
+        bool success = format->findCString(kKeyMIMEType, &mime);
+    }
+    void* local_buf = malloc(BufferSizeToUse);
+    int *lptr = ((int*)local_buf);
+    int bytesWritten = 0;
+    bool lSeeking = false;
+    bool lPaused = false;
+    while (!mKillExtractorThread) {
+
+        if (mReachedEOS || mPaused || !mIsAudioRouted) {
+            ALOGV("Going to sleep before write since "
+                  "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+                  mReachedEOS, mPaused, mIsAudioRouted);
+            mExtractorMutex.lock();
+            mExtractorCv.wait(mExtractorMutex);
+            mExtractorMutex.unlock();
+            ALOGV("Woke up from sleep before write since "
+                  "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+                  mReachedEOS, mPaused, mIsAudioRouted);
+            continue;
+        }
+
+        ALOGV("FillBuffer: MemBuffer size %d", BufferSizeToUse);
+        ALOGV("Fillbuffer started");
+        bytesWritten = fillBuffer(local_buf, BufferSizeToUse);
+        ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+        if(!mKillExtractorThread) {
+            mLock.lock();
+            lPaused = mPaused;
+            mLock.unlock();
+
+            if(lPaused == true) {
+                //write only if player is not in paused state. Sleep on lock
+                // resume is called
+                ALOGV("Going to sleep in decodethreadiwrite since sink is paused");
+                mExtractorMutex.lock();
+                mExtractorCv.wait(mExtractorMutex);
+                ALOGV("Going to unlock n decodethreadwrite since sink "
+                      "resumed mPaused %d, mIsAudioRouted %d, mReachedEOS %d",
+                      mPaused, mIsAudioRouted, mReachedEOS);
+                mExtractorMutex.unlock();
+            }
+            mLock.lock();
+            lSeeking = mSeeking||mInternalSeeking;
+            mLock.unlock();
+
+            if(lSeeking == false && (mKillExtractorThread == false)){
+                //if we are seeking, ignore write, otherwise write
+                ALOGV("Fillbuffer before seek flag %d", mSeeking);
+                int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten);
+                ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking);
+                if(lWrittenBytes > 0) {
+                    //send EOS only if write was successful, if is_buffer_available
+                    // is flushed out (which returns 0 do not SEND EOS
+                    ALOGV("Fillbuffer after write and seek flag %d", mSeeking);
+                    mLock.lock();
+                    lSeeking = mSeeking||mInternalSeeking;
+                    mLock.unlock();
+                    //ignore posting zero length buffer is seeking is set
+                    if(mReachedEOS && bytesWritten && !lSeeking && (mKillExtractorThread == false)) {
+                        ALOGV("Fillbuffer after write sent EOS flag %d", lSeeking);
+                        mAudioSink->write(local_buf, 0);
+                    } else {
+                        ALOGV("Not sending EOS buffer sent since seeking %d, "
+                              "kill %d and mReachedEOS %d",         \
+                              lSeeking, mKillExtractorThread, mReachedEOS);
+                    }
+                } else {
+                    ALOGV("write exited because of flush %d", mSeeking);
+                }
+            } else {
+                ALOGV("Fillbuffer ignored since we seeked after fillBuffer was set %d", mSeeking);
+            }
+        }
+    }
+
+    free(local_buf);
+
+    //TODO: Call fillbuffer with different size and write to mAudioSink()
+}
+void TunnelPlayer::createThreads() {
+
+    // Create extractor Thread
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+    mKillExtractorThread = false;
+
+    mExtractorThreadAlive = true;
+
+    ALOGV("Creating Extractor Thread");
+    pthread_create(&mExtractorThread, &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;
+    //clear the flag since we dont know whether we are seeking or not, yet
+    ALOGV("fillBuffer: Clearing seek flag in fill buffer");
+
+    bool yield = !mIsFirstBuffer;
+
+    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) {
+                    ALOGV("fillBuffer: Posting audio seek complete event");
+                    postSeekComplete = true;
+                }
+                mInternalSeeking = false;
+                ALOGV("fillBuffer: Setting seek flag in fill buffer");
+                //set the flag since we know that this buffer is the new positions buffer
+            }
+        }
+        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 (mHasVideo && yield) {
+            sched_yield();
+        }
+    }
+    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);
+
+    /*
+     * If it so happens that the client (e.g. AwesomePlayer),
+     * queries for the current time before compressed
+     * data from the new position is given to the compressed
+     * driver, we need to return the seek position
+     */
+    if (mSeeking || mInternalSeeking) {
+        ALOGV("Seek yet to be processed, return seek time as current time %lld",
+              mSeekTimeUs);
+        return mSeekTimeUs;
+    }
+
+    getOffsetRealTime_l(&mPositionTimeRealUs);
+    //update media time too
+    mPositionTimeMediaUs = mPositionTimeRealUs;
+    return mPositionTimeRealUs;
+}
+
+void TunnelPlayer::getPlayedTimeFromDSP_l(int64_t* timeStamp ) {
+    ALOGV("going to query timestamp");
+    mAudioSink->getTimeStamp((uint64_t*)timeStamp);
+    ALOGV("timestamp returned from DSP %lld ", (*timeStamp));
+    return;
+}
+
+//offset with pause and seek time
+void TunnelPlayer::getOffsetRealTime_l(int64_t* offsetTime) {
+    if (mPaused) {
+        *offsetTime = mPauseTime;
+        ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime );
+    } else {
+        getPlayedTimeFromDSP_l(offsetTime);
+        ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld, timeStamp %lld", mPaused, mSeekTimeUs, mPauseTime, *offsetTime);
+        *offsetTime = mSeekTimeUs + *offsetTime;
+    }
+}
+
+int64_t TunnelPlayer::getMediaTimeUs() {
+    //essentially there is only one time, the real time
+    return getRealTimeUs();
+}
+
+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;
+}
+
+//lock has been taken in reset() to sync with onpausetimeout
+void TunnelPlayer::requestAndWaitForExtractorThreadExit_l() {
+
+    ALOGV("requestAndWaitForExtractorThreadExit_l -1");
+
+    if (!mExtractorThreadAlive)
+        return;
+
+    mKillExtractorThread = true;
+
+    ALOGV("requestAndWaitForExtractorThreadExit_l +0");
+    if (mIsAudioRouted && !mReachedOutputEOS) {
+        mAudioSink->flush();
+    }
+
+
+    ALOGV("requestAndWaitForExtractorThreadExit_l +1");
+    mExtractorCv.signal();
+    mLock.unlock();
+    ALOGV("requestAndWaitForExtractorThreadExit_l +2");
+    pthread_join(mExtractorThread,NULL);
+    mLock.lock();
+    ALOGV("requestAndWaitForExtractorThreadExit_l +3");
+
+    ALOGV("Extractor thread killed");
+}
+
+void TunnelPlayer::onPauseTimeOut() {
+    Mutex::Autolock autoLock(mLock);
+    int64_t playedTime = 0;
+    ALOGV("onPauseTimeOut");
+    if (!mPauseEventPending) {
+        return;
+    }
+    mPauseEventPending = false;
+    // 1.) Set seek flags
+    mReachedEOS = false;
+    mReachedOutputEOS = false;
+
+    if(mSeeking == false) {
+        ALOGV("onPauseTimeOut +2");
+        mInternalSeeking = true;
+        ALOGV("onPauseTimeOut +3");
+        getPlayedTimeFromDSP_l(&playedTime);
+        mSeekTimeUs += playedTime;
+    } else {
+        ALOGV("Do not update seek time if it was seeked before onpause timeout");
+    }
+
+    // 2.) Close routing Session
+    ALOGV("onPauseTimeOut +4");
+    mAudioSink->flush();
+    ALOGV("onPauseTimeOut +5");
+    mAudioSink->stop();
+    ALOGV("onPauseTimeOut +6");
+    mAudioSink->close();
+    ALOGV("onPauseTimeOut +7");
+    mIsAudioRouted = false;
+}
+
+/*
+ * Returns true if the seek position is too close to the
+ * current playback position.
+ * Caller must acquire mLock
+ */
+bool TunnelPlayer::seekTooClose(int64_t time_us) {
+    int64_t t1 = -1;
+    /* The time as per DSP just before flush is issued */
+    if (mPositionTimeRealUs == -1) {
+        getOffsetRealTime_l(&mPositionTimeRealUs);
+    }
+
+    t1 = mPositionTimeRealUs;
+    /*
+     * empirical
+     * -----------
+     * This constant signifies how much data (in Us) has been rendered by the
+     * DSP in the interval between the moment flush is issued on AudioSink to
+     * after ioctl(PAUSE) returns in Audio HAL. (flush triggers an implicit
+     * pause in audio HAL)
+     *
+     */
+    const int64_t deltaUs = 60000LL; /* 60-70ms on msm8974 */
+    return (time_us > t1) && ((time_us - t1) <= deltaUs);
+}
+
+} //namespace android
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
old mode 100644
new mode 100755
index 1e85a01..e589fdc
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -32,6 +32,7 @@
 #include <hardware/audio.h>
 #include <media/stagefright/Utils.h>
 #include <media/AudioParameter.h>
+#include <media/stagefright/ExtendedCodec.h>
 
 #ifdef ENABLE_QC_AV_ENHANCEMENTS
 #include "QCMetaData.h"
@@ -281,6 +282,7 @@
         msg->setBuffer("csd-1", buffer);
     }
 
+    ExtendedCodec::convertMetaDataToMessage(meta, &msg);
     *format = msg;
 
     return OK;
diff --git a/media/libstagefright/WAVEWriter.cpp b/media/libstagefright/WAVEWriter.cpp
new file mode 100644
index 0000000..468765f
--- /dev/null
+++ b/media/libstagefright/WAVEWriter.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2012 - 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * 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/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index b822868..c0f7322 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -44,7 +44,7 @@
 void FindAVCDimensions(
         const sp<ABuffer> &seqParamSet,
         int32_t *width, int32_t *height,
-        int32_t *sarWidth, int32_t *sarHeight) {
+        int32_t *sarWidth, int32_t *sarHeight, int32_t *isInterlaced) {
     ABitReader br(seqParamSet->data() + 1, seqParamSet->size() - 1);
 
     unsigned profile_idc = br.getBits(8);
@@ -63,7 +63,11 @@
         parseUE(&br);  // bit_depth_luma_minus8
         parseUE(&br);  // bit_depth_chroma_minus8
         br.skipBits(1);  // qpprime_y_zero_transform_bypass_flag
-        CHECK_EQ(br.getBits(1), 0u);  // seq_scaling_matrix_present_flag
+        bool seq_scaling_matrix_present = (br.getBits(1) != 0u);
+        if (isInterlaced != NULL && seq_scaling_matrix_present) {
+            return;
+        }
+        CHECK_EQ(seq_scaling_matrix_present, false);  // seq_scaling_matrix_present_flag
     }
 
     parseUE(&br);  // log2_max_frame_num_minus4
@@ -133,6 +137,10 @@
             (frame_crop_top_offset + frame_crop_bottom_offset) * cropUnitY;
     }
 
+    if (isInterlaced != NULL) {
+        *isInterlaced = !frame_mbs_only_flag;
+    }
+
     if (sarWidth != NULL) {
         *sarWidth = 0;
     }
diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
index 3b3ce0b..bdba267 100644
--- a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
@@ -437,8 +437,12 @@
 
 void SoftAMR::onPortFlushCompleted(OMX_U32 portIndex) {
         ALOGE("onPortFlushCompleted portindex %d, resetting frame ",portIndex);
-        if(portIndex == 0)
-           Speech_Decode_Frame_reset(mState);
+        if(portIndex == 0) {
+           if(mMode == MODE_NARROW)
+              Speech_Decode_Frame_reset(mState);
+           else
+              pvDecoder_AmrWb_Reset(mState, 0);
+        }
 }
 
 void SoftAMR::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index 135c715..9e10527 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -2,6 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
+        MP3Decoder.cpp \
 	src/pvmp3_normalize.cpp \
  	src/pvmp3_alias_reduction.cpp \
  	src/pvmp3_crc.cpp \
diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
new file mode 100644
index 0000000..c757589
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
@@ -0,0 +1,601 @@
+/*
+ * Copyright (C) 2009 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 "MP3Decoder.h"
+
+#include "include/pvmp3decoder_api.h"
+
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include <cutils/log.h>
+
+#define LITERAL_TO_STRING_INTERNAL(x)    #x
+#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
+
+#define CHECK_EQ(x,y)                                                   \
+    LOG_ALWAYS_FATAL_IF(                                                \
+            (x) != (y),                                                 \
+            __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x " != " #y)
+
+#define CHECK(x)                                                        \
+    LOG_ALWAYS_FATAL_IF(                                                \
+            !(x),                                                       \
+            __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x)
+
+
+namespace android {
+
+// Everything must match except for
+// protection, bitrate, padding, private bits, mode extension,
+// copyright bit, original bit and emphasis.
+// Yes ... there are things that must indeed match...
+static const uint32_t kMask = 0xfffe0cc0;
+
+static bool get_mp3_frame_size(
+        uint32_t header, size_t *frame_size,
+        int *out_sampling_rate = NULL, int *out_channels = NULL,
+        int *out_bitrate = NULL) {
+    *frame_size = 0;
+
+    if (out_sampling_rate) {
+        *out_sampling_rate = 0;
+    }
+
+    if (out_channels) {
+        *out_channels = 0;
+    }
+
+    if (out_bitrate) {
+        *out_bitrate = 0;
+    }
+
+    if ((header & 0xffe00000) != 0xffe00000) {
+        return false;
+    }
+
+    unsigned version = (header >> 19) & 3;
+
+    if (version == 0x01) {
+        return false;
+    }
+
+    unsigned layer = (header >> 17) & 3;
+
+    if (layer == 0x00) {
+        return false;
+    }
+
+    unsigned protection = (header >> 16) & 1;
+
+    unsigned bitrate_index = (header >> 12) & 0x0f;
+
+    if (bitrate_index == 0 || bitrate_index == 0x0f) {
+        // Disallow "free" bitrate.
+        return false;
+    }
+
+    unsigned sampling_rate_index = (header >> 10) & 3;
+
+    if (sampling_rate_index == 3) {
+        return false;
+    }
+
+    static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
+    int sampling_rate = kSamplingRateV1[sampling_rate_index];
+    if (version == 2 /* V2 */) {
+        sampling_rate /= 2;
+    } else if (version == 0 /* V2.5 */) {
+        sampling_rate /= 4;
+    }
+
+    unsigned padding = (header >> 9) & 1;
+
+    if (layer == 3) {
+        // layer I
+
+        static const int kBitrateV1[] = {
+            32, 64, 96, 128, 160, 192, 224, 256,
+            288, 320, 352, 384, 416, 448
+        };
+
+        static const int kBitrateV2[] = {
+            32, 48, 56, 64, 80, 96, 112, 128,
+            144, 160, 176, 192, 224, 256
+        };
+
+        int bitrate =
+            (version == 3 /* V1 */)
+                ? kBitrateV1[bitrate_index - 1]
+                : kBitrateV2[bitrate_index - 1];
+
+        if (out_bitrate) {
+            *out_bitrate = bitrate;
+        }
+
+        *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
+    } else {
+        // layer II or III
+
+        static const int kBitrateV1L2[] = {
+            32, 48, 56, 64, 80, 96, 112, 128,
+            160, 192, 224, 256, 320, 384
+        };
+
+        static const int kBitrateV1L3[] = {
+            32, 40, 48, 56, 64, 80, 96, 112,
+            128, 160, 192, 224, 256, 320
+        };
+
+        static const int kBitrateV2[] = {
+            8, 16, 24, 32, 40, 48, 56, 64,
+            80, 96, 112, 128, 144, 160
+        };
+
+        int bitrate;
+        if (version == 3 /* V1 */) {
+            bitrate = (layer == 2 /* L2 */)
+                ? kBitrateV1L2[bitrate_index - 1]
+                : kBitrateV1L3[bitrate_index - 1];
+        } else {
+            // V2 (or 2.5)
+
+            bitrate = kBitrateV2[bitrate_index - 1];
+        }
+
+        if (out_bitrate) {
+            *out_bitrate = bitrate;
+        }
+
+        if (version == 3 /* V1 */) {
+            *frame_size = 144000 * bitrate / sampling_rate + padding;
+        } else {
+            // V2 or V2.5
+            *frame_size = 72000 * bitrate / sampling_rate + padding;
+        }
+    }
+
+    if (out_sampling_rate) {
+        *out_sampling_rate = sampling_rate;
+    }
+
+    if (out_channels) {
+        int channel_mode = (header >> 6) & 3;
+
+        *out_channels = (channel_mode == 3) ? 1 : 2;
+    }
+
+    return true;
+}
+
+static bool resync(
+        uint8_t *data, uint32_t size, uint32_t match_header, off_t *out_pos) {
+
+    bool valid = false;
+    off_t pos = 0;
+    *out_pos = 0;
+    do {
+        if (pos + 4 > size) {
+            // Don't scan forever.
+            ALOGV("no dice, no valid sequence of frames found.");
+            break;
+        }
+
+        uint32_t header = U32_AT(data + pos);
+
+        if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
+            ++pos;
+            continue;
+        }
+
+        ALOGV("found possible frame at %ld (header = 0x%08x)", pos, header);
+
+        // We found what looks like a valid frame,
+        valid = true;
+        *out_pos = pos;
+    } while (!valid);
+
+    return valid;
+}
+
+
+MP3Decoder::MP3Decoder(const sp<MediaSource> &source)
+    : mSource(source),
+      mNumChannels(0),
+      mStarted(false),
+      mBufferGroup(NULL),
+      mConfig(new tPVMP3DecoderExternal),
+      mDecoderBuf(NULL),
+      mAnchorTimeUs(0),
+      mNumFramesOutput(0),
+      mInputBuffer(NULL),
+      mPartialBuffer(NULL),
+      mFixedHeader(0) {
+    init();
+}
+
+void MP3Decoder::init() {
+    sp<MetaData> srcFormat = mSource->getFormat();
+
+    int32_t sampleRate;
+    CHECK(srcFormat->findInt32(kKeyChannelCount, &mNumChannels));
+    CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
+
+    mMeta = new MetaData;
+    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+    mMeta->setInt32(kKeyChannelCount, mNumChannels);
+    mMeta->setInt32(kKeySampleRate, sampleRate);
+
+    int64_t durationUs;
+    if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
+        mMeta->setInt64(kKeyDuration, durationUs);
+    }
+
+    mMeta->setCString(kKeyDecoderComponent, "MP3Decoder");
+}
+
+MP3Decoder::~MP3Decoder() {
+    if (mStarted) {
+        stop();
+    }
+
+    delete mConfig;
+    mConfig = NULL;
+}
+
+status_t MP3Decoder::start(MetaData *params) {
+    CHECK(!mStarted);
+
+    mBufferGroup = new MediaBufferGroup;
+    mBufferGroup->add_buffer(new MediaBuffer(4608 * 2));
+
+    mConfig->equalizerType = flat;
+    mConfig->crcEnabled = false;
+
+    uint32_t memRequirements = pvmp3_decoderMemRequirements();
+    mDecoderBuf = malloc(memRequirements);
+
+    pvmp3_InitDecoder(mConfig, mDecoderBuf);
+
+    mSource->start();
+
+    mAnchorTimeUs = 0;
+    mNumFramesOutput = 0;
+    mStarted = true;
+
+    return OK;
+}
+
+status_t MP3Decoder::stop() {
+    CHECK(mStarted);
+
+    if (mInputBuffer) {
+        mInputBuffer->release();
+        mInputBuffer = NULL;
+    }
+
+    free(mDecoderBuf);
+    mDecoderBuf = NULL;
+
+    delete mBufferGroup;
+    mBufferGroup = NULL;
+
+    mSource->stop();
+
+    mStarted = false;
+
+    return OK;
+}
+
+sp<MetaData> MP3Decoder::getFormat() {
+    return mMeta;
+}
+
+status_t MP3Decoder::updatePartialFrame() {
+    status_t err = OK;
+    if (mPartialBuffer == NULL) {
+        return err;
+    }
+
+    size_t frameSize = 0;
+    uint32_t partialBufLen = mPartialBuffer->range_length();
+    uint32_t inputBufLen = mInputBuffer->range_length();
+    uint8_t frameHeader[4];
+    uint8_t *frmHdr;
+    uint32_t header;
+
+
+    // Look at the frame size and complete the partial frame
+    // Also check if a vaild header is found after the partial frame
+    if (partialBufLen < 4) { // check if partial frame has the 4 bytes header
+        if (inputBufLen < (4 - partialBufLen)) {
+            // input buffer does not have the frame header bytes
+            // bail out TODO
+            ALOGE("MP3Decoder::updatePartialFrame buffer to small header not found"
+                 " partial buffer len %d, input buffer len %d",
+                 partialBufLen, inputBufLen);
+            //mPartialBuffer->release();
+            //mPartialBuffer = NULL;
+            return UNKNOWN_ERROR;
+        }
+
+        // copy the header bytes to frameHeader
+        memcpy (frameHeader, mPartialBuffer->data(), partialBufLen);
+        memcpy (frameHeader + partialBufLen, mInputBuffer->data(), (4 - partialBufLen));
+        // get the first 4 bytes of the buffer
+        header = U32_AT((uint8_t *)frameHeader);
+        frmHdr = frameHeader;
+    } else {
+        frmHdr = (uint8_t *)mPartialBuffer->data();
+    }
+
+    // check if its a good frame, and the frame size
+    // get the first 4 bytes of the buffer
+    header = U32_AT(frmHdr);
+    bool curFrame = get_mp3_frame_size(header,&frameSize);
+    if (!curFrame) {
+        ALOGE("MP3Decoder::read - partial frame does not have a vaild header 0x%x",
+             header);
+        return UNKNOWN_ERROR;
+    }
+
+    // check if the following frame is good
+    uint32_t nextFrameOffset = frameSize - partialBufLen;
+    if ((nextFrameOffset + 4) <= inputBufLen) {
+        header = U32_AT((uint8_t *)mInputBuffer->data() + nextFrameOffset);
+        if ((header & 0xffe00000) != 0xffe00000) {
+            // next frame does not have a valid header,
+            // this may not be the next buffer, bail out.
+            ALOGE("MP3Decoder::read - next frame does not have a vaild header 0x%x",
+                 header);
+            return UNKNOWN_ERROR;
+        }
+    } else {
+        // next frame header is out of range
+        // assume good header for now
+        ALOGE("MP3Decoder::read - assuming next frame is good");
+    }
+
+    // check if the input buffer has the remaining partial frame
+    if (frameSize > (partialBufLen + inputBufLen)) {
+        // input buffer does not have the remaining partial frame,
+        // discard data here as frame split in 3 buffers not supported
+        ALOGE("MP3Decoder::updatePartialFrame - input buffer does not have the complete frame."
+             " frame size %d, saved partial buffer len %d,"
+             " input buffer len %d", frameSize, partialBufLen, inputBufLen);
+        return UNKNOWN_ERROR;
+    }
+
+    // check if the mPartialBuffer can fit the remaining frame
+    if ((mPartialBuffer->size() - partialBufLen) < (frameSize - partialBufLen)) {
+        // mPartialBuffer is small to hold the reaming frame
+        //TODO
+        ALOGE("MP3Decoder::updatePartialFrame - mPartialBuffer is small, size %d, required &d",
+             (mPartialBuffer->size() - partialBufLen), (frameSize - partialBufLen));
+        return UNKNOWN_ERROR;
+    }
+
+    // done with error checks
+    // copy the partial frames to from a complete frame
+    // Copy the remaining frame from input buffer
+    uint32_t bytesRemaining = frameSize - mPartialBuffer->range_length();
+    memcpy ((uint8_t *)mPartialBuffer->data() + mPartialBuffer->range_length(),
+            (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(),
+            bytesRemaining);
+
+    // mark the bytes as consumed from input buffer
+    mInputBuffer->set_range(
+                           mInputBuffer->range_offset() + bytesRemaining,
+                           mInputBuffer->range_length() - bytesRemaining);
+
+    // set the range and length of mPartialBuffer
+    mPartialBuffer->set_range(0,
+                              mPartialBuffer->range_length() + bytesRemaining);
+
+    ALOGE("MP3Decoder::updatePartialFrame - copied the partial frame %d, input buffer length %d",
+         bytesRemaining, mInputBuffer->range_length());
+
+    return err;
+}
+
+status_t MP3Decoder::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    status_t err;
+
+    *out = NULL;
+    bool usedPartialFrame = false;
+    bool seekSource = false;
+
+    int64_t seekTimeUs;
+    ReadOptions::SeekMode mode;
+    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+        CHECK(seekTimeUs >= 0);
+
+        mNumFramesOutput = 0;
+        seekSource = true;
+
+        if (mInputBuffer) {
+            mInputBuffer->release();
+            mInputBuffer = NULL;
+        }
+
+        if (mPartialBuffer) {
+            mPartialBuffer->release();
+            mPartialBuffer = NULL;
+        }
+
+        // Make sure that the next buffer output does not still
+        // depend on fragments from the last one decoded.
+        pvmp3_InitDecoder(mConfig, mDecoderBuf);
+    } else {
+        seekTimeUs = -1;
+    }
+
+    if (mInputBuffer == NULL) {
+        err = mSource->read(&mInputBuffer, options);
+
+        if (err != OK) {
+            return err;
+        }
+
+        if ((mFixedHeader == 0) && (mInputBuffer->range_length() > 4)) {
+            //save the first 4 bytes as fixed header for the reset of the file
+            mFixedHeader = U32_AT((uint8_t *)mInputBuffer->data());
+        }
+
+        if (seekSource == true) {
+            off_t syncOffset = 0;
+            bool valid = resync((uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset()
+                                ,mInputBuffer->range_length(), mFixedHeader, &syncOffset);
+            if (valid) {
+                // consume these bytes, we might find a frame header in next buffer
+                mInputBuffer->set_range(
+                    mInputBuffer->range_offset() + syncOffset,
+                    mInputBuffer->range_length() - syncOffset);
+                ALOGV("mp3 decoder found a sync point after seek syncOffset %d", syncOffset);
+            } else {
+                ALOGV("NO SYNC POINT found, buffer length %d",mInputBuffer->range_length());
+            }
+        }
+
+        int64_t timeUs;
+        if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
+            mAnchorTimeUs = timeUs;
+            mNumFramesOutput = 0;
+        } else {
+            // We must have a new timestamp after seeking.
+            CHECK(seekTimeUs < 0);
+        }
+        // check for partial frame
+        if (mPartialBuffer != NULL) {
+            err = updatePartialFrame();
+            if (err != OK) {
+                // updating partial frame failed, discard the previously
+                // saved partial frame and continue
+                mPartialBuffer->release();
+                mPartialBuffer = NULL;
+                err = OK;
+            }
+        }
+    }
+
+    MediaBuffer *buffer;
+    CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+
+    if (mPartialBuffer != NULL) {
+        mConfig->pInputBuffer =
+        (uint8_t *)mPartialBuffer->data() + mPartialBuffer->range_offset();
+        mConfig->inputBufferCurrentLength = mPartialBuffer->range_length();
+        usedPartialFrame = true;
+    } else {
+        mConfig->pInputBuffer =
+            (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
+        mConfig->inputBufferCurrentLength = mInputBuffer->range_length();
+    }
+
+    mConfig->inputBufferMaxLength = 0;
+    mConfig->inputBufferUsedLength = 0;
+
+    mConfig->outputFrameSize = buffer->size() / sizeof(int16_t);
+    mConfig->pOutputBuffer = static_cast<int16_t *>(buffer->data());
+
+    ERROR_CODE decoderErr;
+    if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
+            != NO_DECODING_ERROR) {
+        ALOGV("mp3 decoder returned error %d", decoderErr);
+
+        if ((decoderErr != NO_ENOUGH_MAIN_DATA_ERROR) &&
+            (decoderErr != SYNCH_LOST_ERROR)) {
+            buffer->release();
+            buffer = NULL;
+
+            mInputBuffer->release();
+            mInputBuffer = NULL;
+            if (mPartialBuffer) {
+                mPartialBuffer->release();
+                mPartialBuffer = NULL;
+            }
+            ALOGE("mp3 decoder returned UNKNOWN_ERROR");
+
+            return UNKNOWN_ERROR;
+        }
+
+        if ((mPartialBuffer == NULL) && (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR)) {
+            // Might be a partial frame, save it
+            mPartialBuffer = new MediaBuffer(mInputBuffer->size());
+            memcpy ((uint8_t *)mPartialBuffer->data(),
+                    mConfig->pInputBuffer, mConfig->inputBufferCurrentLength);
+            mPartialBuffer->set_range(0, mConfig->inputBufferCurrentLength);
+            // set output buffer to 0
+            mConfig->outputFrameSize = 0;
+            // consume the copied bytes from input
+            mConfig->inputBufferUsedLength = mConfig->inputBufferCurrentLength;
+        } else if(decoderErr == SYNCH_LOST_ERROR) {
+            // Try to find the mp3 frame header in the current buffer
+            off_t syncOffset = 0;
+            bool valid = resync(mConfig->pInputBuffer, mConfig->inputBufferCurrentLength,
+                                mFixedHeader, &syncOffset);
+            if (!valid || !syncOffset) {
+                // consume these bytes, we might find a frame header in next buffer
+                syncOffset = mConfig->inputBufferCurrentLength;
+            }
+            // set output buffer to 0
+            mConfig->outputFrameSize = 0;
+            // consume the junk bytes from input buffer
+            mConfig->inputBufferUsedLength = syncOffset;
+        } else {
+            // This is recoverable, just ignore the current frame and
+            // play silence instead.
+            memset(buffer->data(), 0, mConfig->outputFrameSize * sizeof(int16_t));
+            mConfig->inputBufferUsedLength = mInputBuffer->range_length();
+        }
+    }
+
+    buffer->set_range(
+            0, mConfig->outputFrameSize * sizeof(int16_t));
+
+    if ((mPartialBuffer != NULL) && usedPartialFrame) {
+        mPartialBuffer->set_range(
+            mPartialBuffer->range_offset() + mConfig->inputBufferUsedLength,
+            mPartialBuffer->range_length() - mConfig->inputBufferUsedLength);
+        mPartialBuffer->release();
+        mPartialBuffer = NULL;
+    } else {
+        mInputBuffer->set_range(
+            mInputBuffer->range_offset() + mConfig->inputBufferUsedLength,
+            mInputBuffer->range_length() - mConfig->inputBufferUsedLength);
+    }
+
+    if (mInputBuffer->range_length() == 0) {
+        mInputBuffer->release();
+        mInputBuffer = NULL;
+    }
+
+    buffer->meta_data()->setInt64(
+            kKeyTime,
+            mAnchorTimeUs
+                + (mNumFramesOutput * 1000000) / mConfig->samplingRate);
+
+    mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
+
+    *out = buffer;
+
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 271df8e..dd6c409 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -1,4 +1,6 @@
 /*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
  * Copyright (C) 2009 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -102,6 +104,7 @@
     void postAudioEOS(int64_t delayUs = 0ll);
     void postAudioSeekComplete();
     void postAudioTearDown();
+    void printFileName(int fd);
     status_t dump(int fd, const Vector<String16> &args) const;
 
 private:
@@ -204,6 +207,7 @@
 
     bool mWatchForAudioSeekComplete;
     bool mWatchForAudioEOS;
+    static int mTunnelAliveAP;
 
     sp<TimedEventQueue::Event> mVideoEvent;
     bool mVideoEventPending;
@@ -241,6 +245,7 @@
     sp<DecryptHandle> mDecryptHandle;
 
     int64_t mLastVideoTimeUs;
+    int64_t mFrameDurationUs;
     TimedTextDriver *mTextDriver;
 
     sp<WVMExtractor> mWVMExtractor;
@@ -313,6 +318,15 @@
         ASSIGN
     };
     void modifyFlags(unsigned value, FlagMode mode);
+    void checkTunnelExceptions();
+    void logFirstFrame();
+    void logCatchUp(int64_t ts, int64_t clock, int64_t delta);
+    void logLate(int64_t ts, int64_t clock, int64_t delta);
+    void logOnTime(int64_t ts, int64_t clock, int64_t delta);
+    void printStats();
+    int64_t getTimeOfDayUs();
+    bool mStatistics;
+    int64_t mLateAVSyncMargin;
 
     struct TrackStat {
         String8 mMIME;
@@ -338,6 +352,23 @@
         int32_t mVideoHeight;
         uint32_t mFlags;
         Vector<TrackStat> mTracks;
+
+        int64_t mConsecutiveFramesDropped;
+        uint32_t mCatchupTimeStart;
+        uint32_t mNumTimesSyncLoss;
+        uint32_t mMaxEarlyDelta;
+        uint32_t mMaxLateDelta;
+        uint32_t mMaxTimeSyncLoss;
+        uint64_t mTotalFrames;
+        int64_t mFirstFrameLatencyStartUs; //first frame latency start
+        int64_t mFirstFrameLatencyUs;
+        int64_t mLastFrameUs;
+        bool mVeryFirstFrame;
+        int64_t mTotalTimeUs;
+        int64_t mLastPausedTimeMs;
+        int64_t mLastSeekToTimeMs;
+        int64_t mResumeDelayStartUs;
+        int64_t mSeekDelayStartUs;
     } mStats;
 
     bool    mOffloadAudio;
@@ -357,6 +388,9 @@
 
     size_t countTracks() const;
 
+    bool inSupportedTunnelFormats(const char * mime);
+    //Flag to check if tunnel mode audio is enabled
+    bool mIsTunnelAudio;
     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..3bce1ff
--- /dev/null
+++ b/media/libstagefright/include/ExtendedExtractor.h
@@ -0,0 +1,49 @@
+/*Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * 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;
+class ExtendedExtractor
+{
+public:
+    static MediaExtractor* Create (
+            const sp<DataSource> &source, const char *mime);
+    static bool Sniff (
+            const sp<DataSource> &source, String8 *mimeType,
+            float *confidence,sp<AMessage> *meta);
+};
+
+}  // namespace android
+
+#endif //EXTENDED_EXTRACTOR_
diff --git a/media/libstagefright/include/ExtendedUtils.h b/media/libstagefright/include/ExtendedUtils.h
new file mode 100644
index 0000000..1c3f3aa
--- /dev/null
+++ b/media/libstagefright/include/ExtendedUtils.h
@@ -0,0 +1,151 @@
+/*Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * 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 QC_UTILS_H_
+#define QC_UTILS_H_
+
+#include <utils/StrongPointer.h>
+#include <media/Metadata.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/MediaCodecList.h>
+
+#include <media/MediaRecorderBase.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <camera/CameraParameters.h>
+#include <OMX_Video.h>
+#include <android/native_window.h>
+
+#define MIN_BITERATE_AAC 24000
+#define MAX_BITERATE_AAC 192000
+
+namespace android {
+
+/*
+ * This class is a placeholder for utility methods for
+ * QC specific changes
+ */
+struct ExtendedUtils {
+
+    /*
+     * This class is a placeholder for set of methods used
+     * to enable HFR (High Frame Rate) Recording
+     *
+     * HFR is a slow-motion recording feature where framerate
+     * is increased at capture, but file is composed to play
+     * back at normal rate, giving a net result of slow-motion.
+     * If HFR factor = N
+     *   framerate (at capture and encoder) = N * actual value
+     *   timeStamps (at composition) = N * actual value
+     *   bitrate = N * actual value
+     *      (as the encoder still gets actual timestamps)
+     */
+    struct HFR {
+        // set kKeyHFR when 'video-hfr' paramater is enabled
+        static void setHFRIfEnabled(
+                const CameraParameters& params, sp<MetaData> &meta);
+
+        // recalculate fileduration when hfr is enabled
+        static status_t reCalculateFileDuration(
+                sp<MetaData> &meta, sp<MetaData> &enc_meta,
+                int64_t &maxFileDurationUs, int32_t frameRate,
+                video_encoder videoEncoder);
+
+        // compute timestamp when hfr is enabled
+        static void reCalculateTimeStamp(
+                sp<MetaData> &meta, int64_t &timestampUs);
+
+        // recalculate frameRate and bitrate when hfr is enabled
+        static void reCalculateHFRParams(
+                const sp<MetaData> &meta, int32_t &frameRate,
+                int32_t &bitrate);
+
+        // Copy HFR params (bitrate,framerate) from output to
+        // to input format, if HFR is enabled
+        static void copyHFRParams(
+                const sp<MetaData> &inputFormat,
+                sp<MetaData> &outputFormat);
+    };
+
+    /*
+     * This class is a placeholder for methods to override
+     * default heaviour based on shell properties set
+     */
+    struct ShellProp {
+        // check if shell property to disable audio is set
+        static bool isAudioDisabled();
+
+        //helper function to set encoding profiles
+        static void setEncoderProfile(video_encoder &videoEncoder,
+                int32_t &videoEncoderProfile);
+
+        static bool isSmoothStreamingEnabled();
+
+        static int64_t getMaxAVSyncLateMargin();
+    };
+
+    //set B frames for MPEG4
+    static void setBFrames(OMX_VIDEO_PARAM_MPEG4TYPE &mpeg4type, int32_t &numBFrames,
+            const char* componentName);
+
+    //set B frames for H264
+    static void setBFrames(OMX_VIDEO_PARAM_AVCTYPE &h264type, int32_t &numBFrames,
+            int32_t iFramesInterval, int32_t frameRate, const char* componentName);
+
+    static bool UseQCHWAACEncoder(audio_encoder Encoder, int32_t Channel,
+            int32_t BitRate, int32_t SampleRate);
+
+    static sp<MediaExtractor> MediaExtractor_CreateIfNeeded(
+            sp<MediaExtractor> defaultExt, const sp<DataSource> &source,
+            const char *mime);
+
+    //helper function to add media codecs with specific quirks
+    static void helper_addMediaCodec(Vector<MediaCodecList::CodecInfo> &mCodecInfos,
+                                     KeyedVector<AString, size_t> &mTypes,
+                                     bool encoder, const char *name,
+                                     const char *type, uint32_t quirks);
+
+    //helper function to calculate the value of quirks from strings
+    static uint32_t helper_getCodecSpecificQuirks(KeyedVector<AString, size_t> &mCodecQuirks,
+                                                  Vector<AString> quirks);
+
+    static bool isAVCProfileSupported(int32_t profile);
+
+    //notify stride change to ANW
+    static void updateNativeWindowBufferGeometry(ANativeWindow* anw,
+            OMX_U32 width, OMX_U32 height, OMX_COLOR_FORMATTYPE colorFormat);
+
+    static bool checkIsThumbNailMode(const uint32_t flags, char* componentName);
+
+    static void setArbitraryModeIfInterlaced(
+            const uint8_t *ptr, const sp<MetaData> &meta);
+
+    static int32_t checkIsInterlace(sp<MetaData> &meta);
+};
+
+}
+#endif  //QC_UTILS_H_
diff --git a/media/libstagefright/include/MP3Decoder.h b/media/libstagefright/include/MP3Decoder.h
new file mode 100644
index 0000000..8ff570a
--- /dev/null
+++ b/media/libstagefright/include/MP3Decoder.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#ifndef MP3_DECODER_H_
+
+#define MP3_DECODER_H_
+
+#include <media/stagefright/MediaSource.h>
+
+struct tPVMP3DecoderExternal;
+
+namespace android {
+
+struct MediaBufferGroup;
+
+struct MP3Decoder : public MediaSource {
+    MP3Decoder(const sp<MediaSource> &source);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+protected:
+    virtual ~MP3Decoder();
+
+private:
+    sp<MediaSource> mSource;
+    sp<MetaData> mMeta;
+    int32_t mNumChannels;
+
+    bool mStarted;
+
+    MediaBufferGroup *mBufferGroup;
+
+    tPVMP3DecoderExternal *mConfig;
+    void *mDecoderBuf;
+    int64_t mAnchorTimeUs;
+    int64_t mNumFramesOutput;
+    uint32_t mFixedHeader;
+
+    MediaBuffer *mInputBuffer;
+    MediaBuffer *mPartialBuffer;
+
+    void init();
+
+    MP3Decoder(const MP3Decoder &);
+    MP3Decoder &operator=(const MP3Decoder &);
+    status_t updatePartialFrame();
+};
+
+}  // namespace android
+
+#endif  // MP3_DECODER_H_
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index d517320..8e67308 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -40,7 +40,7 @@
 void FindAVCDimensions(
         const sp<ABuffer> &seqParamSet,
         int32_t *width, int32_t *height,
-        int32_t *sarWidth = NULL, int32_t *sarHeight = NULL);
+        int32_t *sarWidth = NULL, int32_t *sarHeight = NULL, int32_t *isInterlaced = NULL);
 
 unsigned parseUE(ABitReader *br);
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 8f9c9c8..0679a1a 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -504,7 +504,9 @@
 
         if (first) {
             timeUs = info->mTimestampUs;
-            first = false;
+            if(mMode != AAC) {
+                first = false;
+            }
         }
 
         if (info->mLength > size) {