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 with the default app event controller range 90 result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG)); 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(AudioSystem::MUSIC, //TODO parametrize this 100 pLibConfig->sampleRate, 101 1, // format = PCM 16bits per sample, 102 (pLibConfig->numChannels == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO, 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 198 mMutex.lock(); // [[[[[[[[ LOCK --------------------------------------- 199 200 if (mEasData == NULL) { 201 mMutex.unlock(); 202 LOGV("JetPlayer::render(): NULL EAS data, exiting render."); 203 goto threadExit; 204 } 205 206 // nothing to render, wait for client thread to wake us up 207 while (!mRender) 208 { 209 LOGV("JetPlayer::render(): signal wait"); 210 if (audioStarted) { 211 mAudioTrack->pause(); 212 // we have to restart the playback once we start rendering again 213 audioStarted = false; 214 } 215 mCondition.wait(mMutex); 216 LOGV("JetPlayer::render(): signal rx'd"); 217 } 218 219 // render midi data into the input buffer 220 int num_output = 0; 221 EAS_PCM* p = mAudioBuffer; 222 for (int i = 0; i < MIX_NUM_BUFFERS; i++) { 223 result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count); 224 if (result != EAS_SUCCESS) { 225 LOGE("JetPlayer::render(): EAS_Render returned error %ld", result); 226 } 227 p += count * pLibConfig->numChannels; 228 num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM); 229 230 // send events that were generated (if any) to the event callback 231 fireEventsFromJetQueue(); 232 } 233 234 // update playback state 235 //LOGV("JetPlayer::render(): updating state"); 236 JET_Status(mEasData, &mJetStatus); 237 fireUpdateOnStatusChange(); 238 mPaused = mJetStatus.paused; 239 240 mMutex.unlock(); // UNLOCK ]]]]]]]] ----------------------------------- 241 242 // check audio output track 243 if (mAudioTrack == NULL) { 244 LOGE("JetPlayer::render(): output AudioTrack was not created"); 245 goto threadExit; 246 } 247 248 // Write data to the audio hardware 249 //LOGV("JetPlayer::render(): writing to audio output"); 250 if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) { 251 LOGE("JetPlayer::render(): Error in writing:%d",temp); 252 return temp; 253 } 254 255 // start audio output if necessary 256 if (!audioStarted) { 257 LOGV("JetPlayer::render(): starting audio playback"); 258 mAudioTrack->start(); 259 audioStarted = true; 260 } 261 262 }//while (1) 263 264threadExit: 265 if (mAudioTrack) { 266 mAudioTrack->stop(); 267 mAudioTrack->flush(); 268 } 269 if (mAudioBuffer) { 270 delete [] mAudioBuffer; 271 mAudioBuffer = NULL; 272 } 273 mMutex.lock(); 274 mTid = -1; 275 mCondition.signal(); 276 mMutex.unlock(); 277 return result; 278} 279 280 281//------------------------------------------------------------------------------------------------- 282// fire up an update if any of the status fields has changed 283// precondition: mMutex locked 284void JetPlayer::fireUpdateOnStatusChange() 285{ 286 if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID) 287 ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) { 288 if(mEventCallback) { 289 mEventCallback( 290 JetPlayer::JET_USERID_UPDATE, 291 mJetStatus.currentUserID, 292 mJetStatus.segmentRepeatCount, 293 mJavaJetPlayerRef); 294 } 295 mPreviousJetStatus.currentUserID = mJetStatus.currentUserID; 296 mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount; 297 } 298 299 if(mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) { 300 if(mEventCallback) { 301 mEventCallback( 302 JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE, 303 mJetStatus.numQueuedSegments, 304 -1, 305 mJavaJetPlayerRef); 306 } 307 mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments; 308 } 309 310 if(mJetStatus.paused != mPreviousJetStatus.paused) { 311 if(mEventCallback) { 312 mEventCallback(JetPlayer::JET_PAUSE_UPDATE, 313 mJetStatus.paused, 314 -1, 315 mJavaJetPlayerRef); 316 } 317 mPreviousJetStatus.paused = mJetStatus.paused; 318 } 319 320} 321 322 323//------------------------------------------------------------------------------------------------- 324// fire up all the JET events in the JET engine queue (until the queue is empty) 325// precondition: mMutex locked 326void JetPlayer::fireEventsFromJetQueue() 327{ 328 if(!mEventCallback) { 329 // no callback, just empty the event queue 330 while (JET_GetEvent(mEasData, NULL, NULL)) { } 331 return; 332 } 333 334 EAS_U32 rawEvent; 335 while (JET_GetEvent(mEasData, &rawEvent, NULL)) { 336 mEventCallback( 337 JetPlayer::JET_EVENT, 338 rawEvent, 339 -1, 340 mJavaJetPlayerRef); 341 } 342} 343 344 345//------------------------------------------------------------------------------------------------- 346int JetPlayer::loadFromFile(const char* path) 347{ 348 LOGV("JetPlayer::loadFromFile(): path=%s", path); 349 350 Mutex::Autolock lock(mMutex); 351 352 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE)); 353 memset(mJetFilePath, 0, 256); 354 strncpy(mJetFilePath, path, strlen(path)); 355 mEasJetFileLoc->path = mJetFilePath; 356 357 mEasJetFileLoc->fd = 0; 358 mEasJetFileLoc->length = 0; 359 mEasJetFileLoc->offset = 0; 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//------------------------------------------------------------------------------------------------- 371int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length) 372{ 373 LOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length); 374 375 Mutex::Autolock lock(mMutex); 376 377 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE)); 378 mEasJetFileLoc->fd = fd; 379 mEasJetFileLoc->offset = offset; 380 mEasJetFileLoc->length = length; 381 mEasJetFileLoc->path = NULL; 382 383 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc); 384 if(result != EAS_SUCCESS) 385 mState = EAS_STATE_ERROR; 386 else 387 mState = EAS_STATE_OPEN; 388 return( result ); 389} 390 391 392//------------------------------------------------------------------------------------------------- 393int JetPlayer::closeFile() 394{ 395 Mutex::Autolock lock(mMutex); 396 return JET_CloseFile(mEasData); 397} 398 399 400//------------------------------------------------------------------------------------------------- 401int JetPlayer::play() 402{ 403 LOGV("JetPlayer::play(): entering"); 404 Mutex::Autolock lock(mMutex); 405 406 EAS_RESULT result = JET_Play(mEasData); 407 408 mPaused = false; 409 mRender = true; 410 411 JET_Status(mEasData, &mJetStatus); 412 this->dumpJetStatus(&mJetStatus); 413 414 fireUpdateOnStatusChange(); 415 416 // wake up render thread 417 LOGV("JetPlayer::play(): wakeup render thread"); 418 mCondition.signal(); 419 420 return result; 421} 422 423//------------------------------------------------------------------------------------------------- 424int JetPlayer::pause() 425{ 426 Mutex::Autolock lock(mMutex); 427 mPaused = true; 428 EAS_RESULT result = JET_Pause(mEasData); 429 430 mRender = false; 431 432 JET_Status(mEasData, &mJetStatus); 433 this->dumpJetStatus(&mJetStatus); 434 fireUpdateOnStatusChange(); 435 436 437 return result; 438} 439 440 441//------------------------------------------------------------------------------------------------- 442int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose, 443 EAS_U32 muteFlags, EAS_U8 userID) 444{ 445 LOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d", 446 segmentNum, libNum, repeatCount, transpose); 447 Mutex::Autolock lock(mMutex); 448 return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID); 449} 450 451//------------------------------------------------------------------------------------------------- 452int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync) 453{ 454 Mutex::Autolock lock(mMutex); 455 return JET_SetMuteFlags(mEasData, muteFlags, sync); 456} 457 458//------------------------------------------------------------------------------------------------- 459int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync) 460{ 461 Mutex::Autolock lock(mMutex); 462 return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync); 463} 464 465//------------------------------------------------------------------------------------------------- 466int JetPlayer::triggerClip(int clipId) 467{ 468 LOGV("JetPlayer::triggerClip clipId=%d", clipId); 469 Mutex::Autolock lock(mMutex); 470 return JET_TriggerClip(mEasData, clipId); 471} 472 473//------------------------------------------------------------------------------------------------- 474int JetPlayer::clearQueue() 475{ 476 LOGV("JetPlayer::clearQueue"); 477 Mutex::Autolock lock(mMutex); 478 return JET_Clear_Queue(mEasData); 479} 480 481//------------------------------------------------------------------------------------------------- 482void JetPlayer::dump() 483{ 484 LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path); 485} 486 487void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus) 488{ 489 if(pJetStatus!=NULL) 490 LOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d", 491 pJetStatus->currentUserID, pJetStatus->segmentRepeatCount, 492 pJetStatus->numQueuedSegments, pJetStatus->paused); 493 else 494 LOGE(">> JET player status is NULL"); 495} 496 497 498} // end namespace android 499 500