blob: 8b953e04fd8f28ada64c8cbfbc896f65080e13de [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Jean-Michel Trivie89554b2009-03-24 18:46:20 -070017//#define LOG_NDEBUG 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018#define LOG_TAG "JetPlayer-C"
19
20#include <utils/Log.h>
21#include <utils/threads.h>
22
23#include <media/JetPlayer.h>
24
25
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026namespace android
27{
28
29static const int MIX_NUM_BUFFERS = 4;
30static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
31
32//-------------------------------------------------------------------------------------------------
33JetPlayer::JetPlayer(jobject 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 LOGV("JetPlayer constructor");
46 mPreviousJetStatus.currentUserID = -1;
47 mPreviousJetStatus.segmentRepeatCount = -1;
48 mPreviousJetStatus.numQueuedSegments = -1;
49 mPreviousJetStatus.paused = true;
50}
51
52//-------------------------------------------------------------------------------------------------
53JetPlayer::~JetPlayer()
54{
55 LOGV("~JetPlayer");
56 release();
57
58}
59
60//-------------------------------------------------------------------------------------------------
61int 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 LOGE("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 LOGE("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 LOGE("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();
Dima Zavin24fc2fb2011-04-19 22:30:36 -070092 mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parametrize this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 pLibConfig->sampleRate,
94 1, // format = PCM 16bits per sample,
Dima Zavin24fc2fb2011-04-19 22:30:36 -070095 (pLibConfig->numChannels == 2) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 mTrackBufferSize,
97 0);
98
99 // create render and playback thread
100 {
101 Mutex::Autolock l(mMutex);
102 LOGV("JetPlayer::init(): trying to start render thread");
103 createThreadEtc(renderThread, this, "jetRenderThread", ANDROID_PRIORITY_AUDIO);
104 mCondition.wait(mMutex);
105 }
106 if (mTid > 0) {
107 // render thread started, we're ready
108 LOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
109 mState = EAS_STATE_READY;
110 } else {
111 LOGE("JetPlayer::init(): failed to start render thread.");
112 mState = EAS_STATE_ERROR;
113 return EAS_FAILURE;
114 }
115
116 return EAS_SUCCESS;
117}
118
119void JetPlayer::setEventCallback(jetevent_callback eventCallback)
120{
121 Mutex::Autolock l(mMutex);
122 mEventCallback = eventCallback;
123}
124
125//-------------------------------------------------------------------------------------------------
126int JetPlayer::release()
127{
128 LOGV("JetPlayer::release()");
129 Mutex::Autolock lock(mMutex);
130 mPaused = true;
131 mRender = false;
132 if (mEasData) {
133 JET_Pause(mEasData);
134 JET_CloseFile(mEasData);
135 JET_Shutdown(mEasData);
136 EAS_Shutdown(mEasData);
137 }
138 if (mEasJetFileLoc) {
139 free(mEasJetFileLoc);
140 mEasJetFileLoc = NULL;
141 }
142 if (mAudioTrack) {
143 mAudioTrack->stop();
144 mAudioTrack->flush();
145 delete mAudioTrack;
146 mAudioTrack = NULL;
147 }
148 if (mAudioBuffer) {
149 delete mAudioBuffer;
150 mAudioBuffer = NULL;
151 }
152 mEasData = NULL;
153
154 return EAS_SUCCESS;
155}
156
157
158//-------------------------------------------------------------------------------------------------
159int JetPlayer::renderThread(void* p) {
160
161 return ((JetPlayer*)p)->render();
162}
163
164//-------------------------------------------------------------------------------------------------
165int JetPlayer::render() {
166 EAS_RESULT result = EAS_FAILURE;
167 EAS_I32 count;
168 int temp;
169 bool audioStarted = false;
170
171 LOGV("JetPlayer::render(): entering");
172
173 // allocate render buffer
174 mAudioBuffer =
175 new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
176 if (!mAudioBuffer) {
177 LOGE("JetPlayer::render(): mAudioBuffer allocate failed");
178 goto threadExit;
179 }
180
181 // signal main thread that we started
182 {
183 Mutex::Autolock l(mMutex);
Glenn Kasten6af763b2011-05-04 17:58:57 -0700184 mTid = gettid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 LOGV("JetPlayer::render(): render thread(%d) signal", mTid);
186 mCondition.signal();
187 }
188
189 while (1) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
192
The Android Open Source Project10592532009-03-18 17:39:46 -0700193 if (mEasData == NULL) {
194 mMutex.unlock();
195 LOGV("JetPlayer::render(): NULL EAS data, exiting render.");
196 goto threadExit;
197 }
198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 // nothing to render, wait for client thread to wake us up
200 while (!mRender)
201 {
202 LOGV("JetPlayer::render(): signal wait");
203 if (audioStarted) {
204 mAudioTrack->pause();
205 // we have to restart the playback once we start rendering again
206 audioStarted = false;
207 }
208 mCondition.wait(mMutex);
209 LOGV("JetPlayer::render(): signal rx'd");
210 }
211
212 // render midi data into the input buffer
213 int num_output = 0;
214 EAS_PCM* p = mAudioBuffer;
215 for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
216 result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
217 if (result != EAS_SUCCESS) {
218 LOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
219 }
220 p += count * pLibConfig->numChannels;
221 num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
222
223 // send events that were generated (if any) to the event callback
224 fireEventsFromJetQueue();
225 }
226
227 // update playback state
228 //LOGV("JetPlayer::render(): updating state");
229 JET_Status(mEasData, &mJetStatus);
230 fireUpdateOnStatusChange();
231 mPaused = mJetStatus.paused;
232
233 mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
234
235 // check audio output track
236 if (mAudioTrack == NULL) {
237 LOGE("JetPlayer::render(): output AudioTrack was not created");
238 goto threadExit;
239 }
240
241 // Write data to the audio hardware
242 //LOGV("JetPlayer::render(): writing to audio output");
243 if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
244 LOGE("JetPlayer::render(): Error in writing:%d",temp);
245 return temp;
246 }
247
248 // start audio output if necessary
249 if (!audioStarted) {
250 LOGV("JetPlayer::render(): starting audio playback");
251 mAudioTrack->start();
252 audioStarted = true;
253 }
254
255 }//while (1)
256
257threadExit:
The Android Open Source Project10592532009-03-18 17:39:46 -0700258 if (mAudioTrack) {
259 mAudioTrack->stop();
260 mAudioTrack->flush();
261 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 if (mAudioBuffer) {
263 delete [] mAudioBuffer;
264 mAudioBuffer = NULL;
265 }
266 mMutex.lock();
267 mTid = -1;
268 mCondition.signal();
269 mMutex.unlock();
270 return result;
271}
272
273
274//-------------------------------------------------------------------------------------------------
275// fire up an update if any of the status fields has changed
276// precondition: mMutex locked
277void JetPlayer::fireUpdateOnStatusChange()
278{
279 if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
280 ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
281 if(mEventCallback) {
282 mEventCallback(
283 JetPlayer::JET_USERID_UPDATE,
284 mJetStatus.currentUserID,
285 mJetStatus.segmentRepeatCount,
286 mJavaJetPlayerRef);
287 }
288 mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
289 mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
290 }
291
292 if(mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
293 if(mEventCallback) {
294 mEventCallback(
295 JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
296 mJetStatus.numQueuedSegments,
297 -1,
298 mJavaJetPlayerRef);
299 }
300 mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
301 }
302
303 if(mJetStatus.paused != mPreviousJetStatus.paused) {
304 if(mEventCallback) {
305 mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
306 mJetStatus.paused,
307 -1,
308 mJavaJetPlayerRef);
309 }
310 mPreviousJetStatus.paused = mJetStatus.paused;
311 }
312
313}
314
315
316//-------------------------------------------------------------------------------------------------
317// fire up all the JET events in the JET engine queue (until the queue is empty)
318// precondition: mMutex locked
319void JetPlayer::fireEventsFromJetQueue()
320{
321 if(!mEventCallback) {
322 // no callback, just empty the event queue
323 while (JET_GetEvent(mEasData, NULL, NULL)) { }
324 return;
325 }
326
327 EAS_U32 rawEvent;
328 while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
329 mEventCallback(
330 JetPlayer::JET_EVENT,
331 rawEvent,
332 -1,
333 mJavaJetPlayerRef);
334 }
335}
336
337
338//-------------------------------------------------------------------------------------------------
339int JetPlayer::loadFromFile(const char* path)
340{
341 LOGV("JetPlayer::loadFromFile(): path=%s", path);
342
343 Mutex::Autolock lock(mMutex);
344
345 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
346 memset(mJetFilePath, 0, 256);
347 strncpy(mJetFilePath, path, strlen(path));
348 mEasJetFileLoc->path = mJetFilePath;
349
350 mEasJetFileLoc->fd = 0;
351 mEasJetFileLoc->length = 0;
352 mEasJetFileLoc->offset = 0;
353
354 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
355 if(result != EAS_SUCCESS)
356 mState = EAS_STATE_ERROR;
357 else
358 mState = EAS_STATE_OPEN;
359 return( result );
360}
361
362
363//-------------------------------------------------------------------------------------------------
364int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
365{
366 LOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
367
368 Mutex::Autolock lock(mMutex);
369
370 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
371 mEasJetFileLoc->fd = fd;
372 mEasJetFileLoc->offset = offset;
373 mEasJetFileLoc->length = length;
374 mEasJetFileLoc->path = NULL;
375
376 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
377 if(result != EAS_SUCCESS)
378 mState = EAS_STATE_ERROR;
379 else
380 mState = EAS_STATE_OPEN;
381 return( result );
382}
383
384
385//-------------------------------------------------------------------------------------------------
386int JetPlayer::closeFile()
387{
388 Mutex::Autolock lock(mMutex);
389 return JET_CloseFile(mEasData);
390}
391
392
393//-------------------------------------------------------------------------------------------------
394int JetPlayer::play()
395{
396 LOGV("JetPlayer::play(): entering");
397 Mutex::Autolock lock(mMutex);
398
399 EAS_RESULT result = JET_Play(mEasData);
400
401 mPaused = false;
402 mRender = true;
403
404 JET_Status(mEasData, &mJetStatus);
405 this->dumpJetStatus(&mJetStatus);
406
407 fireUpdateOnStatusChange();
408
409 // wake up render thread
410 LOGV("JetPlayer::play(): wakeup render thread");
411 mCondition.signal();
412
413 return result;
414}
415
416//-------------------------------------------------------------------------------------------------
417int JetPlayer::pause()
418{
419 Mutex::Autolock lock(mMutex);
420 mPaused = true;
421 EAS_RESULT result = JET_Pause(mEasData);
422
423 mRender = false;
424
425 JET_Status(mEasData, &mJetStatus);
426 this->dumpJetStatus(&mJetStatus);
427 fireUpdateOnStatusChange();
428
429
430 return result;
431}
432
433
434//-------------------------------------------------------------------------------------------------
435int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
436 EAS_U32 muteFlags, EAS_U8 userID)
437{
438 LOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
439 segmentNum, libNum, repeatCount, transpose);
440 Mutex::Autolock lock(mMutex);
441 return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
442}
443
444//-------------------------------------------------------------------------------------------------
445int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
446{
447 Mutex::Autolock lock(mMutex);
448 return JET_SetMuteFlags(mEasData, muteFlags, sync);
449}
450
451//-------------------------------------------------------------------------------------------------
452int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
453{
454 Mutex::Autolock lock(mMutex);
455 return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
456}
457
458//-------------------------------------------------------------------------------------------------
459int JetPlayer::triggerClip(int clipId)
460{
461 LOGV("JetPlayer::triggerClip clipId=%d", clipId);
462 Mutex::Autolock lock(mMutex);
463 return JET_TriggerClip(mEasData, clipId);
464}
465
466//-------------------------------------------------------------------------------------------------
467int JetPlayer::clearQueue()
468{
469 LOGV("JetPlayer::clearQueue");
470 Mutex::Autolock lock(mMutex);
471 return JET_Clear_Queue(mEasData);
472}
473
474//-------------------------------------------------------------------------------------------------
475void JetPlayer::dump()
476{
477 LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path);
478}
479
480void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
481{
482 if(pJetStatus!=NULL)
483 LOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d",
484 pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
485 pJetStatus->numQueuedSegments, pJetStatus->paused);
486 else
487 LOGE(">> JET player status is NULL");
488}
489
490
491} // end namespace android
492