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