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