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