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