Merge "Move JetPlayer implemention and JNI"
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index ce405fe..d9428c5 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -159,7 +159,6 @@
                 "android_media_AudioVolumeGroups.cpp",
                 "android_media_AudioVolumeGroupCallback.cpp",
                 "android_media_DeviceCallback.cpp",
-                "android_media_JetPlayer.cpp",
                 "android_media_MediaMetricsJNI.cpp",
                 "android_media_MicrophoneInfo.cpp",
                 "android_media_midi.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 3497f92..4f7f18e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -95,7 +95,6 @@
 extern int register_android_media_AudioVolumeGroups(JNIEnv *env);
 extern int register_android_media_AudioVolumeGroupChangeHandler(JNIEnv *env);
 extern int register_android_media_MicrophoneInfo(JNIEnv *env);
-extern int register_android_media_JetPlayer(JNIEnv *env);
 extern int register_android_media_ToneGenerator(JNIEnv *env);
 extern int register_android_media_midi(JNIEnv *env);
 
@@ -1502,7 +1501,6 @@
     REG_JNI(register_android_media_AudioProductStrategies),
     REG_JNI(register_android_media_AudioVolumeGroups),
     REG_JNI(register_android_media_AudioVolumeGroupChangeHandler),
-    REG_JNI(register_android_media_JetPlayer),
     REG_JNI(register_android_media_MicrophoneInfo),
     REG_JNI(register_android_media_RemoteDisplay),
     REG_JNI(register_android_media_ToneGenerator),
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index b12e647..e85b3ff9 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -17,18 +17,17 @@
 package android.media;
 
 
-import java.io.FileDescriptor;
-import java.lang.ref.WeakReference;
-import java.lang.CloneNotSupportedException;
-
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.AssetFileDescriptor;
-import android.os.Looper;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
 
