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