android_GenericMediaPlayer.cpp revision 2f6d462d89356cdaa77299ca27b60c5cca198d98
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{ 104 SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()"); 105 106 mServiceManager = defaultServiceManager(); 107 mBinder = mServiceManager->getService(String16("media.player")); 108 mMediaPlayerService = interface_cast<IMediaPlayerService>(mBinder); 109 110 CHECK(mMediaPlayerService.get() != NULL); 111 112 mPlayerClient = new MediaPlayerNotificationClient(this); 113} 114 115GenericMediaPlayer::~GenericMediaPlayer() { 116 SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()"); 117 118} 119 120//-------------------------------------------------- 121void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) { 122 mVideoSurface = surface; 123} 124 125void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) { 126 mVideoSurfaceTexture = surfaceTexture; 127} 128 129 130//-------------------------------------------------- 131// Event handlers 132 133void GenericMediaPlayer::onPrepare() { 134 SL_LOGD("GenericMediaPlayer::onPrepare()"); 135 if (!(mStateFlags & kFlagPrepared) && (mPlayer != 0)) { 136 if (mHasVideo) { 137 if (mVideoSurface != 0) { 138 mPlayer->setVideoSurface(mVideoSurface); 139 } else if (mVideoSurfaceTexture != 0) { 140 mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture); 141 } 142 } 143 mPlayer->setAudioStreamType(mPlaybackParams.streamType); 144 mPlayer->prepareAsync(); 145 mPlayerClient->blockUntilPlayerPrepared(); 146 onAfterMediaPlayerPrepared(); 147 GenericPlayer::onPrepare(); 148 } 149 SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags); 150} 151 152 153void GenericMediaPlayer::onPlay() { 154 SL_LOGD("GenericMediaPlayer::onPlay()"); 155 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) { 156 SL_LOGD("starting player"); 157 mPlayer->start(); 158 mStateFlags |= kFlagPlaying; 159 } else { 160 SL_LOGV("NOT starting player mStateFlags=0x%x", mStateFlags); 161 } 162} 163 164 165void GenericMediaPlayer::onPause() { 166 SL_LOGD("GenericMediaPlayer::onPause()"); 167 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) { 168 mPlayer->pause(); 169 mStateFlags &= ~kFlagPlaying; 170 } 171} 172 173/** 174 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0 175 */ 176void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) { 177 SL_LOGV("GenericMediaPlayer::onSeek"); 178 int64_t timeMsec = ANDROID_UNKNOWN_TIME; 179 if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) { 180 // invalid command, drop it 181 return; 182 } 183 if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec)) { 184 // already seeking to the same time, cancel this command 185 return; 186 } else if (!(mStateFlags & kFlagPrepared)) { 187 // we are not ready to accept a seek command at this time, retry later 188 msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US); 189 } else { 190 if (msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec) && (mPlayer != 0)) { 191 mStateFlags |= kFlagSeeking; 192 mSeekTimeMsec = (int32_t)timeMsec; 193 if (OK != mPlayer->seekTo(timeMsec)) { 194 mStateFlags &= ~kFlagSeeking; 195 mSeekTimeMsec = ANDROID_UNKNOWN_TIME; 196 } else { 197 mPositionMsec = mSeekTimeMsec; 198 } 199 } 200 } 201} 202 203 204void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) { 205 SL_LOGV("GenericMediaPlayer::onLoop"); 206 int32_t loop = 0; 207 if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) { 208 if (mPlayer != 0 && OK == mPlayer->setLooping(loop)) { 209 if (loop) { 210 mStateFlags |= kFlagLooping; 211 } else { 212 mStateFlags &= ~kFlagLooping; 213 } 214 } 215 } 216} 217 218 219void GenericMediaPlayer::onVolumeUpdate() { 220 SL_LOGD("GenericMediaPlayer::onVolumeUpdate()"); 221 // use settings lock to read the volume settings 222 Mutex::Autolock _l(mSettingsLock); 223 if (mPlayer != 0) { 224 if (mAndroidAudioLevels.mMute) { 225 mPlayer->setVolume(0.0f, 0.0f); 226 } else { 227 mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0], 228 mAndroidAudioLevels.mFinalVolume[1]); 229 } 230 } 231} 232 233 234void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) { 235 int32_t fillLevel = 0; 236 if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) { 237 SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel); 238 239 Mutex::Autolock _l(mSettingsLock); 240 mCacheFill = fillLevel; 241 // handle cache fill update 242 if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) { 243 notifyCacheFill(); 244 } 245 // handle prefetch status update 246 // compute how much time ahead of position is buffered 247 int durationMsec, positionMsec = -1; 248 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0) 249 && (OK == mPlayer->getDuration(&durationMsec)) 250 && (OK == mPlayer->getCurrentPosition(&positionMsec))) { 251 if ((-1 != durationMsec) && (-1 != positionMsec)) { 252 // evaluate prefetch status based on buffer time thresholds 253 int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec; 254 CacheStatus_t newCacheStatus = mCacheStatus; 255 if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) { 256 newCacheStatus = kStatusHigh; 257 } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) { 258 newCacheStatus = kStatusEnough; 259 } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) { 260 newCacheStatus = kStatusIntermediate; 261 } else if (bufferedDurationMsec == 0) { 262 newCacheStatus = kStatusEmpty; 263 } else { 264 newCacheStatus = kStatusLow; 265 } 266 267 if (newCacheStatus != mCacheStatus) { 268 mCacheStatus = newCacheStatus; 269 notifyStatus(); 270 } 271 } 272 } 273 } 274} 275 276 277//-------------------------------------------------- 278/** 279 * called from the event handling loop 280 * pre-condition: mPlayer is prepared 281 */ 282void GenericMediaPlayer::onAfterMediaPlayerPrepared() { 283 // the MediaPlayer mPlayer is prepared, retrieve its duration 284 // FIXME retrieve channel count 285 { 286 Mutex::Autolock _l(mSettingsLock); 287 int msec = 0; 288 if (OK == mPlayer->getDuration(&msec)) { 289 mDurationMsec = msec; 290 } 291 } 292 // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers 293 // if the data source was local, and the buffers are considered full so we need to notify that 294 bool isLocalSource = true; 295 if (kDataLocatorUri == mDataLocatorType) { 296 for (unsigned int i = 0 ; i < NB_DISTANT_PROTOCOLS ; i++) { 297 if (!strncasecmp(mDataLocator.uriRef, 298 kDistantProtocolPrefix[i], strlen(kDistantProtocolPrefix[i]))) { 299 isLocalSource = false; 300 break; 301 } 302 } 303 } 304 if (isLocalSource) { 305 SL_LOGD("media player prepared on local source"); 306 { 307 Mutex::Autolock _l(mSettingsLock); 308 mCacheStatus = kStatusHigh; 309 mCacheFill = 1000; 310 notifyStatus(); 311 notifyCacheFill(); 312 } 313 } else { 314 SL_LOGD("media player prepared on non-local source"); 315 } 316} 317 318} // namespace android 319