android_GenericMediaPlayer.cpp revision 9f07ea788f57654acf29d1321b40162e41eb122b
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 27namespace android { 28 29// default delay in Us used when reposting an event when the player is not ready to accept 30// the command yet. This is for instance used when seeking on a MediaPlayer that's still preparing 31#define DEFAULT_COMMAND_DELAY_FOR_REPOST_US (100*1000) // 100ms 32 33static const char* const kDistantProtocolPrefix[] = { "http:", "https:", "ftp:", "rtp:", "rtsp:"}; 34#define NB_DISTANT_PROTOCOLS (sizeof(kDistantProtocolPrefix)/sizeof(kDistantProtocolPrefix[0])) 35 36//-------------------------------------------------------------------------------------------------- 37MediaPlayerNotificationClient::MediaPlayerNotificationClient(GenericMediaPlayer* gmp) : 38 mGenericMediaPlayer(gmp), 39 mPlayerPrepared(PREPARE_NOT_STARTED) 40{ 41 SL_LOGV("MediaPlayerNotificationClient::MediaPlayerNotificationClient()"); 42} 43 44MediaPlayerNotificationClient::~MediaPlayerNotificationClient() { 45 SL_LOGV("MediaPlayerNotificationClient::~MediaPlayerNotificationClient()"); 46} 47 48// Map a MEDIA_* enum to a string 49static const char *media_to_string(int msg) 50{ 51 switch (msg) { 52#define _(x) case MEDIA_##x: return "MEDIA_" #x; 53 _(PREPARED) 54 _(SET_VIDEO_SIZE) 55 _(SEEK_COMPLETE) 56 _(PLAYBACK_COMPLETE) 57 _(BUFFERING_UPDATE) 58 _(ERROR) 59 _(NOP) 60 _(TIMED_TEXT) 61 _(INFO) 62#undef _ 63 default: 64 return NULL; 65 } 66} 67 68//-------------------------------------------------- 69// IMediaPlayerClient implementation 70void MediaPlayerNotificationClient::notify(int msg, int ext1, int ext2, const Parcel *obj) { 71 SL_LOGV("MediaPlayerNotificationClient::notify(msg=%s (%d), ext1=%d, ext2=%d)", 72 media_to_string(msg), msg, ext1, ext2); 73 74 switch (msg) { 75 case MEDIA_PREPARED: 76 mPlayerPrepared = PREPARE_COMPLETED_SUCCESSFULLY; 77 mPlayerPreparedCondition.signal(); 78 break; 79 80 case MEDIA_SET_VIDEO_SIZE: 81 // only send video size updates if the player was flagged as having video, to avoid 82 // sending video size updates of (0,0) 83 if (mGenericMediaPlayer->mHasVideo) { 84 mGenericMediaPlayer->notify(PLAYEREVENT_VIDEO_SIZE_UPDATE, 85 (int32_t)ext1, (int32_t)ext2, true /*async*/); 86 } 87 break; 88 89 case MEDIA_SEEK_COMPLETE: 90 mGenericMediaPlayer->seekComplete(); 91 break; 92 93 case MEDIA_PLAYBACK_COMPLETE: 94 mGenericMediaPlayer->notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/); 95 break; 96 97 case MEDIA_BUFFERING_UPDATE: 98 // values received from Android framework for buffer fill level use percent, 99 // while SL/XA use permille, so does GenericPlayer 100 mGenericMediaPlayer->bufferingUpdate(ext1 * 10 /*fillLevelPerMille*/); 101 break; 102 103 case MEDIA_ERROR: 104 mPlayerPrepared = PREPARE_COMPLETED_UNSUCCESSFULLY; 105 mPlayerPreparedCondition.signal(); 106 break; 107 108 case MEDIA_NOP: 109 case MEDIA_TIMED_TEXT: 110 case MEDIA_INFO: 111 break; 112 113 default: { } 114 } 115 116} 117 118//-------------------------------------------------- 119void MediaPlayerNotificationClient::beforePrepare() 120{ 121 Mutex::Autolock _l(mLock); 122 assert(mPlayerPrepared == PREPARE_NOT_STARTED); 123 mPlayerPrepared = PREPARE_IN_PROGRESS; 124} 125 126//-------------------------------------------------- 127bool MediaPlayerNotificationClient::blockUntilPlayerPrepared() { 128 Mutex::Autolock _l(mLock); 129 assert(mPlayerPrepared != PREPARE_NOT_STARTED); 130 while (mPlayerPrepared == PREPARE_IN_PROGRESS) { 131 mPlayerPreparedCondition.wait(mLock); 132 } 133 assert(mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY || 134 mPlayerPrepared == PREPARE_COMPLETED_UNSUCCESSFULLY); 135 return mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY; 136} 137 138//-------------------------------------------------------------------------------------------------- 139GenericMediaPlayer::GenericMediaPlayer(const AudioPlayback_Parameters* params, bool hasVideo) : 140 GenericPlayer(params), 141 mHasVideo(hasVideo), 142 mSeekTimeMsec(0), 143 mVideoSurface(0), 144 mVideoSurfaceTexture(0), 145 mPlayer(0), 146 mPlayerClient(0), 147 mGetMediaPlayerInfoGenCount(0) 148{ 149 SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()"); 150 151 mServiceManager = defaultServiceManager(); 152 mBinder = mServiceManager->getService(String16("media.player")); 153 mMediaPlayerService = interface_cast<IMediaPlayerService>(mBinder); 154 155 CHECK(mMediaPlayerService.get() != NULL); 156 157 mPlayerClient = new MediaPlayerNotificationClient(this); 158} 159 160GenericMediaPlayer::~GenericMediaPlayer() { 161 SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()"); 162} 163 164void GenericMediaPlayer::preDestroy() { 165 SL_LOGD("GenericMediaPlayer::preDestroy()"); 166 // we might be in the middle of blocking for a getXXX call 167 { 168 android::Mutex::Autolock autoLock(mGetMediaPlayerInfoLock); 169 mGetMediaPlayerInfoGenCount++; 170 mGetMediaPlayerInfoCondition.broadcast(); 171 } 172 GenericPlayer::preDestroy(); 173} 174 175//-------------------------------------------------- 176// overridden from GenericPlayer 177// pre-condition: 178// msec != NULL 179// post-condition 180// *msec == mPositionMsec == 181// ANDROID_UNKNOWN_TIME if position is unknown at time of query, 182// or the current MediaPlayer position 183void GenericMediaPlayer::getPositionMsec(int* msec) { 184 SL_LOGD("GenericMediaPlayer::getPositionMsec()"); 185 uint32_t currentGen = 0; 186 { 187 android::Mutex::Autolock autoLock(mGetMediaPlayerInfoLock); 188 currentGen = mGetMediaPlayerInfoGenCount; 189 } 190 // send a message to update the MediaPlayer position in the event loop where it's safe to 191 // access the MediaPlayer. We block until the message kWhatMediaPlayerInfo has been processed 192 (new AMessage(kWhatMediaPlayerInfo, id()))->post(); 193 { 194 android::Mutex::Autolock autoLock(mGetMediaPlayerInfoLock); 195 // mGetMediaPlayerInfoGenCount will be incremented when the kWhatMediaPlayerInfo 196 // gets processed. 197 while (currentGen == mGetMediaPlayerInfoGenCount) { 198 mGetMediaPlayerInfoCondition.wait(mGetMediaPlayerInfoLock); 199 // if multiple GetPosition calls were issued before any got processed on the event queue 200 // then they will all return the same "recent-enough" position 201 } 202 // at this point mPositionMsec has been updated 203 // so now updates msec from mPositionMsec, while holding the lock protecting it 204 GenericPlayer::getPositionMsec(msec); 205 } 206} 207 208//-------------------------------------------------- 209void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) { 210 SL_LOGV("GenericMediaPlayer::setVideoSurface()"); 211 mVideoSurface = surface; 212} 213 214void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) { 215 SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()"); 216 mVideoSurfaceTexture = surfaceTexture; 217} 218 219//-------------------------------------------------- 220void GenericMediaPlayer::onMessageReceived(const sp<AMessage> &msg) { 221 SL_LOGV("GenericMediaPlayer::onMessageReceived()"); 222 switch (msg->what()) { 223 case kWhatMediaPlayerInfo: 224 onGetMediaPlayerInfo(); 225 break; 226 227 default: 228 GenericPlayer::onMessageReceived(msg); 229 break; 230 } 231} 232 233//-------------------------------------------------- 234// Event handlers 235 236void GenericMediaPlayer::onPrepare() { 237 SL_LOGD("GenericMediaPlayer::onPrepare()"); 238 // Attempt to prepare at most once, and only if there is a MediaPlayer 239 if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) { 240 if (mHasVideo) { 241 if (mVideoSurface != 0) { 242 mPlayer->setVideoSurface(mVideoSurface); 243 } else if (mVideoSurfaceTexture != 0) { 244 mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture); 245 } 246 } 247 mPlayer->setAudioStreamType(mPlaybackParams.streamType); 248 mPlayerClient->beforePrepare(); 249 mPlayer->prepareAsync(); 250 mStateFlags |= mPlayerClient->blockUntilPlayerPrepared() ? 251 kFlagPrepared : kFlagPreparedUnsuccessfully; 252 onAfterMediaPlayerPrepared(); 253 GenericPlayer::onPrepare(); 254 } 255 SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags); 256} 257 258 259void GenericMediaPlayer::onPlay() { 260 SL_LOGD("GenericMediaPlayer::onPlay()"); 261 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) { 262 SL_LOGD("starting player"); 263 mPlayer->start(); 264 mStateFlags |= kFlagPlaying; 265 } else { 266 SL_LOGV("NOT starting player mStateFlags=0x%x", mStateFlags); 267 } 268} 269 270 271void GenericMediaPlayer::onPause() { 272 SL_LOGD("GenericMediaPlayer::onPause()"); 273 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) { 274 mPlayer->pause(); 275 mStateFlags &= ~kFlagPlaying; 276 } 277} 278 279/** 280 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0 281 */ 282void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) { 283 SL_LOGV("GenericMediaPlayer::onSeek"); 284 int64_t timeMsec = ANDROID_UNKNOWN_TIME; 285 if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) { 286 // invalid command, drop it 287 return; 288 } 289 if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec)) { 290 // already seeking to the same time, cancel this command 291 return; 292 } else if (mStateFlags & kFlagPreparedUnsuccessfully) { 293 // discard seeks after unsuccessful prepare 294 } else if (!(mStateFlags & kFlagPrepared)) { 295 // we are not ready to accept a seek command at this time, retry later 296 msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US); 297 } else { 298 if (msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec) && (mPlayer != 0)) { 299 mStateFlags |= kFlagSeeking; 300 mSeekTimeMsec = (int32_t)timeMsec; 301 if (OK != mPlayer->seekTo(timeMsec)) { 302 mStateFlags &= ~kFlagSeeking; 303 mSeekTimeMsec = ANDROID_UNKNOWN_TIME; 304 } else { 305 mPositionMsec = mSeekTimeMsec; 306 } 307 } 308 } 309} 310 311 312void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) { 313 SL_LOGV("GenericMediaPlayer::onLoop"); 314 int32_t loop = 0; 315 if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) { 316 if (loop) { 317 mStateFlags |= kFlagLooping; 318 } else { 319 mStateFlags &= ~kFlagLooping; 320 } 321 // if we have a MediaPlayer then tell it now, otherwise we'll tell it after it's created 322 if (mPlayer != 0) { 323 (void) mPlayer->setLooping(loop); 324 } 325 } 326} 327 328 329void GenericMediaPlayer::onVolumeUpdate() { 330 SL_LOGD("GenericMediaPlayer::onVolumeUpdate()"); 331 // use settings lock to read the volume settings 332 Mutex::Autolock _l(mSettingsLock); 333 if (mPlayer != 0) { 334 mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0], 335 mAndroidAudioLevels.mFinalVolume[1]); 336 } 337} 338 339 340void GenericMediaPlayer::onAttachAuxEffect(const sp<AMessage> &msg) { 341 SL_LOGD("GenericMediaPlayer::onAttachAuxEffect()"); 342 int32_t effectId = 0; 343 if (msg->findInt32(WHATPARAM_ATTACHAUXEFFECT, &effectId)) { 344 if (mPlayer != 0) { 345 status_t status; 346 status = mPlayer->attachAuxEffect(effectId); 347 // attachAuxEffect returns a status but we have no way to report it back to app 348 (void) status; 349 } 350 } 351} 352 353 354void GenericMediaPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) { 355 SL_LOGD("GenericMediaPlayer::onSetAuxEffectSendLevel()"); 356 float level = 0.0f; 357 if (msg->findFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, &level)) { 358 if (mPlayer != 0) { 359 status_t status; 360 status = mPlayer->setAuxEffectSendLevel(level); 361 // setAuxEffectSendLevel returns a status but we have no way to report it back to app 362 (void) status; 363 } 364 } 365} 366 367 368void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) { 369 int32_t fillLevel = 0; 370 if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) { 371 SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel); 372 373 Mutex::Autolock _l(mSettingsLock); 374 mCacheFill = fillLevel; 375 // handle cache fill update 376 if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) { 377 notifyCacheFill(); 378 } 379 // handle prefetch status update 380 // compute how much time ahead of position is buffered 381 int durationMsec, positionMsec = -1; 382 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0) 383 && (OK == mPlayer->getDuration(&durationMsec)) 384 && (OK == mPlayer->getCurrentPosition(&positionMsec))) { 385 if ((-1 != durationMsec) && (-1 != positionMsec)) { 386 // evaluate prefetch status based on buffer time thresholds 387 int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec; 388 CacheStatus_t newCacheStatus = mCacheStatus; 389 if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) { 390 newCacheStatus = kStatusHigh; 391 } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) { 392 newCacheStatus = kStatusEnough; 393 } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) { 394 newCacheStatus = kStatusIntermediate; 395 } else if (bufferedDurationMsec == 0) { 396 newCacheStatus = kStatusEmpty; 397 } else { 398 newCacheStatus = kStatusLow; 399 } 400 401 if (newCacheStatus != mCacheStatus) { 402 mCacheStatus = newCacheStatus; 403 notifyStatus(); 404 } 405 } 406 } 407 } else { 408 SL_LOGV("GenericMediaPlayer::onBufferingUpdate(fillLevel=unknown)"); 409 } 410} 411 412 413void GenericMediaPlayer::onGetMediaPlayerInfo() { 414 SL_LOGD("GenericMediaPlayer::onGetMediaPlayerInfo()"); 415 { 416 android::Mutex::Autolock autoLock(mGetMediaPlayerInfoLock); 417 418 if ((!(mStateFlags & kFlagPrepared)) || (mPlayer == 0)) { 419 mPositionMsec = ANDROID_UNKNOWN_TIME; 420 } else { 421 mPlayer->getCurrentPosition(&mPositionMsec); 422 } 423 424 // the MediaPlayer info has been refreshed 425 mGetMediaPlayerInfoGenCount++; 426 // there might be multiple requests for MediaPlayer info, so use broadcast instead of signal 427 mGetMediaPlayerInfoCondition.broadcast(); 428 } 429} 430 431 432//-------------------------------------------------- 433/** 434 * called from the event handling loop after the MediaPlayer mPlayer is prepared 435 * pre-conditions: 436 * mPlayer != 0 437 * mPlayer is prepared 438 */ 439void GenericMediaPlayer::onAfterMediaPlayerPrepared() { 440 SL_LOGV("GenericMediaPlayer::onAfterMediaPlayerPrepared()"); 441 assert(mPlayer != 0); 442 // retrieve channel count 443 assert(UNKNOWN_NUMCHANNELS == mChannelCount); 444 Parcel *reply = new Parcel(); 445 status_t status = mPlayer->getParameter(KEY_PARAMETER_AUDIO_CHANNEL_COUNT, reply); 446 if (status == NO_ERROR) { 447 mChannelCount = reply->readInt32(); 448 if (UNKNOWN_NUMCHANNELS != mChannelCount) { 449 // now that we know the channel count, re-calculate the volumes 450 notify(PLAYEREVENT_CHANNEL_COUNT, mChannelCount, true /*async*/); 451 } else { 452 LOGW("channel count is still unknown after prepare"); 453 } 454 } 455 delete reply; 456 // retrieve duration 457 { 458 Mutex::Autolock _l(mSettingsLock); 459 int msec = 0; 460 if (OK == mPlayer->getDuration(&msec)) { 461 mDurationMsec = msec; 462 } 463 } 464 // now that we have a MediaPlayer, set the looping flag 465 if (mStateFlags & kFlagLooping) { 466 (void) mPlayer->setLooping(1); 467 } 468 // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers 469 // if the data source was local, and the buffers are considered full so we need to notify that 470 bool isLocalSource = true; 471 if (kDataLocatorUri == mDataLocatorType) { 472 for (unsigned int i = 0 ; i < NB_DISTANT_PROTOCOLS ; i++) { 473 if (!strncasecmp(mDataLocator.uriRef, 474 kDistantProtocolPrefix[i], strlen(kDistantProtocolPrefix[i]))) { 475 isLocalSource = false; 476 break; 477 } 478 } 479 } 480 if (isLocalSource) { 481 SL_LOGD("media player prepared on local source"); 482 { 483 Mutex::Autolock _l(mSettingsLock); 484 mCacheStatus = kStatusHigh; 485 mCacheFill = 1000; 486 notifyStatus(); 487 notifyCacheFill(); 488 } 489 } else { 490 SL_LOGD("media player prepared on non-local source"); 491 } 492} 493 494} // namespace android 495