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 24namespace android 25{ 26 27static const int MIX_NUM_BUFFERS = 4; 28static const S_EAS_LIB_CONFIG* pLibConfig = NULL; 29 30//------------------------------------------------------------------------------------------------- 31JetPlayer::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//------------------------------------------------------------------------------------------------- 49JetPlayer::~JetPlayer() 50{ 51 ALOGV("~JetPlayer"); 52 release(); 53 54} 55 56//------------------------------------------------------------------------------------------------- 57int 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 122void JetPlayer::setEventCallback(jetevent_callback eventCallback) 123{ 124 Mutex::Autolock l(mMutex); 125 mEventCallback = eventCallback; 126} 127 128//------------------------------------------------------------------------------------------------- 129int 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//------------------------------------------------------------------------------------------------- 158int 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 246threadExit: 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 264void 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 306void 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//------------------------------------------------------------------------------------------------- 326int 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//------------------------------------------------------------------------------------------------- 344int 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//------------------------------------------------------------------------------------------------- 362int JetPlayer::closeFile() 363{ 364 Mutex::Autolock lock(mMutex); 365 return JET_CloseFile(mEasData); 366} 367 368 369//------------------------------------------------------------------------------------------------- 370int 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//------------------------------------------------------------------------------------------------- 393int 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//------------------------------------------------------------------------------------------------- 411int 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//------------------------------------------------------------------------------------------------- 422int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync) 423{ 424 Mutex::Autolock lock(mMutex); 425 return JET_SetMuteFlags(mEasData, muteFlags, sync); 426} 427 428//------------------------------------------------------------------------------------------------- 429int 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//------------------------------------------------------------------------------------------------- 436int 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//------------------------------------------------------------------------------------------------- 444int JetPlayer::clearQueue() 445{ 446 ALOGV("JetPlayer::clearQueue"); 447 Mutex::Autolock lock(mMutex); 448 return JET_Clear_Queue(mEasData); 449} 450 451//------------------------------------------------------------------------------------------------- 452void JetPlayer::dump() 453{ 454} 455 456void 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