blob: 8456db567778cbfaf19088d5f0e06b98c46bb3df [file] [log] [blame]
The Android Open Source Project89fa4ad2009-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 Trivi06aff802009-03-24 18:46:20 -070017//#define LOG_NDEBUG 0
The Android Open Source Project89fa4ad2009-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 Project89fa4ad2009-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{
Steve Block3856b092011-10-20 11:56:00 +010045 ALOGV("JetPlayer constructor");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080046 mPreviousJetStatus.currentUserID = -1;
47 mPreviousJetStatus.segmentRepeatCount = -1;
48 mPreviousJetStatus.numQueuedSegments = -1;
49 mPreviousJetStatus.paused = true;
50}
51
52//-------------------------------------------------------------------------------------------------
53JetPlayer::~JetPlayer()
54{
Steve Block3856b092011-10-20 11:56:00 +010055 ALOGV("~JetPlayer");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080056 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) {
Steve Block29357bc2012-01-06 19:20:56 +000071 ALOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting.");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080072 return EAS_FAILURE;
73 }
74
75 // init the EAS library
76 result = EAS_Init(&mEasData);
77 if( result != EAS_SUCCESS) {
Steve Block29357bc2012-01-06 19:20:56 +000078 ALOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting.");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080079 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) {
Steve Block29357bc2012-01-06 19:20:56 +000085 ALOGE("JetPlayer::init(): Error initializing JET library, aborting.");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080086 mState = EAS_STATE_ERROR;
87 return result;
88 }
89
90 // create the output AudioTrack
91 mAudioTrack = new AudioTrack();
Dima Zavinfce7a472011-04-19 22:30:36 -070092 mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parametrize this
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080093 pLibConfig->sampleRate,
Glenn Kastene1c39622012-01-04 09:36:37 -080094 AUDIO_FORMAT_PCM_16_BIT,
Dima Zavinfce7a472011-04-19 22:30:36 -070095 (pLibConfig->numChannels == 2) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080096 mTrackBufferSize,
97 0);
98
99 // create render and playback thread
100 {
101 Mutex::Autolock l(mMutex);
Steve Block3856b092011-10-20 11:56:00 +0100102 ALOGV("JetPlayer::init(): trying to start render thread");
Glenn Kastena23856c2011-06-23 16:43:24 -0700103 mThread = new JetPlayerThread(this);
104 mThread->run("jetRenderThread", ANDROID_PRIORITY_AUDIO);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800105 mCondition.wait(mMutex);
106 }
107 if (mTid > 0) {
108 // render thread started, we're ready
Steve Block3856b092011-10-20 11:56:00 +0100109 ALOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800110 mState = EAS_STATE_READY;
111 } else {
Steve Block29357bc2012-01-06 19:20:56 +0000112 ALOGE("JetPlayer::init(): failed to start render thread.");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800113 mState = EAS_STATE_ERROR;
114 return EAS_FAILURE;
115 }
116
117 return EAS_SUCCESS;
118}
119
120void JetPlayer::setEventCallback(jetevent_callback eventCallback)
121{
122 Mutex::Autolock l(mMutex);
123 mEventCallback = eventCallback;
124}
125
126//-------------------------------------------------------------------------------------------------
127int JetPlayer::release()
128{
Steve Block3856b092011-10-20 11:56:00 +0100129 ALOGV("JetPlayer::release()");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800130 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//-------------------------------------------------------------------------------------------------
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800160int JetPlayer::render() {
161 EAS_RESULT result = EAS_FAILURE;
162 EAS_I32 count;
163 int temp;
164 bool audioStarted = false;
165
Steve Block3856b092011-10-20 11:56:00 +0100166 ALOGV("JetPlayer::render(): entering");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800167
168 // allocate render buffer
169 mAudioBuffer =
170 new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800171
172 // signal main thread that we started
173 {
174 Mutex::Autolock l(mMutex);
Glenn Kasten0512ab52011-05-04 17:58:57 -0700175 mTid = gettid();
Steve Block3856b092011-10-20 11:56:00 +0100176 ALOGV("JetPlayer::render(): render thread(%d) signal", mTid);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800177 mCondition.signal();
178 }
179
180 while (1) {
The Android Open Source Project1179bc92009-03-18 17:39:46 -0700181
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800182 mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
183
The Android Open Source Project1179bc92009-03-18 17:39:46 -0700184 if (mEasData == NULL) {
185 mMutex.unlock();
Steve Block3856b092011-10-20 11:56:00 +0100186 ALOGV("JetPlayer::render(): NULL EAS data, exiting render.");
The Android Open Source Project1179bc92009-03-18 17:39:46 -0700187 goto threadExit;
188 }
189
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800190 // nothing to render, wait for client thread to wake us up
191 while (!mRender)
192 {
Steve Block3856b092011-10-20 11:56:00 +0100193 ALOGV("JetPlayer::render(): signal wait");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800194 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);
Steve Block3856b092011-10-20 11:56:00 +0100200 ALOGV("JetPlayer::render(): signal rx'd");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800201 }
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) {
Steve Block29357bc2012-01-06 19:20:56 +0000209 ALOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800210 }
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
Steve Block3856b092011-10-20 11:56:00 +0100219 //ALOGV("JetPlayer::render(): updating state");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800220 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) {
Steve Block29357bc2012-01-06 19:20:56 +0000228 ALOGE("JetPlayer::render(): output AudioTrack was not created");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800229 goto threadExit;
230 }
231
232 // Write data to the audio hardware
Steve Block3856b092011-10-20 11:56:00 +0100233 //ALOGV("JetPlayer::render(): writing to audio output");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800234 if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000235 ALOGE("JetPlayer::render(): Error in writing:%d",temp);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800236 return temp;
237 }
238
239 // start audio output if necessary
240 if (!audioStarted) {
Steve Block3856b092011-10-20 11:56:00 +0100241 ALOGV("JetPlayer::render(): starting audio playback");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800242 mAudioTrack->start();
243 audioStarted = true;
244 }
245
246 }//while (1)
247
248threadExit:
The Android Open Source Project1179bc92009-03-18 17:39:46 -0700249 if (mAudioTrack) {
250 mAudioTrack->stop();
251 mAudioTrack->flush();
252 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800253 if (mAudioBuffer) {
254 delete [] mAudioBuffer;
255 mAudioBuffer = NULL;
256 }
257 mMutex.lock();
258 mTid = -1;
259 mCondition.signal();
260 mMutex.unlock();
261 return result;
262}
263
264
265//-------------------------------------------------------------------------------------------------
266// fire up an update if any of the status fields has changed
267// precondition: mMutex locked
268void JetPlayer::fireUpdateOnStatusChange()
269{
270 if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
271 ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
272 if(mEventCallback) {
273 mEventCallback(
274 JetPlayer::JET_USERID_UPDATE,
275 mJetStatus.currentUserID,
276 mJetStatus.segmentRepeatCount,
277 mJavaJetPlayerRef);
278 }
279 mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
280 mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
281 }
282
283 if(mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
284 if(mEventCallback) {
285 mEventCallback(
286 JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
287 mJetStatus.numQueuedSegments,
288 -1,
289 mJavaJetPlayerRef);
290 }
291 mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
292 }
293
294 if(mJetStatus.paused != mPreviousJetStatus.paused) {
295 if(mEventCallback) {
296 mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
297 mJetStatus.paused,
298 -1,
299 mJavaJetPlayerRef);
300 }
301 mPreviousJetStatus.paused = mJetStatus.paused;
302 }
303
304}
305
306
307//-------------------------------------------------------------------------------------------------
308// fire up all the JET events in the JET engine queue (until the queue is empty)
309// precondition: mMutex locked
310void JetPlayer::fireEventsFromJetQueue()
311{
312 if(!mEventCallback) {
313 // no callback, just empty the event queue
314 while (JET_GetEvent(mEasData, NULL, NULL)) { }
315 return;
316 }
317
318 EAS_U32 rawEvent;
319 while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
320 mEventCallback(
321 JetPlayer::JET_EVENT,
322 rawEvent,
323 -1,
324 mJavaJetPlayerRef);
325 }
326}
327
328
329//-------------------------------------------------------------------------------------------------
330int JetPlayer::loadFromFile(const char* path)
331{
Steve Block3856b092011-10-20 11:56:00 +0100332 ALOGV("JetPlayer::loadFromFile(): path=%s", path);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800333
334 Mutex::Autolock lock(mMutex);
335
336 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
Glenn Kasten0049acf2012-01-10 08:41:33 -0800337 strncpy(mJetFilePath, path, sizeof(mJetFilePath));
338 mJetFilePath[sizeof(mJetFilePath) - 1] = '\0';
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800339 mEasJetFileLoc->path = mJetFilePath;
340
341 mEasJetFileLoc->fd = 0;
342 mEasJetFileLoc->length = 0;
343 mEasJetFileLoc->offset = 0;
344
345 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
346 if(result != EAS_SUCCESS)
347 mState = EAS_STATE_ERROR;
348 else
349 mState = EAS_STATE_OPEN;
350 return( result );
351}
352
353
354//-------------------------------------------------------------------------------------------------
355int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
356{
Steve Block3856b092011-10-20 11:56:00 +0100357 ALOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800358
359 Mutex::Autolock lock(mMutex);
360
361 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
362 mEasJetFileLoc->fd = fd;
363 mEasJetFileLoc->offset = offset;
364 mEasJetFileLoc->length = length;
365 mEasJetFileLoc->path = NULL;
366
367 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
368 if(result != EAS_SUCCESS)
369 mState = EAS_STATE_ERROR;
370 else
371 mState = EAS_STATE_OPEN;
372 return( result );
373}
374
375
376//-------------------------------------------------------------------------------------------------
377int JetPlayer::closeFile()
378{
379 Mutex::Autolock lock(mMutex);
380 return JET_CloseFile(mEasData);
381}
382
383
384//-------------------------------------------------------------------------------------------------
385int JetPlayer::play()
386{
Steve Block3856b092011-10-20 11:56:00 +0100387 ALOGV("JetPlayer::play(): entering");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800388 Mutex::Autolock lock(mMutex);
389
390 EAS_RESULT result = JET_Play(mEasData);
391
392 mPaused = false;
393 mRender = true;
394
395 JET_Status(mEasData, &mJetStatus);
396 this->dumpJetStatus(&mJetStatus);
397
398 fireUpdateOnStatusChange();
399
400 // wake up render thread
Steve Block3856b092011-10-20 11:56:00 +0100401 ALOGV("JetPlayer::play(): wakeup render thread");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800402 mCondition.signal();
403
404 return result;
405}
406
407//-------------------------------------------------------------------------------------------------
408int JetPlayer::pause()
409{
410 Mutex::Autolock lock(mMutex);
411 mPaused = true;
412 EAS_RESULT result = JET_Pause(mEasData);
413
414 mRender = false;
415
416 JET_Status(mEasData, &mJetStatus);
417 this->dumpJetStatus(&mJetStatus);
418 fireUpdateOnStatusChange();
419
420
421 return result;
422}
423
424
425//-------------------------------------------------------------------------------------------------
426int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
427 EAS_U32 muteFlags, EAS_U8 userID)
428{
Steve Block3856b092011-10-20 11:56:00 +0100429 ALOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800430 segmentNum, libNum, repeatCount, transpose);
431 Mutex::Autolock lock(mMutex);
432 return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
433}
434
435//-------------------------------------------------------------------------------------------------
436int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
437{
438 Mutex::Autolock lock(mMutex);
439 return JET_SetMuteFlags(mEasData, muteFlags, sync);
440}
441
442//-------------------------------------------------------------------------------------------------
443int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
444{
445 Mutex::Autolock lock(mMutex);
446 return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
447}
448
449//-------------------------------------------------------------------------------------------------
450int JetPlayer::triggerClip(int clipId)
451{
Steve Block3856b092011-10-20 11:56:00 +0100452 ALOGV("JetPlayer::triggerClip clipId=%d", clipId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800453 Mutex::Autolock lock(mMutex);
454 return JET_TriggerClip(mEasData, clipId);
455}
456
457//-------------------------------------------------------------------------------------------------
458int JetPlayer::clearQueue()
459{
Steve Block3856b092011-10-20 11:56:00 +0100460 ALOGV("JetPlayer::clearQueue");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800461 Mutex::Autolock lock(mMutex);
462 return JET_Clear_Queue(mEasData);
463}
464
465//-------------------------------------------------------------------------------------------------
466void JetPlayer::dump()
467{
Steve Block29357bc2012-01-06 19:20:56 +0000468 ALOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800469}
470
471void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
472{
473 if(pJetStatus!=NULL)
Steve Block3856b092011-10-20 11:56:00 +0100474 ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d",
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800475 pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
476 pJetStatus->numQueuedSegments, pJetStatus->paused);
477 else
Steve Block29357bc2012-01-06 19:20:56 +0000478 ALOGE(">> JET player status is NULL");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800479}
480
481
482} // end namespace android
483