blob: 271be0cdfba0166b9f02718f9854bc710ea0e582 [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>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080021#include <media/JetPlayer.h>
22
23
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080024namespace android
25{
26
27static const int MIX_NUM_BUFFERS = 4;
28static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
29
30//-------------------------------------------------------------------------------------------------
Eric Laurent2e66a782012-03-26 10:47:22 -070031JetPlayer::JetPlayer(void *javaJetPlayer, int maxTracks, int trackBufferSize) :
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080032 mEventCallback(NULL),
33 mJavaJetPlayerRef(javaJetPlayer),
34 mTid(-1),
35 mRender(false),
36 mPaused(false),
37 mMaxTracks(maxTracks),
38 mEasData(NULL),
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080039 mTrackBufferSize(trackBufferSize)
40{
Steve Block3856b092011-10-20 11:56:00 +010041 ALOGV("JetPlayer constructor");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080042 mPreviousJetStatus.currentUserID = -1;
43 mPreviousJetStatus.segmentRepeatCount = -1;
44 mPreviousJetStatus.numQueuedSegments = -1;
45 mPreviousJetStatus.paused = true;
46}
47
48//-------------------------------------------------------------------------------------------------
49JetPlayer::~JetPlayer()
50{
Steve Block3856b092011-10-20 11:56:00 +010051 ALOGV("~JetPlayer");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080052 release();
53
54}
55
56//-------------------------------------------------------------------------------------------------
57int JetPlayer::init()
58{
59 //Mutex::Autolock lock(&mMutex);
60
61 EAS_RESULT result;
62
63 // retrieve the EAS library settings
64 if (pLibConfig == NULL)
65 pLibConfig = EAS_Config();
66 if (pLibConfig == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +000067 ALOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting.");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080068 return EAS_FAILURE;
69 }
70
71 // init the EAS library
72 result = EAS_Init(&mEasData);
Glenn Kastene53b9ea2012-03-12 16:29:55 -070073 if (result != EAS_SUCCESS) {
Steve Block29357bc2012-01-06 19:20:56 +000074 ALOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting.");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080075 mState = EAS_STATE_ERROR;
76 return result;
77 }
78 // init the JET library with the default app event controller range
79 result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG));
Glenn Kastene53b9ea2012-03-12 16:29:55 -070080 if (result != EAS_SUCCESS) {
Steve Block29357bc2012-01-06 19:20:56 +000081 ALOGE("JetPlayer::init(): Error initializing JET library, aborting.");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080082 mState = EAS_STATE_ERROR;
83 return result;
84 }
85
86 // create the output AudioTrack
87 mAudioTrack = new AudioTrack();
Glenn Kasten17a736c2012-02-14 08:52:15 -080088 mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parameterize this
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080089 pLibConfig->sampleRate,
Glenn Kastene1c39622012-01-04 09:36:37 -080090 AUDIO_FORMAT_PCM_16_BIT,
Glenn Kastenab334fd2012-03-14 12:56:06 -070091 audio_channel_out_mask_from_count(pLibConfig->numChannels),
Glenn Kastenbce50bf2014-02-27 15:29:51 -080092 (size_t) mTrackBufferSize,
Eric Laurent0ca3cf92012-04-18 09:24:29 -070093 AUDIO_OUTPUT_FLAG_NONE);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080094
95 // create render and playback thread
96 {
97 Mutex::Autolock l(mMutex);
Steve Block3856b092011-10-20 11:56:00 +010098 ALOGV("JetPlayer::init(): trying to start render thread");
Glenn Kastena23856c2011-06-23 16:43:24 -070099 mThread = new JetPlayerThread(this);
100 mThread->run("jetRenderThread", ANDROID_PRIORITY_AUDIO);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800101 mCondition.wait(mMutex);
102 }
103 if (mTid > 0) {
104 // render thread started, we're ready
Steve Block3856b092011-10-20 11:56:00 +0100105 ALOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800106 mState = EAS_STATE_READY;
107 } else {
Steve Block29357bc2012-01-06 19:20:56 +0000108 ALOGE("JetPlayer::init(): failed to start render thread.");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800109 mState = EAS_STATE_ERROR;
110 return EAS_FAILURE;
111 }
112
113 return EAS_SUCCESS;
114}
115
116void JetPlayer::setEventCallback(jetevent_callback eventCallback)
117{
118 Mutex::Autolock l(mMutex);
119 mEventCallback = eventCallback;
120}
121
122//-------------------------------------------------------------------------------------------------
123int JetPlayer::release()
124{
Steve Block3856b092011-10-20 11:56:00 +0100125 ALOGV("JetPlayer::release()");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800126 Mutex::Autolock lock(mMutex);
127 mPaused = true;
128 mRender = false;
129 if (mEasData) {
130 JET_Pause(mEasData);
131 JET_CloseFile(mEasData);
132 JET_Shutdown(mEasData);
133 EAS_Shutdown(mEasData);
134 }
Marco Nelissen08b9e2d2014-12-16 12:46:34 -0800135 mIoWrapper.clear();
Glenn Kasten2799d742013-05-30 14:33:29 -0700136 if (mAudioTrack != 0) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800137 mAudioTrack->stop();
138 mAudioTrack->flush();
Glenn Kasten2799d742013-05-30 14:33:29 -0700139 mAudioTrack.clear();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800140 }
141 if (mAudioBuffer) {
142 delete mAudioBuffer;
143 mAudioBuffer = NULL;
144 }
145 mEasData = NULL;
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700146
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800147 return EAS_SUCCESS;
148}
149
150
151//-------------------------------------------------------------------------------------------------
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800152int JetPlayer::render() {
153 EAS_RESULT result = EAS_FAILURE;
154 EAS_I32 count;
155 int temp;
156 bool audioStarted = false;
157
Steve Block3856b092011-10-20 11:56:00 +0100158 ALOGV("JetPlayer::render(): entering");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800159
160 // allocate render buffer
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700161 mAudioBuffer =
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800162 new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800163
164 // signal main thread that we started
165 {
166 Mutex::Autolock l(mMutex);
Glenn Kasten0512ab52011-05-04 17:58:57 -0700167 mTid = gettid();
Steve Block3856b092011-10-20 11:56:00 +0100168 ALOGV("JetPlayer::render(): render thread(%d) signal", mTid);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800169 mCondition.signal();
170 }
171
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700172 while (1) {
173
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800174 mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
175
The Android Open Source Project1179bc92009-03-18 17:39:46 -0700176 if (mEasData == NULL) {
177 mMutex.unlock();
Steve Block3856b092011-10-20 11:56:00 +0100178 ALOGV("JetPlayer::render(): NULL EAS data, exiting render.");
The Android Open Source Project1179bc92009-03-18 17:39:46 -0700179 goto threadExit;
180 }
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700181
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800182 // nothing to render, wait for client thread to wake us up
183 while (!mRender)
184 {
Steve Block3856b092011-10-20 11:56:00 +0100185 ALOGV("JetPlayer::render(): signal wait");
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700186 if (audioStarted) {
187 mAudioTrack->pause();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800188 // we have to restart the playback once we start rendering again
189 audioStarted = false;
190 }
191 mCondition.wait(mMutex);
Steve Block3856b092011-10-20 11:56:00 +0100192 ALOGV("JetPlayer::render(): signal rx'd");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800193 }
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700194
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800195 // render midi data into the input buffer
196 int num_output = 0;
197 EAS_PCM* p = mAudioBuffer;
198 for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
199 result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
200 if (result != EAS_SUCCESS) {
Steve Block29357bc2012-01-06 19:20:56 +0000201 ALOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800202 }
203 p += count * pLibConfig->numChannels;
204 num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700205
206 // send events that were generated (if any) to the event callback
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800207 fireEventsFromJetQueue();
208 }
209
210 // update playback state
Steve Block3856b092011-10-20 11:56:00 +0100211 //ALOGV("JetPlayer::render(): updating state");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800212 JET_Status(mEasData, &mJetStatus);
213 fireUpdateOnStatusChange();
214 mPaused = mJetStatus.paused;
215
216 mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
217
218 // check audio output track
219 if (mAudioTrack == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +0000220 ALOGE("JetPlayer::render(): output AudioTrack was not created");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800221 goto threadExit;
222 }
223
224 // Write data to the audio hardware
Steve Block3856b092011-10-20 11:56:00 +0100225 //ALOGV("JetPlayer::render(): writing to audio output");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800226 if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000227 ALOGE("JetPlayer::render(): Error in writing:%d",temp);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800228 return temp;
229 }
230
231 // start audio output if necessary
232 if (!audioStarted) {
Steve Block3856b092011-10-20 11:56:00 +0100233 ALOGV("JetPlayer::render(): starting audio playback");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800234 mAudioTrack->start();
235 audioStarted = true;
236 }
237
238 }//while (1)
239
240threadExit:
Glenn Kasten9d1f02d2012-02-08 17:47:58 -0800241 if (mAudioTrack != NULL) {
The Android Open Source Project1179bc92009-03-18 17:39:46 -0700242 mAudioTrack->stop();
243 mAudioTrack->flush();
244 }
Glenn Kasten9d1f02d2012-02-08 17:47:58 -0800245 delete [] mAudioBuffer;
246 mAudioBuffer = NULL;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800247 mMutex.lock();
248 mTid = -1;
249 mCondition.signal();
250 mMutex.unlock();
251 return result;
252}
253
254
255//-------------------------------------------------------------------------------------------------
256// fire up an update if any of the status fields has changed
257// precondition: mMutex locked
258void JetPlayer::fireUpdateOnStatusChange()
259{
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700260 if ( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800261 ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700262 if (mEventCallback) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800263 mEventCallback(
264 JetPlayer::JET_USERID_UPDATE,
265 mJetStatus.currentUserID,
266 mJetStatus.segmentRepeatCount,
267 mJavaJetPlayerRef);
268 }
269 mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
270 mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
271 }
272
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700273 if (mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
274 if (mEventCallback) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800275 mEventCallback(
276 JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
277 mJetStatus.numQueuedSegments,
278 -1,
279 mJavaJetPlayerRef);
280 }
281 mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
282 }
283
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700284 if (mJetStatus.paused != mPreviousJetStatus.paused) {
285 if (mEventCallback) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800286 mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
287 mJetStatus.paused,
288 -1,
289 mJavaJetPlayerRef);
290 }
291 mPreviousJetStatus.paused = mJetStatus.paused;
292 }
293
294}
295
296
297//-------------------------------------------------------------------------------------------------
298// fire up all the JET events in the JET engine queue (until the queue is empty)
299// precondition: mMutex locked
300void JetPlayer::fireEventsFromJetQueue()
301{
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700302 if (!mEventCallback) {
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800303 // no callback, just empty the event queue
304 while (JET_GetEvent(mEasData, NULL, NULL)) { }
305 return;
306 }
307
308 EAS_U32 rawEvent;
309 while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
310 mEventCallback(
311 JetPlayer::JET_EVENT,
312 rawEvent,
313 -1,
314 mJavaJetPlayerRef);
315 }
316}
317
318
319//-------------------------------------------------------------------------------------------------
320int JetPlayer::loadFromFile(const char* path)
321{
Steve Block3856b092011-10-20 11:56:00 +0100322 ALOGV("JetPlayer::loadFromFile(): path=%s", path);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800323
324 Mutex::Autolock lock(mMutex);
325
Marco Nelissen08b9e2d2014-12-16 12:46:34 -0800326 mIoWrapper = new MidiIoWrapper(path);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800327
Marco Nelissen08b9e2d2014-12-16 12:46:34 -0800328 EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700329 if (result != EAS_SUCCESS)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800330 mState = EAS_STATE_ERROR;
331 else
332 mState = EAS_STATE_OPEN;
333 return( result );
334}
335
336
337//-------------------------------------------------------------------------------------------------
338int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
339{
Steve Block3856b092011-10-20 11:56:00 +0100340 ALOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700341
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800342 Mutex::Autolock lock(mMutex);
343
Marco Nelissen08b9e2d2014-12-16 12:46:34 -0800344 mIoWrapper = new MidiIoWrapper(fd, offset, length);
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700345
Marco Nelissen08b9e2d2014-12-16 12:46:34 -0800346 EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700347 if (result != EAS_SUCCESS)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800348 mState = EAS_STATE_ERROR;
349 else
350 mState = EAS_STATE_OPEN;
351 return( result );
352}
353
354
355//-------------------------------------------------------------------------------------------------
356int JetPlayer::closeFile()
357{
358 Mutex::Autolock lock(mMutex);
359 return JET_CloseFile(mEasData);
360}
361
362
363//-------------------------------------------------------------------------------------------------
364int JetPlayer::play()
365{
Steve Block3856b092011-10-20 11:56:00 +0100366 ALOGV("JetPlayer::play(): entering");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800367 Mutex::Autolock lock(mMutex);
368
369 EAS_RESULT result = JET_Play(mEasData);
370
371 mPaused = false;
372 mRender = true;
373
374 JET_Status(mEasData, &mJetStatus);
375 this->dumpJetStatus(&mJetStatus);
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700376
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800377 fireUpdateOnStatusChange();
378
379 // wake up render thread
Steve Block3856b092011-10-20 11:56:00 +0100380 ALOGV("JetPlayer::play(): wakeup render thread");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800381 mCondition.signal();
382
383 return result;
384}
385
386//-------------------------------------------------------------------------------------------------
387int JetPlayer::pause()
388{
389 Mutex::Autolock lock(mMutex);
390 mPaused = true;
391 EAS_RESULT result = JET_Pause(mEasData);
392
393 mRender = false;
394
395 JET_Status(mEasData, &mJetStatus);
396 this->dumpJetStatus(&mJetStatus);
397 fireUpdateOnStatusChange();
398
399
400 return result;
401}
402
403
404//-------------------------------------------------------------------------------------------------
405int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
406 EAS_U32 muteFlags, EAS_U8 userID)
407{
Steve Block3856b092011-10-20 11:56:00 +0100408 ALOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800409 segmentNum, libNum, repeatCount, transpose);
410 Mutex::Autolock lock(mMutex);
Glenn Kastenb187de12014-12-30 08:18:15 -0800411 return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags,
412 userID);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800413}
414
415//-------------------------------------------------------------------------------------------------
416int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
417{
418 Mutex::Autolock lock(mMutex);
419 return JET_SetMuteFlags(mEasData, muteFlags, sync);
420}
421
422//-------------------------------------------------------------------------------------------------
423int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
424{
425 Mutex::Autolock lock(mMutex);
426 return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
427}
428
429//-------------------------------------------------------------------------------------------------
430int JetPlayer::triggerClip(int clipId)
431{
Steve Block3856b092011-10-20 11:56:00 +0100432 ALOGV("JetPlayer::triggerClip clipId=%d", clipId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800433 Mutex::Autolock lock(mMutex);
434 return JET_TriggerClip(mEasData, clipId);
435}
436
437//-------------------------------------------------------------------------------------------------
438int JetPlayer::clearQueue()
439{
Steve Block3856b092011-10-20 11:56:00 +0100440 ALOGV("JetPlayer::clearQueue");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800441 Mutex::Autolock lock(mMutex);
442 return JET_Clear_Queue(mEasData);
443}
444
445//-------------------------------------------------------------------------------------------------
446void JetPlayer::dump()
447{
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800448}
449
450void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
451{
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700452 if (pJetStatus!=NULL)
Glenn Kastenb187de12014-12-30 08:18:15 -0800453 ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d "
454 "paused=%d",
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800455 pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
456 pJetStatus->numQueuedSegments, pJetStatus->paused);
457 else
Steve Block29357bc2012-01-06 19:20:56 +0000458 ALOGE(">> JET player status is NULL");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800459}
460
461
462} // end namespace android