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         mIoWrapper(NULL),
     40         mTrackBufferSize(trackBufferSize)
     41 {
     42     ALOGV("JetPlayer constructor");
     43     mPreviousJetStatus.currentUserID = -1;
     44     mPreviousJetStatus.segmentRepeatCount = -1;
     45     mPreviousJetStatus.numQueuedSegments = -1;
     46     mPreviousJetStatus.paused = true;
     47 }
     48 
     49 //-------------------------------------------------------------------------------------------------
     50 JetPlayer::~JetPlayer()
     51 {
     52     ALOGV("~JetPlayer");
     53     release();
     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     delete mIoWrapper;
    142     mIoWrapper = NULL;
    143     if (mAudioTrack != 0) {
    144         mAudioTrack->stop();
    145         mAudioTrack->flush();
    146         mAudioTrack.clear();
    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::render() {
    160     EAS_RESULT result = EAS_FAILURE;
    161     EAS_I32 count;
    162     int temp;
    163     bool audioStarted = false;
    164 
    165     ALOGV("JetPlayer::render(): entering");
    166 
    167     // allocate render buffer
    168     mAudioBuffer =
    169         new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
    170 
    171     // signal main thread that we started
    172     {
    173         Mutex::Autolock l(mMutex);
    174         mTid = gettid();
    175         ALOGV("JetPlayer::render(): render thread(%d) signal", mTid);
    176         mCondition.signal();
    177     }
    178 
    179     while (1) {
    180 
    181         mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
    182 
    183         if (mEasData == NULL) {
    184             mMutex.unlock();
    185             ALOGV("JetPlayer::render(): NULL EAS data, exiting render.");
    186             goto threadExit;
    187         }
    188 
    189         // nothing to render, wait for client thread to wake us up
    190         while (!mRender)
    191         {
    192             ALOGV("JetPlayer::render(): signal wait");
    193             if (audioStarted) {
    194                 mAudioTrack->pause();
    195                 // we have to restart the playback once we start rendering again
    196                 audioStarted = false;
    197             }
    198             mCondition.wait(mMutex);
    199             ALOGV("JetPlayer::render(): signal rx'd");
    200         }
    201 
    202         // render midi data into the input buffer
    203         int num_output = 0;
    204         EAS_PCM* p = mAudioBuffer;
    205         for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
    206             result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
    207             if (result != EAS_SUCCESS) {
    208                 ALOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
    209             }
    210             p += count * pLibConfig->numChannels;
    211             num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
    212 
    213             // send events that were generated (if any) to the event callback
    214             fireEventsFromJetQueue();
    215         }
    216 
    217         // update playback state
    218         //ALOGV("JetPlayer::render(): updating state");
    219         JET_Status(mEasData, &mJetStatus);
    220         fireUpdateOnStatusChange();
    221         mPaused = mJetStatus.paused;
    222 
    223         mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
    224 
    225         // check audio output track
    226         if (mAudioTrack == NULL) {
    227             ALOGE("JetPlayer::render(): output AudioTrack was not created");
    228             goto threadExit;
    229         }
    230 
    231         // Write data to the audio hardware
    232         //ALOGV("JetPlayer::render(): writing to audio output");
    233         if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
    234             ALOGE("JetPlayer::render(): Error in writing:%d",temp);
    235             return temp;
    236         }
    237 
    238         // start audio output if necessary
    239         if (!audioStarted) {
    240             ALOGV("JetPlayer::render(): starting audio playback");
    241             mAudioTrack->start();
    242             audioStarted = true;
    243         }
    244 
    245     }//while (1)
    246 
    247 threadExit:
    248     if (mAudioTrack != NULL) {
    249         mAudioTrack->stop();
    250         mAudioTrack->flush();
    251     }
    252     delete [] mAudioBuffer;
    253     mAudioBuffer = NULL;
    254     mMutex.lock();
    255     mTid = -1;
    256     mCondition.signal();
    257     mMutex.unlock();
    258     return result;
    259 }
    260 
    261 
    262 //-------------------------------------------------------------------------------------------------
    263 // fire up an update if any of the status fields has changed
    264 // precondition: mMutex locked
    265 void JetPlayer::fireUpdateOnStatusChange()
    266 {
    267     if ( (mJetStatus.currentUserID      != mPreviousJetStatus.currentUserID)
    268        ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
    269         if (mEventCallback)  {
    270             mEventCallback(
    271                 JetPlayer::JET_USERID_UPDATE,
    272                 mJetStatus.currentUserID,
    273                 mJetStatus.segmentRepeatCount,
    274                 mJavaJetPlayerRef);
    275         }
    276         mPreviousJetStatus.currentUserID      = mJetStatus.currentUserID;
    277         mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
    278     }
    279 
    280     if (mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
    281         if (mEventCallback)  {
    282             mEventCallback(
    283                 JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
    284                 mJetStatus.numQueuedSegments,
    285                 -1,
    286                 mJavaJetPlayerRef);
    287         }
    288         mPreviousJetStatus.numQueuedSegments  = mJetStatus.numQueuedSegments;
    289     }
    290 
    291     if (mJetStatus.paused != mPreviousJetStatus.paused) {
    292         if (mEventCallback)  {
    293             mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
    294                 mJetStatus.paused,
    295                 -1,
    296                 mJavaJetPlayerRef);
    297         }
    298         mPreviousJetStatus.paused = mJetStatus.paused;
    299     }
    300 
    301 }
    302 
    303 
    304 //-------------------------------------------------------------------------------------------------
    305 // fire up all the JET events in the JET engine queue (until the queue is empty)
    306 // precondition: mMutex locked
    307 void JetPlayer::fireEventsFromJetQueue()
    308 {
    309     if (!mEventCallback) {
    310         // no callback, just empty the event queue
    311         while (JET_GetEvent(mEasData, NULL, NULL)) { }
    312         return;
    313     }
    314 
    315     EAS_U32 rawEvent;
    316     while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
    317         mEventCallback(
    318             JetPlayer::JET_EVENT,
    319             rawEvent,
    320             -1,
    321             mJavaJetPlayerRef);
    322     }
    323 }
    324 
    325 
    326 //-------------------------------------------------------------------------------------------------
    327 int JetPlayer::loadFromFile(const char* path)
    328 {
    329     ALOGV("JetPlayer::loadFromFile(): path=%s", path);
    330 
    331     Mutex::Autolock lock(mMutex);
    332 
    333     delete mIoWrapper;
    334     mIoWrapper = new MidiIoWrapper(path);
    335 
    336     EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
    337     if (result != EAS_SUCCESS)
    338         mState = EAS_STATE_ERROR;
    339     else
    340         mState = EAS_STATE_OPEN;
    341     return( result );
    342 }
    343 
    344 
    345 //-------------------------------------------------------------------------------------------------
    346 int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
    347 {
    348     ALOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
    349 
    350     Mutex::Autolock lock(mMutex);
    351 
    352     delete mIoWrapper;
    353     mIoWrapper = new MidiIoWrapper(fd, offset, length);
    354 
    355     EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
    356     if (result != EAS_SUCCESS)
    357         mState = EAS_STATE_ERROR;
    358     else
    359         mState = EAS_STATE_OPEN;
    360     return( result );
    361 }
    362 
    363 
    364 //-------------------------------------------------------------------------------------------------
    365 int JetPlayer::closeFile()
    366 {
    367     Mutex::Autolock lock(mMutex);
    368     return JET_CloseFile(mEasData);
    369 }
    370 
    371 
    372 //-------------------------------------------------------------------------------------------------
    373 int JetPlayer::play()
    374 {
    375     ALOGV("JetPlayer::play(): entering");
    376     Mutex::Autolock lock(mMutex);
    377 
    378     EAS_RESULT result = JET_Play(mEasData);
    379 
    380     mPaused = false;
    381     mRender = true;
    382 
    383     JET_Status(mEasData, &mJetStatus);
    384     this->dumpJetStatus(&mJetStatus);
    385 
    386     fireUpdateOnStatusChange();
    387 
    388     // wake up render thread
    389     ALOGV("JetPlayer::play(): wakeup render thread");
    390     mCondition.signal();
    391 
    392     return result;
    393 }
    394 
    395 //-------------------------------------------------------------------------------------------------
    396 int JetPlayer::pause()
    397 {
    398     Mutex::Autolock lock(mMutex);
    399     mPaused = true;
    400     EAS_RESULT result = JET_Pause(mEasData);
    401 
    402     mRender = false;
    403 
    404     JET_Status(mEasData, &mJetStatus);
    405     this->dumpJetStatus(&mJetStatus);
    406     fireUpdateOnStatusChange();
    407 
    408 
    409     return result;
    410 }
    411 
    412 
    413 //-------------------------------------------------------------------------------------------------
    414 int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
    415         EAS_U32 muteFlags, EAS_U8 userID)
    416 {
    417     ALOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
    418         segmentNum, libNum, repeatCount, transpose);
    419     Mutex::Autolock lock(mMutex);
    420     return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags,
    421             userID);
    422 }
    423 
    424 //-------------------------------------------------------------------------------------------------
    425 int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
    426 {
    427     Mutex::Autolock lock(mMutex);
    428     return JET_SetMuteFlags(mEasData, muteFlags, sync);
    429 }
    430 
    431 //-------------------------------------------------------------------------------------------------
    432 int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
    433 {
    434     Mutex::Autolock lock(mMutex);
    435     return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
    436 }
    437 
    438 //-------------------------------------------------------------------------------------------------
    439 int JetPlayer::triggerClip(int clipId)
    440 {
    441     ALOGV("JetPlayer::triggerClip clipId=%d", clipId);
    442     Mutex::Autolock lock(mMutex);
    443     return JET_TriggerClip(mEasData, clipId);
    444 }
    445 
    446 //-------------------------------------------------------------------------------------------------
    447 int JetPlayer::clearQueue()
    448 {
    449     ALOGV("JetPlayer::clearQueue");
    450     Mutex::Autolock lock(mMutex);
    451     return JET_Clear_Queue(mEasData);
    452 }
    453 
    454 //-------------------------------------------------------------------------------------------------
    455 void JetPlayer::dump()
    456 {
    457 }
    458 
    459 void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
    460 {
    461     if (pJetStatus!=NULL)
    462         ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d "
    463                 "paused=%d",
    464                 pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
    465                 pJetStatus->numQueuedSegments, pJetStatus->paused);
    466     else
    467         ALOGE(">> JET player status is NULL");
    468 }
    469 
    470 
    471 } // end namespace android
    472