JetPlayer.cpp revision 2799d743ee2ae5a25fe869a7f9c052acc029559f
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(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 mTrackBufferSize(trackBufferSize) 43{ 44 ALOGV("JetPlayer constructor"); 45 mPreviousJetStatus.currentUserID = -1; 46 mPreviousJetStatus.segmentRepeatCount = -1; 47 mPreviousJetStatus.numQueuedSegments = -1; 48 mPreviousJetStatus.paused = true; 49} 50 51//------------------------------------------------------------------------------------------------- 52JetPlayer::~JetPlayer() 53{ 54 ALOGV("~JetPlayer"); 55 release(); 56 57} 58 59//------------------------------------------------------------------------------------------------- 60int JetPlayer::init() 61{ 62 //Mutex::Autolock lock(&mMutex); 63 64 EAS_RESULT result; 65 66 // retrieve the EAS library settings 67 if (pLibConfig == NULL) 68 pLibConfig = EAS_Config(); 69 if (pLibConfig == NULL) { 70 ALOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting."); 71 return EAS_FAILURE; 72 } 73 74 // init the EAS library 75 result = EAS_Init(&mEasData); 76 if (result != EAS_SUCCESS) { 77 ALOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting."); 78 mState = EAS_STATE_ERROR; 79 return result; 80 } 81 // init the JET library with the default app event controller range 82 result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG)); 83 if (result != EAS_SUCCESS) { 84 ALOGE("JetPlayer::init(): Error initializing JET library, aborting."); 85 mState = EAS_STATE_ERROR; 86 return result; 87 } 88 89 // create the output AudioTrack 90 mAudioTrack = new AudioTrack(); 91 mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parameterize this 92 pLibConfig->sampleRate, 93 AUDIO_FORMAT_PCM_16_BIT, 94 audio_channel_out_mask_from_count(pLibConfig->numChannels), 95 mTrackBufferSize, 96 AUDIO_OUTPUT_FLAG_NONE); 97 98 // create render and playback thread 99 { 100 Mutex::Autolock l(mMutex); 101 ALOGV("JetPlayer::init(): trying to start render thread"); 102 mThread = new JetPlayerThread(this); 103 mThread->run("jetRenderThread", ANDROID_PRIORITY_AUDIO); 104 mCondition.wait(mMutex); 105 } 106 if (mTid > 0) { 107 // render thread started, we're ready 108 ALOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid); 109 mState = EAS_STATE_READY; 110 } else { 111 ALOGE("JetPlayer::init(): failed to start render thread."); 112 mState = EAS_STATE_ERROR; 113 return EAS_FAILURE; 114 } 115 116 return EAS_SUCCESS; 117} 118 119void JetPlayer::setEventCallback(jetevent_callback eventCallback) 120{ 121 Mutex::Autolock l(mMutex); 122 mEventCallback = eventCallback; 123} 124 125//------------------------------------------------------------------------------------------------- 126int JetPlayer::release() 127{ 128 ALOGV("JetPlayer::release()"); 129 Mutex::Autolock lock(mMutex); 130 mPaused = true; 131 mRender = false; 132 if (mEasData) { 133 JET_Pause(mEasData); 134 JET_CloseFile(mEasData); 135 JET_Shutdown(mEasData); 136 EAS_Shutdown(mEasData); 137 } 138 if (mEasJetFileLoc) { 139 free(mEasJetFileLoc); 140 mEasJetFileLoc = NULL; 141 } 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 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE)); 333 strncpy(mJetFilePath, path, sizeof(mJetFilePath)); 334 mJetFilePath[sizeof(mJetFilePath) - 1] = '\0'; 335 mEasJetFileLoc->path = mJetFilePath; 336 337 mEasJetFileLoc->fd = 0; 338 mEasJetFileLoc->length = 0; 339 mEasJetFileLoc->offset = 0; 340 341 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc); 342 if (result != EAS_SUCCESS) 343 mState = EAS_STATE_ERROR; 344 else 345 mState = EAS_STATE_OPEN; 346 return( result ); 347} 348 349 350//------------------------------------------------------------------------------------------------- 351int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length) 352{ 353 ALOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length); 354 355 Mutex::Autolock lock(mMutex); 356 357 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE)); 358 mEasJetFileLoc->fd = fd; 359 mEasJetFileLoc->offset = offset; 360 mEasJetFileLoc->length = length; 361 mEasJetFileLoc->path = NULL; 362 363 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc); 364 if (result != EAS_SUCCESS) 365 mState = EAS_STATE_ERROR; 366 else 367 mState = EAS_STATE_OPEN; 368 return( result ); 369} 370 371 372//------------------------------------------------------------------------------------------------- 373int JetPlayer::closeFile() 374{ 375 Mutex::Autolock lock(mMutex); 376 return JET_CloseFile(mEasData); 377} 378 379 380//------------------------------------------------------------------------------------------------- 381int JetPlayer::play() 382{ 383 ALOGV("JetPlayer::play(): entering"); 384 Mutex::Autolock lock(mMutex); 385 386 EAS_RESULT result = JET_Play(mEasData); 387 388 mPaused = false; 389 mRender = true; 390 391 JET_Status(mEasData, &mJetStatus); 392 this->dumpJetStatus(&mJetStatus); 393 394 fireUpdateOnStatusChange(); 395 396 // wake up render thread 397 ALOGV("JetPlayer::play(): wakeup render thread"); 398 mCondition.signal(); 399 400 return result; 401} 402 403//------------------------------------------------------------------------------------------------- 404int JetPlayer::pause() 405{ 406 Mutex::Autolock lock(mMutex); 407 mPaused = true; 408 EAS_RESULT result = JET_Pause(mEasData); 409 410 mRender = false; 411 412 JET_Status(mEasData, &mJetStatus); 413 this->dumpJetStatus(&mJetStatus); 414 fireUpdateOnStatusChange(); 415 416 417 return result; 418} 419 420 421//------------------------------------------------------------------------------------------------- 422int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose, 423 EAS_U32 muteFlags, EAS_U8 userID) 424{ 425 ALOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d", 426 segmentNum, libNum, repeatCount, transpose); 427 Mutex::Autolock lock(mMutex); 428 return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID); 429} 430 431//------------------------------------------------------------------------------------------------- 432int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync) 433{ 434 Mutex::Autolock lock(mMutex); 435 return JET_SetMuteFlags(mEasData, muteFlags, sync); 436} 437 438//------------------------------------------------------------------------------------------------- 439int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync) 440{ 441 Mutex::Autolock lock(mMutex); 442 return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync); 443} 444 445//------------------------------------------------------------------------------------------------- 446int JetPlayer::triggerClip(int clipId) 447{ 448 ALOGV("JetPlayer::triggerClip clipId=%d", clipId); 449 Mutex::Autolock lock(mMutex); 450 return JET_TriggerClip(mEasData, clipId); 451} 452 453//------------------------------------------------------------------------------------------------- 454int JetPlayer::clearQueue() 455{ 456 ALOGV("JetPlayer::clearQueue"); 457 Mutex::Autolock lock(mMutex); 458 return JET_Clear_Queue(mEasData); 459} 460 461//------------------------------------------------------------------------------------------------- 462void JetPlayer::dump() 463{ 464 ALOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path); 465} 466 467void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus) 468{ 469 if (pJetStatus!=NULL) 470 ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d", 471 pJetStatus->currentUserID, pJetStatus->segmentRepeatCount, 472 pJetStatus->numQueuedSegments, pJetStatus->paused); 473 else 474 ALOGE(">> JET player status is NULL"); 475} 476 477 478} // end namespace android 479