auto import from //depot/cupcake/@135843
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
new file mode 100644
index 0000000..8020da2
--- /dev/null
+++ b/media/libmedia/Android.mk
@@ -0,0 +1,39 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	AudioTrack.cpp \
+	IAudioFlinger.cpp \
+	IAudioFlingerClient.cpp \
+	IAudioTrack.cpp \
+	IAudioRecord.cpp \
+	AudioRecord.cpp \
+	AudioSystem.cpp \
+	mediaplayer.cpp \
+	IMediaPlayerService.cpp \
+	IMediaPlayerClient.cpp \
+	IMediaPlayer.cpp \
+	IMediaRecorder.cpp \
+	mediarecorder.cpp \
+	IMediaMetadataRetriever.cpp \
+	mediametadataretriever.cpp \
+	ToneGenerator.cpp \
+	JetPlayer.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libui libcutils libutils libsonivox
+
+LOCAL_MODULE:= libmedia
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+LOCAL_LDLIBS += -ldl
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_C_INCLUDES := \
+	$(call include-path-for, graphics corecg)
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
new file mode 100644
index 0000000..7594ff0
--- /dev/null
+++ b/media/libmedia/AudioRecord.cpp
@@ -0,0 +1,574 @@
+/*
+**
+** Copyright 2008, 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_TAG "AudioRecord"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <private/media/AudioTrackShared.h>
+
+#include <media/AudioSystem.h>
+#include <media/AudioRecord.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+#include <utils/MemoryDealer.h>
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Timers.h>
+#include <cutils/atomic.h>
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+AudioRecord::AudioRecord()
+    : mStatus(NO_INIT)
+{
+}
+
+AudioRecord::AudioRecord(
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        uint32_t flags,
+        callback_t cbf,
+        void* user,
+        int notificationFrames)
+    : mStatus(NO_INIT)
+{
+    mStatus = set(streamType, sampleRate, format, channelCount,
+            frameCount, flags, cbf, user, notificationFrames);
+}
+
+AudioRecord::~AudioRecord()
+{
+    if (mStatus == NO_ERROR) {
+        // Make sure that callback function exits in the case where
+        // it is looping on buffer empty condition in obtainBuffer().
+        // Otherwise the callback thread will never exit.
+        stop();
+        if (mClientRecordThread != 0) {
+            mCblk->cv.signal();
+            mClientRecordThread->requestExitAndWait();
+            mClientRecordThread.clear();
+        }
+        mAudioRecord.clear();
+        IPCThreadState::self()->flushCommands();
+    }
+}
+
+status_t AudioRecord::set(
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        uint32_t flags,
+        callback_t cbf,
+        void* user,
+        int notificationFrames,
+        bool threadCanCallJava)
+{
+
+    LOGV("set(): sampleRate %d, channelCount %d, frameCount %d",sampleRate, channelCount, frameCount);
+    if (mAudioFlinger != 0) {
+        return INVALID_OPERATION;
+    }
+
+    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+    if (audioFlinger == 0) {
+        return NO_INIT;
+    }
+
+    if (streamType == DEFAULT_INPUT) {
+        streamType = MIC_INPUT;
+    }
+
+    if (sampleRate == 0) {
+        sampleRate = DEFAULT_SAMPLE_RATE;
+    }
+    // these below should probably come from the audioFlinger too...
+    if (format == 0) {
+        format = AudioSystem::PCM_16_BIT;
+    }
+    if (channelCount == 0) {
+        channelCount = 1;
+    }
+
+    // validate parameters
+    if (format != AudioSystem::PCM_16_BIT) {
+        return BAD_VALUE;
+    }
+    if (channelCount != 1 && channelCount != 2) {
+        return BAD_VALUE;
+    }
+
+    // validate framecount
+    size_t inputBuffSizeInBytes = -1;
+    if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes)
+            != NO_ERROR) {
+        LOGE("AudioSystem could not query the input buffer size.");
+        return NO_INIT;    
+    }
+    if (inputBuffSizeInBytes == 0) {
+        LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d",
+            sampleRate, channelCount, format);
+        return BAD_VALUE;
+    }
+    int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1);
+
+    // We use 2* size of input buffer for ping pong use of record buffer.
+    int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes;
+    LOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
+
+    if (frameCount == 0) {
+        frameCount = minFrameCount;
+    } else if (frameCount < minFrameCount) {
+        return BAD_VALUE;
+    }
+
+    if (notificationFrames == 0) {
+        notificationFrames = frameCount/2;
+    }
+
+    // open record channel
+    status_t status;
+    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), streamType,
+                                                       sampleRate, format,
+                                                       channelCount,
+                                                       frameCount,
+                                                       ((uint16_t)flags) << 16, 
+                                                       &status);
+    if (record == 0) {
+        LOGE("AudioFlinger could not create record track, status: %d", status);
+        return status;
+    }
+    sp<IMemory> cblk = record->getCblk();
+    if (cblk == 0) {
+        return NO_INIT;
+    }
+    if (cbf != 0) {
+        mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
+        if (mClientRecordThread == 0) {
+            return NO_INIT;
+        }
+    }
+
+    mStatus = NO_ERROR;
+
+    mAudioFlinger = audioFlinger;
+    mAudioRecord = record;
+    mCblkMemory = cblk;
+    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
+    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+    mCblk->out = 0;
+    mSampleRate = sampleRate;
+    mFormat = format;
+    // Update buffer size in case it has been limited by AudioFlinger during track creation
+    mFrameCount = mCblk->frameCount;
+    mChannelCount = channelCount;
+    mActive = 0;
+    mCbf = cbf;
+    mNotificationFrames = notificationFrames;
+    mRemainingFrames = notificationFrames;
+    mUserData = user;
+    // TODO: add audio hardware input latency here
+    mLatency = (1000*mFrameCount) / mSampleRate;
+    mMarkerPosition = 0;
+    mNewPosition = 0;
+    mUpdatePeriod = 0;
+
+    return NO_ERROR;
+}
+
+status_t AudioRecord::initCheck() const
+{
+    return mStatus;
+}
+
+// -------------------------------------------------------------------------
+
+uint32_t AudioRecord::latency() const
+{
+    return mLatency;
+}
+
+uint32_t AudioRecord::sampleRate() const
+{
+    return mSampleRate;
+}
+
+int AudioRecord::format() const
+{
+    return mFormat;
+}
+
+int AudioRecord::channelCount() const
+{
+    return mChannelCount;
+}
+
+uint32_t AudioRecord::frameCount() const
+{
+    return mFrameCount;
+}
+
+int AudioRecord::frameSize() const
+{
+    return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+}
+
+// -------------------------------------------------------------------------
+
+status_t AudioRecord::start()
+{
+    status_t ret = NO_ERROR;
+    sp<ClientRecordThread> t = mClientRecordThread;
+
+    LOGV("start");
+
+    if (t != 0) {
+        if (t->exitPending()) {
+            if (t->requestExitAndWait() == WOULD_BLOCK) {
+                LOGE("AudioRecord::start called from thread");
+                return WOULD_BLOCK;
+            }
+        }
+        t->mLock.lock();
+     }
+
+    if (android_atomic_or(1, &mActive) == 0) {
+        mNewPosition = mCblk->user + mUpdatePeriod;
+        mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+        mCblk->waitTimeMs = 0;
+        if (t != 0) {
+           t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
+        } else {
+            setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+        }
+        ret = mAudioRecord->start();
+    }
+
+    if (t != 0) {
+        t->mLock.unlock();
+    }
+
+    return ret;
+}
+
+status_t AudioRecord::stop()
+{
+    sp<ClientRecordThread> t = mClientRecordThread;
+
+    LOGV("stop");
+
+    if (t != 0) {
+        t->mLock.lock();
+     }
+
+    if (android_atomic_and(~1, &mActive) == 1) {
+        mAudioRecord->stop();
+        if (t != 0) {
+            t->requestExit();
+        } else {
+            setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
+        }
+    }
+
+    if (t != 0) {
+        t->mLock.unlock();
+    }
+
+    return NO_ERROR;
+}
+
+bool AudioRecord::stopped() const
+{
+    return !mActive;
+}
+
+status_t AudioRecord::setMarkerPosition(uint32_t marker)
+{
+    if (mCbf == 0) return INVALID_OPERATION;
+
+    mMarkerPosition = marker;
+
+    return NO_ERROR;
+}
+
+status_t AudioRecord::getMarkerPosition(uint32_t *marker)
+{
+    if (marker == 0) return BAD_VALUE;
+
+    *marker = mMarkerPosition;
+
+    return NO_ERROR;
+}
+
+status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
+{
+    if (mCbf == 0) return INVALID_OPERATION;
+
+    uint32_t curPosition;
+    getPosition(&curPosition);
+    mNewPosition = curPosition + updatePeriod;
+    mUpdatePeriod = updatePeriod;
+
+    return NO_ERROR;
+}
+
+status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
+{
+    if (updatePeriod == 0) return BAD_VALUE;
+
+    *updatePeriod = mUpdatePeriod;
+
+    return NO_ERROR;
+}
+
+status_t AudioRecord::getPosition(uint32_t *position)
+{
+    if (position == 0) return BAD_VALUE;
+
+    *position = mCblk->user;
+
+    return NO_ERROR;
+}
+
+
+// -------------------------------------------------------------------------
+
+status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
+{
+    int active;
+    int timeout = 0;
+    status_t result;
+    audio_track_cblk_t* cblk = mCblk;
+    uint32_t framesReq = audioBuffer->frameCount;
+
+    audioBuffer->frameCount  = 0;
+    audioBuffer->size        = 0;
+
+    uint32_t framesReady = cblk->framesReady();
+
+    if (framesReady == 0) {
+        Mutex::Autolock _l(cblk->lock);
+        goto start_loop_here;
+        while (framesReady == 0) {
+            active = mActive;
+            if (UNLIKELY(!active))
+                return NO_MORE_BUFFERS;
+            if (UNLIKELY(!waitCount))
+                return WOULD_BLOCK;
+            timeout = 0;
+            result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS));
+            if (__builtin_expect(result!=NO_ERROR, false)) {
+                cblk->waitTimeMs += WAIT_PERIOD_MS;
+                if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
+                    LOGW(   "obtainBuffer timed out (is the CPU pegged?) "
+                            "user=%08x, server=%08x", cblk->user, cblk->server);
+                    timeout = 1;
+                    cblk->waitTimeMs = 0;
+                }
+                if (--waitCount == 0) {
+                    return TIMED_OUT;
+                }
+            }
+            // read the server count again
+        start_loop_here:
+            framesReady = cblk->framesReady();
+        }
+    }
+
+    LOGW_IF(timeout,
+        "*** SERIOUS WARNING *** obtainBuffer() timed out "
+        "but didn't need to be locked. We recovered, but "
+        "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
+
+    cblk->waitTimeMs = 0;
+    
+    if (framesReq > framesReady) {
+        framesReq = framesReady;
+    }
+
+    uint32_t u = cblk->user;
+    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+    if (u + framesReq > bufferEnd) {
+        framesReq = bufferEnd - u;
+    }
+
+    audioBuffer->flags       = 0;
+    audioBuffer->channelCount= mChannelCount;
+    audioBuffer->format      = mFormat;
+    audioBuffer->frameCount  = framesReq;
+    audioBuffer->size        = framesReq*mChannelCount*sizeof(int16_t);
+    audioBuffer->raw         = (int8_t*)cblk->buffer(u);
+    active = mActive;
+    return active ? status_t(NO_ERROR) : status_t(STOPPED);
+}
+
+void AudioRecord::releaseBuffer(Buffer* audioBuffer)
+{
+    audio_track_cblk_t* cblk = mCblk;
+    cblk->stepUser(audioBuffer->frameCount);
+}
+
+// -------------------------------------------------------------------------
+
+ssize_t AudioRecord::read(void* buffer, size_t userSize)
+{
+    ssize_t read = 0;
+    Buffer audioBuffer;
+    int8_t *dst = static_cast<int8_t*>(buffer);
+
+    if (ssize_t(userSize) < 0) {
+        // sanity-check. user is most-likely passing an error code.
+        LOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
+                buffer, userSize, userSize);
+        return BAD_VALUE;
+    }
+
+    LOGV("read size: %d", userSize);
+
+    do {
+
+        audioBuffer.frameCount = userSize/mChannelCount/sizeof(int16_t);
+
+        // Calling obtainBuffer() with a negative wait count causes
+        // an (almost) infinite wait time.
+        status_t err = obtainBuffer(&audioBuffer, -1);
+        if (err < 0) {
+            // out of buffers, return #bytes written
+            if (err == status_t(NO_MORE_BUFFERS))
+                break;
+            return ssize_t(err);
+        }
+
+        size_t bytesRead = audioBuffer.size;
+        memcpy(dst, audioBuffer.i8, bytesRead);
+
+        dst += bytesRead;
+        userSize -= bytesRead;
+        read += bytesRead;
+
+        releaseBuffer(&audioBuffer);
+    } while (userSize);
+
+    return read;
+}
+
+// -------------------------------------------------------------------------
+
+bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
+{
+    Buffer audioBuffer;
+    uint32_t frames = mRemainingFrames;
+    size_t readSize;
+
+    // Manage marker callback
+    if (mMarkerPosition > 0) {
+        if (mCblk->user >= mMarkerPosition) {
+            mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
+            mMarkerPosition = 0;
+        }
+    }
+
+    // Manage new position callback
+    if (mUpdatePeriod > 0) {
+        while (mCblk->user >= mNewPosition) {
+            mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
+            mNewPosition += mUpdatePeriod;
+        }
+    }
+
+    do {
+        audioBuffer.frameCount = frames;
+        // Calling obtainBuffer() with a wait count of 1 
+        // limits wait time to WAIT_PERIOD_MS. This prevents from being 
+        // stuck here not being able to handle timed events (position, markers).
+        status_t err = obtainBuffer(&audioBuffer, 1);
+        if (err < NO_ERROR) {
+            if (err != TIMED_OUT) {
+                LOGE("Error obtaining an audio buffer, giving up.");
+                return false;
+            }
+            break;
+        }
+        if (err == status_t(STOPPED)) return false;
+
+        size_t reqSize = audioBuffer.size;
+        mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
+        readSize = audioBuffer.size;
+
+        // Sanity check on returned size
+        if (ssize_t(readSize) <= 0) break;
+        if (readSize > reqSize) readSize = reqSize;
+
+        audioBuffer.size = readSize;
+        audioBuffer.frameCount = readSize/mChannelCount/sizeof(int16_t);
+        frames -= audioBuffer.frameCount;
+
+        releaseBuffer(&audioBuffer);
+
+    } while (frames);
+
+    
+    // Manage overrun callback
+    if (mActive && (mCblk->framesAvailable_l() == 0)) {
+        LOGV("Overrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
+        if (mCblk->flowControlFlag == 0) {
+            mCbf(EVENT_OVERRUN, mUserData, 0);
+            mCblk->flowControlFlag = 1;
+        }
+    }
+
+    if (frames == 0) {
+        mRemainingFrames = mNotificationFrames;
+    } else {
+        mRemainingFrames = frames;
+    }
+    return true;
+}
+
+// =========================================================================
+
+AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
+    : Thread(bCanCallJava), mReceiver(receiver)
+{
+}
+
+bool AudioRecord::ClientRecordThread::threadLoop()
+{
+    return mReceiver.processAudioBuffer(this);
+}
+
+// -------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
new file mode 100644
index 0000000..63dfc3b
--- /dev/null
+++ b/media/libmedia/AudioSystem.cpp
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2006-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 "AudioSystem"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/IServiceManager.h>
+#include <media/AudioSystem.h>
+#include <math.h>
+
+namespace android {
+
+// client singleton for AudioFlinger binder interface
+Mutex AudioSystem::gLock;
+sp<IAudioFlinger> AudioSystem::gAudioFlinger;
+sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
+audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
+// Cached values
+int AudioSystem::gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
+int AudioSystem::gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
+uint32_t AudioSystem::gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
+bool AudioSystem::gA2dpEnabled;
+// Cached values for recording queries
+uint32_t AudioSystem::gPrevInSamplingRate = 16000;
+int AudioSystem::gPrevInFormat = AudioSystem::PCM_16_BIT;
+int AudioSystem::gPrevInChannelCount = 1;
+size_t AudioSystem::gInBuffSize = 0;
+
+
+// establish binder interface to AudioFlinger service
+const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
+{
+    Mutex::Autolock _l(gLock);
+    if (gAudioFlinger.get() == 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16("media.audio_flinger"));
+            if (binder != 0)
+                break;
+            LOGW("AudioFlinger not published, waiting...");
+            usleep(500000); // 0.5 s
+        } while(true);
+        if (gAudioFlingerClient == NULL) {
+            gAudioFlingerClient = new AudioFlingerClient();
+        } else {
+            if (gAudioErrorCallback) {
+                gAudioErrorCallback(NO_ERROR);
+            }
+         }
+        binder->linkToDeath(gAudioFlingerClient);
+        gAudioFlinger = interface_cast<IAudioFlinger>(binder);
+        gAudioFlinger->registerClient(gAudioFlingerClient);
+        // Cache frequently accessed parameters 
+        for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
+            gOutFrameCount[output] = (int)gAudioFlinger->frameCount(output);
+            gOutSamplingRate[output] = (int)gAudioFlinger->sampleRate(output);
+            gOutLatency[output] = gAudioFlinger->latency(output);
+        }
+        gA2dpEnabled = gAudioFlinger->isA2dpEnabled();
+    }
+    LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");
+    return gAudioFlinger;
+}
+
+// routing helper functions
+status_t AudioSystem::speakerphone(bool state) {
+    uint32_t routes = state ? ROUTE_SPEAKER : ROUTE_EARPIECE;
+    return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
+}
+
+status_t AudioSystem::isSpeakerphoneOn(bool* state) {
+    uint32_t routes = 0;
+    status_t s = getRouting(MODE_IN_CALL, &routes);
+    *state = !!(routes & ROUTE_SPEAKER);
+    return s;
+}
+
+status_t AudioSystem::bluetoothSco(bool state) {
+    uint32_t mask = ROUTE_BLUETOOTH_SCO;
+    uint32_t routes = state ? mask : ROUTE_EARPIECE;
+    return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
+}
+
+status_t AudioSystem::isBluetoothScoOn(bool* state) {
+    uint32_t routes = 0;
+    status_t s = getRouting(MODE_IN_CALL, &routes);
+    *state = !!(routes & ROUTE_BLUETOOTH_SCO);
+    return s;
+}
+
+status_t AudioSystem::muteMicrophone(bool state) {
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->setMicMute(state);
+}
+
+status_t AudioSystem::isMicrophoneMuted(bool* state) {
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    *state = af->getMicMute();
+    return NO_ERROR;
+}
+
+status_t AudioSystem::setMasterVolume(float value)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    af->setMasterVolume(value);
+    return NO_ERROR;
+}
+
+status_t AudioSystem::setMasterMute(bool mute)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    af->setMasterMute(mute);
+    return NO_ERROR;
+}
+
+status_t AudioSystem::getMasterVolume(float* volume)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    *volume = af->masterVolume();
+    return NO_ERROR;
+}
+
+status_t AudioSystem::getMasterMute(bool* mute)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    *mute = af->masterMute();
+    return NO_ERROR;
+}
+
+status_t AudioSystem::setStreamVolume(int stream, float value)
+{
+    if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    af->setStreamVolume(stream, value);
+    return NO_ERROR;
+}
+
+status_t AudioSystem::setStreamMute(int stream, bool mute)
+{
+    if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    af->setStreamMute(stream, mute);
+    return NO_ERROR;
+}
+
+status_t AudioSystem::getStreamVolume(int stream, float* volume)
+{
+    if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    *volume = af->streamVolume(stream);
+    return NO_ERROR;
+}
+
+status_t AudioSystem::getStreamMute(int stream, bool* mute)
+{
+    if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    *mute = af->streamMute(stream);
+    return NO_ERROR;
+}
+
+status_t AudioSystem::setMode(int mode)
+{
+    if (mode >= NUM_MODES) return BAD_VALUE;
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->setMode(mode);
+}
+
+status_t AudioSystem::getMode(int* mode)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    *mode = af->getMode();
+    return NO_ERROR;
+}
+
+status_t AudioSystem::setRouting(int mode, uint32_t routes, uint32_t mask)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->setRouting(mode, routes, mask);
+}
+
+status_t AudioSystem::getRouting(int mode, uint32_t* routes)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    uint32_t r = af->getRouting(mode);
+    *routes = r;
+    return NO_ERROR;
+}
+
+status_t AudioSystem::isMusicActive(bool* state) {
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    *state = af->isMusicActive();
+    return NO_ERROR;
+}
+
+// Temporary interface, do not use
+// TODO: Replace with a more generic key:value get/set mechanism
+status_t AudioSystem::setParameter(const char* key, const char* value) {
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->setParameter(key, value);
+}
+
+// convert volume steps to natural log scale
+
+// change this value to change volume scaling
+static const float dBPerStep = 0.5f;
+// shouldn't need to touch these
+static const float dBConvert = -dBPerStep * 2.302585093f / 20.0f;
+static const float dBConvertInverse = 1.0f / dBConvert;
+
+float AudioSystem::linearToLog(int volume)
+{
+    // float v = volume ? exp(float(100 - volume) * dBConvert) : 0;
+    // LOGD("linearToLog(%d)=%f", volume, v);
+    // return v;
+    return volume ? exp(float(100 - volume) * dBConvert) : 0;
+}
+
+int AudioSystem::logToLinear(float volume)
+{
+    // int v = volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0;
+    // LOGD("logTolinear(%d)=%f", v, volume);
+    // return v;
+    return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0;
+}
+
+status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
+{
+    int output = getOutput(streamType);
+
+    if (gOutSamplingRate[output] == 0) {
+        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+        if (af == 0) return PERMISSION_DENIED;
+        // gOutSamplingRate is updated by get_audio_flinger()
+    }
+    LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, gOutSamplingRate[output]);
+    *samplingRate = gOutSamplingRate[output];
+    
+    return NO_ERROR;
+}
+
+status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType)
+{
+    int output = getOutput(streamType);
+
+    if (gOutFrameCount[output] == 0) {
+        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+        if (af == 0) return PERMISSION_DENIED;
+        // gOutFrameCount is updated by get_audio_flinger()
+    }
+    LOGV("getOutputFrameCount() streamType %d, output %d, frame count %d", streamType, output, gOutFrameCount[output]);
+
+    *frameCount = gOutFrameCount[output];
+    return NO_ERROR;
+}
+
+status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType)
+{
+    int output = getOutput(streamType);
+
+    if (gOutLatency[output] == 0) {
+        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+        if (af == 0) return PERMISSION_DENIED;
+        // gOutLatency is updated by get_audio_flinger()
+    }
+    LOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, gOutLatency[output]);
+
+    *latency = gOutLatency[output];
+    
+    return NO_ERROR;
+}
+
+status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount, 
+    size_t* buffSize)
+{
+    // Do we have a stale gInBufferSize or are we requesting the input buffer size for new values
+    if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat) 
+        || (channelCount != gPrevInChannelCount)) {
+        // save the request params
+        gPrevInSamplingRate = sampleRate;
+        gPrevInFormat = format; 
+        gPrevInChannelCount = channelCount;
+
+        gInBuffSize = 0;
+        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+        if (af == 0) {
+            return PERMISSION_DENIED;
+        }
+        gInBuffSize = af->getInputBufferSize(sampleRate, format, channelCount);
+    } 
+    *buffSize = gInBuffSize;
+    
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
+void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {   
+    Mutex::Autolock _l(AudioSystem::gLock);
+    AudioSystem::gAudioFlinger.clear();
+
+    for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
+        gOutFrameCount[output] = 0;
+        gOutSamplingRate[output] = 0;
+        gOutLatency[output] = 0;
+    }
+    AudioSystem::gInBuffSize = 0;
+
+    if (gAudioErrorCallback) {
+        gAudioErrorCallback(DEAD_OBJECT);
+    }
+    LOGW("AudioFlinger server died!");
+}
+
+void AudioSystem::AudioFlingerClient::a2dpEnabledChanged(bool enabled) {
+    gA2dpEnabled = enabled;        
+    LOGV("AudioFlinger A2DP enabled status changed! %d", enabled);
+}
+
+void AudioSystem::setErrorCallback(audio_error_callback cb) {
+    Mutex::Autolock _l(AudioSystem::gLock);
+    gAudioErrorCallback = cb;
+}
+
+int AudioSystem::getOutput(int streamType)
+{  
+    if (streamType == DEFAULT) {
+        streamType = MUSIC;
+    }
+    if (gA2dpEnabled && routedToA2dpOutput(streamType)) {
+        return AUDIO_OUTPUT_A2DP;
+    } else {
+        return AUDIO_OUTPUT_HARDWARE;
+    }
+}
+
+bool AudioSystem::routedToA2dpOutput(int streamType) {
+    switch(streamType) {
+    case MUSIC:
+    case VOICE_CALL:
+    case BLUETOOTH_SCO:
+    case SYSTEM:
+        return true;
+    default:
+        return false;
+    }
+}
+
+
+
+}; // namespace android
+
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
new file mode 100644
index 0000000..e79f336
--- /dev/null
+++ b/media/libmedia/AudioTrack.cpp
@@ -0,0 +1,1021 @@
+/* //device/extlibs/pv/android/AudioTrack.cpp
+**
+** 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_NDEBUG 0
+#define LOG_TAG "AudioTrack"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <private/media/AudioTrackShared.h>
+
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+
+#include <utils/Log.h>
+#include <utils/MemoryDealer.h>
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Timers.h>
+#include <cutils/atomic.h>
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+AudioTrack::AudioTrack()
+    : mStatus(NO_INIT)
+{
+}
+
+AudioTrack::AudioTrack(
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        uint32_t flags,
+        callback_t cbf,
+        void* user,
+        int notificationFrames)
+    : mStatus(NO_INIT)
+{
+    mStatus = set(streamType, sampleRate, format, channelCount,
+            frameCount, flags, cbf, user, notificationFrames, 0);
+}
+
+AudioTrack::AudioTrack(
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        const sp<IMemory>& sharedBuffer,
+        uint32_t flags,
+        callback_t cbf,
+        void* user,
+        int notificationFrames)
+    : mStatus(NO_INIT)
+{
+    mStatus = set(streamType, sampleRate, format, channelCount,
+            0, flags, cbf, user, notificationFrames, sharedBuffer);
+}
+
+AudioTrack::~AudioTrack()
+{
+    LOGV_IF(mSharedBuffer != 0, "Destructor sharedBuffer: %p", mSharedBuffer->pointer());
+
+    if (mStatus == NO_ERROR) {
+        // Make sure that callback function exits in the case where
+        // it is looping on buffer full condition in obtainBuffer().
+        // Otherwise the callback thread will never exit.
+        stop();
+        if (mAudioTrackThread != 0) {
+            mCblk->cv.signal();
+            mAudioTrackThread->requestExitAndWait();
+            mAudioTrackThread.clear();
+        }
+        mAudioTrack.clear();
+        IPCThreadState::self()->flushCommands();
+    }
+}
+
+status_t AudioTrack::set(
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        uint32_t flags,
+        callback_t cbf,
+        void* user,
+        int notificationFrames,
+        const sp<IMemory>& sharedBuffer,
+        bool threadCanCallJava)
+{
+
+    LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
+
+    if (mAudioFlinger != 0) {
+        LOGE("Track already in use");
+        return INVALID_OPERATION;
+    }
+
+    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+    if (audioFlinger == 0) {
+       LOGE("Could not get audioflinger");
+       return NO_INIT;
+    }
+    int afSampleRate;
+    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
+        return NO_INIT;
+    }
+    int afFrameCount;
+    if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
+        return NO_INIT;
+    }
+    uint32_t afLatency;
+    if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
+        return NO_INIT;
+    }
+
+    // handle default values first.
+    if (streamType == AudioSystem::DEFAULT) {
+        streamType = AudioSystem::MUSIC;
+    }
+    if (sampleRate == 0) {
+        sampleRate = afSampleRate;
+    }
+    // these below should probably come from the audioFlinger too...
+    if (format == 0) {
+        format = AudioSystem::PCM_16_BIT;
+    }
+    if (channelCount == 0) {
+        channelCount = 2;
+    }
+
+    // validate parameters
+    if (((format != AudioSystem::PCM_8_BIT) || sharedBuffer != 0) &&
+        (format != AudioSystem::PCM_16_BIT)) {
+        LOGE("Invalid format");
+        return BAD_VALUE;
+    }
+    if (channelCount != 1 && channelCount != 2) {
+        LOGE("Invalid channel number");
+        return BAD_VALUE;
+    }
+
+    // Ensure that buffer depth covers at least audio hardware latency
+    uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
+    if (minBufCount < 2) minBufCount = 2;
+
+    // When playing from shared buffer, playback will start even if last audioflinger
+    // block is partly filled.
+    if (sharedBuffer != 0 && minBufCount > 1) {
+        minBufCount--;
+    }
+
+    int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
+
+    if (sharedBuffer == 0) {
+        if (frameCount == 0) {
+            frameCount = minFrameCount;
+        }
+        if (notificationFrames == 0) {
+            notificationFrames = frameCount/2;
+        }
+        // Make sure that application is notified with sufficient margin
+        // before underrun
+        if (notificationFrames > frameCount/2) {
+            notificationFrames = frameCount/2;
+        }
+    } else {
+        // Ensure that buffer alignment matches channelcount
+        if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
+            LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
+            return BAD_VALUE;
+        }
+        frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
+    }
+
+    if (frameCount < minFrameCount) {
+      LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
+      return BAD_VALUE;
+    }
+
+    // create the track
+    status_t status;
+    sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
+                streamType, sampleRate, format, channelCount, frameCount, flags, sharedBuffer, &status);
+
+    if (track == 0) {
+        LOGE("AudioFlinger could not create track, status: %d", status);
+        return status;
+    }
+    sp<IMemory> cblk = track->getCblk();
+    if (cblk == 0) {
+        LOGE("Could not get control block");
+        return NO_INIT;
+    }
+    if (cbf != 0) {
+        mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
+        if (mAudioTrackThread == 0) {
+          LOGE("Could not create callback thread");
+          return NO_INIT;
+        }
+    }
+
+    mStatus = NO_ERROR;
+
+    mAudioFlinger = audioFlinger;
+    mAudioTrack = track;
+    mCblkMemory = cblk;
+    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
+    mCblk->out = 1;
+    // Update buffer size in case it has been limited by AudioFlinger during track creation
+    mFrameCount = mCblk->frameCount;
+    if (sharedBuffer == 0) {
+        mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+    } else {
+        mCblk->buffers = sharedBuffer->pointer();
+         // Force buffer full condition as data is already present in shared memory
+        mCblk->stepUser(mFrameCount);
+    }
+    mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+    mVolume[LEFT] = 1.0f;
+    mVolume[RIGHT] = 1.0f;
+    mSampleRate = sampleRate;
+    mStreamType = streamType;
+    mFormat = format;
+    mChannelCount = channelCount;
+    mSharedBuffer = sharedBuffer;
+    mMuted = false;
+    mActive = 0;
+    mCbf = cbf;
+    mNotificationFrames = notificationFrames;
+    mRemainingFrames = notificationFrames;
+    mUserData = user;
+    mLatency = afLatency + (1000*mFrameCount) / mSampleRate;
+    mLoopCount = 0;
+    mMarkerPosition = 0;
+    mNewPosition = 0;
+    mUpdatePeriod = 0;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::initCheck() const
+{
+    return mStatus;
+}
+
+// -------------------------------------------------------------------------
+
+uint32_t AudioTrack::latency() const
+{
+    return mLatency;
+}
+
+int AudioTrack::streamType() const
+{
+    return mStreamType;
+}
+
+uint32_t AudioTrack::sampleRate() const
+{
+    return mSampleRate;
+}
+
+int AudioTrack::format() const
+{
+    return mFormat;
+}
+
+int AudioTrack::channelCount() const
+{
+    return mChannelCount;
+}
+
+uint32_t AudioTrack::frameCount() const
+{
+    return mFrameCount;
+}
+
+int AudioTrack::frameSize() const
+{
+    return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+}
+
+sp<IMemory>& AudioTrack::sharedBuffer()
+{
+    return mSharedBuffer;
+}
+
+// -------------------------------------------------------------------------
+
+void AudioTrack::start()
+{
+    sp<AudioTrackThread> t = mAudioTrackThread;
+
+    LOGV("start %p", this);
+    if (t != 0) {
+        if (t->exitPending()) {
+            if (t->requestExitAndWait() == WOULD_BLOCK) {
+                LOGE("AudioTrack::start called from thread");
+                return;
+            }
+        }
+        t->mLock.lock();
+     }
+
+    if (android_atomic_or(1, &mActive) == 0) {
+        mNewPosition = mCblk->server + mUpdatePeriod;
+        mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
+        mCblk->waitTimeMs = 0;
+        if (t != 0) {
+           t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
+        } else {
+            setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+        }
+        mAudioTrack->start();
+    }
+
+    if (t != 0) {
+        t->mLock.unlock();
+    }
+}
+
+void AudioTrack::stop()
+{
+    sp<AudioTrackThread> t = mAudioTrackThread;
+
+    LOGV("stop %p", this);
+    if (t != 0) {
+        t->mLock.lock();
+    }
+
+    if (android_atomic_and(~1, &mActive) == 1) {
+        mAudioTrack->stop();
+        // Cancel loops (If we are in the middle of a loop, playback
+        // would not stop until loopCount reaches 0).
+        setLoop(0, 0, 0);
+        // Force flush if a shared buffer is used otherwise audioflinger
+        // will not stop before end of buffer is reached.
+        if (mSharedBuffer != 0) {
+            flush();
+        }
+        if (t != 0) {
+            t->requestExit();
+        } else {
+            setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
+        }
+    }
+
+    if (t != 0) {
+        t->mLock.unlock();
+    }
+}
+
+bool AudioTrack::stopped() const
+{
+    return !mActive;
+}
+
+void AudioTrack::flush()
+{
+    LOGV("flush");
+
+    if (!mActive) {
+        mCblk->lock.lock();
+        mAudioTrack->flush();
+        // Release AudioTrack callback thread in case it was waiting for new buffers
+        // in AudioTrack::obtainBuffer()
+        mCblk->cv.signal();
+        mCblk->lock.unlock();
+    }
+}
+
+void AudioTrack::pause()
+{
+    LOGV("pause");
+    if (android_atomic_and(~1, &mActive) == 1) {
+        mActive = 0;
+        mAudioTrack->pause();
+    }
+}
+
+void AudioTrack::mute(bool e)
+{
+    mAudioTrack->mute(e);
+    mMuted = e;
+}
+
+bool AudioTrack::muted() const
+{
+    return mMuted;
+}
+
+void AudioTrack::setVolume(float left, float right)
+{
+    mVolume[LEFT] = left;
+    mVolume[RIGHT] = right;
+
+    // write must be atomic
+    mCblk->volumeLR = (int32_t(int16_t(left * 0x1000)) << 16) | int16_t(right * 0x1000);
+}
+
+void AudioTrack::getVolume(float* left, float* right)
+{
+    *left  = mVolume[LEFT];
+    *right = mVolume[RIGHT];
+}
+
+void AudioTrack::setSampleRate(int rate)
+{
+    int afSamplingRate;
+
+    if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
+        return;
+    }
+    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+    if (rate <= 0) rate = 1;
+    if (rate > afSamplingRate*2) rate = afSamplingRate*2;
+    if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE;
+
+    mCblk->sampleRate = rate;
+}
+
+uint32_t AudioTrack::getSampleRate()
+{
+    return uint32_t(mCblk->sampleRate);
+}
+
+status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
+{
+    audio_track_cblk_t* cblk = mCblk;
+
+
+    Mutex::Autolock _l(cblk->lock);
+
+    if (loopCount == 0) {
+        cblk->loopStart = UINT_MAX;
+        cblk->loopEnd = UINT_MAX;
+        cblk->loopCount = 0;
+        mLoopCount = 0;
+        return NO_ERROR;
+    }
+
+    if (loopStart >= loopEnd ||
+        loopEnd - loopStart > mFrameCount) {
+        LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user);
+        return BAD_VALUE;
+    }
+
+    if ((mSharedBuffer != 0) && (loopEnd   > mFrameCount)) {
+        LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
+            loopStart, loopEnd, mFrameCount);
+        return BAD_VALUE;
+    }   
+
+    cblk->loopStart = loopStart;
+    cblk->loopEnd = loopEnd;
+    cblk->loopCount = loopCount;
+    mLoopCount = loopCount;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount)
+{
+    if (loopStart != 0) {
+        *loopStart = mCblk->loopStart;
+    }
+    if (loopEnd != 0) {
+        *loopEnd = mCblk->loopEnd;
+    }
+    if (loopCount != 0) {
+        if (mCblk->loopCount < 0) {
+            *loopCount = -1;
+        } else {
+            *loopCount = mCblk->loopCount;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::setMarkerPosition(uint32_t marker)
+{
+    if (mCbf == 0) return INVALID_OPERATION;
+
+    mMarkerPosition = marker;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::getMarkerPosition(uint32_t *marker)
+{
+    if (marker == 0) return BAD_VALUE;
+
+    *marker = mMarkerPosition;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
+{
+    if (mCbf == 0) return INVALID_OPERATION;
+
+    uint32_t curPosition;
+    getPosition(&curPosition);
+    mNewPosition = curPosition + updatePeriod;
+    mUpdatePeriod = updatePeriod;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod)
+{
+    if (updatePeriod == 0) return BAD_VALUE;
+
+    *updatePeriod = mUpdatePeriod;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::setPosition(uint32_t position)
+{
+    Mutex::Autolock _l(mCblk->lock);
+
+    if (!stopped()) return INVALID_OPERATION;
+
+    if (position > mCblk->user) return BAD_VALUE;
+
+    mCblk->server = position;
+    mCblk->forceReady = 1;
+    
+    return NO_ERROR;
+}
+
+status_t AudioTrack::getPosition(uint32_t *position)
+{
+    if (position == 0) return BAD_VALUE;
+
+    *position = mCblk->server;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::reload()
+{
+    if (!stopped()) return INVALID_OPERATION;
+    
+    flush();
+
+    mCblk->stepUser(mFrameCount);
+
+    return NO_ERROR;
+}
+
+// -------------------------------------------------------------------------
+
+status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
+{
+    int active;
+    int timeout = 0;
+    status_t result;
+    audio_track_cblk_t* cblk = mCblk;
+    uint32_t framesReq = audioBuffer->frameCount;
+
+    audioBuffer->frameCount  = 0;
+    audioBuffer->size = 0;
+
+    uint32_t framesAvail = cblk->framesAvailable();
+
+    if (framesAvail == 0) {
+        Mutex::Autolock _l(cblk->lock);
+        goto start_loop_here;
+        while (framesAvail == 0) {
+            active = mActive;
+            if (UNLIKELY(!active)) {
+                LOGV("Not active and NO_MORE_BUFFERS");
+                return NO_MORE_BUFFERS;
+            }
+            if (UNLIKELY(!waitCount))
+                return WOULD_BLOCK;
+            timeout = 0;
+            result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS));
+            if (__builtin_expect(result!=NO_ERROR, false)) { 
+                cblk->waitTimeMs += WAIT_PERIOD_MS;
+                if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
+                    // timing out when a loop has been set and we have already written upto loop end
+                    // is a normal condition: no need to wake AudioFlinger up.
+                    if (cblk->user < cblk->loopEnd) {
+                        LOGW(   "obtainBuffer timed out (is the CPU pegged?) %p "
+                                "user=%08x, server=%08x", this, cblk->user, cblk->server);
+                        //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140) 
+                        cblk->lock.unlock();
+                        mAudioTrack->start();
+                        cblk->lock.lock();
+                        timeout = 1;
+                    }
+                    cblk->waitTimeMs = 0;
+                }
+                
+                if (--waitCount == 0) {
+                    return TIMED_OUT;
+                }
+            }
+            // read the server count again
+        start_loop_here:
+            framesAvail = cblk->framesAvailable_l();
+        }
+    }
+
+    cblk->waitTimeMs = 0;
+    
+    if (framesReq > framesAvail) {
+        framesReq = framesAvail;
+    }
+
+    uint32_t u = cblk->user;
+    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+    if (u + framesReq > bufferEnd) {
+        framesReq = bufferEnd - u;
+    }
+
+    LOGW_IF(timeout,
+        "*** SERIOUS WARNING *** obtainBuffer() timed out "
+        "but didn't need to be locked. We recovered, but "
+        "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
+
+    audioBuffer->flags       = mMuted ? Buffer::MUTE : 0;
+    audioBuffer->channelCount= mChannelCount;
+    audioBuffer->format      = AudioSystem::PCM_16_BIT;
+    audioBuffer->frameCount  = framesReq;
+    audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t);
+    audioBuffer->raw         = (int8_t *)cblk->buffer(u);
+    active = mActive;
+    return active ? status_t(NO_ERROR) : status_t(STOPPED);
+}
+
+void AudioTrack::releaseBuffer(Buffer* audioBuffer)
+{
+    audio_track_cblk_t* cblk = mCblk;
+    cblk->stepUser(audioBuffer->frameCount);
+}
+
+// -------------------------------------------------------------------------
+
+ssize_t AudioTrack::write(const void* buffer, size_t userSize)
+{
+
+    if (mSharedBuffer != 0) return INVALID_OPERATION;
+
+    if (ssize_t(userSize) < 0) {
+        // sanity-check. user is most-likely passing an error code.
+        LOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
+                buffer, userSize, userSize);
+        return BAD_VALUE;
+    }
+
+    LOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive);
+
+    ssize_t written = 0;
+    const int8_t *src = (const int8_t *)buffer;
+    Buffer audioBuffer;
+
+    do {
+        audioBuffer.frameCount = userSize/mChannelCount;
+        if (mFormat == AudioSystem::PCM_16_BIT) {
+            audioBuffer.frameCount >>= 1;
+        }
+        // Calling obtainBuffer() with a negative wait count causes
+        // an (almost) infinite wait time.
+        status_t err = obtainBuffer(&audioBuffer, -1);
+        if (err < 0) {
+            // out of buffers, return #bytes written
+            if (err == status_t(NO_MORE_BUFFERS))
+                break;
+            return ssize_t(err);
+        }
+
+        size_t toWrite;
+        if (mFormat == AudioSystem::PCM_8_BIT) {
+            // Divide capacity by 2 to take expansion into account
+            toWrite = audioBuffer.size>>1;
+            // 8 to 16 bit conversion
+            int count = toWrite;
+            int16_t *dst = (int16_t *)(audioBuffer.i8);
+            while(count--) {
+                *dst++ = (int16_t)(*src++^0x80) << 8;
+            }
+        }else {
+            toWrite = audioBuffer.size;
+            memcpy(audioBuffer.i8, src, toWrite);
+            src += toWrite;
+        }
+        userSize -= toWrite;
+        written += toWrite;
+
+        releaseBuffer(&audioBuffer);
+    } while (userSize);
+
+    return written;
+}
+
+// -------------------------------------------------------------------------
+
+bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
+{
+    Buffer audioBuffer;
+    uint32_t frames;
+    size_t writtenSize;
+
+    // Manage underrun callback
+    if (mActive && (mCblk->framesReady() == 0)) {
+        LOGV("Underrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
+        if (mCblk->flowControlFlag == 0) {
+            mCbf(EVENT_UNDERRUN, mUserData, 0);
+            if (mCblk->server == mCblk->frameCount) {
+                mCbf(EVENT_BUFFER_END, mUserData, 0);                
+            }
+            mCblk->flowControlFlag = 1;
+            if (mSharedBuffer != 0) return false;
+        }
+    }
+    
+    // Manage loop end callback
+    while (mLoopCount > mCblk->loopCount) {
+        int loopCount = -1;
+        mLoopCount--;
+        if (mLoopCount >= 0) loopCount = mLoopCount;
+
+        mCbf(EVENT_LOOP_END, mUserData, (void *)&loopCount);
+    }
+
+    // Manage marker callback
+    if(mMarkerPosition > 0) {
+        if (mCblk->server >= mMarkerPosition) {
+            mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
+            mMarkerPosition = 0;
+        }
+    }
+
+    // Manage new position callback
+    if(mUpdatePeriod > 0) {
+        while (mCblk->server >= mNewPosition) {
+            mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
+            mNewPosition += mUpdatePeriod;
+        }
+    }
+
+    // If Shared buffer is used, no data is requested from client.
+    if (mSharedBuffer != 0) {
+        frames = 0;
+    } else {
+        frames = mRemainingFrames;
+    }
+
+    do {
+
+        audioBuffer.frameCount = frames;
+        
+        // Calling obtainBuffer() with a wait count of 1 
+        // limits wait time to WAIT_PERIOD_MS. This prevents from being 
+        // stuck here not being able to handle timed events (position, markers, loops). 
+        status_t err = obtainBuffer(&audioBuffer, 1);
+        if (err < NO_ERROR) {
+            if (err != TIMED_OUT) {
+                LOGE("Error obtaining an audio buffer, giving up.");
+                return false;
+            }
+            break;
+        }
+        if (err == status_t(STOPPED)) return false;
+
+        // Divide buffer size by 2 to take into account the expansion
+        // due to 8 to 16 bit conversion: the callback must fill only half
+        // of the destination buffer
+        if (mFormat == AudioSystem::PCM_8_BIT) {
+            audioBuffer.size >>= 1;
+        }
+
+        size_t reqSize = audioBuffer.size;
+        mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
+        writtenSize = audioBuffer.size;
+
+        // Sanity check on returned size
+        if (ssize_t(writtenSize) <= 0) break;
+        if (writtenSize > reqSize) writtenSize = reqSize;
+
+        if (mFormat == AudioSystem::PCM_8_BIT) {
+            // 8 to 16 bit conversion
+            const int8_t *src = audioBuffer.i8 + writtenSize-1;
+            int count = writtenSize;
+            int16_t *dst = audioBuffer.i16 + writtenSize-1;
+            while(count--) {
+                *dst-- = (int16_t)(*src--^0x80) << 8;
+            }
+            writtenSize <<= 1;
+        }
+
+        audioBuffer.size = writtenSize;
+        audioBuffer.frameCount = writtenSize/mChannelCount/sizeof(int16_t);
+        frames -= audioBuffer.frameCount;
+
+        releaseBuffer(&audioBuffer);
+    }
+    while (frames);
+
+    if (frames == 0) {
+        mRemainingFrames = mNotificationFrames;
+    } else {
+        mRemainingFrames = frames;
+    }
+    return true;
+}
+
+status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
+{
+
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    result.append(" AudioTrack::dump\n");
+    snprintf(buffer, 255, "  stream type(%d), left - right volume(%f, %f)\n", mStreamType, mVolume[0], mVolume[1]);
+    result.append(buffer);
+    snprintf(buffer, 255, "  format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mFrameCount);
+    result.append(buffer);
+    snprintf(buffer, 255, "  sample rate(%d), status(%d), muted(%d)\n", mSampleRate, mStatus, mMuted);
+    result.append(buffer);
+    snprintf(buffer, 255, "  active(%d), latency (%d)\n", mActive, mLatency);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// =========================================================================
+
+AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
+    : Thread(bCanCallJava), mReceiver(receiver)
+{
+}
+
+bool AudioTrack::AudioTrackThread::threadLoop()
+{
+    return mReceiver.processAudioBuffer(this);
+}
+
+status_t AudioTrack::AudioTrackThread::readyToRun()
+{
+    return NO_ERROR;
+}
+
+void AudioTrack::AudioTrackThread::onFirstRef()
+{
+}
+
+// =========================================================================
+
+audio_track_cblk_t::audio_track_cblk_t()
+    : user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
+    loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), flowControlFlag(1), forceReady(0)
+{
+}
+
+uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)
+{
+    uint32_t u = this->user;
+
+    u += frameCount;
+    // Ensure that user is never ahead of server for AudioRecord
+    if (out) {
+        // If stepServer() has been called once, switch to normal obtainBuffer() timeout period
+        if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) {
+            bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+        }
+    } else if (u > this->server) {
+        LOGW("stepServer occured after track reset");
+        u = this->server;
+    }
+
+    if (u >= userBase + this->frameCount) {
+        userBase += this->frameCount;
+    }
+
+    this->user = u;
+
+    // Clear flow control error condition as new data has been written/read to/from buffer.
+    flowControlFlag = 0;
+
+    return u;
+}
+
+bool audio_track_cblk_t::stepServer(uint32_t frameCount)
+{
+    // the code below simulates lock-with-timeout
+    // we MUST do this to protect the AudioFlinger server
+    // as this lock is shared with the client.
+    status_t err;
+
+    err = lock.tryLock();
+    if (err == -EBUSY) { // just wait a bit
+        usleep(1000);
+        err = lock.tryLock();
+    }
+    if (err != NO_ERROR) {
+        // probably, the client just died.
+        return false;
+    }
+
+    uint32_t s = this->server;
+
+    s += frameCount;
+    if (out) {
+        // Mark that we have read the first buffer so that next time stepUser() is called
+        // we switch to normal obtainBuffer() timeout period
+        if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
+            bufferTimeoutMs = MAX_RUN_TIMEOUT_MS - 1;
+        }        
+        // It is possible that we receive a flush()
+        // while the mixer is processing a block: in this case,
+        // stepServer() is called After the flush() has reset u & s and
+        // we have s > u
+        if (s > this->user) {
+            LOGW("stepServer occured after track reset");
+            s = this->user;
+        }
+    }
+
+    if (s >= loopEnd) {
+        LOGW_IF(s > loopEnd, "stepServer: s %u > loopEnd %u", s, loopEnd);
+        s = loopStart;
+        if (--loopCount == 0) {
+            loopEnd = UINT_MAX;
+            loopStart = UINT_MAX;
+        }
+    }
+    if (s >= serverBase + this->frameCount) {
+        serverBase += this->frameCount;
+    }
+
+    this->server = s;
+
+    cv.signal();
+    lock.unlock();
+    return true;
+}
+
+void* audio_track_cblk_t::buffer(uint32_t offset) const
+{
+    return (int16_t *)this->buffers + (offset-userBase)*this->channels;
+}
+
+uint32_t audio_track_cblk_t::framesAvailable()
+{
+    Mutex::Autolock _l(lock);
+    return framesAvailable_l();
+}
+
+uint32_t audio_track_cblk_t::framesAvailable_l()
+{
+    uint32_t u = this->user;
+    uint32_t s = this->server;
+
+    if (out) {
+        uint32_t limit = (s < loopStart) ? s : loopStart;
+        return limit + frameCount - u;
+    } else {
+        return frameCount + u - s;
+    }
+}
+
+uint32_t audio_track_cblk_t::framesReady()
+{
+    uint32_t u = this->user;
+    uint32_t s = this->server;
+
+    if (out) {
+        if (u < loopEnd) {
+            return u - s;
+        } else {
+            Mutex::Autolock _l(lock);
+            if (loopCount >= 0) {
+                return (loopEnd - loopStart)*loopCount + u - s;
+            } else {
+                return UINT_MAX;
+            }
+        }
+    } else {
+        return s - u;
+    }
+}
+
+// -------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
new file mode 100644
index 0000000..5cbb25c
--- /dev/null
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -0,0 +1,553 @@
+/* //device/extlibs/pv/android/IAudioflinger.cpp
+**
+** 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 "IAudioFlinger"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioFlinger.h>
+
+namespace android {
+
+enum {
+    CREATE_TRACK = IBinder::FIRST_CALL_TRANSACTION,
+    OPEN_RECORD,
+    SAMPLE_RATE,
+    CHANNEL_COUNT,
+    FORMAT,
+    FRAME_COUNT,
+    LATENCY,
+    SET_MASTER_VOLUME,
+    SET_MASTER_MUTE,
+    MASTER_VOLUME,
+    MASTER_MUTE,
+    SET_STREAM_VOLUME,
+    SET_STREAM_MUTE,
+    STREAM_VOLUME,
+    STREAM_MUTE,
+    SET_MODE,
+    GET_MODE,
+    SET_ROUTING,
+    GET_ROUTING,
+    SET_MIC_MUTE,
+    GET_MIC_MUTE,
+    IS_MUSIC_ACTIVE,
+    SET_PARAMETER,
+    REGISTER_CLIENT,
+    GET_INPUTBUFFERSIZE,
+    WAKE_UP,
+    IS_A2DP_ENABLED
+};
+
+class BpAudioFlinger : public BpInterface<IAudioFlinger>
+{
+public:
+    BpAudioFlinger(const sp<IBinder>& impl)
+        : BpInterface<IAudioFlinger>(impl)
+    {
+    }
+
+    virtual sp<IAudioTrack> createTrack(
+                                pid_t pid,
+                                int streamType,
+                                uint32_t sampleRate,
+                                int format,
+                                int channelCount,
+                                int frameCount,
+                                uint32_t flags,
+                                const sp<IMemory>& sharedBuffer,
+                                status_t *status)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        data.writeInt32(streamType);
+        data.writeInt32(sampleRate);
+        data.writeInt32(format);
+        data.writeInt32(channelCount);
+        data.writeInt32(frameCount);
+        data.writeInt32(flags);
+        data.writeStrongBinder(sharedBuffer->asBinder());
+        status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
+        if (lStatus != NO_ERROR) {
+            LOGE("createTrack error: %s", strerror(-lStatus));
+        }
+        lStatus = reply.readInt32();
+        if (status) {
+            *status = lStatus;
+        }
+        return interface_cast<IAudioTrack>(reply.readStrongBinder());
+    }
+
+    virtual sp<IAudioRecord> openRecord(
+                                pid_t pid,
+                                int streamType,
+                                uint32_t sampleRate,
+                                int format,
+                                int channelCount,
+                                int frameCount,
+                                uint32_t flags,
+                                status_t *status)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        data.writeInt32(streamType);
+        data.writeInt32(sampleRate);
+        data.writeInt32(format);
+        data.writeInt32(channelCount);
+        data.writeInt32(frameCount);
+        data.writeInt32(flags);
+        remote()->transact(OPEN_RECORD, data, &reply);
+        status_t lStatus = reply.readInt32();
+        if (status) {
+            *status = lStatus;
+        }
+        return interface_cast<IAudioRecord>(reply.readStrongBinder());
+    }
+
+    virtual uint32_t sampleRate(int output) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(output);
+        remote()->transact(SAMPLE_RATE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual int channelCount(int output) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(output);
+        remote()->transact(CHANNEL_COUNT, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual int format(int output) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(output);
+        remote()->transact(FORMAT, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual size_t frameCount(int output) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(output);
+        remote()->transact(FRAME_COUNT, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual uint32_t latency(int output) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(output);
+        remote()->transact(LATENCY, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t setMasterVolume(float value)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeFloat(value);
+        remote()->transact(SET_MASTER_VOLUME, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t setMasterMute(bool muted)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(muted);
+        remote()->transact(SET_MASTER_MUTE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual float masterVolume() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        remote()->transact(MASTER_VOLUME, data, &reply);
+        return reply.readFloat();
+    }
+
+    virtual bool masterMute() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        remote()->transact(MASTER_MUTE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t setStreamVolume(int stream, float value)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(stream);
+        data.writeFloat(value);
+        remote()->transact(SET_STREAM_VOLUME, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t setStreamMute(int stream, bool muted)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(stream);
+        data.writeInt32(muted);
+        remote()->transact(SET_STREAM_MUTE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual float streamVolume(int stream) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(stream);
+        remote()->transact(STREAM_VOLUME, data, &reply);
+        return reply.readFloat();
+    }
+
+    virtual bool streamMute(int stream) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(stream);
+        remote()->transact(STREAM_MUTE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(mode);
+        data.writeInt32(routes);
+        data.writeInt32(mask);
+        remote()->transact(SET_ROUTING, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual uint32_t getRouting(int mode) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(mode);
+        remote()->transact(GET_ROUTING, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t setMode(int mode)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(mode);
+        remote()->transact(SET_MODE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual int getMode() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        remote()->transact(GET_MODE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t setMicMute(bool state)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(state);
+        remote()->transact(SET_MIC_MUTE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual bool getMicMute() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        remote()->transact(GET_MIC_MUTE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual bool isMusicActive() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        remote()->transact(IS_MUSIC_ACTIVE, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t setParameter(const char* key, const char* value)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeCString(key);
+        data.writeCString(value);
+        remote()->transact(SET_PARAMETER, data, &reply);
+        return reply.readInt32();
+    }
+    
+    virtual void registerClient(const sp<IAudioFlingerClient>& client)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeStrongBinder(client->asBinder());
+        remote()->transact(REGISTER_CLIENT, data, &reply);
+    }
+    
+    virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(sampleRate);
+        data.writeInt32(format);
+        data.writeInt32(channelCount);
+        remote()->transact(GET_INPUTBUFFERSIZE, data, &reply);
+        return reply.readInt32();
+    }
+    
+    virtual void wakeUp()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        remote()->transact(WAKE_UP, data, &reply);
+        return;
+    }
+
+    virtual bool isA2dpEnabled() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        remote()->transact(IS_A2DP_ENABLED, data, &reply);
+        return (bool)reply.readInt32();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnAudioFlinger::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case CREATE_TRACK: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            pid_t pid = data.readInt32();
+            int streamType = data.readInt32();
+            uint32_t sampleRate = data.readInt32();
+            int format = data.readInt32();
+            int channelCount = data.readInt32();
+            size_t bufferCount = data.readInt32();
+            uint32_t flags = data.readInt32();
+            sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
+            status_t status;
+            sp<IAudioTrack> track = createTrack(pid,
+                    streamType, sampleRate, format,
+                    channelCount, bufferCount, flags, buffer, &status);
+            reply->writeInt32(status);
+            reply->writeStrongBinder(track->asBinder());
+            return NO_ERROR;
+        } break;
+        case OPEN_RECORD: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            pid_t pid = data.readInt32();
+            int streamType = data.readInt32();
+            uint32_t sampleRate = data.readInt32();
+            int format = data.readInt32();
+            int channelCount = data.readInt32();
+            size_t bufferCount = data.readInt32();
+            uint32_t flags = data.readInt32();
+            status_t status;
+            sp<IAudioRecord> record = openRecord(pid, streamType,
+                    sampleRate, format, channelCount, bufferCount, flags, &status);
+            reply->writeInt32(status);
+            reply->writeStrongBinder(record->asBinder());
+            return NO_ERROR;
+        } break;
+        case SAMPLE_RATE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int output = data.readInt32();
+            reply->writeInt32( sampleRate(output) );
+            return NO_ERROR;
+        } break;
+        case CHANNEL_COUNT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int output = data.readInt32();
+            reply->writeInt32( channelCount(output) );
+            return NO_ERROR;
+        } break;
+        case FORMAT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int output = data.readInt32();
+            reply->writeInt32( format(output) );
+            return NO_ERROR;
+        } break;
+        case FRAME_COUNT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int output = data.readInt32();
+            reply->writeInt32( frameCount(output) );
+            return NO_ERROR;
+        } break;
+        case LATENCY: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int output = data.readInt32();
+            reply->writeInt32( latency(output) );
+            return NO_ERROR;
+        } break;
+         case SET_MASTER_VOLUME: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32( setMasterVolume(data.readFloat()) );
+            return NO_ERROR;
+        } break;
+        case SET_MASTER_MUTE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32( setMasterMute(data.readInt32()) );
+            return NO_ERROR;
+        } break;
+        case MASTER_VOLUME: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeFloat( masterVolume() );
+            return NO_ERROR;
+        } break;
+        case MASTER_MUTE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32( masterMute() );
+            return NO_ERROR;
+        } break;
+        case SET_STREAM_VOLUME: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int stream = data.readInt32();
+            reply->writeInt32( setStreamVolume(stream, data.readFloat()) );
+            return NO_ERROR;
+        } break;
+        case SET_STREAM_MUTE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int stream = data.readInt32();
+            reply->writeInt32( setStreamMute(stream, data.readInt32()) );
+            return NO_ERROR;
+        } break;
+        case STREAM_VOLUME: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int stream = data.readInt32();
+            reply->writeFloat( streamVolume(stream) );
+            return NO_ERROR;
+        } break;
+        case STREAM_MUTE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int stream = data.readInt32();
+            reply->writeInt32( streamMute(stream) );
+            return NO_ERROR;
+        } break;
+        case SET_ROUTING: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int mode = data.readInt32();
+            uint32_t routes = data.readInt32();
+            uint32_t mask = data.readInt32();
+            reply->writeInt32( setRouting(mode, routes, mask) );
+            return NO_ERROR;
+        } break;
+        case GET_ROUTING: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int mode = data.readInt32();
+            reply->writeInt32( getRouting(mode) );
+            return NO_ERROR;
+        } break;
+        case SET_MODE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int mode = data.readInt32();
+            reply->writeInt32( setMode(mode) );
+            return NO_ERROR;
+        } break;
+        case GET_MODE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32( getMode() );
+            return NO_ERROR;
+        } break;
+        case SET_MIC_MUTE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            int state = data.readInt32();
+            reply->writeInt32( setMicMute(state) );
+            return NO_ERROR;
+        } break;
+        case GET_MIC_MUTE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32( getMicMute() );
+            return NO_ERROR;
+        } break;
+        case IS_MUSIC_ACTIVE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32( isMusicActive() );
+            return NO_ERROR;
+        } break;
+        case SET_PARAMETER: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            const char *key = data.readCString();
+            const char *value = data.readCString();
+            reply->writeInt32( setParameter(key, value) );
+            return NO_ERROR;
+        } break;
+        case REGISTER_CLIENT: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient>(data.readStrongBinder());
+            registerClient(client);
+            return NO_ERROR;
+        } break;
+        case GET_INPUTBUFFERSIZE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            uint32_t sampleRate = data.readInt32();
+            int format = data.readInt32();
+            int channelCount = data.readInt32();
+            reply->writeInt32( getInputBufferSize(sampleRate, format, channelCount) );
+            return NO_ERROR;
+        } break;
+        case WAKE_UP: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            wakeUp();
+            return NO_ERROR;
+        } break;
+        case IS_A2DP_ENABLED: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32( (int)isA2dpEnabled() );
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
new file mode 100644
index 0000000..5feb11f
--- /dev/null
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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_TAG "IAudioFlingerClient"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioFlingerClient.h>
+
+namespace android {
+
+enum {
+    AUDIO_OUTPUT_CHANGED = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpAudioFlingerClient : public BpInterface<IAudioFlingerClient>
+{
+public:
+    BpAudioFlingerClient(const sp<IBinder>& impl)
+        : BpInterface<IAudioFlingerClient>(impl)
+    {
+    }
+
+    void a2dpEnabledChanged(bool enabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
+        data.writeInt32((int)enabled);
+        remote()->transact(AUDIO_OUTPUT_CHANGED, data, &reply);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(AudioFlingerClient, "android.media.IAudioFlingerClient");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnAudioFlingerClient::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case AUDIO_OUTPUT_CHANGED: {
+            CHECK_INTERFACE(IAudioFlingerClient, data, reply);
+            bool enabled = (bool)data.readInt32();
+            a2dpEnabledChanged(enabled);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
new file mode 100644
index 0000000..6e42dac
--- /dev/null
+++ b/media/libmedia/IAudioRecord.cpp
@@ -0,0 +1,100 @@
+/*
+**
+** 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 <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioRecord.h>
+
+namespace android {
+
+enum {
+    GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
+    START,
+    STOP
+};
+
+class BpAudioRecord : public BpInterface<IAudioRecord>
+{
+public:
+    BpAudioRecord(const sp<IBinder>& impl)
+        : BpInterface<IAudioRecord>(impl)
+    {
+    }
+    
+    virtual status_t start()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+        remote()->transact(START, data, &reply);
+        return reply.readInt32();
+    }
+    
+    virtual void stop()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+        remote()->transact(STOP, data, &reply);
+    }
+    
+    virtual sp<IMemory> getCblk() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+        remote()->transact(GET_CBLK, data, &reply);
+        return interface_cast<IMemory>(reply.readStrongBinder());
+    }    
+};
+
+IMPLEMENT_META_INTERFACE(AudioRecord, "android.media.IAudioRecord");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnAudioRecord::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+       case GET_CBLK: {
+            CHECK_INTERFACE(IAudioRecord, data, reply);
+            reply->writeStrongBinder(getCblk()->asBinder());
+            return NO_ERROR;
+        } break;
+        case START: {
+            CHECK_INTERFACE(IAudioRecord, data, reply);
+            reply->writeInt32(start());
+            return NO_ERROR;
+        } break;
+        case STOP: {
+            CHECK_INTERFACE(IAudioRecord, data, reply);
+            stop();
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
new file mode 100644
index 0000000..abc202d
--- /dev/null
+++ b/media/libmedia/IAudioTrack.cpp
@@ -0,0 +1,140 @@
+/* //device/extlibs/pv/android/IAudioTrack.cpp
+**
+** 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 <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioTrack.h>
+
+namespace android {
+
+enum {
+    GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
+    START,
+    STOP,
+    FLUSH,
+    MUTE,
+    PAUSE
+};
+
+class BpAudioTrack : public BpInterface<IAudioTrack>
+{
+public:
+    BpAudioTrack(const sp<IBinder>& impl)
+        : BpInterface<IAudioTrack>(impl)
+    {
+    }
+    
+    virtual status_t start()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        remote()->transact(START, data, &reply);
+        return reply.readInt32();
+    }
+    
+    virtual void stop()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        remote()->transact(STOP, data, &reply);
+    }
+    
+    virtual void flush()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        remote()->transact(FLUSH, data, &reply);
+    }
+
+    virtual void mute(bool e)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        data.writeInt32(e);
+        remote()->transact(MUTE, data, &reply);
+    }
+    
+    virtual void pause()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        remote()->transact(PAUSE, data, &reply);
+    }
+    
+    virtual sp<IMemory> getCblk() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        remote()->transact(GET_CBLK, data, &reply);
+        return interface_cast<IMemory>(reply.readStrongBinder());
+    }    
+};
+
+IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnAudioTrack::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+       case GET_CBLK: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            reply->writeStrongBinder(getCblk()->asBinder());
+            return NO_ERROR;
+        } break;
+        case START: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            reply->writeInt32(start());
+            return NO_ERROR;
+        } break;
+        case STOP: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            stop();
+            return NO_ERROR;
+        } break;
+        case FLUSH: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            flush();
+            return NO_ERROR;
+        } break;
+        case MUTE: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            mute( data.readInt32() );
+            return NO_ERROR;
+        } break;
+        case PAUSE: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            pause();
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
new file mode 100644
index 0000000..85b5944
--- /dev/null
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -0,0 +1,218 @@
+/*
+**
+** Copyright (C) 2008 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 <stdint.h>
+#include <sys/types.h>
+#include <utils/Parcel.h>
+#include <SkBitmap.h>
+#include <media/IMediaMetadataRetriever.h>
+
+namespace android {
+
+enum {
+    DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    SET_DATA_SOURCE_URL,
+    SET_DATA_SOURCE_FD,
+    SET_MODE,
+    GET_MODE,
+    CAPTURE_FRAME,
+    EXTARCT_ALBUM_ART,
+    EXTRACT_METADATA,
+};
+
+class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever>
+{
+public:
+    BpMediaMetadataRetriever(const sp<IBinder>& impl)
+        : BpInterface<IMediaMetadataRetriever>(impl)
+    {
+    }
+
+    // disconnect from media metadata retriever service
+    void disconnect()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        remote()->transact(DISCONNECT, data, &reply);
+    }
+
+    status_t setDataSource(const char* srcUrl)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeCString(srcUrl);
+        remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setDataSource(int fd, int64_t offset, int64_t length)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeFileDescriptor(fd);
+        data.writeInt64(offset);
+        data.writeInt64(length);
+        remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setMode(int mode)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeInt32(mode);
+        remote()->transact(SET_MODE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t getMode(int* mode) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        remote()->transact(GET_MODE, data, &reply);
+        *mode = reply.readInt32();
+        return reply.readInt32();
+    }
+
+    sp<IMemory> captureFrame()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        remote()->transact(CAPTURE_FRAME, data, &reply);
+        status_t ret = reply.readInt32();
+        if (ret != NO_ERROR) {
+            return NULL;
+        }
+        return interface_cast<IMemory>(reply.readStrongBinder());
+    }
+
+    sp<IMemory> extractAlbumArt()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        remote()->transact(EXTARCT_ALBUM_ART, data, &reply);
+        status_t ret = reply.readInt32();
+        if (ret != NO_ERROR) {
+            return NULL;
+        }
+        return interface_cast<IMemory>(reply.readStrongBinder());
+    }
+
+    const char* extractMetadata(int keyCode)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeInt32(keyCode);
+        remote()->transact(EXTRACT_METADATA, data, &reply);
+        status_t ret = reply.readInt32();
+        if (ret != NO_ERROR) {
+            return NULL;
+        }
+        return reply.readCString();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.hardware.IMediaMetadataRetriever");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnMediaMetadataRetriever::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case DISCONNECT: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            disconnect();
+            return NO_ERROR;
+        } break;
+        case SET_DATA_SOURCE_URL: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            const char* srcUrl = data.readCString();
+            reply->writeInt32(setDataSource(srcUrl));
+            return NO_ERROR;
+        } break;
+        case SET_DATA_SOURCE_FD: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int fd = dup(data.readFileDescriptor());
+            int64_t offset = data.readInt64();
+            int64_t length = data.readInt64();
+            reply->writeInt32(setDataSource(fd, offset, length));
+            return NO_ERROR;
+        } break;
+        case SET_MODE: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int mode = data.readInt32();
+            reply->writeInt32(setMode(mode));
+            return NO_ERROR;
+        } break;
+        case GET_MODE: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int mode;
+            status_t status = getMode(&mode);
+            reply->writeInt32(mode);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        } break;
+        case CAPTURE_FRAME: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            sp<IMemory> bitmap = captureFrame();
+            if (bitmap != 0) {  // Don't send NULL across the binder interface
+                reply->writeInt32(NO_ERROR);
+                reply->writeStrongBinder(bitmap->asBinder());
+            } else {
+                reply->writeInt32(UNKNOWN_ERROR);
+            }
+            return NO_ERROR;
+        } break;
+        case EXTARCT_ALBUM_ART: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            sp<IMemory> albumArt = extractAlbumArt();
+            if (albumArt != 0) {  // Don't send NULL across the binder interface
+                reply->writeInt32(NO_ERROR);
+                reply->writeStrongBinder(albumArt->asBinder());
+            } else {
+                reply->writeInt32(UNKNOWN_ERROR);
+            }
+            return NO_ERROR;
+        } break;
+        case EXTRACT_METADATA: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int keyCode = data.readInt32();
+            const char* value = extractMetadata(keyCode);
+            if (value != NULL) {  // Don't send NULL across the binder interface
+                reply->writeInt32(NO_ERROR);
+                reply->writeCString(value);
+            } else {
+                reply->writeInt32(UNKNOWN_ERROR);
+            }
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
new file mode 100644
index 0000000..f37519f
--- /dev/null
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -0,0 +1,275 @@
+/*
+**
+** Copyright 2008, 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 <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IMediaPlayer.h>
+#include <ui/ISurface.h>
+
+namespace android {
+
+enum {
+    DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    SET_VIDEO_SURFACE,
+    PREPARE_ASYNC,
+    START,
+    STOP,
+    IS_PLAYING,
+    PAUSE,
+    SEEK_TO,
+    GET_CURRENT_POSITION,
+    GET_DURATION,
+    RESET,
+    SET_AUDIO_STREAM_TYPE,
+    SET_LOOPING,
+    SET_VOLUME
+};
+
+class BpMediaPlayer: public BpInterface<IMediaPlayer>
+{
+public:
+    BpMediaPlayer(const sp<IBinder>& impl)
+        : BpInterface<IMediaPlayer>(impl)
+    {
+    }
+
+    // disconnect from media player service
+    void disconnect()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        remote()->transact(DISCONNECT, data, &reply);
+    }
+
+    status_t setVideoSurface(const sp<ISurface>& surface)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeStrongBinder(surface->asBinder());
+        remote()->transact(SET_VIDEO_SURFACE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t prepareAsync()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        remote()->transact(PREPARE_ASYNC, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t start()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        remote()->transact(START, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t stop()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        remote()->transact(STOP, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t isPlaying(bool* state)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        remote()->transact(IS_PLAYING, data, &reply);
+        *state = reply.readInt32();
+        return reply.readInt32();
+    }
+
+    status_t pause()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        remote()->transact(PAUSE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t seekTo(int msec)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeInt32(msec);
+        remote()->transact(SEEK_TO, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t getCurrentPosition(int* msec)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        remote()->transact(GET_CURRENT_POSITION, data, &reply);
+        *msec = reply.readInt32();
+        return reply.readInt32();
+    }
+
+    status_t getDuration(int* msec)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        remote()->transact(GET_DURATION, data, &reply);
+        *msec = reply.readInt32();
+        return reply.readInt32();
+    }
+
+    status_t reset()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        remote()->transact(RESET, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setAudioStreamType(int type)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeInt32(type);
+        remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setLooping(int loop)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeInt32(loop);
+        remote()->transact(SET_LOOPING, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setVolume(float leftVolume, float rightVolume)
+    {
+        Parcel data, reply;
+        data.writeFloat(leftVolume);
+        data.writeFloat(rightVolume);
+        remote()->transact(SET_VOLUME, data, &reply);
+        return reply.readInt32();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(MediaPlayer, "android.hardware.IMediaPlayer");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnMediaPlayer::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case DISCONNECT: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            disconnect();
+            return NO_ERROR;
+        } break;
+        case SET_VIDEO_SURFACE: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+            reply->writeInt32(setVideoSurface(surface));
+            return NO_ERROR;
+        } break;
+        case PREPARE_ASYNC: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(prepareAsync());
+            return NO_ERROR;
+        } break;
+        case START: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(start());
+            return NO_ERROR;
+        } break;
+        case STOP: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(stop());
+            return NO_ERROR;
+        } break;
+        case IS_PLAYING: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            bool state;
+            status_t ret = isPlaying(&state);
+            reply->writeInt32(state);
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case PAUSE: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(pause());
+            return NO_ERROR;
+        } break;
+        case SEEK_TO: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(seekTo(data.readInt32()));
+            return NO_ERROR;
+        } break;
+        case GET_CURRENT_POSITION: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            int msec;
+            status_t ret = getCurrentPosition(&msec);
+            reply->writeInt32(msec);
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case GET_DURATION: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            int msec;
+            status_t ret = getDuration(&msec);
+            reply->writeInt32(msec);
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case RESET: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(reset());
+            return NO_ERROR;
+        } break;
+        case SET_AUDIO_STREAM_TYPE: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(setAudioStreamType(data.readInt32()));
+            return NO_ERROR;
+        } break;
+        case SET_LOOPING: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(setLooping(data.readInt32()));
+            return NO_ERROR;
+        } break;
+        case SET_VOLUME: {
+            reply->writeInt32(setVolume(data.readFloat(), data.readFloat()));
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp
new file mode 100644
index 0000000..65022cd
--- /dev/null
+++ b/media/libmedia/IMediaPlayerClient.cpp
@@ -0,0 +1,77 @@
+/*
+**
+** Copyright 2008, 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 <utils/IInterface.h>
+#include <utils/Parcel.h>
+
+#include <media/IMediaPlayerClient.h>
+
+namespace android {
+
+enum {
+    NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpMediaPlayerClient: public BpInterface<IMediaPlayerClient>
+{
+public:
+    BpMediaPlayerClient(const sp<IBinder>& impl)
+        : BpInterface<IMediaPlayerClient>(impl)
+    {
+    }
+
+    virtual void notify(int msg, int ext1, int ext2)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());
+        data.writeInt32(msg);
+        data.writeInt32(ext1);
+        data.writeInt32(ext2);
+        remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnMediaPlayerClient::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case NOTIFY: {
+            CHECK_INTERFACE(IMediaPlayerClient, data, reply);
+            int msg = data.readInt32();
+            int ext1 = data.readInt32();
+            int ext2 = data.readInt32();
+            notify(msg, ext1, ext2);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
new file mode 100644
index 0000000..370e3fb
--- /dev/null
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -0,0 +1,198 @@
+/*
+**
+** Copyright 2008, 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 <stdint.h>
+#include <sys/types.h>
+#include <utils/Parcel.h>
+
+#include <utils/IMemory.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+enum {
+    CREATE_URL = IBinder::FIRST_CALL_TRANSACTION,
+    CREATE_FD,
+    DECODE_URL,
+    DECODE_FD,
+    CREATE_MEDIA_RECORDER,
+    CREATE_METADATA_RETRIEVER,
+};
+
+class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
+{
+public:
+    BpMediaPlayerService(const sp<IBinder>& impl)
+        : BpInterface<IMediaPlayerService>(impl)
+    {
+    }
+
+    virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        remote()->transact(CREATE_METADATA_RETRIEVER, data, &reply);
+        return interface_cast<IMediaMetadataRetriever>(reply.readStrongBinder());
+    }
+
+    virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        data.writeStrongBinder(client->asBinder());
+        data.writeCString(url);
+        remote()->transact(CREATE_URL, data, &reply);
+        return interface_cast<IMediaPlayer>(reply.readStrongBinder());
+    }
+
+    virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);
+        return interface_cast<IMediaRecorder>(reply.readStrongBinder());
+    }
+
+    virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        data.writeStrongBinder(client->asBinder());
+        data.writeFileDescriptor(fd);
+        data.writeInt64(offset);
+        data.writeInt64(length);
+        remote()->transact(CREATE_FD, data, &reply);
+        return interface_cast<IMediaPlayer>(reply.readStrongBinder());
+    }
+
+    virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        data.writeCString(url);
+        remote()->transact(DECODE_URL, data, &reply);
+        *pSampleRate = uint32_t(reply.readInt32());
+        *pNumChannels = reply.readInt32();
+        *pFormat = reply.readInt32();
+        return interface_cast<IMemory>(reply.readStrongBinder());
+    }
+
+    virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        data.writeFileDescriptor(fd);
+        data.writeInt64(offset);
+        data.writeInt64(length);
+        remote()->transact(DECODE_FD, data, &reply);
+        *pSampleRate = uint32_t(reply.readInt32());
+        *pNumChannels = reply.readInt32();
+        *pFormat = reply.readInt32();
+        return interface_cast<IMemory>(reply.readStrongBinder());
+    }
+};
+
+IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerService");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnMediaPlayerService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case CREATE_URL: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            pid_t pid = data.readInt32();
+            sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
+            const char* url = data.readCString();
+            sp<IMediaPlayer> player = create(pid, client, url);
+            reply->writeStrongBinder(player->asBinder());
+            return NO_ERROR;
+        } break;
+        case CREATE_FD: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            pid_t pid = data.readInt32();
+            sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
+            int fd = dup(data.readFileDescriptor());
+            int64_t offset = data.readInt64();
+            int64_t length = data.readInt64();
+            sp<IMediaPlayer> player = create(pid, client, fd, offset, length);
+            reply->writeStrongBinder(player->asBinder());
+            return NO_ERROR;
+        } break;
+        case DECODE_URL: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            const char* url = data.readCString();
+            uint32_t sampleRate;
+            int numChannels;
+            int format;
+            sp<IMemory> player = decode(url, &sampleRate, &numChannels, &format);
+            reply->writeInt32(sampleRate);
+            reply->writeInt32(numChannels);
+            reply->writeInt32(format);
+            reply->writeStrongBinder(player->asBinder());
+            return NO_ERROR;
+        } break;
+        case DECODE_FD: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            int fd = dup(data.readFileDescriptor());
+            int64_t offset = data.readInt64();
+            int64_t length = data.readInt64();
+            uint32_t sampleRate;
+            int numChannels;
+            int format;
+            sp<IMemory> player = decode(fd, offset, length, &sampleRate, &numChannels, &format);
+            reply->writeInt32(sampleRate);
+            reply->writeInt32(numChannels);
+            reply->writeInt32(format);
+            reply->writeStrongBinder(player->asBinder());
+            return NO_ERROR;
+        } break;
+        case CREATE_MEDIA_RECORDER: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            pid_t pid = data.readInt32();
+            sp<IMediaRecorder> recorder = createMediaRecorder(pid);
+            reply->writeStrongBinder(recorder->asBinder());
+            return NO_ERROR;
+        } break;
+        case CREATE_METADATA_RETRIEVER: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            pid_t pid = data.readInt32();
+            sp<IMediaMetadataRetriever> retriever = createMetadataRetriever(pid);
+            reply->writeStrongBinder(retriever->asBinder());
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
new file mode 100644
index 0000000..f187bf5
--- /dev/null
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -0,0 +1,417 @@
+/*
+ **
+ ** Copyright 2008, HTC Inc.
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IMediaRecorder"
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <ui/ISurface.h>
+#include <ui/ICamera.h>
+#include <media/IMediaPlayerClient.h>
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+enum {
+    RELEASE = IBinder::FIRST_CALL_TRANSACTION,
+    INIT,
+    CLOSE,
+    RESET,
+    STOP,
+    START,
+    PREPARE,
+    GET_MAX_AMPLITUDE,
+    SET_VIDEO_SOURCE,
+    SET_AUDIO_SOURCE,
+    SET_OUTPUT_FORMAT,
+    SET_VIDEO_ENCODER,
+    SET_AUDIO_ENCODER,
+    SET_OUTPUT_FILE_PATH,
+    SET_OUTPUT_FILE_FD,
+    SET_VIDEO_SIZE,
+    SET_VIDEO_FRAMERATE,
+    SET_PREVIEW_SURFACE,
+    SET_CAMERA,
+    SET_LISTENER
+};
+
+class BpMediaRecorder: public BpInterface<IMediaRecorder>
+{
+public:
+    BpMediaRecorder(const sp<IBinder>& impl)
+    : BpInterface<IMediaRecorder>(impl)
+    {
+    }
+
+    status_t setCamera(const sp<ICamera>& camera)
+    {
+        LOGV("setCamera(%p)", camera.get());
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeStrongBinder(camera->asBinder());
+        remote()->transact(SET_CAMERA, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setPreviewSurface(const sp<ISurface>& surface)
+    {
+        LOGV("setPreviewSurface(%p)", surface.get());
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeStrongBinder(surface->asBinder());
+        remote()->transact(SET_PREVIEW_SURFACE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t init()
+    {
+        LOGV("init");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(INIT, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setVideoSource(int vs)
+    {
+        LOGV("setVideoSource(%d)", vs);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(vs);
+        remote()->transact(SET_VIDEO_SOURCE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setAudioSource(int as)
+    {
+        LOGV("setAudioSource(%d)", as);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(as);
+        remote()->transact(SET_AUDIO_SOURCE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setOutputFormat(int of)
+    {
+        LOGV("setOutputFormat(%d)", of);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(of);
+        remote()->transact(SET_OUTPUT_FORMAT, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setVideoEncoder(int ve)
+    {
+        LOGV("setVideoEncoder(%d)", ve);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(ve);
+        remote()->transact(SET_VIDEO_ENCODER, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setAudioEncoder(int ae)
+    {
+        LOGV("setAudioEncoder(%d)", ae);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(ae);
+        remote()->transact(SET_AUDIO_ENCODER, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setOutputFile(const char* path)
+    {
+        LOGV("setOutputFile(%s)", path);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeCString(path);
+        remote()->transact(SET_OUTPUT_FILE_PATH, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setOutputFile(int fd, int64_t offset, int64_t length) {
+        LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeFileDescriptor(fd);
+        data.writeInt64(offset);
+        data.writeInt64(length);
+        remote()->transact(SET_OUTPUT_FILE_FD, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setVideoSize(int width, int height)
+    {
+        LOGV("setVideoSize(%dx%d)", width, height);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(width);
+        data.writeInt32(height);
+        remote()->transact(SET_VIDEO_SIZE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setVideoFrameRate(int frames_per_second)
+    {
+        LOGV("setVideoFrameRate(%d)", frames_per_second);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(frames_per_second);
+        remote()->transact(SET_VIDEO_FRAMERATE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setListener(const sp<IMediaPlayerClient>& listener)
+    {
+        LOGV("setListener(%p)", listener.get());
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeStrongBinder(listener->asBinder());
+        remote()->transact(SET_LISTENER, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t prepare()
+    {
+        LOGV("prepare");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(PREPARE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t getMaxAmplitude(int* max)
+    {
+        LOGV("getMaxAmplitude");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(GET_MAX_AMPLITUDE, data, &reply);
+        *max = reply.readInt32();
+        return reply.readInt32();
+    }
+
+    status_t start()
+    {
+        LOGV("start");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(START, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t stop()
+    {
+        LOGV("stop");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(STOP, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t reset()
+    {
+        LOGV("reset");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(RESET, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t close()
+    {
+        LOGV("close");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(CLOSE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t release()
+    {
+        LOGV("release");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(RELEASE, data, &reply);
+        return reply.readInt32();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(MediaRecorder, "android.hardware.IMediaRecorder");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+    do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+        LOGW("Call incorrectly routed to " #interface); \
+        return PERMISSION_DENIED; \
+    } } while (0)
+
+status_t BnMediaRecorder::onTransact(
+                                     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case RELEASE: {
+            LOGV("RELEASE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(release());
+            return NO_ERROR;
+        } break;
+        case INIT: {
+            LOGV("INIT");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(init());
+            return NO_ERROR;
+        } break;
+        case CLOSE: {
+            LOGV("CLOSE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(close());
+            return NO_ERROR;
+        } break;
+        case RESET: {
+            LOGV("RESET");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(reset());
+            return NO_ERROR;
+        } break;
+        case STOP: {
+            LOGV("STOP");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(stop());
+            return NO_ERROR;
+        } break;
+        case START: {
+            LOGV("START");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(start());
+            return NO_ERROR;
+        } break;
+        case PREPARE: {
+            LOGV("PREPARE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(prepare());
+            return NO_ERROR;
+        } break;
+        case GET_MAX_AMPLITUDE: {
+            LOGV("GET_MAX_AMPLITUDE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int max = 0;
+            status_t ret = getMaxAmplitude(&max);
+            reply->writeInt32(max);
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case SET_VIDEO_SOURCE: {
+            LOGV("SET_VIDEO_SOURCE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int vs = data.readInt32();
+            reply->writeInt32(setVideoSource(vs));
+            return NO_ERROR;
+        } break;
+        case SET_AUDIO_SOURCE: {
+            LOGV("SET_AUDIO_SOURCE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int as = data.readInt32();
+            reply->writeInt32(setAudioSource(as));
+            return NO_ERROR;
+        } break;
+        case SET_OUTPUT_FORMAT: {
+            LOGV("SET_OUTPUT_FORMAT");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int of = data.readInt32();
+            reply->writeInt32(setOutputFormat(of));
+            return NO_ERROR;
+        } break;
+        case SET_VIDEO_ENCODER: {
+            LOGV("SET_VIDEO_ENCODER");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int ve = data.readInt32();
+            reply->writeInt32(setVideoEncoder(ve));
+            return NO_ERROR;
+        } break;
+        case SET_AUDIO_ENCODER: {
+            LOGV("SET_AUDIO_ENCODER");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int ae = data.readInt32();
+            reply->writeInt32(setAudioEncoder(ae));
+            return NO_ERROR;
+
+        } break;
+        case SET_OUTPUT_FILE_PATH: {
+            LOGV("SET_OUTPUT_FILE_PATH");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            const char* path = data.readCString();
+            reply->writeInt32(setOutputFile(path));
+            return NO_ERROR;
+        } break;
+        case SET_OUTPUT_FILE_FD: {
+            LOGV("SET_OUTPUT_FILE_FD");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int fd = dup(data.readFileDescriptor());
+            int64_t offset = data.readInt64();
+            int64_t length = data.readInt64();
+            reply->writeInt32(setOutputFile(fd, offset, length));
+            return NO_ERROR;
+        } break;
+        case SET_VIDEO_SIZE: {
+            LOGV("SET_VIDEO_SIZE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int width = data.readInt32();
+            int height = data.readInt32();
+            reply->writeInt32(setVideoSize(width, height));
+            return NO_ERROR;
+        } break;
+        case SET_VIDEO_FRAMERATE: {
+            LOGV("SET_VIDEO_FRAMERATE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int frames_per_second = data.readInt32();
+            reply->writeInt32(setVideoFrameRate(frames_per_second));
+            return NO_ERROR;
+        } break;
+        case SET_LISTENER: {
+            LOGV("SET_LISTENER");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            sp<IMediaPlayerClient> listener =
+                interface_cast<IMediaPlayerClient>(data.readStrongBinder());
+            reply->writeInt32(setListener(listener));
+            return NO_ERROR;
+        } break;
+        case SET_PREVIEW_SURFACE: {
+            LOGV("SET_PREVIEW_SURFACE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+            reply->writeInt32(setPreviewSurface(surface));
+            return NO_ERROR;
+        } break;
+        case SET_CAMERA: {
+            LOGV("SET_CAMERA");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            sp<ICamera> camera = interface_cast<ICamera>(data.readStrongBinder());
+            reply->writeInt32(setCamera(camera));
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
new file mode 100644
index 0000000..2c62104
--- /dev/null
+++ b/media/libmedia/JetPlayer.cpp
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 2008 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_TAG "JetPlayer-C"
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <media/JetPlayer.h>
+
+
+#ifdef HAVE_GETTID
+static pid_t myTid() { return gettid(); }
+#else
+static pid_t myTid() { return getpid(); }
+#endif
+
+
+namespace android
+{
+
+static const int MIX_NUM_BUFFERS = 4;
+static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
+
+//-------------------------------------------------------------------------------------------------
+JetPlayer::JetPlayer(jobject javaJetPlayer, int maxTracks, int trackBufferSize) :
+        mEventCallback(NULL),
+        mJavaJetPlayerRef(javaJetPlayer),
+        mTid(-1),
+        mRender(false),
+        mPaused(false),
+        mMaxTracks(maxTracks),
+        mEasData(NULL),
+        mEasJetFileLoc(NULL),
+        mAudioTrack(NULL),
+        mTrackBufferSize(trackBufferSize)
+{
+    LOGV("JetPlayer constructor");
+    mPreviousJetStatus.currentUserID = -1;
+    mPreviousJetStatus.segmentRepeatCount = -1;
+    mPreviousJetStatus.numQueuedSegments = -1;
+    mPreviousJetStatus.paused = true;
+}
+
+//-------------------------------------------------------------------------------------------------
+JetPlayer::~JetPlayer()
+{
+    LOGV("~JetPlayer");
+    release();
+
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::init()
+{
+    //Mutex::Autolock lock(&mMutex);
+
+    EAS_RESULT result;
+
+    // retrieve the EAS library settings
+    if (pLibConfig == NULL)
+        pLibConfig = EAS_Config();
+    if (pLibConfig == NULL) {
+        LOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting.");
+        return EAS_FAILURE;
+    }
+
+    // init the EAS library
+    result = EAS_Init(&mEasData);
+    if( result != EAS_SUCCESS) {
+        LOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting.");
+        mState = EAS_STATE_ERROR;
+        return result;
+    }
+    // init the JET library with the default app event controller range
+    result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG));
+    if( result != EAS_SUCCESS) {
+        LOGE("JetPlayer::init(): Error initializing JET library, aborting.");
+        mState = EAS_STATE_ERROR;
+        return result;
+    }
+
+    // create the output AudioTrack
+    mAudioTrack = new AudioTrack();
+    mAudioTrack->set(AudioSystem::MUSIC,  //TODO parametrize this
+            pLibConfig->sampleRate,
+            1, // format = PCM 16bits per sample,
+            pLibConfig->numChannels,
+            mTrackBufferSize,
+            0);
+
+    // create render and playback thread
+    {
+        Mutex::Autolock l(mMutex);
+        LOGV("JetPlayer::init(): trying to start render thread");
+        createThreadEtc(renderThread, this, "jetRenderThread", ANDROID_PRIORITY_AUDIO);
+        mCondition.wait(mMutex);
+    }
+    if (mTid > 0) {
+        // render thread started, we're ready
+        LOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
+        mState = EAS_STATE_READY;
+    } else {
+        LOGE("JetPlayer::init(): failed to start render thread.");
+        mState = EAS_STATE_ERROR;
+        return EAS_FAILURE;
+    }
+
+    return EAS_SUCCESS;
+}
+
+void JetPlayer::setEventCallback(jetevent_callback eventCallback)
+{
+    Mutex::Autolock l(mMutex);
+    mEventCallback = eventCallback;
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::release()
+{
+    LOGV("JetPlayer::release()");
+    Mutex::Autolock lock(mMutex);
+    mPaused = true;
+    mRender = false;
+    if (mEasData) {
+        JET_Pause(mEasData);
+        JET_CloseFile(mEasData);
+        JET_Shutdown(mEasData);
+        EAS_Shutdown(mEasData);
+    }
+    if (mEasJetFileLoc) {
+        free(mEasJetFileLoc);
+        mEasJetFileLoc = NULL;
+    }
+    if (mAudioTrack) {
+        mAudioTrack->stop();
+        mAudioTrack->flush();
+        delete mAudioTrack;
+        mAudioTrack = NULL;
+    }
+    if (mAudioBuffer) {
+        delete mAudioBuffer;
+        mAudioBuffer = NULL;
+    }
+    mEasData = NULL;
+    
+    return EAS_SUCCESS;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::renderThread(void* p) {
+
+    return ((JetPlayer*)p)->render();
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::render() {
+    EAS_RESULT result = EAS_FAILURE;
+    EAS_I32 count;
+    int temp;
+    bool audioStarted = false;
+
+    LOGV("JetPlayer::render(): entering");
+
+    // allocate render buffer
+    mAudioBuffer = 
+        new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
+    if (!mAudioBuffer) {
+        LOGE("JetPlayer::render(): mAudioBuffer allocate failed");
+        goto threadExit;
+    }
+
+    // signal main thread that we started
+    {
+        Mutex::Autolock l(mMutex);
+        mTid = myTid();
+        LOGV("JetPlayer::render(): render thread(%d) signal", mTid);
+        mCondition.signal();
+    }
+
+   while (1) {
+        mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
+
+        // nothing to render, wait for client thread to wake us up
+        while (!mRender)
+        {
+            LOGV("JetPlayer::render(): signal wait");
+            if (audioStarted) { 
+                mAudioTrack->pause(); 
+                // we have to restart the playback once we start rendering again
+                audioStarted = false;
+            }
+            mCondition.wait(mMutex);
+            LOGV("JetPlayer::render(): signal rx'd");
+        }
+        
+        // render midi data into the input buffer
+        int num_output = 0;
+        EAS_PCM* p = mAudioBuffer;
+        for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
+            result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
+            if (result != EAS_SUCCESS) {
+                LOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
+            }
+            p += count * pLibConfig->numChannels;
+            num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
+            
+             // send events that were generated (if any) to the event callback
+            fireEventsFromJetQueue();
+        }
+
+        // update playback state
+        //LOGV("JetPlayer::render(): updating state");
+        JET_Status(mEasData, &mJetStatus);
+        fireUpdateOnStatusChange();
+        mPaused = mJetStatus.paused;
+
+        mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
+
+        // check audio output track
+        if (mAudioTrack == NULL) {
+            LOGE("JetPlayer::render(): output AudioTrack was not created");
+            goto threadExit;
+        }
+
+        // Write data to the audio hardware
+        //LOGV("JetPlayer::render(): writing to audio output");
+        if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
+            LOGE("JetPlayer::render(): Error in writing:%d",temp);
+            return temp;
+        }
+
+        // start audio output if necessary
+        if (!audioStarted) {
+            LOGV("JetPlayer::render(): starting audio playback");
+            mAudioTrack->start();
+            audioStarted = true;
+        }
+
+    }//while (1)
+
+threadExit:
+    mAudioTrack->flush();
+    if (mAudioBuffer) {
+        delete [] mAudioBuffer;
+        mAudioBuffer = NULL;
+    }
+    mMutex.lock();
+    mTid = -1;
+    mCondition.signal();
+    mMutex.unlock();
+    return result;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+// fire up an update if any of the status fields has changed
+// precondition: mMutex locked
+void JetPlayer::fireUpdateOnStatusChange()
+{
+    if(  (mJetStatus.currentUserID      != mPreviousJetStatus.currentUserID)
+       ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
+        if(mEventCallback)  {
+            mEventCallback(
+                JetPlayer::JET_USERID_UPDATE,
+                mJetStatus.currentUserID,
+                mJetStatus.segmentRepeatCount,
+                mJavaJetPlayerRef);
+        }
+        mPreviousJetStatus.currentUserID      = mJetStatus.currentUserID;
+        mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
+    }
+
+    if(mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
+        if(mEventCallback)  {
+            mEventCallback(
+                JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
+                mJetStatus.numQueuedSegments,
+                -1,
+                mJavaJetPlayerRef);
+        }
+        mPreviousJetStatus.numQueuedSegments  = mJetStatus.numQueuedSegments;
+    }
+
+    if(mJetStatus.paused != mPreviousJetStatus.paused) {
+        if(mEventCallback)  {
+            mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
+                mJetStatus.paused,
+                -1,
+                mJavaJetPlayerRef);
+        }
+        mPreviousJetStatus.paused = mJetStatus.paused;
+    }
+
+}
+
+
+//-------------------------------------------------------------------------------------------------
+// fire up all the JET events in the JET engine queue (until the queue is empty)
+// precondition: mMutex locked
+void JetPlayer::fireEventsFromJetQueue()
+{
+    if(!mEventCallback) {
+        // no callback, just empty the event queue
+        while (JET_GetEvent(mEasData, NULL, NULL)) { }
+        return;
+    }
+
+    EAS_U32 rawEvent;
+    while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
+        mEventCallback(
+            JetPlayer::JET_EVENT,
+            rawEvent,
+            -1,
+            mJavaJetPlayerRef);
+    }
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::loadFromFile(const char* path)
+{
+    LOGV("JetPlayer::loadFromFile(): path=%s", path);
+
+    Mutex::Autolock lock(mMutex);
+
+    mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
+    memset(mJetFilePath, 0, 256);
+    strncpy(mJetFilePath, path, strlen(path));
+    mEasJetFileLoc->path = mJetFilePath;
+
+    mEasJetFileLoc->fd = 0;
+    mEasJetFileLoc->length = 0;
+    mEasJetFileLoc->offset = 0;
+
+    EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
+    if(result != EAS_SUCCESS)
+        mState = EAS_STATE_ERROR;
+    else
+        mState = EAS_STATE_OPEN;
+    return( result );
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
+{
+    LOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
+    
+    Mutex::Autolock lock(mMutex);
+
+    mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
+    mEasJetFileLoc->fd = fd;
+    mEasJetFileLoc->offset = offset;
+    mEasJetFileLoc->length = length;
+    mEasJetFileLoc->path = NULL;
+    
+    EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
+    if(result != EAS_SUCCESS)
+        mState = EAS_STATE_ERROR;
+    else
+        mState = EAS_STATE_OPEN;
+    return( result );
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::closeFile()
+{
+    Mutex::Autolock lock(mMutex);
+    return JET_CloseFile(mEasData);
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::play()
+{
+    LOGV("JetPlayer::play(): entering");
+    Mutex::Autolock lock(mMutex);
+
+    EAS_RESULT result = JET_Play(mEasData);
+
+    mPaused = false;
+    mRender = true;
+
+    JET_Status(mEasData, &mJetStatus);
+    this->dumpJetStatus(&mJetStatus);
+    
+    fireUpdateOnStatusChange();
+
+    // wake up render thread
+    LOGV("JetPlayer::play(): wakeup render thread");
+    mCondition.signal();
+
+    return result;
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::pause()
+{
+    Mutex::Autolock lock(mMutex);
+    mPaused = true;
+    EAS_RESULT result = JET_Pause(mEasData);
+
+    mRender = false;
+
+    JET_Status(mEasData, &mJetStatus);
+    this->dumpJetStatus(&mJetStatus);
+    fireUpdateOnStatusChange();
+
+
+    return result;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
+        EAS_U32 muteFlags, EAS_U8 userID)
+{
+    LOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
+        segmentNum, libNum, repeatCount, transpose);
+    Mutex::Autolock lock(mMutex);
+    return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
+{
+    Mutex::Autolock lock(mMutex);
+    return JET_SetMuteFlags(mEasData, muteFlags, sync);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
+{
+    Mutex::Autolock lock(mMutex);
+    return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::triggerClip(int clipId)
+{
+    LOGV("JetPlayer::triggerClip clipId=%d", clipId);
+    Mutex::Autolock lock(mMutex);
+    return JET_TriggerClip(mEasData, clipId);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::clearQueue()
+{
+    LOGV("JetPlayer::clearQueue");
+    Mutex::Autolock lock(mMutex);
+    return JET_Clear_Queue(mEasData);
+}
+
+//-------------------------------------------------------------------------------------------------
+void JetPlayer::dump()
+{
+    LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path);
+}
+
+void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
+{
+    if(pJetStatus!=NULL)
+        LOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d",
+                pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
+                pJetStatus->numQueuedSegments, pJetStatus->paused);
+    else
+        LOGE(">> JET player status is NULL");
+}
+
+
+} // end namespace android
+
diff --git a/media/libmedia/MODULE_LICENSE_APACHE2 b/media/libmedia/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libmedia/MODULE_LICENSE_APACHE2
diff --git a/media/libmedia/NOTICE b/media/libmedia/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/media/libmedia/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
new file mode 100644
index 0000000..5416629
--- /dev/null
+++ b/media/libmedia/ToneGenerator.cpp
@@ -0,0 +1,730 @@
+/*
+ * Copyright (C) 2008 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_TAG "ToneGenerator"
+#include <utils/threads.h>
+
+#include <stdio.h>
+#include <math.h>
+#include <utils/Log.h>
+#include <sys/resource.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+#include "media/ToneGenerator.h"
+
+namespace android {
+
+// Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
+const ToneGenerator::ToneDescriptor
+    ToneGenerator::toneDescriptors[NUM_TONES] = {
+    // waveFreq[]                     segments[]                         repeatCnt
+        { { 1336, 941, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_0
+        { { 1209, 697, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_1
+        { { 1336, 697, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_2
+        { { 1477, 697, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_3
+        { { 1209, 770, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_4
+        { { 1336, 770, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_5
+        { { 1477, 770, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_6
+        { { 1209, 852, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_7
+        { { 1336, 852, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_8
+        { { 1477, 852, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_9
+        { { 1209, 941, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_S
+        { { 1477, 941, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_P
+        { { 1633, 697, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_A
+        { { 1633, 770, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_B
+        { { 1633, 852, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_C
+        { { 1633, 941, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_D
+        { { 425, 0 },             { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_SUP_DIAL
+        { { 425, 0 },             { 500, 500, 0 },                   ToneGenerator::TONEGEN_INF },  // TONE_SUP_BUSY
+        { { 425, 0 },             { 200, 200, 0 },                   ToneGenerator::TONEGEN_INF },  // TONE_SUP_CONGESTION
+        { { 425, 0 },             { 200, 0 },                        0 },                           // TONE_SUP_RADIO_ACK
+        { { 425, 0 },             { 200, 200, 0 },                   2 },                           // TONE_SUP_RADIO_NOTAVAIL
+        { { 950, 1400, 1800, 0 }, { 330, 1000, 0 },                  ToneGenerator::TONEGEN_INF },  // TONE_SUP_ERROR
+        { { 425, 0 },             { 200, 600, 200, 3000, 0 },        ToneGenerator::TONEGEN_INF },  // TONE_SUP_CALL_WAITING
+        { { 425, 0 },             { 1000, 4000, 0 },                 ToneGenerator::TONEGEN_INF },  // TONE_SUP_RINGTONE
+        { { 400, 1200, 0 },       { 40, 0 },                         0 },                           // TONE_PROP_BEEP
+        { { 1200, 0 },            { 100, 100, 0 },                   1 },                           // TONE_PROP_ACK
+        { { 300, 400, 500, 0 },   { 400, 0 },                        0 },                           // TONE_PROP_NACK
+        { { 400, 1200, 0 },       { 200, 0 },                        0 },                           // TONE_PROP_PROMPT
+        { { 400, 1200, 0 },       { 40, 200, 40, 0 },                0 }                            // TONE_PROP_BEEP2
+    };
+
+////////////////////////////////////////////////////////////////////////////////
+//                           ToneGenerator class Implementation
+////////////////////////////////////////////////////////////////////////////////
+
+
+//---------------------------------- public methods ----------------------------
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        ToneGenerator::ToneGenerator()
+//
+//    Description:    Constructor. Initializes the tone sequencer, intantiates required sine wave
+//        generators, instantiates output audio track.
+//
+//    Input:
+//        toneType:        Type of tone generated (values in enum tone_type)
+//        streamType:        Type of stream used for tone playback (enum AudioTrack::stream_type)
+//        volume:            volume applied to tone (0.0 to 1.0)
+//
+//    Output:
+//        none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::ToneGenerator(int streamType, float volume) {
+
+    LOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume);
+
+    mState = TONE_IDLE;
+
+    if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) {
+        LOGE("Unable to marshal AudioFlinger");
+        return;
+    }
+    mStreamType = streamType;
+    mVolume = volume;
+    mpAudioTrack = 0;
+    mpToneDesc = 0;
+    mpNewToneDesc = 0;
+    // Generate tone by chunks of 20 ms to keep cadencing precision
+    mProcessSize = (mSamplingRate * 20) / 1000;
+
+    if (initAudioTrack()) {
+        LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
+    } else {
+        LOGV("!!!ToneGenerator INIT FAILED!!!\n");
+    }
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        ToneGenerator::~ToneGenerator()
+//
+//    Description:    Destructor. Stop sound playback and delete audio track if
+//      needed and delete sine wave generators.
+//
+//    Input:
+//        none
+//
+//    Output:
+//        none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::~ToneGenerator() {
+    LOGV("ToneGenerator destructor\n");
+
+    if (mpAudioTrack) {
+        stopTone();
+        LOGV("Delete Track: %p\n", mpAudioTrack);
+        delete mpAudioTrack;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        ToneGenerator::startTone()
+//
+//    Description:    Starts tone playback.
+//
+//    Input:
+//        none
+//
+//    Output:
+//        none
+//
+////////////////////////////////////////////////////////////////////////////////
+bool ToneGenerator::startTone(int toneType) {
+    bool lResult = false;
+
+    if (toneType >= NUM_TONES)
+        return lResult;
+
+    if (mState == TONE_IDLE) {
+        LOGV("startTone: try to re-init AudioTrack");
+        if (!initAudioTrack()) {
+            return lResult;
+        }
+    }
+
+    LOGV("startTone\n");
+
+    mLock.lock();
+
+    // Get descriptor for requested tone
+    mpNewToneDesc = &toneDescriptors[toneType];
+
+    if (mState == TONE_INIT) {
+        if (prepareWave()) {
+            LOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000));
+            lResult = true;
+            mState = TONE_STARTING;
+            mLock.unlock();
+            mpAudioTrack->start();
+            mLock.lock();
+            if (mState == TONE_STARTING) {
+                LOGV("Wait for start callback");
+                if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR) {
+                    LOGE("--- Immediate start timed out");
+                    mState = TONE_IDLE;
+                    lResult = false;
+                }
+            }
+        } else {
+            mState == TONE_IDLE;
+        }
+    } else {
+        LOGV("Delayed start\n");
+
+        mState = TONE_RESTARTING;
+        if (mWaitCbkCond.waitRelative(mLock, seconds(1)) == NO_ERROR) {
+            if (mState != TONE_IDLE) {
+                lResult = true;
+            }
+            LOGV("cond received");
+        } else {
+            LOGE("--- Delayed start timed out");
+            mState = TONE_IDLE;
+        }
+    }
+    mLock.unlock();
+
+    LOGV_IF(lResult, "Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
+    LOGW_IF(!lResult, "Tone start failed!!!, time %d\n", (unsigned int)(systemTime()/1000000));
+
+    return lResult;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        ToneGenerator::stopTone()
+//
+//    Description:    Stops tone playback.
+//
+//    Input:
+//        none
+//
+//    Output:
+//        none
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::stopTone() {
+    LOGV("stopTone");
+
+    mLock.lock();
+    if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) {
+        mState = TONE_STOPPING;
+        LOGV("waiting cond");
+        status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(1));
+        if (lStatus == NO_ERROR) {
+            LOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000));
+        } else {
+            LOGE("--- Stop timed out");
+            mState = TONE_IDLE;
+            mpAudioTrack->stop();
+        }
+    }
+
+    clearWaveGens();
+
+    mLock.unlock();
+}
+
+//---------------------------------- private methods ---------------------------
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        ToneGenerator::initAudioTrack()
+//
+//    Description:    Allocates and configures AudioTrack used for PCM output.
+//
+//    Input:
+//        none
+//
+//    Output:
+//        none
+//
+////////////////////////////////////////////////////////////////////////////////
+bool ToneGenerator::initAudioTrack() {
+
+    if (mpAudioTrack) {
+        delete mpAudioTrack;
+        mpAudioTrack = 0;
+    }
+
+   // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
+    mpAudioTrack
+            = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, 0, 0, audioCallback, this, 0);
+
+    if (mpAudioTrack == 0) {
+        LOGE("AudioTrack allocation failed");
+        goto initAudioTrack_exit;
+    }
+    LOGV("Create Track: %p\n", mpAudioTrack);
+
+    if (mpAudioTrack->initCheck() != NO_ERROR) {
+        LOGE("AudioTrack->initCheck failed");
+        goto initAudioTrack_exit;
+    }
+
+    mpAudioTrack->setVolume(mVolume, mVolume);
+
+    mState = TONE_INIT;
+
+    return true;
+
+initAudioTrack_exit:
+
+    // Cleanup
+    if (mpAudioTrack) {
+        LOGV("Delete Track I: %p\n", mpAudioTrack);
+        delete mpAudioTrack;
+        mpAudioTrack = 0;
+    }
+
+    return false;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        ToneGenerator::audioCallback()
+//
+//    Description:    AudioTrack callback implementation. Generates a block of
+//        PCM samples
+//        and manages tone generator sequencer: tones pulses, tone duration...
+//
+//    Input:
+//        user    reference (pointer to our ToneGenerator)
+//        info    audio buffer descriptor
+//
+//    Output:
+//        returned value: always true.
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::audioCallback(int event, void* user, void *info) {
+    
+    if (event != AudioTrack::EVENT_MORE_DATA) return;
+    
+    const AudioTrack::Buffer *buffer = static_cast<const AudioTrack::Buffer *>(info);
+    ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user);
+    short *lpOut = buffer->i16;
+    unsigned int lNumSmp = buffer->size/sizeof(short);
+
+    if (buffer->size == 0) return;
+
+
+    // Clear output buffer: WaveGenerator accumulates into lpOut buffer
+    memset(lpOut, 0, buffer->size);
+
+    while (lNumSmp) {
+        unsigned int lReqSmp = lNumSmp < lpToneGen->mProcessSize*2 ? lNumSmp : lpToneGen->mProcessSize;
+        unsigned int lGenSmp;
+        unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT;
+        bool lSignal = false;
+ 
+        lpToneGen->mLock.lock();
+
+        // Update pcm frame count and end time (current time at the end of this process)
+        lpToneGen->mTotalSmp += lReqSmp;
+    
+        // Update tone gen state machine and select wave gen command
+        switch (lpToneGen->mState) {
+        case TONE_PLAYING:
+            lWaveCmd = WaveGenerator::WAVEGEN_CONT;
+            break;
+        case TONE_STARTING:
+            LOGV("Starting Cbk");
+    
+            lWaveCmd = WaveGenerator::WAVEGEN_START;
+            break;
+        case TONE_STOPPING:
+        case TONE_RESTARTING:
+            LOGV("Stop/restart Cbk");
+    
+            lWaveCmd = WaveGenerator::WAVEGEN_STOP;
+            lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
+            break;
+        default:
+            LOGV("Extra Cbk");
+            goto audioCallback_EndLoop;
+        }
+        
+    
+        // Exit if tone sequence is over
+        if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) {
+            if (lpToneGen->mState == TONE_PLAYING) {
+                lpToneGen->mState = TONE_STOPPING;            
+            }
+            goto audioCallback_EndLoop;
+        }
+    
+        if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
+            // Time to go to next sequence segment
+    
+            LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
+    
+            lGenSmp = lReqSmp;
+    
+            if (lpToneGen->mCurSegment & 0x0001) {
+                // If odd segment,  OFF -> ON transition : reset wave generator
+                lWaveCmd = WaveGenerator::WAVEGEN_START;
+    
+                LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+            } else {
+                // If even segment,  ON -> OFF transition : ramp volume down
+                lWaveCmd = WaveGenerator::WAVEGEN_STOP;
+    
+                LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+            }
+    
+            // Pre increment segment index and handle loop if last segment reached
+            if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) {
+                LOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
+    
+                // Pre increment loop count and restart if total count not reached. Stop sequence otherwise
+                if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) {
+                    LOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
+    
+                    lpToneGen->mCurSegment = 0;
+    
+                    LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+                            (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
+    
+                } else {
+                    LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
+    
+                    // Cancel OFF->ON transition in case previous segment tone state was OFF
+                    if (!(lpToneGen->mCurSegment & 0x0001)) {
+                        lGenSmp = 0;
+                    }
+                }
+            } else {
+                LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+                        (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
+            }
+    
+            // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
+            lpToneGen->mNextSegSmp
+                    += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000;
+    
+        } else {
+            // Inside a segment keep tone ON or OFF
+            if (lpToneGen->mCurSegment & 0x0001) {
+                lGenSmp = 0;  // If odd segment, tone is currently OFF
+            } else {
+                lGenSmp = lReqSmp;  // If event segment, tone is currently ON
+            }
+        }
+    
+        if (lGenSmp) {
+            // If samples must be generated, call all active wave generators and acumulate waves in lpOut
+            unsigned int lWaveIdx;
+    
+            for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) {
+                WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx];
+                lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
+            }
+        }
+        
+        lNumSmp -= lReqSmp;
+        lpOut += lReqSmp;
+    
+audioCallback_EndLoop:
+    
+        switch (lpToneGen->mState) {
+        case TONE_RESTARTING:
+            LOGV("Cbk restarting track\n");
+            if (lpToneGen->prepareWave()) {
+                lpToneGen->mState = TONE_STARTING;
+            } else {
+                LOGW("Cbk restarting prepareWave() failed\n");
+                lpToneGen->mState = TONE_IDLE;
+                lpToneGen->mpAudioTrack->stop();
+                // Force loop exit
+                lNumSmp = 0;
+            }
+            lSignal = true;
+            break;
+        case TONE_STOPPING:
+            lpToneGen->mState = TONE_INIT;
+            LOGV("Cbk Stopping track\n");
+            lSignal = true;
+            lpToneGen->mpAudioTrack->stop();
+            
+            // Force loop exit
+            lNumSmp = 0;
+            break;
+        case TONE_STARTING:
+            LOGV("Cbk starting track\n");
+            lpToneGen->mState = TONE_PLAYING;
+            lSignal = true;
+           break;
+        default:
+            break;
+        }
+
+        if (lSignal)
+            lpToneGen->mWaitCbkCond.signal();
+        lpToneGen->mLock.unlock();
+    }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        ToneGenerator::prepareWave()
+//
+//    Description:    Prepare wave generators and reset tone sequencer state machine.
+//      mpNewToneDesc must have been initialized befoire calling this function.
+//    Input:
+//        none
+//
+//    Output:
+//        returned value:   true if wave generators have been created, false otherwise
+//
+////////////////////////////////////////////////////////////////////////////////
+bool ToneGenerator::prepareWave() {
+    unsigned int lCnt = 0;
+    unsigned int lNumWaves;
+
+    if (!mpNewToneDesc) {
+        return false;
+    }
+    // Remove existing wave generators if any
+    clearWaveGens();
+
+    mpToneDesc = mpNewToneDesc;
+
+    // Get total number of sine waves: needed to adapt sine wave gain.
+    lNumWaves = numWaves();
+
+    // Instantiate as many wave generators as listed in descriptor
+    while (lCnt < lNumWaves) {
+        ToneGenerator::WaveGenerator *lpWaveGen =
+                new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate,
+                        mpToneDesc->waveFreq[lCnt],
+                        TONEGEN_GAIN/lNumWaves);
+        if (lpWaveGen == 0) {
+            goto prepareWave_exit;
+        }
+
+        mWaveGens.push(lpWaveGen);
+        LOGV("Create sine: %d\n", mpToneDesc->waveFreq[lCnt]);
+        lCnt++;
+    }
+
+    // Initialize tone sequencer
+    mTotalSmp = 0;
+    mCurSegment = 0;
+    mCurCount = 0;
+    mNextSegSmp = (mpToneDesc->segments[0] * mSamplingRate) / 1000;
+
+    return true;
+
+prepareWave_exit:
+
+    clearWaveGens();
+
+    return false;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        ToneGenerator::numWaves()
+//
+//    Description:    Count number of sine waves needed to generate tone (e.g 2 for DTMF).
+//
+//    Input:
+//        none
+//
+//    Output:
+//        returned value:    nummber of sine waves
+//
+////////////////////////////////////////////////////////////////////////////////
+unsigned int ToneGenerator::numWaves() {
+    unsigned int lCnt = 0;
+
+    while (mpToneDesc->waveFreq[lCnt]) {
+        lCnt++;
+    }
+
+    return lCnt;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        ToneGenerator::clearWaveGens()
+//
+//    Description:    Removes all wave generators.
+//
+//    Input:
+//        none
+//
+//    Output:
+//        none
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::clearWaveGens() {
+    LOGV("Clearing mWaveGens:");
+
+    while (!mWaveGens.isEmpty()) {
+        delete mWaveGens.top();
+        mWaveGens.pop();
+    }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//                WaveGenerator::WaveGenerator class    Implementation
+////////////////////////////////////////////////////////////////////////////////
+
+//---------------------------------- public methods ----------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        WaveGenerator::WaveGenerator()
+//
+//    Description:    Constructor.
+//
+//    Input:
+//        samplingRate:    Output sampling rate in Hz
+//        frequency:       Frequency of the sine wave to generate in Hz
+//        volume:          volume (0.0 to 1.0)
+//
+//    Output:
+//        none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::WaveGenerator::WaveGenerator(unsigned short samplingRate,
+        unsigned short frequency, float volume) {
+    double d0;
+    double F_div_Fs;  // frequency / samplingRate
+
+    F_div_Fs = frequency / (double)samplingRate;
+    d0 = - (float)GEN_AMP * sin(2 * M_PI * F_div_Fs);
+    mS2_0 = (short)d0;
+    mS1 = 0;
+    mS2 = mS2_0;
+
+    mAmplitude_Q15 = (short)(32767. * 32767. * volume / GEN_AMP);
+    // take some margin for amplitude fluctuation
+    if (mAmplitude_Q15 > 32500)
+        mAmplitude_Q15 = 32500;
+
+    d0 = 32768.0 * cos(2 * M_PI * F_div_Fs);  // Q14*2*cos()
+    if (d0 > 32767)
+        d0 = 32767;
+    mA1_Q14 = (short) d0;
+
+    LOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d\n",
+            mA1_Q14, mS2_0, mAmplitude_Q15);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        WaveGenerator::~WaveGenerator()
+//
+//    Description:    Destructor.
+//
+//    Input:
+//        none
+//
+//    Output:
+//        none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::WaveGenerator::~WaveGenerator() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        WaveGenerator::getSamples()
+//
+//    Description:    Generates count samples of a sine wave and accumulates
+//        result in outBuffer.
+//
+//    Input:
+//        outBuffer:      Output buffer where to accumulate samples.
+//        count:          number of samples to produce.
+//        command:        special action requested (see enum gen_command).
+//
+//    Output:
+//        none
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::WaveGenerator::getSamples(short *outBuffer,
+        unsigned int count, unsigned int command) {
+    long lS1, lS2;
+    long lA1, lAmplitude;
+    long Sample;  // current sample
+
+    // init local
+    if (command == WAVEGEN_START) {
+        lS1 = (long)0;
+        lS2 = (long)mS2_0;
+    } else {
+        lS1 = (long)mS1;
+        lS2 = (long)mS2;
+    }
+    lA1 = (long)mA1_Q14;
+    lAmplitude = (long)mAmplitude_Q15;
+
+    if (command == WAVEGEN_STOP) {
+        lAmplitude <<= 16;
+        if (count == 0) {
+            return;
+        }
+        long dec = lAmplitude/count;
+        // loop generation
+        while (count--) {
+            Sample = ((lA1 * lS1) >> S_Q14) - lS2;
+            // shift delay
+            lS2 = lS1;
+            lS1 = Sample;
+            Sample = ((lAmplitude>>16) * Sample) >> S_Q15;
+            *(outBuffer++) += (short)Sample;  // put result in buffer
+            lAmplitude -= dec;
+        }
+    } else {
+        // loop generation
+        while (count--) {
+            Sample = ((lA1 * lS1) >> S_Q14) - lS2;
+            // shift delay
+            lS2 = lS1;
+            lS1 = Sample;
+            Sample = (lAmplitude * Sample) >> S_Q15;
+            *(outBuffer++) += (short)Sample;  // put result in buffer
+        }
+    }
+
+    // save status
+    mS1 = (short)lS1;
+    mS2 = (short)lS2;
+}
+
+}  // end namespace android
+
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
new file mode 100644
index 0000000..09afc6c
--- /dev/null
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -0,0 +1,188 @@
+/*
+**
+** Copyright 2008, 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_TAG "MediaMetadataRetriever"
+
+#include <utils/IServiceManager.h>
+#include <utils/IPCThreadState.h>
+#include <media/mediametadataretriever.h>
+#include <media/IMediaPlayerService.h>
+#include <utils/Log.h>
+#include <dlfcn.h>
+
+namespace android {
+
+// client singleton for binder interface to service
+Mutex MediaMetadataRetriever::sServiceLock;
+sp<IMediaPlayerService> MediaMetadataRetriever::sService;
+sp<MediaMetadataRetriever::DeathNotifier> MediaMetadataRetriever::sDeathNotifier;
+
+const sp<IMediaPlayerService>& MediaMetadataRetriever::getService()
+{
+    Mutex::Autolock lock(sServiceLock);
+    if (sService.get() == 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16("media.player"));
+            if (binder != 0) {
+                break;
+            }
+            LOGW("MediaPlayerService not published, waiting...");
+            usleep(500000); // 0.5 s
+        } while(true);
+        if (sDeathNotifier == NULL) {
+            sDeathNotifier = new DeathNotifier();
+        }
+        binder->linkToDeath(sDeathNotifier);
+        sService = interface_cast<IMediaPlayerService>(binder);
+    }
+    LOGE_IF(sService == 0, "no MediaPlayerService!?");
+    return sService;
+}
+
+MediaMetadataRetriever::MediaMetadataRetriever()
+{
+    LOGV("constructor");
+    const sp<IMediaPlayerService>& service(getService());
+    if (service == 0) {
+        LOGE("failed to obtain MediaMetadataRetrieverService");
+        return;
+    }
+    sp<IMediaMetadataRetriever> retriever(service->createMetadataRetriever(getpid()));
+    if (retriever == 0) {
+        LOGE("failed to create IMediaMetadataRetriever object from server");
+    }
+    mRetriever = retriever;
+}
+
+MediaMetadataRetriever::~MediaMetadataRetriever()
+{
+    LOGV("destructor");
+    disconnect();
+    IPCThreadState::self()->flushCommands();
+}
+
+void MediaMetadataRetriever::disconnect()
+{
+    LOGV("disconnect");
+    sp<IMediaMetadataRetriever> retriever;
+    {
+        Mutex::Autolock _l(mLock);
+        retriever = mRetriever;
+        mRetriever.clear();
+    }
+    if (retriever != 0) {
+        retriever->disconnect();
+    }
+}
+
+status_t MediaMetadataRetriever::setDataSource(const char* srcUrl)
+{
+    LOGV("setDataSource");
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
+    if (srcUrl == NULL) {
+        LOGE("data source is a null pointer");
+        return UNKNOWN_ERROR;
+    }
+    LOGV("data source (%s)", srcUrl);
+    return mRetriever->setDataSource(srcUrl);
+}
+
+status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
+{
+    LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
+    if (fd < 0 || offset < 0 || length < 0) {
+        LOGE("Invalid negative argument");
+        return UNKNOWN_ERROR;
+    }
+    return mRetriever->setDataSource(fd, offset, length);
+}
+
+status_t MediaMetadataRetriever::setMode(int mode)
+{
+    LOGV("setMode(%d)", mode);
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
+    return mRetriever->setMode(mode);
+}
+
+status_t MediaMetadataRetriever::getMode(int* mode)
+{
+    LOGV("getMode");
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
+    return mRetriever->getMode(mode);
+}
+
+sp<IMemory> MediaMetadataRetriever::captureFrame()
+{
+    LOGV("captureFrame");
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return NULL;
+    }
+    return mRetriever->captureFrame();
+}
+
+const char* MediaMetadataRetriever::extractMetadata(int keyCode)
+{
+    LOGV("extractMetadata(%d)", keyCode);
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return NULL;
+    }
+    return mRetriever->extractMetadata(keyCode);
+}
+
+sp<IMemory> MediaMetadataRetriever::extractAlbumArt()
+{
+    LOGV("extractAlbumArt");
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return NULL;
+    }
+    return mRetriever->extractAlbumArt();
+}
+
+void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who) {
+    Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
+    MediaMetadataRetriever::sService.clear();
+    LOGW("MediaMetadataRetriever server died!");
+}
+
+MediaMetadataRetriever::DeathNotifier::~DeathNotifier()
+{
+    Mutex::Autolock lock(sServiceLock);
+    if (sService != 0) {
+        sService->asBinder()->unlinkToDeath(this);
+    }
+}
+
+}; // namespace android
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
new file mode 100644
index 0000000..bd8579c
--- /dev/null
+++ b/media/libmedia/mediaplayer.cpp
@@ -0,0 +1,624 @@
+/* mediaplayer.cpp
+**
+** Copyright 2006, 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_TAG "MediaPlayer"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/IPCThreadState.h>
+
+#include <media/mediaplayer.h>
+#include <media/AudioTrack.h>
+
+#include <utils/MemoryBase.h>
+
+namespace android {
+
+// client singleton for binder interface to service
+Mutex MediaPlayer::sServiceLock;
+sp<IMediaPlayerService> MediaPlayer::sMediaPlayerService;
+sp<MediaPlayer::DeathNotifier> MediaPlayer::sDeathNotifier;
+SortedVector< wp<MediaPlayer> > MediaPlayer::sObitRecipients;
+
+// establish binder interface to service
+const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
+{
+    Mutex::Autolock _l(sServiceLock);
+    if (sMediaPlayerService.get() == 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16("media.player"));
+            if (binder != 0)
+                break;
+            LOGW("MediaPlayerService not published, waiting...");
+            usleep(500000); // 0.5 s
+        } while(true);
+        if (sDeathNotifier == NULL) {
+            sDeathNotifier = new DeathNotifier();
+        }
+        binder->linkToDeath(sDeathNotifier);
+        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
+    }
+    LOGE_IF(sMediaPlayerService==0, "no MediaPlayerService!?");
+    return sMediaPlayerService;
+}
+
+void MediaPlayer::addObitRecipient(const wp<MediaPlayer>& recipient)
+{
+    Mutex::Autolock _l(sServiceLock);
+    sObitRecipients.add(recipient);
+}
+
+void MediaPlayer::removeObitRecipient(const wp<MediaPlayer>& recipient)
+{
+    Mutex::Autolock _l(sServiceLock);
+    sObitRecipients.remove(recipient);
+}
+
+MediaPlayer::MediaPlayer()
+{
+    LOGV("constructor");
+    mListener = NULL;
+    mCookie = NULL;
+    mDuration = -1;
+    mStreamType = AudioSystem::MUSIC;
+    mCurrentPosition = -1;
+    mSeekPosition = -1;
+    mCurrentState = MEDIA_PLAYER_IDLE;
+    mPrepareSync = false;
+    mPrepareStatus = NO_ERROR;
+    mLoop = false;
+    mLeftVolume = mRightVolume = 1.0;
+    mVideoWidth = mVideoHeight = 0;
+}
+
+void MediaPlayer::onFirstRef()
+{
+    addObitRecipient(this);
+}
+
+MediaPlayer::~MediaPlayer()
+{
+    LOGV("destructor");
+    removeObitRecipient(this);
+    disconnect();
+    IPCThreadState::self()->flushCommands();
+}
+
+void MediaPlayer::disconnect()
+{
+    LOGV("disconnect");
+    sp<IMediaPlayer> p;
+    {
+        Mutex::Autolock _l(mLock);
+        p = mPlayer;
+        mPlayer.clear();
+    }
+
+    if (p != 0) {
+        p->disconnect();
+    }
+}
+
+// always call with lock held
+void MediaPlayer::clear_l()
+{
+    mDuration = -1;
+    mCurrentPosition = -1;
+    mSeekPosition = -1;
+    mVideoWidth = mVideoHeight = 0;
+}
+
+status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
+{
+    LOGV("setListener");
+    Mutex::Autolock _l(mLock);
+    mListener = listener;
+    return NO_ERROR;
+}
+
+
+status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
+{
+    status_t err = UNKNOWN_ERROR;
+    sp<IMediaPlayer> p;
+    { // scope for the lock
+        Mutex::Autolock _l(mLock);
+
+        if ( !( mCurrentState & ( MEDIA_PLAYER_IDLE | MEDIA_PLAYER_STATE_ERROR ) ) ) {
+            LOGE("setDataSource called in state %d", mCurrentState);
+            return INVALID_OPERATION;
+        }
+
+        clear_l();
+        p = mPlayer;
+        mPlayer = player;
+        if (player != 0) {
+            mCurrentState = MEDIA_PLAYER_INITIALIZED;
+            err = NO_ERROR;
+        } else {
+            LOGE("Unable to to create media player");
+        }
+    }
+
+    if (p != 0) {
+        p->disconnect();
+    }
+
+    return err;
+}
+
+status_t MediaPlayer::setDataSource(const char *url)
+{
+    LOGV("setDataSource(%s)", url);
+    status_t err = BAD_VALUE;
+    if (url != NULL) {
+        const sp<IMediaPlayerService>& service(getMediaPlayerService());
+        if (service != 0) {
+            sp<IMediaPlayer> player(service->create(getpid(), this, url));
+            err = setDataSource(player);
+        }
+    }
+    return err;
+}
+
+status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
+{
+    LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
+    status_t err = UNKNOWN_ERROR;
+    const sp<IMediaPlayerService>& service(getMediaPlayerService());
+    if (service != 0) {
+        sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length));
+        err = setDataSource(player);
+    }
+    return err;
+}
+
+status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
+{
+    LOGV("setVideoSurface");
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == 0) return NO_INIT;
+    return  mPlayer->setVideoSurface(surface->getISurface());
+}
+
+// must call with lock held
+status_t MediaPlayer::prepareAsync_l()
+{
+    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
+        mPlayer->setAudioStreamType(mStreamType);
+        mCurrentState = MEDIA_PLAYER_PREPARING;
+        return mPlayer->prepareAsync();
+    }
+    LOGE("prepareAsync called in state %d", mCurrentState);
+    return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::prepare()
+{
+    LOGV("prepare");
+    Mutex::Autolock _l(mLock);
+    if (mPrepareSync) return -EALREADY;
+    mPrepareSync = true;
+    status_t ret = prepareAsync_l();
+    if (ret != NO_ERROR) return ret;
+
+    if (mPrepareSync) {
+        mSignal.wait(mLock);  // wait for prepare done
+        mPrepareSync = false;
+    }
+    LOGV("prepare complete - status=%d", mPrepareStatus);
+    return mPrepareStatus;
+}
+
+status_t MediaPlayer::prepareAsync()
+{
+    LOGV("prepareAsync");
+    Mutex::Autolock _l(mLock);
+    return prepareAsync_l();
+}
+
+status_t MediaPlayer::start()
+{
+    LOGV("start");
+    Mutex::Autolock _l(mLock);
+    if (mCurrentState & MEDIA_PLAYER_STARTED)
+        return NO_ERROR;
+    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
+                    MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
+        mPlayer->setLooping(mLoop);
+        mPlayer->setVolume(mLeftVolume, mRightVolume);
+        mCurrentState = MEDIA_PLAYER_STARTED;
+        status_t ret = mPlayer->start();
+        if (ret != NO_ERROR) {
+            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+        } else {
+            if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
+                LOGV("playback completed immediately following start()");
+            }
+        }
+        return ret;
+    }
+    LOGE("start called in state %d", mCurrentState);
+    return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::stop()
+{
+    LOGV("stop");
+    Mutex::Autolock _l(mLock);
+    if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
+    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
+                    MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
+        status_t ret = mPlayer->stop();
+        if (ret != NO_ERROR) {
+            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+        } else {
+            mCurrentState = MEDIA_PLAYER_STOPPED;
+        }
+        return ret;
+    }
+    LOGE("stop called in state %d", mCurrentState);
+    return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::pause()
+{
+    LOGV("pause");
+    Mutex::Autolock _l(mLock);
+    if (mCurrentState & MEDIA_PLAYER_PAUSED)
+        return NO_ERROR;
+    if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
+        status_t ret = mPlayer->pause();
+        if (ret != NO_ERROR) {
+            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+        } else {
+            mCurrentState = MEDIA_PLAYER_PAUSED;
+        }
+        return ret;
+    }
+    LOGE("pause called in state %d", mCurrentState);
+    return INVALID_OPERATION;
+}
+
+bool MediaPlayer::isPlaying()
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer != 0) {
+        bool temp = false;
+        mPlayer->isPlaying(&temp);
+        LOGV("isPlaying: %d", temp);
+        if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
+            LOGE("internal/external state mismatch corrected");
+            mCurrentState = MEDIA_PLAYER_PAUSED;
+        }
+        return temp;
+    }
+    LOGV("isPlaying: no active player");
+    return false;
+}
+
+status_t MediaPlayer::getVideoWidth(int *w)
+{
+    LOGV("getVideoWidth");
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == 0) return INVALID_OPERATION;
+    *w = mVideoWidth;
+    return NO_ERROR;
+}
+
+status_t MediaPlayer::getVideoHeight(int *h)
+{
+    LOGV("getVideoHeight");
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == 0) return INVALID_OPERATION;
+    *h = mVideoHeight;
+    return NO_ERROR;
+}
+
+status_t MediaPlayer::getCurrentPosition(int *msec)
+{
+    LOGV("getCurrentPosition");
+    Mutex::Autolock _l(mLock);
+    if (mPlayer != 0) {
+        if (mCurrentPosition >= 0) {
+            LOGV("Using cached seek position: %d", mCurrentPosition);
+            *msec = mCurrentPosition;
+            return NO_ERROR;
+        }
+        return mPlayer->getCurrentPosition(msec);
+    }
+    return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::getDuration_l(int *msec)
+{
+    LOGV("getDuration");
+    bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
+    if (mPlayer != 0 && isValidState) {
+        status_t ret = NO_ERROR;
+        if (mDuration <= 0)
+            ret = mPlayer->getDuration(&mDuration);
+        if (msec)
+            *msec = mDuration;
+        return ret;
+    }
+    LOGE("Attempt to call getDuration without a valid mediaplayer");
+    return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::getDuration(int *msec)
+{
+    Mutex::Autolock _l(mLock);
+    return getDuration_l(msec);
+}
+
+status_t MediaPlayer::seekTo_l(int msec)
+{
+    LOGV("seekTo %d", msec);
+    if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED |  MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
+        if ( msec < 0 ) {
+            LOGW("Attempt to seek to invalid position: %d", msec);
+            msec = 0;
+        } else if ((mDuration > 0) && (msec > mDuration)) {
+            LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
+            msec = mDuration;
+        }
+        // cache duration
+        mCurrentPosition = msec;
+        if (mSeekPosition < 0) {
+            getDuration_l(NULL);
+            mSeekPosition = msec;
+            return mPlayer->seekTo(msec);
+        }
+        else {
+            LOGV("Seek in progress - queue up seekTo[%d]", msec);
+            return NO_ERROR;
+        }
+    }
+    LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
+    return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::seekTo(int msec)
+{
+    Mutex::Autolock _l(mLock);
+    return seekTo_l(msec);
+}
+
+status_t MediaPlayer::reset()
+{
+    LOGV("reset");
+    Mutex::Autolock _l(mLock);
+    mLoop = false;
+    if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
+    mPrepareSync = false;
+    if (mPlayer != 0) {
+        status_t ret = mPlayer->reset();
+        if (ret != NO_ERROR) {
+            LOGE("reset() failed with return code (%d)", ret);
+            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+        } else {
+            mCurrentState = MEDIA_PLAYER_IDLE;
+        }
+        return ret;
+    }
+    clear_l();
+    return NO_ERROR;
+}
+
+status_t MediaPlayer::setAudioStreamType(int type)
+{
+    LOGV("MediaPlayer::setAudioStreamType");
+    Mutex::Autolock _l(mLock);
+    if (mStreamType == type) return NO_ERROR;
+    if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
+                MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
+        // Can't change the stream type after prepare
+        LOGE("setAudioStream called in state %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    // cache
+    mStreamType = type;
+    return OK;
+}
+
+status_t MediaPlayer::setLooping(int loop)
+{
+    LOGV("MediaPlayer::setLooping");
+    Mutex::Autolock _l(mLock);
+    mLoop = (loop != 0);
+    if (mPlayer != 0) {
+        return mPlayer->setLooping(loop);
+    }
+    return OK;
+}
+
+bool MediaPlayer::isLooping() {
+    LOGV("isLooping");
+    Mutex::Autolock _l(mLock);
+    if (mPlayer != 0) {
+        return mLoop;
+    }
+    LOGV("isLooping: no active player");
+    return false;
+}
+
+status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
+{
+    LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
+    Mutex::Autolock _l(mLock);
+    mLeftVolume = leftVolume;
+    mRightVolume = rightVolume;
+    if (mPlayer != 0) {
+        return mPlayer->setVolume(leftVolume, rightVolume);
+    }
+    return OK;
+}
+
+void MediaPlayer::notify(int msg, int ext1, int ext2)
+{
+    LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+    bool send = true;
+
+    // TODO: In the future, we might be on the same thread if the app is
+    // running in the same process as the media server. In that case,
+    // this will deadlock.
+    mLock.lock();
+    if (mPlayer == 0) {
+        LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
+        mLock.unlock();   // release the lock when done.
+        return;
+    }
+
+    switch (msg) {
+    case MEDIA_NOP: // interface test message
+        break;
+    case MEDIA_PREPARED:
+        LOGV("prepared");
+        mCurrentState = MEDIA_PLAYER_PREPARED;
+        if (mPrepareSync) {
+            LOGV("signal application thread");
+            mPrepareSync = false;
+            mPrepareStatus = NO_ERROR;
+            mSignal.signal();
+        }
+        break;
+    case MEDIA_PLAYBACK_COMPLETE:
+        LOGV("playback complete");
+        if (!mLoop) {
+            mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
+        }
+        break;
+    case MEDIA_ERROR:
+        // Always log errors
+        LOGE("error (%d, %d)", ext1, ext2);
+        mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+        if (mPrepareSync)
+        {
+            LOGV("signal application thread");
+            mPrepareSync = false;
+            mPrepareStatus = ext1;
+            mSignal.signal();
+            send = false;
+        }
+        break;
+    case MEDIA_SEEK_COMPLETE:
+        LOGV("Received seek complete");
+        if (mSeekPosition != mCurrentPosition) {
+            LOGV("Executing queued seekTo(%d)", mSeekPosition);
+            mSeekPosition = -1;
+            seekTo_l(mCurrentPosition);
+        }
+        else {
+            LOGV("All seeks complete - return to regularly scheduled program");
+            mCurrentPosition = mSeekPosition = -1;
+        }
+        break;
+    case MEDIA_BUFFERING_UPDATE:
+        LOGV("buffering %d", ext1);
+        break;
+    case MEDIA_SET_VIDEO_SIZE:
+        LOGV("New video size %d x %d", ext1, ext2);
+        mVideoWidth = ext1;
+        mVideoHeight = ext2;
+        break;
+    default:
+        LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
+        break;
+    }
+
+    sp<MediaPlayerListener> listener = mListener;
+    mLock.unlock();
+
+    // this prevents re-entrant calls into client code
+    if ((listener != 0) && send) {
+        Mutex::Autolock _l(mNotifyLock);
+        LOGV("callback application");
+        listener->notify(msg, ext1, ext2);
+        LOGV("back from callback");
+    }
+}
+
+void MediaPlayer::DeathNotifier::binderDied(const wp<IBinder>& who) {
+    LOGW("MediaPlayer server died!");
+
+    // Need to do this with the lock held
+    SortedVector< wp<MediaPlayer> > list;
+    {
+        Mutex::Autolock _l(MediaPlayer::sServiceLock);
+        MediaPlayer::sMediaPlayerService.clear();
+        list = sObitRecipients;
+    }
+
+    // Notify application when media server dies.
+    // Don't hold the static lock during callback in case app
+    // makes a call that needs the lock.
+    size_t count = list.size();
+    for (size_t iter = 0; iter < count; ++iter) {
+        sp<MediaPlayer> player = list[iter].promote();
+        if ((player != 0) && (player->mPlayer != 0)) {
+            player->notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
+        }
+    }
+}
+
+MediaPlayer::DeathNotifier::~DeathNotifier()
+{
+    Mutex::Autolock _l(sServiceLock);
+    sObitRecipients.clear();
+    if (sMediaPlayerService != 0) {
+        sMediaPlayerService->asBinder()->unlinkToDeath(this);
+    }
+}
+
+/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
+{
+    LOGV("decode(%s)", url);
+    sp<IMemory> p;
+    const sp<IMediaPlayerService>& service = getMediaPlayerService();
+    if (service != 0) {
+        p = sMediaPlayerService->decode(url, pSampleRate, pNumChannels, pFormat);
+    } else {
+        LOGE("Unable to locate media service");
+    }
+    return p;
+
+}
+
+/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
+{
+    LOGV("decode(%d, %lld, %lld)", fd, offset, length);
+    sp<IMemory> p;
+    const sp<IMediaPlayerService>& service = getMediaPlayerService();
+    if (service != 0) {
+        p = sMediaPlayerService->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
+    } else {
+        LOGE("Unable to locate media service");
+    }
+    return p;
+
+}
+
+}; // namespace android
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
new file mode 100644
index 0000000..98aac39
--- /dev/null
+++ b/media/libmedia/mediarecorder.cpp
@@ -0,0 +1,617 @@
+/*
+ **
+ ** Copyright (c) 2008 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_TAG "MediaRecorder"
+#include <utils/Log.h>
+#include <ui/Surface.h>
+#include <media/mediarecorder.h>
+#include <utils/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+status_t MediaRecorder::setCamera(const sp<ICamera>& camera)
+{
+    LOGV("setCamera(%p)", camera.get());
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_IDLE)) {
+        LOGE("setCamera called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setCamera(camera);
+    if (OK != ret) {
+        LOGV("setCamera failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::setPreviewSurface(const sp<Surface>& surface)
+{
+    LOGV("setPreviewSurface(%p)", surface.get());
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setPreviewSurface called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        LOGE("try to set preview surface without setting the video source first");
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setPreviewSurface(surface->getISurface());
+    if (OK != ret) {
+        LOGV("setPreviewSurface failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::init()
+{
+    LOGV("init");
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_IDLE)) {
+        LOGE("init called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->init();
+    if (OK != ret) {
+        LOGV("init failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+
+    ret = mMediaRecorder->setListener(this);
+    if (OK != ret) {
+        LOGV("setListener failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+
+    mCurrentState = MEDIA_RECORDER_INITIALIZED;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoSource(int vs)
+{
+    LOGV("setVideoSource(%d)", vs);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsVideoSourceSet) {
+        LOGE("video source has already been set");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_IDLE) {
+        LOGV("Call init() since the media recorder is not initialized yet");
+        status_t ret = init();
+        if (OK != ret) {
+            return ret;
+        }
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        LOGE("setVideoSource called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoSource(vs);
+    if (OK != ret) {
+        LOGV("setVideoSource failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsVideoSourceSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setAudioSource(int as)
+{
+    LOGV("setAudioSource(%d)", as);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_IDLE) {
+        LOGV("Call init() since the media recorder is not initialized yet");
+        status_t ret = init();
+        if (OK != ret) {
+            return ret;
+        }
+    }
+    if (mIsAudioSourceSet) {
+        LOGE("audio source has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        LOGE("setAudioSource called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setAudioSource(as);
+    if (OK != ret) {
+        LOGV("setAudioSource failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsAudioSourceSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setOutputFormat(int of)
+{
+    LOGV("setOutputFormat(%d)", of);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        LOGE("setOutputFormat called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (mIsVideoSourceSet && of >= OUTPUT_FORMAT_RAW_AMR) {
+        LOGE("output format (%d) is meant for audio recording only and incompatible with video recording", of);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFormat(of);
+    if (OK != ret) {
+        LOGE("setOutputFormat failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mCurrentState = MEDIA_RECORDER_DATASOURCE_CONFIGURED;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoEncoder(int ve)
+{
+    LOGV("setVideoEncoder(%d)", ve);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        LOGE("try to set the video encoder without setting the video source first");
+        return INVALID_OPERATION;
+    }
+    if (mIsVideoEncoderSet) {
+        LOGE("video encoder has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setVideoEncoder called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoEncoder(ve);
+    if (OK != ret) {
+        LOGV("setVideoEncoder failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsVideoEncoderSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setAudioEncoder(int ae)
+{
+    LOGV("setAudioEncoder(%d)", ae);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!mIsAudioSourceSet) {
+        LOGE("try to set the audio encoder without setting the audio source first");
+        return INVALID_OPERATION;
+    }
+    if (mIsAudioEncoderSet) {
+        LOGE("audio encoder has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setAudioEncoder called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setAudioEncoder(ae);
+    if (OK != ret) {
+        LOGV("setAudioEncoder failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsAudioEncoderSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setOutputFile(const char* path)
+{
+    LOGV("setOutputFile(%s)", path);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsOutputFileSet) {
+        LOGE("output file has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setOutputFile called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFile(path);
+    if (OK != ret) {
+        LOGV("setOutputFile failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsOutputFileSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setOutputFile(int fd, int64_t offset, int64_t length)
+{
+    LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsOutputFileSet) {
+        LOGE("output file has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setOutputFile called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFile(fd, offset, length);
+    if (OK != ret) {
+        LOGV("setOutputFile failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsOutputFileSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoSize(int width, int height)
+{
+    LOGV("setVideoSize(%d, %d)", width, height);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setVideoSize called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        LOGE("try to set video size without setting video source first");
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoSize(width, height);
+    if (OK != ret) {
+        LOGE("setVideoSize failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::setVideoFrameRate(int frames_per_second)
+{
+    LOGV("setVideoFrameRate(%d)", frames_per_second);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        LOGE("try to set video frame rate without setting video source first");
+        return INVALID_OPERATION; 
+    }
+
+    status_t ret = mMediaRecorder->setVideoFrameRate(frames_per_second);
+    if (OK != ret) {
+        LOGE("setVideoFrameRate failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::prepare()
+{
+    LOGV("prepare");
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("prepare called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (mIsAudioSourceSet != mIsAudioEncoderSet) {
+        if (mIsAudioSourceSet) {
+            LOGE("audio source is set, but audio encoder is not set");
+        } else {  // must not happen, since setAudioEncoder checks this already
+            LOGE("audio encoder is set, but audio source is not set");
+        }
+        return INVALID_OPERATION;
+    }
+
+    if (mIsVideoSourceSet != mIsVideoEncoderSet) {
+        if (mIsVideoSourceSet) {
+            LOGE("video source is set, but video encoder is not set");
+        } else {  // must not happen, since setVideoEncoder checks this already
+            LOGE("video encoder is set, but video source is not set");
+        }
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->prepare();
+    if (OK != ret) {
+        LOGE("prepare failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mCurrentState = MEDIA_RECORDER_PREPARED;
+    return ret;
+}
+
+status_t MediaRecorder::getMaxAmplitude(int* max)
+{
+    LOGV("getMaxAmplitude");
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_ERROR) {
+        LOGE("getMaxAmplitude called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->getMaxAmplitude(max);
+    if (OK != ret) {
+        LOGE("getMaxAmplitude failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::start()
+{
+    LOGV("start");
+    if (mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_PREPARED)) {
+        LOGE("start called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->start();
+    if (OK != ret) {
+        LOGE("start failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mCurrentState = MEDIA_RECORDER_RECORDING;
+    return ret;
+}
+
+status_t MediaRecorder::stop()
+{
+    LOGV("stop");
+    if (mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) {
+        LOGE("stop called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->stop();
+    if (OK != ret) {
+        LOGE("stop failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mCurrentState = MEDIA_RECORDER_IDLE;
+    return ret;
+}
+
+// Reset should be OK in any state
+status_t MediaRecorder::reset()
+{
+    LOGV("reset");
+    if (mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    
+    doCleanUp();
+    status_t ret = UNKNOWN_ERROR;
+    switch(mCurrentState) {
+        case MEDIA_RECORDER_IDLE:
+            ret = OK;
+            break;
+
+        case MEDIA_RECORDER_RECORDING:
+        case MEDIA_RECORDER_DATASOURCE_CONFIGURED:
+        case MEDIA_RECORDER_PREPARED:
+        case MEDIA_RECORDER_ERROR: {
+            ret = doReset();
+            if (OK != ret) {
+               return ret;  // No need to continue
+            }
+        }  // Intentional fall through
+        case MEDIA_RECORDER_INITIALIZED:
+            ret = close();
+            break;
+
+        default: {
+            LOGE("Unexpected non-existing state: %d", mCurrentState);
+            break;
+        }
+    }
+    return ret;
+}
+
+status_t MediaRecorder::close()
+{
+    LOGV("close");
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        LOGE("close called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    status_t ret = mMediaRecorder->close();
+    if (OK != ret) {
+        LOGE("close failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    } else {
+        mCurrentState = MEDIA_RECORDER_IDLE;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::doReset()
+{
+    LOGV("doReset");
+    status_t ret = mMediaRecorder->reset();
+    if (OK != ret) {
+        LOGE("doReset failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    } else {
+        mCurrentState = MEDIA_RECORDER_INITIALIZED;
+    }
+    return ret;
+}
+
+void MediaRecorder::doCleanUp()
+{
+    LOGV("doCleanUp");
+    mIsAudioSourceSet  = false;
+    mIsVideoSourceSet  = false;
+    mIsAudioEncoderSet = false;
+    mIsVideoEncoderSet = false;
+    mIsOutputFileSet   = false;
+}
+
+// Release should be OK in any state
+status_t MediaRecorder::release()
+{
+    LOGV("release");
+    if (mMediaRecorder != NULL) {
+        return mMediaRecorder->release();
+    }
+    return INVALID_OPERATION;
+}
+
+MediaRecorder::MediaRecorder()
+{
+    LOGV("constructor");
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder;
+
+    do {
+        binder = sm->getService(String16("media.player"));
+        if (binder != NULL) {
+            break;
+        }
+        LOGW("MediaPlayerService not published, waiting...");
+        usleep(500000); // 0.5 s
+    } while(true);
+
+    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+    if (service != NULL) {
+        mMediaRecorder = service->createMediaRecorder(getpid());
+    }
+    if (mMediaRecorder != NULL) {
+        mCurrentState = MEDIA_RECORDER_IDLE;
+    }
+    doCleanUp();
+}
+
+status_t MediaRecorder::initCheck()
+{
+    return mMediaRecorder != 0 ? NO_ERROR : NO_INIT;
+}
+
+MediaRecorder::~MediaRecorder()
+{
+    LOGV("destructor");
+    if (mMediaRecorder != NULL) {
+        mMediaRecorder.clear();
+    }
+}
+
+status_t MediaRecorder::setListener(const sp<MediaRecorderListener>& listener)
+{
+    LOGV("setListener");
+    Mutex::Autolock _l(mLock);
+    mListener = listener;
+
+    return NO_ERROR;
+}
+
+void MediaRecorder::notify(int msg, int ext1, int ext2)
+{
+    LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+
+    sp<MediaRecorderListener> listener;
+    mLock.lock();
+    listener = mListener;
+    mLock.unlock();
+
+    if (listener != NULL) {
+        Mutex::Autolock _l(mNotifyLock);
+        LOGV("callback application");
+        listener->notify(msg, ext1, ext2);
+        LOGV("back from callback");
+    }
+}
+
+}; // namespace android
+