+import java.io.FileDescriptor;
+import java.lang.ref.WeakReference;
+
 /**
  * JetPlayer provides access to JET content playback and control.
  * 
@@ -120,6 +119,9 @@
     
     private static JetPlayer singletonRef;
     
+    static {
+        System.loadLibrary("media_jni");
+    }
     
     //--------------------------------
     // Used exclusively by native code
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index bd9ea13..b4edabf 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -4,6 +4,7 @@
     srcs: [
         "android_media_ImageWriter.cpp",
         "android_media_ImageReader.cpp",
+        "android_media_JetPlayer.cpp",
         "android_media_MediaCrypto.cpp",
         "android_media_MediaCodec.cpp",
         "android_media_MediaCodecList.cpp",
@@ -24,10 +25,12 @@
         "android_mtp_MtpDatabase.cpp",
         "android_mtp_MtpDevice.cpp",
         "android_mtp_MtpServer.cpp",
+        "JetPlayer.cpp",
     ],
 
     shared_libs: [
         "libandroid_runtime",
+        "libaudioclient",
         "libnativehelper",
         "libnativewindow",
         "libutils",
@@ -52,6 +55,7 @@
         "libandroidfw",
         "libhidlallocatorutils",
         "libhidlbase",
+        "libsonivox",
         "android.hardware.cas@1.0",
         "android.hardware.cas.native@1.0",
         "android.hidl.memory@1.0",
@@ -63,7 +67,10 @@
         "libmediadrm_headers",
     ],
 
-    static_libs: ["libgrallocusage"],
+    static_libs: [
+        "libgrallocusage",
+        "libmedia_midiiowrapper",
+    ],
 
     include_dirs: [
         "frameworks/base/core/jni",
diff --git a/media/jni/JetPlayer.cpp b/media/jni/JetPlayer.cpp
new file mode 100644
index 0000000..358feb7
--- /dev/null
+++ b/media/jni/JetPlayer.cpp
@@ -0,0 +1,471 @@
+/*
+ * 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 "JetPlayer.h"
+
+
+namespace android
+{
+
+static const int MIX_NUM_BUFFERS = 4;
+static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
+
+//-------------------------------------------------------------------------------------------------
+JetPlayer::JetPlayer(void *javaJetPlayer, int maxTracks, int trackBufferSize) :
+        mEventCallback(NULL),
+        mJavaJetPlayerRef(javaJetPlayer),
+        mTid(-1),
+        mRender(false),
+        mPaused(false),
+        mMaxTracks(maxTracks),
+        mEasData(NULL),
+        mIoWrapper(NULL),
+        mTrackBufferSize(trackBufferSize)
+{
+    ALOGV("JetPlayer constructor");
+    mPreviousJetStatus.currentUserID = -1;
+    mPreviousJetStatus.segmentRepeatCount = -1;
+    mPreviousJetStatus.numQueuedSegments = -1;
+    mPreviousJetStatus.paused = true;
+}
+
+//-------------------------------------------------------------------------------------------------
+JetPlayer::~JetPlayer()
+{
+    ALOGV("~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) {
+        ALOGE("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) {
+        ALOGE("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) {
+        ALOGE("JetPlayer::init(): Error initializing JET library, aborting.");
+        mState = EAS_STATE_ERROR;
+        return result;
+    }
+
+    // create the output AudioTrack
+    mAudioTrack = new AudioTrack();
+    status_t status = mAudioTrack->set(AUDIO_STREAM_MUSIC,  //TODO parameterize this
+            pLibConfig->sampleRate,
+            AUDIO_FORMAT_PCM_16_BIT,
+            audio_channel_out_mask_from_count(pLibConfig->numChannels),
+            (size_t) mTrackBufferSize,
+            AUDIO_OUTPUT_FLAG_NONE);
+    if (status != OK) {
+        ALOGE("JetPlayer::init(): Error initializing JET library; AudioTrack error %d", status);
+        mAudioTrack.clear();
+        mState = EAS_STATE_ERROR;
+        return EAS_FAILURE;
+    }
+
+    // create render and playback thread
+    {
+        Mutex::Autolock l(mMutex);
+        ALOGV("JetPlayer::init(): trying to start render thread");
+        mThread = new JetPlayerThread(this);
+        mThread->run("jetRenderThread", ANDROID_PRIORITY_AUDIO);
+        mCondition.wait(mMutex);
+    }
+    if (mTid > 0) {
+        // render thread started, we're ready
+        ALOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
+        mState = EAS_STATE_READY;
+    } else {
+        ALOGE("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()
+{
+    ALOGV("JetPlayer::release()");
+    Mutex::Autolock lock(mMutex);
+    mPaused = true;
+    mRender = false;
+    if (mEasData) {
+        JET_Pause(mEasData);
+        JET_CloseFile(mEasData);
+        JET_Shutdown(mEasData);
+        EAS_Shutdown(mEasData);
+    }
+    delete mIoWrapper;
+    mIoWrapper = NULL;
+    if (mAudioTrack != 0) {
+        mAudioTrack->stop();
+        mAudioTrack->flush();
+        mAudioTrack.clear();
+    }
+    if (mAudioBuffer) {
+        delete mAudioBuffer;
+        mAudioBuffer = NULL;
+    }
+    mEasData = NULL;
+
+    return EAS_SUCCESS;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::render() {
+    EAS_RESULT result = EAS_FAILURE;
+    EAS_I32 count;
+    int temp;
+    bool audioStarted = false;
+
+    ALOGV("JetPlayer::render(): entering");
+
+    // allocate render buffer
+    mAudioBuffer =
+        new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
+
+    // signal main thread that we started
+    {
+        Mutex::Autolock l(mMutex);
+        mTid = gettid();
+        ALOGV("JetPlayer::render(): render thread(%d) signal", mTid);
+        mCondition.signal();
+    }
+
+    while (1) {
+
+        mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
+
+        if (mEasData == NULL) {
+            mMutex.unlock();
+            ALOGV("JetPlayer::render(): NULL EAS data, exiting render.");
+            goto threadExit;
+        }
+
+        // nothing to render, wait for client thread to wake us up
+        while (!mRender)
+        {
+            ALOGV("JetPlayer::render(): signal wait");
+            if (audioStarted) {
+                mAudioTrack->pause();
+                // we have to restart the playback once we start rendering again
+                audioStarted = false;
+            }
+            mCondition.wait(mMutex);
+            ALOGV("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) {
+                ALOGE("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
+        //ALOGV("JetPlayer::render(): updating state");
+        JET_Status(mEasData, &mJetStatus);
+        fireUpdateOnStatusChange();
+        mPaused = mJetStatus.paused;
+
+        mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
+
+        // check audio output track
+        if (mAudioTrack == NULL) {
+            ALOGE("JetPlayer::render(): output AudioTrack was not created");
+            goto threadExit;
+        }
+
+        // Write data to the audio hardware
+        //ALOGV("JetPlayer::render(): writing to audio output");
+        if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
+            ALOGE("JetPlayer::render(): Error in writing:%d",temp);
+            return temp;
+        }
+
+        // start audio output if necessary
+        if (!audioStarted) {
+            ALOGV("JetPlayer::render(): starting audio playback");
+            mAudioTrack->start();
+            audioStarted = true;
+        }
+
+    }//while (1)
+
+threadExit:
+    if (mAudioTrack != NULL) {
+        mAudioTrack->stop();
+        mAudioTrack->flush();
+    }
+    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)
+{
+    ALOGV("JetPlayer::loadFromFile(): path=%s", path);
+
+    Mutex::Autolock lock(mMutex);
+
+    delete mIoWrapper;
+    mIoWrapper = new MidiIoWrapper(path);
+
+    EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
+    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)
+{
+    ALOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
+
+    Mutex::Autolock lock(mMutex);
+
+    delete mIoWrapper;
+    mIoWrapper = new MidiIoWrapper(fd, offset, length);
+
+    EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
+    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()
+{
+    ALOGV("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
+    ALOGV("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)
+{
+    ALOGV("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)
+{
+    ALOGV("JetPlayer::triggerClip clipId=%d", clipId);
+    Mutex::Autolock lock(mMutex);
+    return JET_TriggerClip(mEasData, clipId);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::clearQueue()
+{
+    ALOGV("JetPlayer::clearQueue");
+    Mutex::Autolock lock(mMutex);
+    return JET_Clear_Queue(mEasData);
+}
+
+//-------------------------------------------------------------------------------------------------
+void JetPlayer::dump()
+{
+}
+
+void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
+{
+    if (pJetStatus!=NULL)
+        ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d "
+                "paused=%d",
+                pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
+                pJetStatus->numQueuedSegments, pJetStatus->paused);
+    else
+        ALOGE(">> JET player status is NULL");
+}
+
+
+} // end namespace android
diff --git a/media/jni/JetPlayer.h b/media/jni/JetPlayer.h
new file mode 100644
index 0000000..bb569bc
--- /dev/null
+++ b/media/jni/JetPlayer.h
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#ifndef JETPLAYER_H_
+#define JETPLAYER_H_
+
+#include <utils/threads.h>
+
+#include <libsonivox/jet.h>
+#include <libsonivox/eas_types.h>
+#include <media/AudioTrack.h>
+#include <media/MidiIoWrapper.h>
+
+
+namespace android {
+
+typedef void (*jetevent_callback)(int eventType, int val1, int val2, void *cookie);
+
+class JetPlayer {
+
+public:
+
+    // to keep in sync with the JetPlayer class constants
+    // defined in frameworks/base/media/java/android/media/JetPlayer.java
+    static const int JET_EVENT                   = 1;
+    static const int JET_USERID_UPDATE           = 2;
+    static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
+    static const int JET_PAUSE_UPDATE            = 4;
+
+    JetPlayer(void *javaJetPlayer,
+            int maxTracks = 32,
+            int trackBufferSize = 1200);
+    ~JetPlayer();
+    int init();
+    int release();
+
+    int loadFromFile(const char* url);
+    int loadFromFD(const int fd, const long long offset, const long long length);
+    int closeFile();
+    int play();
+    int pause();
+    int queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
+            EAS_U32 muteFlags, EAS_U8 userID);
+    int setMuteFlags(EAS_U32 muteFlags, bool sync);
+    int setMuteFlag(int trackNum, bool muteFlag, bool sync);
+    int triggerClip(int clipId);
+    int clearQueue();
+
+    void setEventCallback(jetevent_callback callback);
+
+    int getMaxTracks() { return mMaxTracks; };
+
+
+private:
+    int                 render();
+    void                fireUpdateOnStatusChange();
+    void                fireEventsFromJetQueue();
+
+    JetPlayer() {} // no default constructor
+    void dump();
+    void dumpJetStatus(S_JET_STATUS* pJetStatus);
+
+    jetevent_callback   mEventCallback;
+
+    void*               mJavaJetPlayerRef;
+    Mutex               mMutex; // mutex to sync the render and playback thread with the JET calls
+    pid_t               mTid;
+    Condition           mCondition;
+    volatile bool       mRender;
+    bool                mPaused;
+
+    EAS_STATE           mState;
+    int*                mMemFailedVar;
+
+    int                 mMaxTracks; // max number of MIDI tracks, usually 32
+    EAS_DATA_HANDLE     mEasData;
+    MidiIoWrapper*      mIoWrapper;
+    EAS_PCM*            mAudioBuffer;// EAS renders the MIDI data into this buffer,
+    sp<AudioTrack>      mAudioTrack; // and we play it in this audio track
+    int                 mTrackBufferSize;
+    S_JET_STATUS        mJetStatus;
+    S_JET_STATUS        mPreviousJetStatus;
+
+    class JetPlayerThread : public Thread {
+    public:
+        JetPlayerThread(JetPlayer *player) : mPlayer(player) {
+        }
+
+    protected:
+        virtual ~JetPlayerThread() {}
+
+    private:
+        JetPlayer *mPlayer;
+
+        bool threadLoop() {
+            int result;
+            result = mPlayer->render();
+            return false;
+        }
+
+        JetPlayerThread(const JetPlayerThread &);
+        JetPlayerThread &operator=(const JetPlayerThread &);
+    };
+
+    sp<JetPlayerThread> mThread;
+
+}; // end class JetPlayer
+
+} // end namespace android
+
+
+
+#endif /*JETPLAYER_H_*/
diff --git a/core/jni/android_media_JetPlayer.cpp b/media/jni/android_media_JetPlayer.cpp
similarity index 99%
rename from core/jni/android_media_JetPlayer.cpp
rename to media/jni/android_media_JetPlayer.cpp
index da116bf..8a05f85 100644
--- a/core/jni/android_media_JetPlayer.cpp
+++ b/media/jni/android_media_JetPlayer.cpp
@@ -27,7 +27,7 @@
 #include "core_jni_helpers.h"
 
 #include <utils/Log.h>
-#include <media/JetPlayer.h>
+#include "JetPlayer.h"
 
 
 using namespace android;
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 94299bc..b4fa07b 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1436,6 +1436,7 @@
 }
 extern int register_android_media_ImageReader(JNIEnv *env);
 extern int register_android_media_ImageWriter(JNIEnv *env);
+extern int register_android_media_JetPlayer(JNIEnv *env);
 extern int register_android_media_Crypto(JNIEnv *env);
 extern int register_android_media_Drm(JNIEnv *env);
 extern int register_android_media_Descrambler(JNIEnv *env);
@@ -1474,6 +1475,11 @@
         goto bail;
     }
 
+    if (register_android_media_JetPlayer(env) < 0) {
+        ALOGE("ERROR: JetPlayer native registration failed");
+        goto bail;
+    }
+
     if (register_android_media_MediaPlayer(env) < 0) {
         ALOGE("ERROR: MediaPlayer native registration failed\n");
         goto bail;