• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
myTid()34 static pid_t myTid() { return gettid(); }
35 #else
myTid()36 static pid_t myTid() { return getpid(); }
37 #endif
38 
39 // ----------------------------------------------------------------------------
40 
41 namespace android {
42 
43 // ----------------------------------------------------------------------------
44 
45 // TODO: Determine appropriate return codes
46 static status_t ERROR_NOT_OPEN = -1;
47 static status_t ERROR_OPEN_FAILED = -2;
48 static status_t ERROR_ALLOCATE_FAILED = -4;
49 static status_t ERROR_NOT_SUPPORTED = -8;
50 static status_t ERROR_NOT_READY = -16;
51 static status_t STATE_INIT = 0;
52 static status_t STATE_ERROR = 1;
53 static status_t STATE_OPEN = 2;
54 
55 
VorbisPlayer()56 VorbisPlayer::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 
onFirstRef()65 void 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 
initCheck()78 status_t VorbisPlayer::initCheck()
79 {
80     if (mState != STATE_ERROR) return NO_ERROR;
81     return ERROR_NOT_READY;
82 }
83 
~VorbisPlayer()84 VorbisPlayer::~VorbisPlayer() {
85     LOGV("VorbisPlayer destructor\n");
86     release();
87 }
88 
setDataSource(const char * path)89 status_t VorbisPlayer::setDataSource(const char* path)
90 {
91     return setdatasource(path, -1, 0, 0x7ffffffffffffffLL); // intentionally less than LONG_MAX
92 }
93 
setDataSource(int fd,int64_t offset,int64_t length)94 status_t VorbisPlayer::setDataSource(int fd, int64_t offset, int64_t length)
95 {
96     return setdatasource(NULL, fd, offset, length);
97 }
98 
vp_fread(void * buf,size_t size,size_t nmemb,void * me)99 size_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 
vp_fseek(void * me,ogg_int64_t off,int whence)109 int 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 
vp_fclose(void * me)120 int 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 
vp_ftell(void * me)128 long VorbisPlayer::vp_ftell(void *me) {
129     VorbisPlayer *self = (VorbisPlayer*) me;
130     return ftell(self->mFile) - self->mOffset;
131 }
132 
setdatasource(const char * path,int fd,int64_t offset,int64_t length)133 status_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 
prepare()208 status_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 
prepareAsync()217 status_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 
start()229 status_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 
stop()246 status_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 
seekTo(int position)258 status_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 
pause()275 status_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 
isPlaying()286 bool VorbisPlayer::isPlaying()
287 {
288     LOGV("isPlaying\n");
289     if (mState == STATE_OPEN) {
290         return mRender;
291     }
292     return false;
293 }
294 
getCurrentPosition(int * position)295 status_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 
getDuration(int * duration)311 status_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 
release()328 status_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 
reset()344 status_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
reset_nosync()352 status_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 
setLooping(int loop)374 status_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 
createOutputTrack()382 status_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 
renderThread(void * p)395 int VorbisPlayer::renderThread(void* p) {
396     return ((VorbisPlayer*)p)->render();
397 }
398 
399 #define AUDIOBUFFER_SIZE 4096
400 
render()401 int 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 
515 threadExit:
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