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 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