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