blob: ead24d497f23aa566e522d7ed0919c2961bb722b [file] [log] [blame]
The Android Open Source Projectcce8bd12009-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 }
89 // init the JET library
90 result = JET_Init(mEasData, NULL, 0);
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();
99 mAudioTrack->set(AudioTrack::MUSIC, //TODO parametrize this
100 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");
203 mCondition.wait(mMutex);
204 LOGV("JetPlayer::render(): signal rx'd");
205 }
206
207 // render midi data into the input buffer
208 int num_output = 0;
209 EAS_PCM* p = mAudioBuffer;
210 for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
211 result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
212 if (result != EAS_SUCCESS) {
213 LOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
214 }
215 p += count * pLibConfig->numChannels;
216 num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
The Android Open Source Project5e07b572009-02-10 15:44:00 -0800217
218 // send events that were generated (if any) to the event callback
219 fireEventsFromJetQueue();
The Android Open Source Projectcce8bd12009-01-09 17:51:23 -0800220 }
221
222 // update playback state
223 //LOGV("JetPlayer::render(): updating state");
224 JET_Status(mEasData, &mJetStatus);
The Android Open Source Project5e07b572009-02-10 15:44:00 -0800225 fireUpdateOnStatusChange();
The Android Open Source Projectcce8bd12009-01-09 17:51:23 -0800226 mPaused = mJetStatus.paused;
227
228 mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
229
230 // check audio output track
231 if (mAudioTrack == NULL) {
232 LOGE("JetPlayer::render(): output AudioTrack was not created");
233 goto threadExit;
234 }
235
236 // Write data to the audio hardware
237 //LOGV("JetPlayer::render(): writing to audio output");
238 if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
239 LOGE("JetPlayer::render(): Error in writing:%d",temp);
240 return temp;
241 }
242
243 // start audio output if necessary
244 if (!audioStarted) {
245 LOGV("JetPlayer::render(): starting audio playback");
246 mAudioTrack->start();
247 audioStarted = true;
248 }
249
250 }//while (1)
251
252threadExit:
253 mAudioTrack->flush();
254 if (mAudioBuffer) {
255 delete [] mAudioBuffer;
256 mAudioBuffer = NULL;
257 }
258 mMutex.lock();
259 mTid = -1;
260 mCondition.signal();
261 mMutex.unlock();
262 return result;
263}
264
265
266//-------------------------------------------------------------------------------------------------
The Android Open Source Project5e07b572009-02-10 15:44:00 -0800267// fire up an update if any of the status fields has changed
The Android Open Source Projectcce8bd12009-01-09 17:51:23 -0800268// precondition: mMutex locked
The Android Open Source Project5e07b572009-02-10 15:44:00 -0800269void JetPlayer::fireUpdateOnStatusChange()
The Android Open Source Projectcce8bd12009-01-09 17:51:23 -0800270{
271 if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
272 ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
273 if(mEventCallback) {
274 mEventCallback(
275 JetPlayer::JET_USERID_UPDATE,
276 mJetStatus.currentUserID,
277 mJetStatus.segmentRepeatCount,
278 mJavaJetPlayerRef);
279 }
280 mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
281 mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
282 }
283
284 if(mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
285 if(mEventCallback) {
286 mEventCallback(
287 JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
288 mJetStatus.numQueuedSegments,
289 -1,
290 mJavaJetPlayerRef);
291 }
292 mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
293 }
294
295 if(mJetStatus.paused != mPreviousJetStatus.paused) {
296 if(mEventCallback) {
297 mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
298 mJetStatus.paused,
299 -1,
300 mJavaJetPlayerRef);
301 }
302 mPreviousJetStatus.paused = mJetStatus.paused;
303 }
304
305}
306
307
308//-------------------------------------------------------------------------------------------------
The Android Open Source Project5e07b572009-02-10 15:44:00 -0800309// fire up all the JET events in the JET engine queue (until the queue is empty)
310// precondition: mMutex locked
311void JetPlayer::fireEventsFromJetQueue()
The Android Open Source Projectcce8bd12009-01-09 17:51:23 -0800312{
The Android Open Source Project5e07b572009-02-10 15:44:00 -0800313 if(!mEventCallback) {
314 // no callback, just empty the event queue
315 while (JET_GetEvent(mEasData, NULL, NULL)) { }
316 return;
317 }
318
319 EAS_U32 rawEvent;
320 while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
321 mEventCallback(
322 JetPlayer::JET_EVENT,
323 rawEvent,
324 -1,
325 mJavaJetPlayerRef);
326 }
327}
328
329
330//-------------------------------------------------------------------------------------------------
331int JetPlayer::loadFromFile(const char* path)
332{
333 LOGV("JetPlayer::loadFromFile(): path=%s", path);
The Android Open Source Projectcce8bd12009-01-09 17:51:23 -0800334
335 Mutex::Autolock lock(mMutex);
336
337 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
338 memset(mJetFilePath, 0, 256);
339 strncpy(mJetFilePath, path, strlen(path));
340 mEasJetFileLoc->path = mJetFilePath;
341
342 mEasJetFileLoc->fd = 0;
343 mEasJetFileLoc->length = 0;
344 mEasJetFileLoc->offset = 0;
345
346 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
347 if(result != EAS_SUCCESS)
348 mState = EAS_STATE_ERROR;
349 else
350 mState = EAS_STATE_OPEN;
351 return( result );
352}
353
The Android Open Source Project5e07b572009-02-10 15:44:00 -0800354
355//-------------------------------------------------------------------------------------------------
356int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
357{
358 LOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
359
360 Mutex::Autolock lock(mMutex);
361
362 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
363 mEasJetFileLoc->fd = fd;
364 mEasJetFileLoc->offset = offset;
365 mEasJetFileLoc->length = length;
366 mEasJetFileLoc->path = NULL;
367
368 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
369 if(result != EAS_SUCCESS)
370 mState = EAS_STATE_ERROR;
371 else
372 mState = EAS_STATE_OPEN;
373 return( result );
374}
375
376
The Android Open Source Projectcce8bd12009-01-09 17:51:23 -0800377//-------------------------------------------------------------------------------------------------
378int JetPlayer::closeFile()
379{
380 Mutex::Autolock lock(mMutex);
381 return JET_CloseFile(mEasData);
382}
383
384
385//-------------------------------------------------------------------------------------------------
386int JetPlayer::play()
387{
388 LOGV("JetPlayer::play(): entering");
389 Mutex::Autolock lock(mMutex);
390
391 EAS_RESULT result = JET_Play(mEasData);
392
393 mPaused = false;
394 mRender = true;
395
396 JET_Status(mEasData, &mJetStatus);
397 this->dumpJetStatus(&mJetStatus);
398
The Android Open Source Project5e07b572009-02-10 15:44:00 -0800399 fireUpdateOnStatusChange();
The Android Open Source Projectcce8bd12009-01-09 17:51:23 -0800400
401 // wake up render thread
402 LOGV("JetPlayer::play(): wakeup render thread");
403 mCondition.signal();
404
405 return result;
406}
407
408//-------------------------------------------------------------------------------------------------
409int JetPlayer::pause()
410{
411 Mutex::Autolock lock(mMutex);
412 mPaused = true;
413 EAS_RESULT result = JET_Pause(mEasData);
414
415 mRender = false;
416
417 JET_Status(mEasData, &mJetStatus);
418 this->dumpJetStatus(&mJetStatus);
The Android Open Source Project5e07b572009-02-10 15:44:00 -0800419 fireUpdateOnStatusChange();
The Android Open Source Projectcce8bd12009-01-09 17:51:23 -0800420
421
422 return result;
423}
424
425
426//-------------------------------------------------------------------------------------------------
427int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
428 EAS_U32 muteFlags, EAS_U8 userID)
429{
430 LOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
431 segmentNum, libNum, repeatCount, transpose);
432 Mutex::Autolock lock(mMutex);
433 return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
434}
435
436//-------------------------------------------------------------------------------------------------
437int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
438{
439 Mutex::Autolock lock(mMutex);
440 return JET_SetMuteFlags(mEasData, muteFlags, sync);
441}
442
443//-------------------------------------------------------------------------------------------------
444int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
445{
446 Mutex::Autolock lock(mMutex);
447 return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
448}
449
450//-------------------------------------------------------------------------------------------------
451int JetPlayer::triggerClip(int clipId)
452{
453 LOGV("JetPlayer::triggerClip clipId=%d", clipId);
454 Mutex::Autolock lock(mMutex);
455 return JET_TriggerClip(mEasData, clipId);
456}
457
458//-------------------------------------------------------------------------------------------------
The Android Open Source Project5e07b572009-02-10 15:44:00 -0800459int JetPlayer::clearQueue()
460{
461 LOGV("JetPlayer::clearQueue");
462 Mutex::Autolock lock(mMutex);
463 return JET_Clear_Queue(mEasData);
464}
465
466//-------------------------------------------------------------------------------------------------
The Android Open Source Projectcce8bd12009-01-09 17:51:23 -0800467void JetPlayer::dump()
468{
469 LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path);
470}
471
472void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
473{
474 if(pJetStatus!=NULL)
475 LOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d",
476 pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
477 pJetStatus->numQueuedSegments, pJetStatus->paused);
478 else
479 LOGE(">> JET player status is NULL");
480}
481
482
483} // end namespace android
484