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