android_GenericMediaPlayer.cpp revision 7c40d3b78c609b2a84acd0dd6e874ab24a73f8d7
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 32static 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? 36bool 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 46namespace android { 47 48//-------------------------------------------------------------------------------------------------- 49MediaPlayerNotificationClient::MediaPlayerNotificationClient(GenericMediaPlayer* gmp) : 50 mGenericMediaPlayer(gmp), 51 mPlayerPrepared(PREPARE_NOT_STARTED) 52{ 53 SL_LOGV("MediaPlayerNotificationClient::MediaPlayerNotificationClient()"); 54} 55 56MediaPlayerNotificationClient::~MediaPlayerNotificationClient() { 57 SL_LOGV("MediaPlayerNotificationClient::~MediaPlayerNotificationClient()"); 58} 59 60// Map a MEDIA_* enum to a string 61static 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 82void 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 // FIXME Currently no mechanism to inform client of errors after preparation 140 } 141 } 142 break; 143 144 case MEDIA_NOP: 145 case MEDIA_TIMED_TEXT: 146 case MEDIA_INFO: 147 break; 148 149 default: { } 150 } 151 152} 153 154//-------------------------------------------------- 155void MediaPlayerNotificationClient::beforePrepare() 156{ 157 Mutex::Autolock _l(mLock); 158 assert(mPlayerPrepared == PREPARE_NOT_STARTED); 159 mPlayerPrepared = PREPARE_IN_PROGRESS; 160} 161 162//-------------------------------------------------- 163bool MediaPlayerNotificationClient::blockUntilPlayerPrepared() { 164 Mutex::Autolock _l(mLock); 165 assert(mPlayerPrepared != PREPARE_NOT_STARTED); 166 while (mPlayerPrepared == PREPARE_IN_PROGRESS) { 167 mPlayerPreparedCondition.wait(mLock); 168 } 169 assert(mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY || 170 mPlayerPrepared == PREPARE_COMPLETED_UNSUCCESSFULLY); 171 return mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY; 172} 173 174//-------------------------------------------------------------------------------------------------- 175GenericMediaPlayer::GenericMediaPlayer(const AudioPlayback_Parameters* params, bool hasVideo) : 176 GenericPlayer(params), 177 mHasVideo(hasVideo), 178 mSeekTimeMsec(0), 179 mVideoSurface(0), 180 mVideoSurfaceTexture(0), 181 mPlayer(0), 182 mPlayerClient(new MediaPlayerNotificationClient(this)) 183{ 184 SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()"); 185 186} 187 188GenericMediaPlayer::~GenericMediaPlayer() { 189 SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()"); 190} 191 192void GenericMediaPlayer::preDestroy() { 193 // FIXME can't access mPlayer from outside the looper (no mutex!) so using mPreparedPlayer 194 sp<IMediaPlayer> player; 195 getPreparedPlayer(player); 196 if (player != NULL) { 197 player->stop(); 198 // causes CHECK failure in Nuplayer, but commented out in the subclass preDestroy 199 // randomly causes a NPE in StagefrightPlayer, heap corruption, or app hang 200 //player->setDataSource(NULL); 201 player->setVideoSurface(NULL); 202 player->disconnect(); 203 // release all references to the IMediaPlayer 204 // FIXME illegal if not on looper 205 //mPlayer.clear(); 206 { 207 Mutex::Autolock _l(mPreparedPlayerLock); 208 mPreparedPlayer.clear(); 209 } 210 } 211 GenericPlayer::preDestroy(); 212} 213 214//-------------------------------------------------- 215// overridden from GenericPlayer 216// pre-condition: 217// msec != NULL 218// post-condition 219// *msec == 220// ANDROID_UNKNOWN_TIME if position is unknown at time of query, 221// or the current MediaPlayer position 222void GenericMediaPlayer::getPositionMsec(int* msec) { 223 SL_LOGD("GenericMediaPlayer::getPositionMsec()"); 224 sp<IMediaPlayer> player; 225 getPreparedPlayer(player); 226 // To avoid deadlock, directly call the MediaPlayer object 227 if (player == 0 || player->getCurrentPosition(msec) != NO_ERROR) { 228 *msec = ANDROID_UNKNOWN_TIME; 229 } 230} 231 232//-------------------------------------------------- 233void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) { 234 SL_LOGV("GenericMediaPlayer::setVideoSurface()"); 235 // FIXME bug - race condition, should do in looper 236 if (mVideoSurface.get() == surface.get()) { 237 return; 238 } 239 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) { 240 mPlayer->setVideoSurface(surface); 241 } 242 mVideoSurface = surface; 243 mVideoSurfaceTexture = NULL; 244} 245 246void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) { 247 SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()"); 248 // FIXME bug - race condition, should do in looper 249 if (mVideoSurfaceTexture.get() == surfaceTexture.get()) { 250 return; 251 } 252 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) { 253 mPlayer->setVideoSurfaceTexture(surfaceTexture); 254 } 255 mVideoSurfaceTexture = surfaceTexture; 256 mVideoSurface = NULL; 257} 258 259 260//-------------------------------------------------- 261// Event handlers 262 263// blocks until mPlayer is prepared 264void GenericMediaPlayer::onPrepare() { 265 SL_LOGD("GenericMediaPlayer::onPrepare()"); 266 // Attempt to prepare at most once, and only if there is a MediaPlayer 267 if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) { 268 if (mHasVideo) { 269 if (mVideoSurface != 0) { 270 mPlayer->setVideoSurface(mVideoSurface); 271 } else if (mVideoSurfaceTexture != 0) { 272 mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture); 273 } 274 } 275 mPlayer->setAudioStreamType(mPlaybackParams.streamType); 276 mPlayerClient->beforePrepare(); 277 mPlayer->prepareAsync(); 278 if (mPlayerClient->blockUntilPlayerPrepared()) { 279 mStateFlags |= kFlagPrepared; 280 afterMediaPlayerPreparedSuccessfully(); 281 } else { 282 mStateFlags |= kFlagPreparedUnsuccessfully; 283 } 284 } 285 GenericPlayer::onPrepare(); 286 SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags); 287} 288 289 290void GenericMediaPlayer::onPlay() { 291 SL_LOGD("GenericMediaPlayer::onPlay()"); 292 if (((mStateFlags & (kFlagPrepared | kFlagPlaying)) == kFlagPrepared) && (mPlayer != 0)) { 293 mPlayer->start(); 294 } 295 GenericPlayer::onPlay(); 296} 297 298 299void GenericMediaPlayer::onPause() { 300 SL_LOGD("GenericMediaPlayer::onPause()"); 301 if (!(~mStateFlags & (kFlagPrepared | kFlagPlaying)) && (mPlayer != 0)) { 302 mPlayer->pause(); 303 } 304 GenericPlayer::onPause(); 305} 306 307 308void GenericMediaPlayer::onSeekComplete() { 309 SL_LOGV("GenericMediaPlayer::onSeekComplete()"); 310 // did we initiate the seek? 311 if (!(mStateFlags & kFlagSeeking)) { 312 // no, are we looping? 313 if (mStateFlags & kFlagLooping) { 314 // yes, per OpenSL ES 1.0.1 and 1.1 do NOT report it to client 315 // notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/); 316 // no, well that's surprising, but it's probably just a benign race condition 317 } else { 318 SL_LOGW("Unexpected seek complete event ignored"); 319 } 320 } 321 GenericPlayer::onSeekComplete(); 322} 323 324 325/** 326 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0 327 */ 328void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) { 329 SL_LOGV("GenericMediaPlayer::onSeek"); 330 int64_t timeMsec = ANDROID_UNKNOWN_TIME; 331 if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) { 332 // invalid command, drop it 333 return; 334 } 335 if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec) && 336 (timeMsec != ANDROID_UNKNOWN_TIME)) { 337 // already seeking to the same non-unknown time, cancel this command 338 return; 339 } else if (mStateFlags & kFlagPreparedUnsuccessfully) { 340 // discard seeks after unsuccessful prepare 341 } else if (!(mStateFlags & kFlagPrepared)) { 342 // we are not ready to accept a seek command at this time, retry later 343 msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US); 344 } else { 345 if (mPlayer != 0) { 346 mStateFlags |= kFlagSeeking; 347 mSeekTimeMsec = (int32_t)timeMsec; 348 // seek to unknown time is used by StreamPlayer after discontinuity 349 if (timeMsec == ANDROID_UNKNOWN_TIME) { 350 // FIXME simulate a MEDIA_SEEK_COMPLETE event in 250 ms; 351 // this is a terrible hack to make up for mediaserver not sending one 352 (new AMessage(kWhatSeekComplete, id()))->post(250000); 353 } else if (OK != mPlayer->seekTo(timeMsec)) { 354 mStateFlags &= ~kFlagSeeking; 355 mSeekTimeMsec = ANDROID_UNKNOWN_TIME; 356 } 357 } 358 } 359} 360 361 362void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) { 363 SL_LOGV("GenericMediaPlayer::onLoop"); 364 int32_t loop = 0; 365 if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) { 366 if (loop) { 367 mStateFlags |= kFlagLooping; 368 } else { 369 mStateFlags &= ~kFlagLooping; 370 } 371 // if we have a MediaPlayer then tell it now, otherwise we'll tell it after it's created 372 if (mPlayer != 0) { 373 (void) mPlayer->setLooping(loop); 374 } 375 } 376} 377 378 379void GenericMediaPlayer::onVolumeUpdate() { 380 SL_LOGD("GenericMediaPlayer::onVolumeUpdate()"); 381 // use settings lock to read the volume settings 382 Mutex::Autolock _l(mSettingsLock); 383 if (mPlayer != 0) { 384 mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0], 385 mAndroidAudioLevels.mFinalVolume[1]); 386 } 387} 388 389 390void GenericMediaPlayer::onAttachAuxEffect(const sp<AMessage> &msg) { 391 SL_LOGD("GenericMediaPlayer::onAttachAuxEffect()"); 392 int32_t effectId = 0; 393 if (msg->findInt32(WHATPARAM_ATTACHAUXEFFECT, &effectId)) { 394 if (mPlayer != 0) { 395 status_t status; 396 status = mPlayer->attachAuxEffect(effectId); 397 // attachAuxEffect returns a status but we have no way to report it back to app 398 (void) status; 399 } 400 } 401} 402 403 404void GenericMediaPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) { 405 SL_LOGD("GenericMediaPlayer::onSetAuxEffectSendLevel()"); 406 float level = 0.0f; 407 if (msg->findFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, &level)) { 408 if (mPlayer != 0) { 409 status_t status; 410 status = mPlayer->setAuxEffectSendLevel(level); 411 // setAuxEffectSendLevel returns a status but we have no way to report it back to app 412 (void) status; 413 } 414 } 415} 416 417 418void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) { 419 int32_t fillLevel = 0; 420 if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) { 421 SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel); 422 423 Mutex::Autolock _l(mSettingsLock); 424 mCacheFill = fillLevel; 425 // handle cache fill update 426 if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) { 427 notifyCacheFill(); 428 } 429 // handle prefetch status update 430 // compute how much time ahead of position is buffered 431 int durationMsec, positionMsec = -1; 432 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0) 433 && (OK == mPlayer->getDuration(&durationMsec)) 434 && (OK == mPlayer->getCurrentPosition(&positionMsec))) { 435 if ((-1 != durationMsec) && (-1 != positionMsec)) { 436 // evaluate prefetch status based on buffer time thresholds 437 int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec; 438 CacheStatus_t newCacheStatus = mCacheStatus; 439 if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) { 440 newCacheStatus = kStatusHigh; 441 } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) { 442 newCacheStatus = kStatusEnough; 443 } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) { 444 newCacheStatus = kStatusIntermediate; 445 } else if (bufferedDurationMsec == 0) { 446 newCacheStatus = kStatusEmpty; 447 } else { 448 newCacheStatus = kStatusLow; 449 } 450 451 if (newCacheStatus != mCacheStatus) { 452 mCacheStatus = newCacheStatus; 453 notifyStatus(); 454 } 455 } 456 } 457 } else { 458 SL_LOGV("GenericMediaPlayer::onBufferingUpdate(fillLevel=unknown)"); 459 } 460} 461 462 463//-------------------------------------------------- 464/** 465 * called from GenericMediaPlayer::onPrepare after the MediaPlayer mPlayer is prepared successfully 466 * pre-conditions: 467 * mPlayer != 0 468 * mPlayer is prepared successfully 469 */ 470void GenericMediaPlayer::afterMediaPlayerPreparedSuccessfully() { 471 SL_LOGV("GenericMediaPlayer::afterMediaPlayerPrepared()"); 472 assert(mPlayer != 0); 473 assert(mStateFlags & kFlagPrepared); 474 // Mark this player as prepared successfully, so safe to directly call getCurrentPosition 475 { 476 Mutex::Autolock _l(mPreparedPlayerLock); 477 assert(mPreparedPlayer == 0); 478 mPreparedPlayer = mPlayer; 479 } 480 // retrieve channel count 481 int32_t channelCount; 482 Parcel *reply = new Parcel(); 483 status_t status = mPlayer->getParameter(KEY_PARAMETER_AUDIO_CHANNEL_COUNT, reply); 484 if (status == NO_ERROR) { 485 channelCount = reply->readInt32(); 486 } else { 487 // FIXME MPEG-2 TS doesn't yet implement this key, so default to stereo 488 channelCount = 2; 489 } 490 if (UNKNOWN_NUMCHANNELS != channelCount) { 491 // now that we know the channel count, re-calculate the volumes 492 notify(PLAYEREVENT_CHANNEL_COUNT, channelCount, true /*async*/); 493 } else { 494 LOGW("channel count is still unknown after prepare"); 495 } 496 delete reply; 497 // retrieve duration 498 { 499 Mutex::Autolock _l(mSettingsLock); 500 int msec = 0; 501 if (OK == mPlayer->getDuration(&msec)) { 502 mDurationMsec = msec; 503 } 504 } 505 // now that we have a MediaPlayer, set the looping flag 506 if (mStateFlags & kFlagLooping) { 507 (void) mPlayer->setLooping(1); 508 } 509 // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers 510 // if the data source was local, and the buffers are considered full so we need to notify that 511 bool isLocalSource = true; 512 if (kDataLocatorUri == mDataLocatorType) { 513 isLocalSource = !isDistantProtocol(mDataLocator.uriRef); 514 } 515 if (isLocalSource) { 516 SL_LOGD("media player prepared on local source"); 517 { 518 Mutex::Autolock _l(mSettingsLock); 519 mCacheStatus = kStatusHigh; 520 mCacheFill = 1000; 521 notifyStatus(); 522 notifyCacheFill(); 523 } 524 } else { 525 SL_LOGD("media player prepared on non-local source"); 526 } 527} 528 529 530//-------------------------------------------------- 531// If player is prepared successfully, set output parameter to that reference, otherwise NULL 532void GenericMediaPlayer::getPreparedPlayer(sp<IMediaPlayer> &preparedPlayer) 533{ 534 Mutex::Autolock _l(mPreparedPlayerLock); 535 preparedPlayer = mPreparedPlayer; 536} 537 538} // namespace android 539