android_GenericMediaPlayer.cpp revision 85edd878a30caa535b0267d8d6e61b4ccc0d5fd0
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 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 = PREPARE_COMPLETED_SUCCESSFULLY; 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 mPlayerPrepared = PREPARE_COMPLETED_UNSUCCESSFULLY; 105 mPlayerPreparedCondition.signal(); 106 break; 107 108 case MEDIA_NOP: 109 case MEDIA_TIMED_TEXT: 110 case MEDIA_INFO: 111 break; 112 113 default: { } 114 } 115 116} 117 118//-------------------------------------------------- 119void MediaPlayerNotificationClient::beforePrepare() 120{ 121 Mutex::Autolock _l(mLock); 122 assert(mPlayerPrepared == PREPARE_NOT_STARTED); 123 mPlayerPrepared = PREPARE_IN_PROGRESS; 124} 125 126//-------------------------------------------------- 127bool MediaPlayerNotificationClient::blockUntilPlayerPrepared() { 128 Mutex::Autolock _l(mLock); 129 assert(mPlayerPrepared != PREPARE_NOT_STARTED); 130 while (mPlayerPrepared == PREPARE_IN_PROGRESS) { 131 mPlayerPreparedCondition.wait(mLock); 132 } 133 assert(mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY || 134 mPlayerPrepared == PREPARE_COMPLETED_UNSUCCESSFULLY); 135 return mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY; 136} 137 138//-------------------------------------------------------------------------------------------------- 139GenericMediaPlayer::GenericMediaPlayer(const AudioPlayback_Parameters* params, bool hasVideo) : 140 GenericPlayer(params), 141 mHasVideo(hasVideo), 142 mSeekTimeMsec(0), 143 mVideoSurface(0), 144 mVideoSurfaceTexture(0), 145 mPlayer(0), 146 mPlayerClient(0) 147{ 148 SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()"); 149 150 mPlayerClient = new MediaPlayerNotificationClient(this); 151} 152 153GenericMediaPlayer::~GenericMediaPlayer() { 154 SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()"); 155} 156 157void GenericMediaPlayer::preDestroy() { 158 SL_LOGD("GenericMediaPlayer::preDestroy()"); 159 GenericPlayer::preDestroy(); 160} 161 162//-------------------------------------------------- 163// overridden from GenericPlayer 164// pre-condition: 165// msec != NULL 166// post-condition 167// *msec == 168// ANDROID_UNKNOWN_TIME if position is unknown at time of query, 169// or the current MediaPlayer position 170void GenericMediaPlayer::getPositionMsec(int* msec) { 171 SL_LOGD("GenericMediaPlayer::getPositionMsec()"); 172 sp<IMediaPlayer> player; 173 getPlayerPrepared(player); 174 // To avoid deadlock, directly call the MediaPlayer object 175 if (player == 0 || player->getCurrentPosition(msec) != NO_ERROR) { 176 *msec = ANDROID_UNKNOWN_TIME; 177 } 178} 179 180//-------------------------------------------------- 181void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) { 182 SL_LOGV("GenericMediaPlayer::setVideoSurface()"); 183 mVideoSurface = surface; 184} 185 186void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) { 187 SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()"); 188 mVideoSurfaceTexture = surfaceTexture; 189} 190 191 192//-------------------------------------------------- 193// Event handlers 194 195// blocks until mPlayer is prepared 196void GenericMediaPlayer::onPrepare() { 197 SL_LOGD("GenericMediaPlayer::onPrepare()"); 198 // Attempt to prepare at most once, and only if there is a MediaPlayer 199 if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) { 200 if (mHasVideo) { 201 if (mVideoSurface != 0) { 202 mPlayer->setVideoSurface(mVideoSurface); 203 } else if (mVideoSurfaceTexture != 0) { 204 mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture); 205 } 206 } 207 mPlayer->setAudioStreamType(mPlaybackParams.streamType); 208 mPlayerClient->beforePrepare(); 209 mPlayer->prepareAsync(); 210 if (mPlayerClient->blockUntilPlayerPrepared()) { 211 mStateFlags |= kFlagPrepared; 212 afterMediaPlayerPreparedSuccessfully(); 213 } else { 214 mStateFlags |= kFlagPreparedUnsuccessfully; 215 } 216 } 217 GenericPlayer::onPrepare(); 218 SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags); 219} 220 221 222void GenericMediaPlayer::onPlay() { 223 SL_LOGD("GenericMediaPlayer::onPlay()"); 224 if (((mStateFlags & (kFlagPrepared | kFlagPlaying)) == kFlagPrepared) && (mPlayer != 0)) { 225 mPlayer->start(); 226 } 227 GenericPlayer::onPlay(); 228} 229 230 231void GenericMediaPlayer::onPause() { 232 SL_LOGD("GenericMediaPlayer::onPause()"); 233 if (!(~mStateFlags & (kFlagPrepared | kFlagPlaying)) && (mPlayer != 0)) { 234 mPlayer->pause(); 235 } 236 GenericPlayer::onPause(); 237} 238 239 240void GenericMediaPlayer::onSeekComplete() { 241 SL_LOGV("GenericMediaPlayer::onSeekComplete()"); 242 // did we initiate the seek? 243 if (!(mStateFlags & kFlagSeeking)) { 244 // no, are we looping? 245 if (mStateFlags & kFlagLooping) { 246 // yes, per OpenSL ES 1.0.1 and 1.1 do NOT report it to client 247 // notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/); 248 // no, well that's surprising, but it's probably just a benign race condition 249 } else { 250 SL_LOGW("Unexpected seek complete event ignored"); 251 } 252 } 253 GenericPlayer::onSeekComplete(); 254} 255 256 257/** 258 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0 259 */ 260void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) { 261 SL_LOGV("GenericMediaPlayer::onSeek"); 262 int64_t timeMsec = ANDROID_UNKNOWN_TIME; 263 if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) { 264 // invalid command, drop it 265 return; 266 } 267 if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec)) { 268 // already seeking to the same time, cancel this command 269 return; 270 } else if (mStateFlags & kFlagPreparedUnsuccessfully) { 271 // discard seeks after unsuccessful prepare 272 } else if (!(mStateFlags & kFlagPrepared)) { 273 // we are not ready to accept a seek command at this time, retry later 274 msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US); 275 } else { 276 if (msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec) && (mPlayer != 0)) { 277 mStateFlags |= kFlagSeeking; 278 mSeekTimeMsec = (int32_t)timeMsec; 279 if (OK != mPlayer->seekTo(timeMsec)) { 280 mStateFlags &= ~kFlagSeeking; 281 mSeekTimeMsec = ANDROID_UNKNOWN_TIME; 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 (loop) { 293 mStateFlags |= kFlagLooping; 294 } else { 295 mStateFlags &= ~kFlagLooping; 296 } 297 // if we have a MediaPlayer then tell it now, otherwise we'll tell it after it's created 298 if (mPlayer != 0) { 299 (void) mPlayer->setLooping(loop); 300 } 301 } 302} 303 304 305void GenericMediaPlayer::onVolumeUpdate() { 306 SL_LOGD("GenericMediaPlayer::onVolumeUpdate()"); 307 // use settings lock to read the volume settings 308 Mutex::Autolock _l(mSettingsLock); 309 if (mPlayer != 0) { 310 mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0], 311 mAndroidAudioLevels.mFinalVolume[1]); 312 } 313} 314 315 316void GenericMediaPlayer::onAttachAuxEffect(const sp<AMessage> &msg) { 317 SL_LOGD("GenericMediaPlayer::onAttachAuxEffect()"); 318 int32_t effectId = 0; 319 if (msg->findInt32(WHATPARAM_ATTACHAUXEFFECT, &effectId)) { 320 if (mPlayer != 0) { 321 status_t status; 322 status = mPlayer->attachAuxEffect(effectId); 323 // attachAuxEffect returns a status but we have no way to report it back to app 324 (void) status; 325 } 326 } 327} 328 329 330void GenericMediaPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) { 331 SL_LOGD("GenericMediaPlayer::onSetAuxEffectSendLevel()"); 332 float level = 0.0f; 333 if (msg->findFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, &level)) { 334 if (mPlayer != 0) { 335 status_t status; 336 status = mPlayer->setAuxEffectSendLevel(level); 337 // setAuxEffectSendLevel returns a status but we have no way to report it back to app 338 (void) status; 339 } 340 } 341} 342 343 344void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) { 345 int32_t fillLevel = 0; 346 if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) { 347 SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel); 348 349 Mutex::Autolock _l(mSettingsLock); 350 mCacheFill = fillLevel; 351 // handle cache fill update 352 if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) { 353 notifyCacheFill(); 354 } 355 // handle prefetch status update 356 // compute how much time ahead of position is buffered 357 int durationMsec, positionMsec = -1; 358 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0) 359 && (OK == mPlayer->getDuration(&durationMsec)) 360 && (OK == mPlayer->getCurrentPosition(&positionMsec))) { 361 if ((-1 != durationMsec) && (-1 != positionMsec)) { 362 // evaluate prefetch status based on buffer time thresholds 363 int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec; 364 CacheStatus_t newCacheStatus = mCacheStatus; 365 if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) { 366 newCacheStatus = kStatusHigh; 367 } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) { 368 newCacheStatus = kStatusEnough; 369 } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) { 370 newCacheStatus = kStatusIntermediate; 371 } else if (bufferedDurationMsec == 0) { 372 newCacheStatus = kStatusEmpty; 373 } else { 374 newCacheStatus = kStatusLow; 375 } 376 377 if (newCacheStatus != mCacheStatus) { 378 mCacheStatus = newCacheStatus; 379 notifyStatus(); 380 } 381 } 382 } 383 } else { 384 SL_LOGV("GenericMediaPlayer::onBufferingUpdate(fillLevel=unknown)"); 385 } 386} 387 388 389//-------------------------------------------------- 390/** 391 * called from GenericMediaPlayer::onPrepare after the MediaPlayer mPlayer is prepared successfully 392 * pre-conditions: 393 * mPlayer != 0 394 * mPlayer is prepared successfully 395 */ 396void GenericMediaPlayer::afterMediaPlayerPreparedSuccessfully() { 397 SL_LOGV("GenericMediaPlayer::afterMediaPlayerPrepared()"); 398 assert(mPlayer != 0); 399 assert(mStateFlags & kFlagPrepared); 400 // Mark this player as prepared successfully, so safe to directly call getCurrentPosition 401 { 402 Mutex::Autolock _l(mPlayerPreparedLock); 403 assert(mPlayerPrepared == 0); 404 mPlayerPrepared = mPlayer; 405 } 406 // retrieve channel count 407 assert(UNKNOWN_NUMCHANNELS == mChannelCount); 408 Parcel *reply = new Parcel(); 409 status_t status = mPlayer->getParameter(KEY_PARAMETER_AUDIO_CHANNEL_COUNT, reply); 410 if (status == NO_ERROR) { 411 mChannelCount = reply->readInt32(); 412 } else { 413 // FIXME MPEG-2 TS doesn't yet implement this key, so default to stereo 414 mChannelCount = 2; 415 } 416 if (UNKNOWN_NUMCHANNELS != mChannelCount) { 417 // now that we know the channel count, re-calculate the volumes 418 notify(PLAYEREVENT_CHANNEL_COUNT, mChannelCount, true /*async*/); 419 } else { 420 LOGW("channel count is still unknown after prepare"); 421 } 422 delete reply; 423 // retrieve duration 424 { 425 Mutex::Autolock _l(mSettingsLock); 426 int msec = 0; 427 if (OK == mPlayer->getDuration(&msec)) { 428 mDurationMsec = msec; 429 } 430 } 431 // now that we have a MediaPlayer, set the looping flag 432 if (mStateFlags & kFlagLooping) { 433 (void) mPlayer->setLooping(1); 434 } 435 // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers 436 // if the data source was local, and the buffers are considered full so we need to notify that 437 bool isLocalSource = true; 438 if (kDataLocatorUri == mDataLocatorType) { 439 for (unsigned int i = 0 ; i < NB_DISTANT_PROTOCOLS ; i++) { 440 if (!strncasecmp(mDataLocator.uriRef, 441 kDistantProtocolPrefix[i], strlen(kDistantProtocolPrefix[i]))) { 442 isLocalSource = false; 443 break; 444 } 445 } 446 } 447 if (isLocalSource) { 448 SL_LOGD("media player prepared on local source"); 449 { 450 Mutex::Autolock _l(mSettingsLock); 451 mCacheStatus = kStatusHigh; 452 mCacheFill = 1000; 453 notifyStatus(); 454 notifyCacheFill(); 455 } 456 } else { 457 SL_LOGD("media player prepared on non-local source"); 458 } 459} 460 461 462//-------------------------------------------------- 463// If player is prepared successfully, set output parameter to that reference, otherwise NULL 464void GenericMediaPlayer::getPlayerPrepared(sp<IMediaPlayer> &playerPrepared) 465{ 466 Mutex::Autolock _l(mPlayerPreparedLock); 467 playerPrepared = mPlayerPrepared; 468} 469 470} // namespace android 471