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