From 89fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 19:31:44 -0800 Subject: auto import from //depot/cupcake/@135843 --- media/libmedia/JetPlayer.cpp | 489 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 489 insertions(+) create mode 100644 media/libmedia/JetPlayer.cpp (limited to 'media/libmedia/JetPlayer.cpp') diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp new file mode 100644 index 0000000..2c62104 --- /dev/null +++ b/media/libmedia/JetPlayer.cpp @@ -0,0 +1,489 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "JetPlayer-C" + +#include +#include + +#include + + +#ifdef HAVE_GETTID +static pid_t myTid() { return gettid(); } +#else +static pid_t myTid() { return getpid(); } +#endif + + +namespace android +{ + +static const int MIX_NUM_BUFFERS = 4; +static const S_EAS_LIB_CONFIG* pLibConfig = NULL; + +//------------------------------------------------------------------------------------------------- +JetPlayer::JetPlayer(jobject javaJetPlayer, int maxTracks, int trackBufferSize) : + mEventCallback(NULL), + mJavaJetPlayerRef(javaJetPlayer), + mTid(-1), + mRender(false), + mPaused(false), + mMaxTracks(maxTracks), + mEasData(NULL), + mEasJetFileLoc(NULL), + mAudioTrack(NULL), + mTrackBufferSize(trackBufferSize) +{ + LOGV("JetPlayer constructor"); + mPreviousJetStatus.currentUserID = -1; + mPreviousJetStatus.segmentRepeatCount = -1; + mPreviousJetStatus.numQueuedSegments = -1; + mPreviousJetStatus.paused = true; +} + +//------------------------------------------------------------------------------------------------- +JetPlayer::~JetPlayer() +{ + LOGV("~JetPlayer"); + release(); + +} + +//------------------------------------------------------------------------------------------------- +int JetPlayer::init() +{ + //Mutex::Autolock lock(&mMutex); + + EAS_RESULT result; + + // retrieve the EAS library settings + if (pLibConfig == NULL) + pLibConfig = EAS_Config(); + if (pLibConfig == NULL) { + LOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting."); + return EAS_FAILURE; + } + + // init the EAS library + result = EAS_Init(&mEasData); + if( result != EAS_SUCCESS) { + LOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting."); + mState = EAS_STATE_ERROR; + return result; + } + // init the JET library with the default app event controller range + result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG)); + if( result != EAS_SUCCESS) { + LOGE("JetPlayer::init(): Error initializing JET library, aborting."); + mState = EAS_STATE_ERROR; + return result; + } + + // create the output AudioTrack + mAudioTrack = new AudioTrack(); + mAudioTrack->set(AudioSystem::MUSIC, //TODO parametrize this + pLibConfig->sampleRate, + 1, // format = PCM 16bits per sample, + pLibConfig->numChannels, + mTrackBufferSize, + 0); + + // create render and playback thread + { + Mutex::Autolock l(mMutex); + LOGV("JetPlayer::init(): trying to start render thread"); + createThreadEtc(renderThread, this, "jetRenderThread", ANDROID_PRIORITY_AUDIO); + mCondition.wait(mMutex); + } + if (mTid > 0) { + // render thread started, we're ready + LOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid); + mState = EAS_STATE_READY; + } else { + LOGE("JetPlayer::init(): failed to start render thread."); + mState = EAS_STATE_ERROR; + return EAS_FAILURE; + } + + return EAS_SUCCESS; +} + +void JetPlayer::setEventCallback(jetevent_callback eventCallback) +{ + Mutex::Autolock l(mMutex); + mEventCallback = eventCallback; +} + +//------------------------------------------------------------------------------------------------- +int JetPlayer::release() +{ + LOGV("JetPlayer::release()"); + Mutex::Autolock lock(mMutex); + mPaused = true; + mRender = false; + if (mEasData) { + JET_Pause(mEasData); + JET_CloseFile(mEasData); + JET_Shutdown(mEasData); + EAS_Shutdown(mEasData); + } + if (mEasJetFileLoc) { + free(mEasJetFileLoc); + mEasJetFileLoc = NULL; + } + if (mAudioTrack) { + mAudioTrack->stop(); + mAudioTrack->flush(); + delete mAudioTrack; + mAudioTrack = NULL; + } + if (mAudioBuffer) { + delete mAudioBuffer; + mAudioBuffer = NULL; + } + mEasData = NULL; + + return EAS_SUCCESS; +} + + +//------------------------------------------------------------------------------------------------- +int JetPlayer::renderThread(void* p) { + + return ((JetPlayer*)p)->render(); +} + +//------------------------------------------------------------------------------------------------- +int JetPlayer::render() { + EAS_RESULT result = EAS_FAILURE; + EAS_I32 count; + int temp; + bool audioStarted = false; + + LOGV("JetPlayer::render(): entering"); + + // allocate render buffer + mAudioBuffer = + new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS]; + if (!mAudioBuffer) { + LOGE("JetPlayer::render(): mAudioBuffer allocate failed"); + goto threadExit; + } + + // signal main thread that we started + { + Mutex::Autolock l(mMutex); + mTid = myTid(); + LOGV("JetPlayer::render(): render thread(%d) signal", mTid); + mCondition.signal(); + } + + while (1) { + mMutex.lock(); // [[[[[[[[ LOCK --------------------------------------- + + // nothing to render, wait for client thread to wake us up + while (!mRender) + { + LOGV("JetPlayer::render(): signal wait"); + if (audioStarted) { + mAudioTrack->pause(); + // we have to restart the playback once we start rendering again + audioStarted = false; + } + mCondition.wait(mMutex); + LOGV("JetPlayer::render(): signal rx'd"); + } + + // render midi data into the input buffer + int num_output = 0; + EAS_PCM* p = mAudioBuffer; + for (int i = 0; i < MIX_NUM_BUFFERS; i++) { + result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count); + if (result != EAS_SUCCESS) { + LOGE("JetPlayer::render(): EAS_Render returned error %ld", result); + } + p += count * pLibConfig->numChannels; + num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM); + + // send events that were generated (if any) to the event callback + fireEventsFromJetQueue(); + } + + // update playback state + //LOGV("JetPlayer::render(): updating state"); + JET_Status(mEasData, &mJetStatus); + fireUpdateOnStatusChange(); + mPaused = mJetStatus.paused; + + mMutex.unlock(); // UNLOCK ]]]]]]]] ----------------------------------- + + // check audio output track + if (mAudioTrack == NULL) { + LOGE("JetPlayer::render(): output AudioTrack was not created"); + goto threadExit; + } + + // Write data to the audio hardware + //LOGV("JetPlayer::render(): writing to audio output"); + if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) { + LOGE("JetPlayer::render(): Error in writing:%d",temp); + return temp; + } + + // start audio output if necessary + if (!audioStarted) { + LOGV("JetPlayer::render(): starting audio playback"); + mAudioTrack->start(); + audioStarted = true; + } + + }//while (1) + +threadExit: + mAudioTrack->flush(); + if (mAudioBuffer) { + delete [] mAudioBuffer; + mAudioBuffer = NULL; + } + mMutex.lock(); + mTid = -1; + mCondition.signal(); + mMutex.unlock(); + return result; +} + + +//------------------------------------------------------------------------------------------------- +// fire up an update if any of the status fields has changed +// precondition: mMutex locked +void JetPlayer::fireUpdateOnStatusChange() +{ + if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID) + ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) { + if(mEventCallback) { + mEventCallback( + JetPlayer::JET_USERID_UPDATE, + mJetStatus.currentUserID, + mJetStatus.segmentRepeatCount, + mJavaJetPlayerRef); + } + mPreviousJetStatus.currentUserID = mJetStatus.currentUserID; + mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount; + } + + if(mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) { + if(mEventCallback) { + mEventCallback( + JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE, + mJetStatus.numQueuedSegments, + -1, + mJavaJetPlayerRef); + } + mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments; + } + + if(mJetStatus.paused != mPreviousJetStatus.paused) { + if(mEventCallback) { + mEventCallback(JetPlayer::JET_PAUSE_UPDATE, + mJetStatus.paused, + -1, + mJavaJetPlayerRef); + } + mPreviousJetStatus.paused = mJetStatus.paused; + } + +} + + +//------------------------------------------------------------------------------------------------- +// fire up all the JET events in the JET engine queue (until the queue is empty) +// precondition: mMutex locked +void JetPlayer::fireEventsFromJetQueue() +{ + if(!mEventCallback) { + // no callback, just empty the event queue + while (JET_GetEvent(mEasData, NULL, NULL)) { } + return; + } + + EAS_U32 rawEvent; + while (JET_GetEvent(mEasData, &rawEvent, NULL)) { + mEventCallback( + JetPlayer::JET_EVENT, + rawEvent, + -1, + mJavaJetPlayerRef); + } +} + + +//------------------------------------------------------------------------------------------------- +int JetPlayer::loadFromFile(const char* path) +{ + LOGV("JetPlayer::loadFromFile(): path=%s", path); + + Mutex::Autolock lock(mMutex); + + mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE)); + memset(mJetFilePath, 0, 256); + strncpy(mJetFilePath, path, strlen(path)); + mEasJetFileLoc->path = mJetFilePath; + + mEasJetFileLoc->fd = 0; + mEasJetFileLoc->length = 0; + mEasJetFileLoc->offset = 0; + + EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc); + if(result != EAS_SUCCESS) + mState = EAS_STATE_ERROR; + else + mState = EAS_STATE_OPEN; + return( result ); +} + + +//------------------------------------------------------------------------------------------------- +int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length) +{ + LOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length); + + Mutex::Autolock lock(mMutex); + + mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE)); + mEasJetFileLoc->fd = fd; + mEasJetFileLoc->offset = offset; + mEasJetFileLoc->length = length; + mEasJetFileLoc->path = NULL; + + EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc); + if(result != EAS_SUCCESS) + mState = EAS_STATE_ERROR; + else + mState = EAS_STATE_OPEN; + return( result ); +} + + +//------------------------------------------------------------------------------------------------- +int JetPlayer::closeFile() +{ + Mutex::Autolock lock(mMutex); + return JET_CloseFile(mEasData); +} + + +//------------------------------------------------------------------------------------------------- +int JetPlayer::play() +{ + LOGV("JetPlayer::play(): entering"); + Mutex::Autolock lock(mMutex); + + EAS_RESULT result = JET_Play(mEasData); + + mPaused = false; + mRender = true; + + JET_Status(mEasData, &mJetStatus); + this->dumpJetStatus(&mJetStatus); + + fireUpdateOnStatusChange(); + + // wake up render thread + LOGV("JetPlayer::play(): wakeup render thread"); + mCondition.signal(); + + return result; +} + +//------------------------------------------------------------------------------------------------- +int JetPlayer::pause() +{ + Mutex::Autolock lock(mMutex); + mPaused = true; + EAS_RESULT result = JET_Pause(mEasData); + + mRender = false; + + JET_Status(mEasData, &mJetStatus); + this->dumpJetStatus(&mJetStatus); + fireUpdateOnStatusChange(); + + + return result; +} + + +//------------------------------------------------------------------------------------------------- +int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose, + EAS_U32 muteFlags, EAS_U8 userID) +{ + LOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d", + segmentNum, libNum, repeatCount, transpose); + Mutex::Autolock lock(mMutex); + return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID); +} + +//------------------------------------------------------------------------------------------------- +int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync) +{ + Mutex::Autolock lock(mMutex); + return JET_SetMuteFlags(mEasData, muteFlags, sync); +} + +//------------------------------------------------------------------------------------------------- +int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync) +{ + Mutex::Autolock lock(mMutex); + return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync); +} + +//------------------------------------------------------------------------------------------------- +int JetPlayer::triggerClip(int clipId) +{ + LOGV("JetPlayer::triggerClip clipId=%d", clipId); + Mutex::Autolock lock(mMutex); + return JET_TriggerClip(mEasData, clipId); +} + +//------------------------------------------------------------------------------------------------- +int JetPlayer::clearQueue() +{ + LOGV("JetPlayer::clearQueue"); + Mutex::Autolock lock(mMutex); + return JET_Clear_Queue(mEasData); +} + +//------------------------------------------------------------------------------------------------- +void JetPlayer::dump() +{ + LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path); +} + +void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus) +{ + if(pJetStatus!=NULL) + LOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d", + pJetStatus->currentUserID, pJetStatus->segmentRepeatCount, + pJetStatus->numQueuedSegments, pJetStatus->paused); + else + LOGE(">> JET player status is NULL"); +} + + +} // end namespace android + -- cgit v1.1