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