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