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