blob: 7f0ef217f2b185d64a926b8b5c40a673d4c86413 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2** Copyright 2007, 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 "VorbisPlayer"
19#include "utils/Log.h"
20
21#include <stdio.h>
22#include <assert.h>
23#include <limits.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <sched.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29
30
31#include "VorbisPlayer.h"
32
33#ifdef HAVE_GETTID
34static pid_t myTid() { return gettid(); }
35#else
36static pid_t myTid() { return getpid(); }
37#endif
38
39// ----------------------------------------------------------------------------
40
41namespace android {
42
43// ----------------------------------------------------------------------------
44
45// TODO: Determine appropriate return codes
46static status_t ERROR_NOT_OPEN = -1;
47static status_t ERROR_OPEN_FAILED = -2;
48static status_t ERROR_ALLOCATE_FAILED = -4;
49static status_t ERROR_NOT_SUPPORTED = -8;
50static status_t ERROR_NOT_READY = -16;
51static status_t STATE_INIT = 0;
52static status_t STATE_ERROR = 1;
53static status_t STATE_OPEN = 2;
54
55
56VorbisPlayer::VorbisPlayer() :
57 mAudioBuffer(NULL), mPlayTime(-1), mDuration(-1), mState(STATE_ERROR),
58 mStreamType(AudioSystem::MUSIC), mLoop(false), mAndroidLoop(false),
59 mExit(false), mPaused(false), mRender(false), mRenderTid(-1)
60{
61 LOGV("constructor\n");
62 memset(&mVorbisFile, 0, sizeof mVorbisFile);
63}
64
65void VorbisPlayer::onFirstRef()
66{
67 LOGV("onFirstRef");
68 // create playback thread
69 Mutex::Autolock l(mMutex);
Dave Sparks0e051b12009-04-29 12:42:28 -070070 createThreadEtc(renderThread, this, "vorbis decoder", ANDROID_PRIORITY_AUDIO);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 mCondition.wait(mMutex);
72 if (mRenderTid > 0) {
73 LOGV("render thread(%d) started", mRenderTid);
74 mState = STATE_INIT;
75 }
76}
77
78status_t VorbisPlayer::initCheck()
79{
80 if (mState != STATE_ERROR) return NO_ERROR;
81 return ERROR_NOT_READY;
82}
83
84VorbisPlayer::~VorbisPlayer() {
85 LOGV("VorbisPlayer destructor\n");
86 release();
87}
88
89status_t VorbisPlayer::setDataSource(const char* path)
90{
91 return setdatasource(path, -1, 0, 0x7ffffffffffffffLL); // intentionally less than LONG_MAX
92}
93
94status_t VorbisPlayer::setDataSource(int fd, int64_t offset, int64_t length)
95{
96 return setdatasource(NULL, fd, offset, length);
97}
98
99size_t VorbisPlayer::vp_fread(void *buf, size_t size, size_t nmemb, void *me) {
100 VorbisPlayer *self = (VorbisPlayer*) me;
101
102 long curpos = vp_ftell(me);
103 while (nmemb != 0 && (curpos + size * nmemb) > self->mLength) {
104 nmemb--;
105 }
106 return fread(buf, size, nmemb, self->mFile);
107}
108
109int VorbisPlayer::vp_fseek(void *me, ogg_int64_t off, int whence) {
110 VorbisPlayer *self = (VorbisPlayer*) me;
111 if (whence == SEEK_SET)
112 return fseek(self->mFile, off + self->mOffset, whence);
113 else if (whence == SEEK_CUR)
114 return fseek(self->mFile, off, whence);
115 else if (whence == SEEK_END)
116 return fseek(self->mFile, self->mOffset + self->mLength + off, SEEK_SET);
117 return -1;
118}
119
120int VorbisPlayer::vp_fclose(void *me) {
121 LOGV("vp_fclose");
122 VorbisPlayer *self = (VorbisPlayer*) me;
123 int ret = fclose (self->mFile);
124 self->mFile = NULL;
125 return ret;
126}
127
128long VorbisPlayer::vp_ftell(void *me) {
129 VorbisPlayer *self = (VorbisPlayer*) me;
130 return ftell(self->mFile) - self->mOffset;
131}
132
133status_t VorbisPlayer::setdatasource(const char *path, int fd, int64_t offset, int64_t length)
134{
135 LOGV("setDataSource url=%s, fd=%d\n", path, fd);
136
137 // file still open?
138 Mutex::Autolock l(mMutex);
139 if (mState == STATE_OPEN) {
140 reset_nosync();
141 }
142
143 // open file and set paused state
144 if (path) {
145 mFile = fopen(path, "r");
146 } else {
147 mFile = fdopen(dup(fd), "r");
148 }
149 if (mFile == NULL) {
150 return ERROR_OPEN_FAILED;
151 }
152
153 struct stat sb;
154 int ret;
155 if (path) {
156 ret = stat(path, &sb);
157 } else {
158 ret = fstat(fd, &sb);
159 }
160 if (ret != 0) {
161 mState = STATE_ERROR;
162 fclose(mFile);
163 return ERROR_OPEN_FAILED;
164 }
165 if (sb.st_size > (length + offset)) {
166 mLength = length;
167 } else {
168 mLength = sb.st_size - offset;
169 }
170
171 ov_callbacks callbacks = {
172 (size_t (*)(void *, size_t, size_t, void *)) vp_fread,
173 (int (*)(void *, ogg_int64_t, int)) vp_fseek,
174 (int (*)(void *)) vp_fclose,
175 (long (*)(void *)) vp_ftell
176 };
177
178 mOffset = offset;
179 fseek(mFile, offset, SEEK_SET);
180
181 int result = ov_open_callbacks(this, &mVorbisFile, NULL, 0, callbacks);
182 if (result < 0) {
183 LOGE("ov_open() failed: [%d]\n", (int)result);
184 mState = STATE_ERROR;
185 fclose(mFile);
186 return ERROR_OPEN_FAILED;
187 }
188
189 // look for the android loop tag (for ringtones)
190 char **ptr = ov_comment(&mVorbisFile,-1)->user_comments;
191 while(*ptr) {
192 // does the comment start with ANDROID_LOOP_TAG
193 if(strncmp(*ptr, ANDROID_LOOP_TAG, strlen(ANDROID_LOOP_TAG)) == 0) {
194 // read the value of the tag
195 char *val = *ptr + strlen(ANDROID_LOOP_TAG) + 1;
196 mAndroidLoop = (strncmp(val, "true", 4) == 0);
197 }
198 // we keep parsing even after finding one occurence of ANDROID_LOOP_TAG,
199 // as we could find another one (the tag might have been appended more than once).
200 ++ptr;
201 }
202 LOGV_IF(mAndroidLoop, "looped sound");
203
204 mState = STATE_OPEN;
205 return NO_ERROR;
206}
207
208status_t VorbisPlayer::prepare()
209{
210 LOGV("prepare\n");
211 if (mState != STATE_OPEN ) {
212 return ERROR_NOT_OPEN;
213 }
214 return NO_ERROR;
215}
216
217status_t VorbisPlayer::prepareAsync() {
218 LOGV("prepareAsync\n");
219 // can't hold the lock here because of the callback
220 // it's safe because we don't change state
221 if (mState != STATE_OPEN ) {
222 sendEvent(MEDIA_ERROR);
223 return NO_ERROR;
224 }
225 sendEvent(MEDIA_PREPARED);
226 return NO_ERROR;
227}
228
229status_t VorbisPlayer::start()
230{
231 LOGV("start\n");
232 Mutex::Autolock l(mMutex);
233 if (mState != STATE_OPEN) {
234 return ERROR_NOT_OPEN;
235 }
236
237 mPaused = false;
238 mRender = true;
239
240 // wake up render thread
241 LOGV(" wakeup render thread\n");
242 mCondition.signal();
243 return NO_ERROR;
244}
245
246status_t VorbisPlayer::stop()
247{
248 LOGV("stop\n");
249 Mutex::Autolock l(mMutex);
250 if (mState != STATE_OPEN) {
251 return ERROR_NOT_OPEN;
252 }
253 mPaused = true;
254 mRender = false;
255 return NO_ERROR;
256}
257
258status_t VorbisPlayer::seekTo(int position)
259{
260 LOGV("seekTo %d\n", position);
261 Mutex::Autolock l(mMutex);
262 if (mState != STATE_OPEN) {
263 return ERROR_NOT_OPEN;
264 }
265
266 int result = ov_time_seek(&mVorbisFile, position);
267 if (result != 0) {
268 LOGE("ov_time_seek() returned %d\n", result);
269 return result;
270 }
271 sendEvent(MEDIA_SEEK_COMPLETE);
272 return NO_ERROR;
273}
274
275status_t VorbisPlayer::pause()
276{
277 LOGV("pause\n");
278 Mutex::Autolock l(mMutex);
279 if (mState != STATE_OPEN) {
280 return ERROR_NOT_OPEN;
281 }
282 mPaused = true;
283 return NO_ERROR;
284}
285
286bool VorbisPlayer::isPlaying()
287{
288 LOGV("isPlaying\n");
289 if (mState == STATE_OPEN) {
290 return mRender;
291 }
292 return false;
293}
294
295status_t VorbisPlayer::getCurrentPosition(int* position)
296{
297 LOGV("getCurrentPosition\n");
298 Mutex::Autolock l(mMutex);
299 if (mState != STATE_OPEN) {
300 LOGE("getCurrentPosition(): file not open");
301 return ERROR_NOT_OPEN;
302 }
303 *position = ov_time_tell(&mVorbisFile);
304 if (*position < 0) {
305 LOGE("getCurrentPosition(): ov_time_tell returned %d", *position);
306 return *position;
307 }
308 return NO_ERROR;
309}
310
311status_t VorbisPlayer::getDuration(int* duration)
312{
313 LOGV("getDuration\n");
314 Mutex::Autolock l(mMutex);
315 if (mState != STATE_OPEN) {
316 return ERROR_NOT_OPEN;
317 }
318
319 int ret = ov_time_total(&mVorbisFile, -1);
320 if (ret == OV_EINVAL) {
321 return -1;
322 }
323
324 *duration = ret;
325 return NO_ERROR;
326}
327
328status_t VorbisPlayer::release()
329{
330 LOGV("release\n");
331 Mutex::Autolock l(mMutex);
332 reset_nosync();
333
334 // TODO: timeout when thread won't exit
335 // wait for render thread to exit
336 if (mRenderTid > 0) {
337 mExit = true;
338 mCondition.signal();
339 mCondition.wait(mMutex);
340 }
341 return NO_ERROR;
342}
343
344status_t VorbisPlayer::reset()
345{
346 LOGV("reset\n");
347 Mutex::Autolock l(mMutex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 return reset_nosync();
349}
350
351// always call with lock held
352status_t VorbisPlayer::reset_nosync()
353{
354 // close file
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 if (mFile != NULL) {
Dave Sparks97881192009-06-26 17:24:22 -0700356 ov_clear(&mVorbisFile); // this also closes the FILE
357 if (mFile != NULL) {
358 LOGV("OOPS! Vorbis didn't close the file");
359 fclose(mFile);
360 mFile = NULL;
361 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 }
363 mState = STATE_ERROR;
364
365 mPlayTime = -1;
366 mDuration = -1;
367 mLoop = false;
368 mAndroidLoop = false;
369 mPaused = false;
370 mRender = false;
371 return NO_ERROR;
372}
373
374status_t VorbisPlayer::setLooping(int loop)
375{
376 LOGV("setLooping\n");
377 Mutex::Autolock l(mMutex);
378 mLoop = (loop != 0);
379 return NO_ERROR;
380}
381
382status_t VorbisPlayer::createOutputTrack() {
383 // open audio track
384 vorbis_info *vi = ov_info(&mVorbisFile, -1);
385
386 LOGV("Create AudioTrack object: rate=%ld, channels=%d\n",
387 vi->rate, vi->channels);
388 if (mAudioSink->open(vi->rate, vi->channels, AudioSystem::PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT) != NO_ERROR) {
389 LOGE("mAudioSink open failed");
390 return ERROR_OPEN_FAILED;
391 }
392 return NO_ERROR;
393}
394
395int VorbisPlayer::renderThread(void* p) {
396 return ((VorbisPlayer*)p)->render();
397}
398
399#define AUDIOBUFFER_SIZE 4096
400
401int VorbisPlayer::render() {
402 int result = -1;
403 int temp;
404 int current_section = 0;
405 bool audioStarted = false;
406
407 LOGV("render\n");
408
409 // allocate render buffer
410 mAudioBuffer = new char[AUDIOBUFFER_SIZE];
411 if (!mAudioBuffer) {
412 LOGE("mAudioBuffer allocate failed\n");
413 goto threadExit;
414 }
415
416 // let main thread know we're ready
417 {
418 Mutex::Autolock l(mMutex);
419 mRenderTid = myTid();
420 mCondition.signal();
421 }
422
423 while (1) {
424 long numread = 0;
425 {
426 Mutex::Autolock l(mMutex);
427
428 // pausing?
429 if (mPaused) {
430 if (mAudioSink->ready()) mAudioSink->pause();
431 mRender = false;
432 audioStarted = false;
433 }
434
435 // nothing to render, wait for client thread to wake us up
436 if (!mExit && !mRender) {
437 LOGV("render - signal wait\n");
438 mCondition.wait(mMutex);
439 LOGV("render - signal rx'd\n");
440 }
441 if (mExit) break;
442
443 // We could end up here if start() is called, and before we get a
444 // chance to run, the app calls stop() or reset(). Re-check render
445 // flag so we don't try to render in stop or reset state.
446 if (!mRender) continue;
447
448 // render vorbis data into the input buffer
449 numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, &current_section);
450 if (numread == 0) {
451 // end of file, do we need to loop?
452 // ...
453 if (mLoop || mAndroidLoop) {
454 ov_time_seek(&mVorbisFile, 0);
455 current_section = 0;
456 numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, &current_section);
457 } else {
458 mAudioSink->stop();
459 audioStarted = false;
460 mRender = false;
461 mPaused = true;
462 int endpos = ov_time_tell(&mVorbisFile);
463
464 LOGV("send MEDIA_PLAYBACK_COMPLETE");
465 sendEvent(MEDIA_PLAYBACK_COMPLETE);
466
467 // wait until we're started again
468 LOGV("playback complete - wait for signal");
469 mCondition.wait(mMutex);
470 LOGV("playback complete - signal rx'd");
471 if (mExit) break;
472
473 // if we're still at the end, restart from the beginning
474 if (mState == STATE_OPEN) {
475 int curpos = ov_time_tell(&mVorbisFile);
476 if (curpos == endpos) {
477 ov_time_seek(&mVorbisFile, 0);
478 }
479 current_section = 0;
480 numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, &current_section);
481 }
482 }
483 }
484 }
485
486 // codec returns negative number on error
487 if (numread < 0) {
488 LOGE("Error in Vorbis decoder");
489 sendEvent(MEDIA_ERROR);
490 break;
491 }
492
493 // create audio output track if necessary
494 if (!mAudioSink->ready()) {
495 LOGV("render - create output track\n");
496 if (createOutputTrack() != NO_ERROR)
497 break;
498 }
499
500 // Write data to the audio hardware
501 if ((temp = mAudioSink->write(mAudioBuffer, numread)) < 0) {
502 LOGE("Error in writing:%d",temp);
503 result = temp;
504 break;
505 }
506
507 // start audio output if necessary
508 if (!audioStarted && !mPaused && !mExit) {
509 LOGV("render - starting audio\n");
510 mAudioSink->start();
511 audioStarted = true;
512 }
513 }
514
515threadExit:
516 mAudioSink.clear();
517 if (mAudioBuffer) {
518 delete [] mAudioBuffer;
519 mAudioBuffer = NULL;
520 }
521
522 // tell main thread goodbye
523 Mutex::Autolock l(mMutex);
524 mRenderTid = -1;
525 mCondition.signal();
526 return result;
527}
528
529} // end namespace android