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