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, ¤t_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, ¤t_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, ¤t_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