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