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