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