Home | History | Annotate | Download | only in libmedia
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "JetPlayer-C"
     19 
     20 #include <utils/Log.h>
     21 #include <utils/threads.h>
     22 
     23 #include <media/JetPlayer.h>
     24 
     25 
     26 namespace android
     27 {
     28 
     29 static const int MIX_NUM_BUFFERS = 4;
     30 static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
     31 
     32 //-------------------------------------------------------------------------------------------------
     33 JetPlayer::JetPlayer(jobject javaJetPlayer, int maxTracks, int trackBufferSize) :
     34         mEventCallback(NULL),
     35         mJavaJetPlayerRef(javaJetPlayer),
     36         mTid(-1),
     37         mRender(false),
     38         mPaused(false),
     39         mMaxTracks(maxTracks),
     40         mEasData(NULL),
     41         mEasJetFileLoc(NULL),
     42         mAudioTrack(NULL),
     43         mTrackBufferSize(trackBufferSize)
     44 {
     45     LOGV("JetPlayer constructor");
     46     mPreviousJetStatus.currentUserID = -1;
     47     mPreviousJetStatus.segmentRepeatCount = -1;
     48     mPreviousJetStatus.numQueuedSegments = -1;
     49     mPreviousJetStatus.paused = true;
     50 }
     51 
     52 //-------------------------------------------------------------------------------------------------
     53 JetPlayer::~JetPlayer()
     54 {
     55     LOGV("~JetPlayer");
     56     release();
     57 
     58 }
     59 
     60 //-------------------------------------------------------------------------------------------------
     61 int JetPlayer::init()
     62 {
     63     //Mutex::Autolock lock(&mMutex);
     64 
     65     EAS_RESULT result;
     66 
     67     // retrieve the EAS library settings
     68     if (pLibConfig == NULL)
     69         pLibConfig = EAS_Config();
     70     if (pLibConfig == NULL) {
     71         LOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting.");
     72         return EAS_FAILURE;
     73     }
     74 
     75     // init the EAS library
     76     result = EAS_Init(&mEasData);
     77     if( result != EAS_SUCCESS) {
     78         LOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting.");
     79         mState = EAS_STATE_ERROR;
     80         return result;
     81     }
     82     // init the JET library with the default app event controller range
     83     result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG));
     84     if( result != EAS_SUCCESS) {
     85         LOGE("JetPlayer::init(): Error initializing JET library, aborting.");
     86         mState = EAS_STATE_ERROR;
     87         return result;
     88     }
     89 
     90     // create the output AudioTrack
     91     mAudioTrack = new AudioTrack();
     92     mAudioTrack->set(AUDIO_STREAM_MUSIC,  //TODO parametrize this
     93             pLibConfig->sampleRate,
     94             1, // format = PCM 16bits per sample,
     95             (pLibConfig->numChannels == 2) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO,
     96             mTrackBufferSize,
     97             0);
     98 
     99     // create render and playback thread
    100     {
    101         Mutex::Autolock l(mMutex);
    102         LOGV("JetPlayer::init(): trying to start render thread");
    103         createThreadEtc(renderThread, this, "jetRenderThread", ANDROID_PRIORITY_AUDIO);
    104         mCondition.wait(mMutex);
    105     }
    106     if (mTid > 0) {
    107         // render thread started, we're ready
    108         LOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
    109         mState = EAS_STATE_READY;
    110     } else {
    111         LOGE("JetPlayer::init(): failed to start render thread.");
    112         mState = EAS_STATE_ERROR;
    113         return EAS_FAILURE;
    114     }
    115 
    116     return EAS_SUCCESS;
    117 }
    118 
    119 void JetPlayer::setEventCallback(jetevent_callback eventCallback)
    120 {
    121     Mutex::Autolock l(mMutex);
    122     mEventCallback = eventCallback;
    123 }
    124 
    125 //-------------------------------------------------------------------------------------------------
    126 int JetPlayer::release()
    127 {
    128     LOGV("JetPlayer::release()");
    129     Mutex::Autolock lock(mMutex);
    130     mPaused = true;
    131     mRender = false;
    132     if (mEasData) {
    133         JET_Pause(mEasData);
    134         JET_CloseFile(mEasData);
    135         JET_Shutdown(mEasData);
    136         EAS_Shutdown(mEasData);
    137     }
    138     if (mEasJetFileLoc) {
    139         free(mEasJetFileLoc);
    140         mEasJetFileLoc = NULL;
    141     }
    142     if (mAudioTrack) {
    143         mAudioTrack->stop();
    144         mAudioTrack->flush();
    145         delete mAudioTrack;
    146         mAudioTrack = NULL;
    147     }
    148     if (mAudioBuffer) {
    149         delete mAudioBuffer;
    150         mAudioBuffer = NULL;
    151     }
    152     mEasData = NULL;
    153 
    154     return EAS_SUCCESS;
    155 }
    156 
    157 
    158 //-------------------------------------------------------------------------------------------------
    159 int JetPlayer::renderThread(void* p) {
    160 
    161     return ((JetPlayer*)p)->render();
    162 }
    163 
    164 //-------------------------------------------------------------------------------------------------
    165 int JetPlayer::render() {
    166     EAS_RESULT result = EAS_FAILURE;
    167     EAS_I32 count;
    168     int temp;
    169     bool audioStarted = false;
    170 
    171     LOGV("JetPlayer::render(): entering");
    172 
    173     // allocate render buffer
    174     mAudioBuffer =
    175         new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
    176     if (!mAudioBuffer) {
    177         LOGE("JetPlayer::render(): mAudioBuffer allocate failed");
    178         goto threadExit;
    179     }
    180 
    181     // signal main thread that we started
    182     {
    183         Mutex::Autolock l(mMutex);
    184         mTid = gettid();
    185         LOGV("JetPlayer::render(): render thread(%d) signal", mTid);
    186         mCondition.signal();
    187     }
    188 
    189    while (1) {
    190 
    191         mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
    192 
    193         if (mEasData == NULL) {
    194             mMutex.unlock();
    195             LOGV("JetPlayer::render(): NULL EAS data, exiting render.");
    196             goto threadExit;
    197         }
    198 
    199         // nothing to render, wait for client thread to wake us up
    200         while (!mRender)
    201         {
    202             LOGV("JetPlayer::render(): signal wait");
    203             if (audioStarted) {
    204                 mAudioTrack->pause();
    205                 // we have to restart the playback once we start rendering again
    206                 audioStarted = false;
    207             }
    208             mCondition.wait(mMutex);
    209             LOGV("JetPlayer::render(): signal rx'd");
    210         }
    211 
    212         // render midi data into the input buffer
    213         int num_output = 0;
    214         EAS_PCM* p = mAudioBuffer;
    215         for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
    216             result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
    217             if (result != EAS_SUCCESS) {
    218                 LOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
    219             }
    220             p += count * pLibConfig->numChannels;
    221             num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
    222 
    223              // send events that were generated (if any) to the event callback
    224             fireEventsFromJetQueue();
    225         }
    226 
    227         // update playback state
    228         //LOGV("JetPlayer::render(): updating state");
    229         JET_Status(mEasData, &mJetStatus);
    230         fireUpdateOnStatusChange();
    231         mPaused = mJetStatus.paused;
    232 
    233         mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
    234 
    235         // check audio output track
    236         if (mAudioTrack == NULL) {
    237             LOGE("JetPlayer::render(): output AudioTrack was not created");
    238             goto threadExit;
    239         }
    240 
    241         // Write data to the audio hardware
    242         //LOGV("JetPlayer::render(): writing to audio output");
    243         if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
    244             LOGE("JetPlayer::render(): Error in writing:%d",temp);
    245             return temp;
    246         }
    247 
    248         // start audio output if necessary
    249         if (!audioStarted) {
    250             LOGV("JetPlayer::render(): starting audio playback");
    251             mAudioTrack->start();
    252             audioStarted = true;
    253         }
    254 
    255     }//while (1)
    256 
    257 threadExit:
    258     if (mAudioTrack) {
    259         mAudioTrack->stop();
    260         mAudioTrack->flush();
    261     }
    262     if (mAudioBuffer) {
    263         delete [] mAudioBuffer;
    264         mAudioBuffer = NULL;
    265     }
    266     mMutex.lock();
    267     mTid = -1;
    268     mCondition.signal();
    269     mMutex.unlock();
    270     return result;
    271 }
    272 
    273 
    274 //-------------------------------------------------------------------------------------------------
    275 // fire up an update if any of the status fields has changed
    276 // precondition: mMutex locked
    277 void JetPlayer::fireUpdateOnStatusChange()
    278 {
    279     if(  (mJetStatus.currentUserID      != mPreviousJetStatus.currentUserID)
    280        ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
    281         if(mEventCallback)  {
    282             mEventCallback(
    283                 JetPlayer::JET_USERID_UPDATE,
    284                 mJetStatus.currentUserID,
    285                 mJetStatus.segmentRepeatCount,
    286                 mJavaJetPlayerRef);
    287         }
    288         mPreviousJetStatus.currentUserID      = mJetStatus.currentUserID;
    289         mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
    290     }
    291 
    292     if(mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
    293         if(mEventCallback)  {
    294             mEventCallback(
    295                 JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
    296                 mJetStatus.numQueuedSegments,
    297                 -1,
    298                 mJavaJetPlayerRef);
    299         }
    300         mPreviousJetStatus.numQueuedSegments  = mJetStatus.numQueuedSegments;
    301     }
    302 
    303     if(mJetStatus.paused != mPreviousJetStatus.paused) {
    304         if(mEventCallback)  {
    305             mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
    306                 mJetStatus.paused,
    307                 -1,
    308                 mJavaJetPlayerRef);
    309         }
    310         mPreviousJetStatus.paused = mJetStatus.paused;
    311     }
    312 
    313 }
    314 
    315 
    316 //-------------------------------------------------------------------------------------------------
    317 // fire up all the JET events in the JET engine queue (until the queue is empty)
    318 // precondition: mMutex locked
    319 void JetPlayer::fireEventsFromJetQueue()
    320 {
    321     if(!mEventCallback) {
    322         // no callback, just empty the event queue
    323         while (JET_GetEvent(mEasData, NULL, NULL)) { }
    324         return;
    325     }
    326 
    327     EAS_U32 rawEvent;
    328     while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
    329         mEventCallback(
    330             JetPlayer::JET_EVENT,
    331             rawEvent,
    332             -1,
    333             mJavaJetPlayerRef);
    334     }
    335 }
    336 
    337 
    338 //-------------------------------------------------------------------------------------------------
    339 int JetPlayer::loadFromFile(const char* path)
    340 {
    341     LOGV("JetPlayer::loadFromFile(): path=%s", path);
    342 
    343     Mutex::Autolock lock(mMutex);
    344 
    345     mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
    346     memset(mJetFilePath, 0, 256);
    347     strncpy(mJetFilePath, path, strlen(path));
    348     mEasJetFileLoc->path = mJetFilePath;
    349 
    350     mEasJetFileLoc->fd = 0;
    351     mEasJetFileLoc->length = 0;
    352     mEasJetFileLoc->offset = 0;
    353 
    354     EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
    355     if(result != EAS_SUCCESS)
    356         mState = EAS_STATE_ERROR;
    357     else
    358         mState = EAS_STATE_OPEN;
    359     return( result );
    360 }
    361 
    362 
    363 //-------------------------------------------------------------------------------------------------
    364 int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
    365 {
    366     LOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
    367 
    368     Mutex::Autolock lock(mMutex);
    369 
    370     mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
    371     mEasJetFileLoc->fd = fd;
    372     mEasJetFileLoc->offset = offset;
    373     mEasJetFileLoc->length = length;
    374     mEasJetFileLoc->path = NULL;
    375 
    376     EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
    377     if(result != EAS_SUCCESS)
    378         mState = EAS_STATE_ERROR;
    379     else
    380         mState = EAS_STATE_OPEN;
    381     return( result );
    382 }
    383 
    384 
    385 //-------------------------------------------------------------------------------------------------
    386 int JetPlayer::closeFile()
    387 {
    388     Mutex::Autolock lock(mMutex);
    389     return JET_CloseFile(mEasData);
    390 }
    391 
    392 
    393 //-------------------------------------------------------------------------------------------------
    394 int JetPlayer::play()
    395 {
    396     LOGV("JetPlayer::play(): entering");
    397     Mutex::Autolock lock(mMutex);
    398 
    399     EAS_RESULT result = JET_Play(mEasData);
    400 
    401     mPaused = false;
    402     mRender = true;
    403 
    404     JET_Status(mEasData, &mJetStatus);
    405     this->dumpJetStatus(&mJetStatus);
    406 
    407     fireUpdateOnStatusChange();
    408 
    409     // wake up render thread
    410     LOGV("JetPlayer::play(): wakeup render thread");
    411     mCondition.signal();
    412 
    413     return result;
    414 }
    415 
    416 //-------------------------------------------------------------------------------------------------
    417 int JetPlayer::pause()
    418 {
    419     Mutex::Autolock lock(mMutex);
    420     mPaused = true;
    421     EAS_RESULT result = JET_Pause(mEasData);
    422 
    423     mRender = false;
    424 
    425     JET_Status(mEasData, &mJetStatus);
    426     this->dumpJetStatus(&mJetStatus);
    427     fireUpdateOnStatusChange();
    428 
    429 
    430     return result;
    431 }
    432 
    433 
    434 //-------------------------------------------------------------------------------------------------
    435 int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
    436         EAS_U32 muteFlags, EAS_U8 userID)
    437 {
    438     LOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
    439         segmentNum, libNum, repeatCount, transpose);
    440     Mutex::Autolock lock(mMutex);
    441     return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
    442 }
    443 
    444 //-------------------------------------------------------------------------------------------------
    445 int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
    446 {
    447     Mutex::Autolock lock(mMutex);
    448     return JET_SetMuteFlags(mEasData, muteFlags, sync);
    449 }
    450 
    451 //-------------------------------------------------------------------------------------------------
    452 int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
    453 {
    454     Mutex::Autolock lock(mMutex);
    455     return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
    456 }
    457 
    458 //-------------------------------------------------------------------------------------------------
    459 int JetPlayer::triggerClip(int clipId)
    460 {
    461     LOGV("JetPlayer::triggerClip clipId=%d", clipId);
    462     Mutex::Autolock lock(mMutex);
    463     return JET_TriggerClip(mEasData, clipId);
    464 }
    465 
    466 //-------------------------------------------------------------------------------------------------
    467 int JetPlayer::clearQueue()
    468 {
    469     LOGV("JetPlayer::clearQueue");
    470     Mutex::Autolock lock(mMutex);
    471     return JET_Clear_Queue(mEasData);
    472 }
    473 
    474 //-------------------------------------------------------------------------------------------------
    475 void JetPlayer::dump()
    476 {
    477     LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path);
    478 }
    479 
    480 void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
    481 {
    482     if(pJetStatus!=NULL)
    483         LOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d",
    484                 pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
    485                 pJetStatus->numQueuedSegments, pJetStatus->paused);
    486     else
    487         LOGE(">> JET player status is NULL");
    488 }
    489 
    490 
    491 } // end namespace android
    492 
    493