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