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