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