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