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