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