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