1 /* 2 * Copyright (C) 2011 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 USE_LOG SLAndroidLogLevel_Verbose 18 19 #include "sles_allinclusive.h" 20 #include "android_GenericMediaPlayer.h" 21 22 #include <media/IMediaPlayerService.h> 23 #include <surfaceflinger/ISurfaceComposer.h> 24 #include <surfaceflinger/SurfaceComposerClient.h> 25 #include <media/stagefright/foundation/ADebug.h> 26 27 // default delay in Us used when reposting an event when the player is not ready to accept 28 // the command yet. This is for instance used when seeking on a MediaPlayer that's still preparing 29 #define DEFAULT_COMMAND_DELAY_FOR_REPOST_US (100*1000) // 100ms 30 31 // table of prefixes for known distant protocols; these are immediately dispatched to mediaserver 32 static const char* const kDistantProtocolPrefix[] = { "http://", "https://", "rtsp://"}; 33 #define NB_DISTANT_PROTOCOLS (sizeof(kDistantProtocolPrefix)/sizeof(kDistantProtocolPrefix[0])) 34 35 // is the specified URI a known distant protocol? 36 bool isDistantProtocol(const char *uri) 37 { 38 for (unsigned int i = 0; i < NB_DISTANT_PROTOCOLS; i++) { 39 if (!strncasecmp(uri, kDistantProtocolPrefix[i], strlen(kDistantProtocolPrefix[i]))) { 40 return true; 41 } 42 } 43 return false; 44 } 45 46 namespace android { 47 48 //-------------------------------------------------------------------------------------------------- 49 MediaPlayerNotificationClient::MediaPlayerNotificationClient(GenericMediaPlayer* gmp) : 50 mGenericMediaPlayer(gmp), 51 mPlayerPrepared(PREPARE_NOT_STARTED) 52 { 53 SL_LOGV("MediaPlayerNotificationClient::MediaPlayerNotificationClient()"); 54 } 55 56 MediaPlayerNotificationClient::~MediaPlayerNotificationClient() { 57 SL_LOGV("MediaPlayerNotificationClient::~MediaPlayerNotificationClient()"); 58 } 59 60 // Map a MEDIA_* enum to a string 61 static const char *media_to_string(int msg) 62 { 63 switch (msg) { 64 #define _(x) case MEDIA_##x: return "MEDIA_" #x; 65 _(PREPARED) 66 _(SET_VIDEO_SIZE) 67 _(SEEK_COMPLETE) 68 _(PLAYBACK_COMPLETE) 69 _(BUFFERING_UPDATE) 70 _(ERROR) 71 _(NOP) 72 _(TIMED_TEXT) 73 _(INFO) 74 #undef _ 75 default: 76 return NULL; 77 } 78 } 79 80 //-------------------------------------------------- 81 // IMediaPlayerClient implementation 82 void MediaPlayerNotificationClient::notify(int msg, int ext1, int ext2, const Parcel *obj) { 83 SL_LOGV("MediaPlayerNotificationClient::notify(msg=%s (%d), ext1=%d, ext2=%d)", 84 media_to_string(msg), msg, ext1, ext2); 85 86 sp<GenericMediaPlayer> genericMediaPlayer(mGenericMediaPlayer.promote()); 87 if (genericMediaPlayer == NULL) { 88 SL_LOGW("MediaPlayerNotificationClient::notify after GenericMediaPlayer destroyed"); 89 return; 90 } 91 92 switch (msg) { 93 case MEDIA_PREPARED: 94 { 95 Mutex::Autolock _l(mLock); 96 if (PREPARE_IN_PROGRESS == mPlayerPrepared) { 97 mPlayerPrepared = PREPARE_COMPLETED_SUCCESSFULLY; 98 mPlayerPreparedCondition.signal(); 99 } else { 100 SL_LOGE("Unexpected MEDIA_PREPARED"); 101 } 102 } 103 break; 104 105 case MEDIA_SET_VIDEO_SIZE: 106 // only send video size updates if the player was flagged as having video, to avoid 107 // sending video size updates of (0,0) 108 // We're running on a different thread than genericMediaPlayer's ALooper thread, 109 // so it would normally be racy to access fields within genericMediaPlayer. 110 // But in this case mHasVideo is const, so it is safe to access. 111 // Or alternatively, we could notify unconditionally and let it decide whether to handle. 112 if (genericMediaPlayer->mHasVideo) { 113 genericMediaPlayer->notify(PLAYEREVENT_VIDEO_SIZE_UPDATE, 114 (int32_t)ext1, (int32_t)ext2, true /*async*/); 115 } 116 break; 117 118 case MEDIA_SEEK_COMPLETE: 119 genericMediaPlayer->seekComplete(); 120 break; 121 122 case MEDIA_PLAYBACK_COMPLETE: 123 genericMediaPlayer->notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/); 124 break; 125 126 case MEDIA_BUFFERING_UPDATE: 127 // values received from Android framework for buffer fill level use percent, 128 // while SL/XA use permille, so does GenericPlayer 129 genericMediaPlayer->bufferingUpdate(ext1 * 10 /*fillLevelPerMille*/); 130 break; 131 132 case MEDIA_ERROR: 133 { 134 Mutex::Autolock _l(mLock); 135 if (PREPARE_IN_PROGRESS == mPlayerPrepared) { 136 mPlayerPrepared = PREPARE_COMPLETED_UNSUCCESSFULLY; 137 mPlayerPreparedCondition.signal(); 138 } else { 139 // inform client of errors after preparation 140 genericMediaPlayer->notify(PLAYEREVENT_ERRORAFTERPREPARE, ext1, true /*async*/); 141 } 142 } 143 break; 144 145 case MEDIA_NOP: 146 case MEDIA_TIMED_TEXT: 147 case MEDIA_INFO: 148 break; 149 150 default: { } 151 } 152 153 } 154 155 //-------------------------------------------------- 156 void MediaPlayerNotificationClient::beforePrepare() 157 { 158 Mutex::Autolock _l(mLock); 159 assert(mPlayerPrepared == PREPARE_NOT_STARTED); 160 mPlayerPrepared = PREPARE_IN_PROGRESS; 161 } 162 163 //-------------------------------------------------- 164 bool MediaPlayerNotificationClient::blockUntilPlayerPrepared() { 165 Mutex::Autolock _l(mLock); 166 assert(mPlayerPrepared != PREPARE_NOT_STARTED); 167 while (mPlayerPrepared == PREPARE_IN_PROGRESS) { 168 mPlayerPreparedCondition.wait(mLock); 169 } 170 assert(mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY || 171 mPlayerPrepared == PREPARE_COMPLETED_UNSUCCESSFULLY); 172 return mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY; 173 } 174 175 //-------------------------------------------------------------------------------------------------- 176 GenericMediaPlayer::GenericMediaPlayer(const AudioPlayback_Parameters* params, bool hasVideo) : 177 GenericPlayer(params), 178 mHasVideo(hasVideo), 179 mSeekTimeMsec(0), 180 mVideoSurface(0), 181 mVideoSurfaceTexture(0), 182 mPlayer(0), 183 mPlayerClient(new MediaPlayerNotificationClient(this)) 184 { 185 SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()"); 186 187 } 188 189 GenericMediaPlayer::~GenericMediaPlayer() { 190 SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()"); 191 } 192 193 void GenericMediaPlayer::preDestroy() { 194 // FIXME can't access mPlayer from outside the looper (no mutex!) so using mPreparedPlayer 195 sp<IMediaPlayer> player; 196 getPreparedPlayer(player); 197 if (player != NULL) { 198 player->stop(); 199 // causes CHECK failure in Nuplayer, but commented out in the subclass preDestroy 200 // randomly causes a NPE in StagefrightPlayer, heap corruption, or app hang 201 //player->setDataSource(NULL); 202 player->setVideoSurface(NULL); 203 player->disconnect(); 204 // release all references to the IMediaPlayer 205 // FIXME illegal if not on looper 206 //mPlayer.clear(); 207 { 208 Mutex::Autolock _l(mPreparedPlayerLock); 209 mPreparedPlayer.clear(); 210 } 211 } 212 GenericPlayer::preDestroy(); 213 } 214 215 //-------------------------------------------------- 216 // overridden from GenericPlayer 217 // pre-condition: 218 // msec != NULL 219 // post-condition 220 // *msec == 221 // ANDROID_UNKNOWN_TIME if position is unknown at time of query, 222 // or the current MediaPlayer position 223 void GenericMediaPlayer::getPositionMsec(int* msec) { 224 SL_LOGD("GenericMediaPlayer::getPositionMsec()"); 225 sp<IMediaPlayer> player; 226 getPreparedPlayer(player); 227 // To avoid deadlock, directly call the MediaPlayer object 228 if (player == 0 || player->getCurrentPosition(msec) != NO_ERROR) { 229 *msec = ANDROID_UNKNOWN_TIME; 230 } 231 } 232 233 //-------------------------------------------------- 234 void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) { 235 SL_LOGV("GenericMediaPlayer::setVideoSurface()"); 236 // FIXME bug - race condition, should do in looper 237 if (mVideoSurface.get() == surface.get()) { 238 return; 239 } 240 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) { 241 mPlayer->setVideoSurface(surface); 242 } 243 mVideoSurface = surface; 244 mVideoSurfaceTexture = NULL; 245 } 246 247 void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) { 248 SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()"); 249 // FIXME bug - race condition, should do in looper 250 if (mVideoSurfaceTexture.get() == surfaceTexture.get()) { 251 return; 252 } 253 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) { 254 mPlayer->setVideoSurfaceTexture(surfaceTexture); 255 } 256 mVideoSurfaceTexture = surfaceTexture; 257 mVideoSurface = NULL; 258 } 259 260 261 //-------------------------------------------------- 262 // Event handlers 263 264 // blocks until mPlayer is prepared 265 void GenericMediaPlayer::onPrepare() { 266 SL_LOGD("GenericMediaPlayer::onPrepare()"); 267 // Attempt to prepare at most once, and only if there is a MediaPlayer 268 if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) { 269 if (mHasVideo) { 270 if (mVideoSurface != 0) { 271 mPlayer->setVideoSurface(mVideoSurface); 272 } else if (mVideoSurfaceTexture != 0) { 273 mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture); 274 } 275 } 276 mPlayer->setAudioStreamType(mPlaybackParams.streamType); 277 mPlayerClient->beforePrepare(); 278 mPlayer->prepareAsync(); 279 if (mPlayerClient->blockUntilPlayerPrepared()) { 280 mStateFlags |= kFlagPrepared; 281 afterMediaPlayerPreparedSuccessfully(); 282 } else { 283 mStateFlags |= kFlagPreparedUnsuccessfully; 284 } 285 } 286 GenericPlayer::onPrepare(); 287 SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags); 288 } 289 290 291 void GenericMediaPlayer::onPlay() { 292 SL_LOGD("GenericMediaPlayer::onPlay()"); 293 if (((mStateFlags & (kFlagPrepared | kFlagPlaying)) == kFlagPrepared) && (mPlayer != 0)) { 294 mPlayer->start(); 295 } 296 GenericPlayer::onPlay(); 297 } 298 299 300 void GenericMediaPlayer::onPause() { 301 SL_LOGD("GenericMediaPlayer::onPause()"); 302 if (!(~mStateFlags & (kFlagPrepared | kFlagPlaying)) && (mPlayer != 0)) { 303 mPlayer->pause(); 304 } 305 GenericPlayer::onPause(); 306 } 307 308 309 void GenericMediaPlayer::onSeekComplete() { 310 SL_LOGV("GenericMediaPlayer::onSeekComplete()"); 311 // did we initiate the seek? 312 if (!(mStateFlags & kFlagSeeking)) { 313 // no, are we looping? 314 if (mStateFlags & kFlagLooping) { 315 // yes, per OpenSL ES 1.0.1 and 1.1 do NOT report it to client 316 // notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/); 317 // no, well that's surprising, but it's probably just a benign race condition 318 } else { 319 SL_LOGW("Unexpected seek complete event ignored"); 320 } 321 } 322 GenericPlayer::onSeekComplete(); 323 } 324 325 326 /** 327 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0 328 */ 329 void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) { 330 SL_LOGV("GenericMediaPlayer::onSeek"); 331 int64_t timeMsec = ANDROID_UNKNOWN_TIME; 332 if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) { 333 // invalid command, drop it 334 return; 335 } 336 if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec) && 337 (timeMsec != ANDROID_UNKNOWN_TIME)) { 338 // already seeking to the same non-unknown time, cancel this command 339 return; 340 } else if (mStateFlags & kFlagPreparedUnsuccessfully) { 341 // discard seeks after unsuccessful prepare 342 } else if (!(mStateFlags & kFlagPrepared)) { 343 // we are not ready to accept a seek command at this time, retry later 344 msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US); 345 } else { 346 if (mPlayer != 0) { 347 mStateFlags |= kFlagSeeking; 348 mSeekTimeMsec = (int32_t)timeMsec; 349 // seek to unknown time is used by StreamPlayer after discontinuity 350 if (timeMsec == ANDROID_UNKNOWN_TIME) { 351 // FIXME simulate a MEDIA_SEEK_COMPLETE event in 250 ms; 352 // this is a terrible hack to make up for mediaserver not sending one 353 (new AMessage(kWhatSeekComplete, id()))->post(250000); 354 } else if (OK != mPlayer->seekTo(timeMsec)) { 355 mStateFlags &= ~kFlagSeeking; 356 mSeekTimeMsec = ANDROID_UNKNOWN_TIME; 357 } 358 } 359 } 360 } 361 362 363 void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) { 364 SL_LOGV("GenericMediaPlayer::onLoop"); 365 int32_t loop = 0; 366 if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) { 367 if (loop) { 368 mStateFlags |= kFlagLooping; 369 } else { 370 mStateFlags &= ~kFlagLooping; 371 } 372 // if we have a MediaPlayer then tell it now, otherwise we'll tell it after it's created 373 if (mPlayer != 0) { 374 (void) mPlayer->setLooping(loop); 375 } 376 } 377 } 378 379 380 void GenericMediaPlayer::onVolumeUpdate() { 381 SL_LOGD("GenericMediaPlayer::onVolumeUpdate()"); 382 // use settings lock to read the volume settings 383 Mutex::Autolock _l(mSettingsLock); 384 if (mPlayer != 0) { 385 mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0], 386 mAndroidAudioLevels.mFinalVolume[1]); 387 } 388 } 389 390 391 void GenericMediaPlayer::onAttachAuxEffect(const sp<AMessage> &msg) { 392 SL_LOGD("GenericMediaPlayer::onAttachAuxEffect()"); 393 int32_t effectId = 0; 394 if (msg->findInt32(WHATPARAM_ATTACHAUXEFFECT, &effectId)) { 395 if (mPlayer != 0) { 396 status_t status; 397 status = mPlayer->attachAuxEffect(effectId); 398 // attachAuxEffect returns a status but we have no way to report it back to app 399 (void) status; 400 } 401 } 402 } 403 404 405 void GenericMediaPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) { 406 SL_LOGD("GenericMediaPlayer::onSetAuxEffectSendLevel()"); 407 float level = 0.0f; 408 if (msg->findFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, &level)) { 409 if (mPlayer != 0) { 410 status_t status; 411 status = mPlayer->setAuxEffectSendLevel(level); 412 // setAuxEffectSendLevel returns a status but we have no way to report it back to app 413 (void) status; 414 } 415 } 416 } 417 418 419 void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) { 420 int32_t fillLevel = 0; 421 if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) { 422 SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel); 423 424 Mutex::Autolock _l(mSettingsLock); 425 mCacheFill = fillLevel; 426 // handle cache fill update 427 if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) { 428 notifyCacheFill(); 429 } 430 // handle prefetch status update 431 // compute how much time ahead of position is buffered 432 int durationMsec, positionMsec = -1; 433 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0) 434 && (OK == mPlayer->getDuration(&durationMsec)) 435 && (OK == mPlayer->getCurrentPosition(&positionMsec))) { 436 if ((-1 != durationMsec) && (-1 != positionMsec)) { 437 // evaluate prefetch status based on buffer time thresholds 438 int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec; 439 CacheStatus_t newCacheStatus = mCacheStatus; 440 if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) { 441 newCacheStatus = kStatusHigh; 442 } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) { 443 newCacheStatus = kStatusEnough; 444 } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) { 445 newCacheStatus = kStatusIntermediate; 446 } else if (bufferedDurationMsec == 0) { 447 newCacheStatus = kStatusEmpty; 448 } else { 449 newCacheStatus = kStatusLow; 450 } 451 452 if (newCacheStatus != mCacheStatus) { 453 mCacheStatus = newCacheStatus; 454 notifyStatus(); 455 } 456 } 457 } 458 } else { 459 SL_LOGV("GenericMediaPlayer::onBufferingUpdate(fillLevel=unknown)"); 460 } 461 } 462 463 464 //-------------------------------------------------- 465 /** 466 * called from GenericMediaPlayer::onPrepare after the MediaPlayer mPlayer is prepared successfully 467 * pre-conditions: 468 * mPlayer != 0 469 * mPlayer is prepared successfully 470 */ 471 void GenericMediaPlayer::afterMediaPlayerPreparedSuccessfully() { 472 SL_LOGV("GenericMediaPlayer::afterMediaPlayerPrepared()"); 473 assert(mPlayer != 0); 474 assert(mStateFlags & kFlagPrepared); 475 // Mark this player as prepared successfully, so safe to directly call getCurrentPosition 476 { 477 Mutex::Autolock _l(mPreparedPlayerLock); 478 assert(mPreparedPlayer == 0); 479 mPreparedPlayer = mPlayer; 480 } 481 // retrieve channel count 482 int32_t channelCount; 483 Parcel *reply = new Parcel(); 484 status_t status = mPlayer->getParameter(KEY_PARAMETER_AUDIO_CHANNEL_COUNT, reply); 485 if (status == NO_ERROR) { 486 channelCount = reply->readInt32(); 487 } else { 488 // FIXME MPEG-2 TS doesn't yet implement this key, so default to stereo 489 channelCount = 2; 490 } 491 if (UNKNOWN_NUMCHANNELS != channelCount) { 492 // now that we know the channel count, re-calculate the volumes 493 notify(PLAYEREVENT_CHANNEL_COUNT, channelCount, true /*async*/); 494 } else { 495 LOGW("channel count is still unknown after prepare"); 496 } 497 delete reply; 498 // retrieve duration 499 { 500 Mutex::Autolock _l(mSettingsLock); 501 int msec = 0; 502 if (OK == mPlayer->getDuration(&msec)) { 503 mDurationMsec = msec; 504 } 505 } 506 // now that we have a MediaPlayer, set the looping flag 507 if (mStateFlags & kFlagLooping) { 508 (void) mPlayer->setLooping(1); 509 } 510 // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers 511 // if the data source was local, and the buffers are considered full so we need to notify that 512 bool isLocalSource = true; 513 if (kDataLocatorUri == mDataLocatorType) { 514 isLocalSource = !isDistantProtocol(mDataLocator.uriRef); 515 } 516 if (isLocalSource) { 517 SL_LOGD("media player prepared on local source"); 518 { 519 Mutex::Autolock _l(mSettingsLock); 520 mCacheStatus = kStatusHigh; 521 mCacheFill = 1000; 522 notifyStatus(); 523 notifyCacheFill(); 524 } 525 } else { 526 SL_LOGD("media player prepared on non-local source"); 527 } 528 } 529 530 531 //-------------------------------------------------- 532 // If player is prepared successfully, set output parameter to that reference, otherwise NULL 533 void GenericMediaPlayer::getPreparedPlayer(sp<IMediaPlayer> &preparedPlayer) 534 { 535 Mutex::Autolock _l(mPreparedPlayerLock); 536 preparedPlayer = mPreparedPlayer; 537 } 538 539 } // namespace android 540