VorbisPlayer.cpp revision 256430093679e1d62b54fb0c852126e54d162f6f
1/*
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);
70    createThreadEtc(renderThread, this, "vorbis decoder", ANDROID_PRIORITY_AUDIO);
71    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(
90        const char *uri, const KeyedVector<String8, String8> *headers) {
91    return setdatasource(uri, -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);
348    return reset_nosync();
349}
350
351// always call with lock held
352status_t VorbisPlayer::reset_nosync()
353{
354    // close file
355    if (mFile != NULL) {
356        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        }
362    }
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
530