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