blob: 2c6210471d3a2c2d296914f2d6109dd6edf3f20a [file] [log] [blame]
The Android Open Source Projectb7986892009-01-09 17:51:23 -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
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#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 }
The Android Open Source Project3001a032009-02-19 10:57:31 -080089 // init the JET library with the default app event controller range
90 result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG));
The Android Open Source Projectb7986892009-01-09 17:51:23 -080091 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();
The Android Open Source Projectda996f32009-02-13 12:57:50 -080099 mAudioTrack->set(AudioSystem::MUSIC, //TODO parametrize this
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800100 pLibConfig->sampleRate,
101 1, // format = PCM 16bits per sample,
102 pLibConfig->numChannels,
103 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) {
197 mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
198
199 // nothing to render, wait for client thread to wake us up
200 while (!mRender)
201 {
202 LOGV("JetPlayer::render(): signal wait");
The Android Open Source Project3001a032009-02-19 10:57:31 -0800203 if (audioStarted) {
204 mAudioTrack->pause();
205 // we have to restart the playback once we start rendering again
206 audioStarted = false;
207 }
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800208 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);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800222
223 // send events that were generated (if any) to the event callback
224 fireEventsFromJetQueue();
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800225 }
226
227 // update playback state
228 //LOGV("JetPlayer::render(): updating state");
229 JET_Status(mEasData, &mJetStatus);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800230 fireUpdateOnStatusChange();
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800231 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:
258 mAudioTrack->flush();
259 if (mAudioBuffer) {
260 delete [] mAudioBuffer;
261 mAudioBuffer = NULL;
262 }
263 mMutex.lock();
264 mTid = -1;
265 mCondition.signal();
266 mMutex.unlock();
267 return result;
268}
269
270
271//-------------------------------------------------------------------------------------------------
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800272// fire up an update if any of the status fields has changed
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800273// precondition: mMutex locked
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800274void JetPlayer::fireUpdateOnStatusChange()
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800275{
276 if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
277 ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
278 if(mEventCallback) {
279 mEventCallback(
280 JetPlayer::JET_USERID_UPDATE,
281 mJetStatus.currentUserID,
282 mJetStatus.segmentRepeatCount,
283 mJavaJetPlayerRef);
284 }
285 mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
286 mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
287 }
288
289 if(mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
290 if(mEventCallback) {
291 mEventCallback(
292 JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
293 mJetStatus.numQueuedSegments,
294 -1,
295 mJavaJetPlayerRef);
296 }
297 mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
298 }
299
300 if(mJetStatus.paused != mPreviousJetStatus.paused) {
301 if(mEventCallback) {
302 mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
303 mJetStatus.paused,
304 -1,
305 mJavaJetPlayerRef);
306 }
307 mPreviousJetStatus.paused = mJetStatus.paused;
308 }
309
310}
311
312
313//-------------------------------------------------------------------------------------------------
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800314// fire up all the JET events in the JET engine queue (until the queue is empty)
315// precondition: mMutex locked
316void JetPlayer::fireEventsFromJetQueue()
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800317{
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800318 if(!mEventCallback) {
319 // no callback, just empty the event queue
320 while (JET_GetEvent(mEasData, NULL, NULL)) { }
321 return;
322 }
The Android Open Source Project3001a032009-02-19 10:57:31 -0800323
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800324 EAS_U32 rawEvent;
325 while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
326 mEventCallback(
327 JetPlayer::JET_EVENT,
328 rawEvent,
329 -1,
330 mJavaJetPlayerRef);
331 }
332}
333
334
335//-------------------------------------------------------------------------------------------------
336int JetPlayer::loadFromFile(const char* path)
337{
338 LOGV("JetPlayer::loadFromFile(): path=%s", path);
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800339
340 Mutex::Autolock lock(mMutex);
341
342 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
343 memset(mJetFilePath, 0, 256);
344 strncpy(mJetFilePath, path, strlen(path));
345 mEasJetFileLoc->path = mJetFilePath;
346
347 mEasJetFileLoc->fd = 0;
348 mEasJetFileLoc->length = 0;
349 mEasJetFileLoc->offset = 0;
350
351 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
352 if(result != EAS_SUCCESS)
353 mState = EAS_STATE_ERROR;
354 else
355 mState = EAS_STATE_OPEN;
356 return( result );
357}
358
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800359
360//-------------------------------------------------------------------------------------------------
361int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
362{
363 LOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
364
365 Mutex::Autolock lock(mMutex);
366
367 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
368 mEasJetFileLoc->fd = fd;
369 mEasJetFileLoc->offset = offset;
370 mEasJetFileLoc->length = length;
371 mEasJetFileLoc->path = NULL;
372
373 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
374 if(result != EAS_SUCCESS)
375 mState = EAS_STATE_ERROR;
376 else
377 mState = EAS_STATE_OPEN;
378 return( result );
379}
380
381
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800382//-------------------------------------------------------------------------------------------------
383int JetPlayer::closeFile()
384{
385 Mutex::Autolock lock(mMutex);
386 return JET_CloseFile(mEasData);
387}
388
389
390//-------------------------------------------------------------------------------------------------
391int JetPlayer::play()
392{
393 LOGV("JetPlayer::play(): entering");
394 Mutex::Autolock lock(mMutex);
395
396 EAS_RESULT result = JET_Play(mEasData);
397
398 mPaused = false;
399 mRender = true;
400
401 JET_Status(mEasData, &mJetStatus);
402 this->dumpJetStatus(&mJetStatus);
403
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800404 fireUpdateOnStatusChange();
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800405
406 // wake up render thread
407 LOGV("JetPlayer::play(): wakeup render thread");
408 mCondition.signal();
409
410 return result;
411}
412
413//-------------------------------------------------------------------------------------------------
414int JetPlayer::pause()
415{
416 Mutex::Autolock lock(mMutex);
417 mPaused = true;
418 EAS_RESULT result = JET_Pause(mEasData);
419
420 mRender = false;
421
422 JET_Status(mEasData, &mJetStatus);
423 this->dumpJetStatus(&mJetStatus);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800424 fireUpdateOnStatusChange();
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800425
426
427 return result;
428}
429
430
431//-------------------------------------------------------------------------------------------------
432int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
433 EAS_U32 muteFlags, EAS_U8 userID)
434{
435 LOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
436 segmentNum, libNum, repeatCount, transpose);
437 Mutex::Autolock lock(mMutex);
438 return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
439}
440
441//-------------------------------------------------------------------------------------------------
442int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
443{
444 Mutex::Autolock lock(mMutex);
445 return JET_SetMuteFlags(mEasData, muteFlags, sync);
446}
447
448//-------------------------------------------------------------------------------------------------
449int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
450{
451 Mutex::Autolock lock(mMutex);
452 return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
453}
454
455//-------------------------------------------------------------------------------------------------
456int JetPlayer::triggerClip(int clipId)
457{
458 LOGV("JetPlayer::triggerClip clipId=%d", clipId);
459 Mutex::Autolock lock(mMutex);
460 return JET_TriggerClip(mEasData, clipId);
461}
462
463//-------------------------------------------------------------------------------------------------
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800464int JetPlayer::clearQueue()
465{
466 LOGV("JetPlayer::clearQueue");
467 Mutex::Autolock lock(mMutex);
468 return JET_Clear_Queue(mEasData);
469}
470
471//-------------------------------------------------------------------------------------------------
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800472void JetPlayer::dump()
473{
474 LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path);
475}
476
477void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
478{
479 if(pJetStatus!=NULL)
480 LOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d",
481 pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
482 pJetStatus->numQueuedSegments, pJetStatus->paused);
483 else
484 LOGE(">> JET player status is NULL");
485}
486
487
488} // end namespace android
489