blob: f0edf887d64334a7e9bff55e121f02990700a405 [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 }
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);
217 }
218
219 // update playback state
220 //LOGV("JetPlayer::render(): updating state");
221 JET_Status(mEasData, &mJetStatus);
222 fireEventOnStatusChange();
223 mPaused = mJetStatus.paused;
224
225 mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
226
227 // check audio output track
228 if (mAudioTrack == NULL) {
229 LOGE("JetPlayer::render(): output AudioTrack was not created");
230 goto threadExit;
231 }
232
233 // Write data to the audio hardware
234 //LOGV("JetPlayer::render(): writing to audio output");
235 if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
236 LOGE("JetPlayer::render(): Error in writing:%d",temp);
237 return temp;
238 }
239
240 // start audio output if necessary
241 if (!audioStarted) {
242 LOGV("JetPlayer::render(): starting audio playback");
243 mAudioTrack->start();
244 audioStarted = true;
245 }
246
247 }//while (1)
248
249threadExit:
250 mAudioTrack->flush();
251 if (mAudioBuffer) {
252 delete [] mAudioBuffer;
253 mAudioBuffer = NULL;
254 }
255 mMutex.lock();
256 mTid = -1;
257 mCondition.signal();
258 mMutex.unlock();
259 return result;
260}
261
262
263//-------------------------------------------------------------------------------------------------
264// fire up an event if any of the status fields has changed
265// precondition: mMutex locked
266void JetPlayer::fireEventOnStatusChange()
267{
268 if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
269 ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
270 if(mEventCallback) {
271 mEventCallback(
272 JetPlayer::JET_USERID_UPDATE,
273 mJetStatus.currentUserID,
274 mJetStatus.segmentRepeatCount,
275 mJavaJetPlayerRef);
276 }
277 mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
278 mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
279 }
280
281 if(mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
282 if(mEventCallback) {
283 mEventCallback(
284 JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
285 mJetStatus.numQueuedSegments,
286 -1,
287 mJavaJetPlayerRef);
288 }
289 mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
290 }
291
292 if(mJetStatus.paused != mPreviousJetStatus.paused) {
293 if(mEventCallback) {
294 mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
295 mJetStatus.paused,
296 -1,
297 mJavaJetPlayerRef);
298 }
299 mPreviousJetStatus.paused = mJetStatus.paused;
300 }
301
302}
303
304
305//-------------------------------------------------------------------------------------------------
306int JetPlayer::openFile(const char* path)
307{
308 LOGV("JetPlayer::openFile(): path=%s", path);
309
310 Mutex::Autolock lock(mMutex);
311
312 mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
313 memset(mJetFilePath, 0, 256);
314 strncpy(mJetFilePath, path, strlen(path));
315 mEasJetFileLoc->path = mJetFilePath;
316
317 mEasJetFileLoc->fd = 0;
318 mEasJetFileLoc->length = 0;
319 mEasJetFileLoc->offset = 0;
320
321 EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
322 if(result != EAS_SUCCESS)
323 mState = EAS_STATE_ERROR;
324 else
325 mState = EAS_STATE_OPEN;
326 return( result );
327}
328
329//-------------------------------------------------------------------------------------------------
330int JetPlayer::closeFile()
331{
332 Mutex::Autolock lock(mMutex);
333 return JET_CloseFile(mEasData);
334}
335
336
337//-------------------------------------------------------------------------------------------------
338int JetPlayer::play()
339{
340 LOGV("JetPlayer::play(): entering");
341 Mutex::Autolock lock(mMutex);
342
343 EAS_RESULT result = JET_Play(mEasData);
344
345 mPaused = false;
346 mRender = true;
347
348 JET_Status(mEasData, &mJetStatus);
349 this->dumpJetStatus(&mJetStatus);
350
351 fireEventOnStatusChange();
352
353 // wake up render thread
354 LOGV("JetPlayer::play(): wakeup render thread");
355 mCondition.signal();
356
357 return result;
358}
359
360//-------------------------------------------------------------------------------------------------
361int JetPlayer::pause()
362{
363 Mutex::Autolock lock(mMutex);
364 mPaused = true;
365 EAS_RESULT result = JET_Pause(mEasData);
366
367 mRender = false;
368
369 JET_Status(mEasData, &mJetStatus);
370 this->dumpJetStatus(&mJetStatus);
371 fireEventOnStatusChange();
372
373
374 return result;
375}
376
377
378//-------------------------------------------------------------------------------------------------
379int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
380 EAS_U32 muteFlags, EAS_U8 userID)
381{
382 LOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
383 segmentNum, libNum, repeatCount, transpose);
384 Mutex::Autolock lock(mMutex);
385 return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
386}
387
388//-------------------------------------------------------------------------------------------------
389int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
390{
391 Mutex::Autolock lock(mMutex);
392 return JET_SetMuteFlags(mEasData, muteFlags, sync);
393}
394
395//-------------------------------------------------------------------------------------------------
396int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
397{
398 Mutex::Autolock lock(mMutex);
399 return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
400}
401
402//-------------------------------------------------------------------------------------------------
403int JetPlayer::triggerClip(int clipId)
404{
405 LOGV("JetPlayer::triggerClip clipId=%d", clipId);
406 Mutex::Autolock lock(mMutex);
407 return JET_TriggerClip(mEasData, clipId);
408}
409
410//-------------------------------------------------------------------------------------------------
411void JetPlayer::dump()
412{
413 LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path);
414}
415
416void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
417{
418 if(pJetStatus!=NULL)
419 LOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d",
420 pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
421 pJetStatus->numQueuedSegments, pJetStatus->paused);
422 else
423 LOGE(">> JET player status is NULL");
424}
425
426
427} // end namespace android
428