android_GenericMediaPlayer.cpp revision a9f22e6f5f53e90daa779e38b22f88e4faa35c95
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 27// default delay in Us used when reposting an event when the player is not ready to accept 28// the command yet. This is for instance used when seeking on a MediaPlayer that's still preparing 29#define DEFAULT_COMMAND_DELAY_FOR_REPOST_US (100*1000) // 100ms 30 31// table of prefixes for known distant protocols; these are immediately dispatched to mediaserver 32static const char* const kDistantProtocolPrefix[] = { "http://", "https://", "rtsp://"}; 33#define NB_DISTANT_PROTOCOLS (sizeof(kDistantProtocolPrefix)/sizeof(kDistantProtocolPrefix[0])) 34 35// is the specified URI a known distant protocol? 36bool isDistantProtocol(const char *uri) 37{ 38 for (unsigned int i = 0; i < NB_DISTANT_PROTOCOLS; i++) { 39 if (!strncasecmp(uri, kDistantProtocolPrefix[i], strlen(kDistantProtocolPrefix[i]))) { 40 return true; 41 } 42 } 43 return false; 44} 45 46namespace android { 47 48//-------------------------------------------------------------------------------------------------- 49MediaPlayerNotificationClient::MediaPlayerNotificationClient(GenericMediaPlayer* gmp) : 50 mGenericMediaPlayer(gmp), 51 mPlayerPrepared(PREPARE_NOT_STARTED) 52{ 53 SL_LOGV("MediaPlayerNotificationClient::MediaPlayerNotificationClient()"); 54} 55 56MediaPlayerNotificationClient::~MediaPlayerNotificationClient() { 57 SL_LOGV("MediaPlayerNotificationClient::~MediaPlayerNotificationClient()"); 58} 59 60// Map a MEDIA_* enum to a string 61static const char *media_to_string(int msg) 62{ 63 switch (msg) { 64#define _(x) case MEDIA_##x: return "MEDIA_" #x; 65 _(PREPARED) 66 _(SET_VIDEO_SIZE) 67 _(SEEK_COMPLETE) 68 _(PLAYBACK_COMPLETE) 69 _(BUFFERING_UPDATE) 70 _(ERROR) 71 _(NOP) 72 _(TIMED_TEXT) 73 _(INFO) 74#undef _ 75 default: 76 return NULL; 77 } 78} 79 80//-------------------------------------------------- 81// IMediaPlayerClient implementation 82void MediaPlayerNotificationClient::notify(int msg, int ext1, int ext2, const Parcel *obj) { 83 SL_LOGV("MediaPlayerNotificationClient::notify(msg=%s (%d), ext1=%d, ext2=%d)", 84 media_to_string(msg), msg, ext1, ext2); 85 86 switch (msg) { 87 case MEDIA_PREPARED: 88 mPlayerPrepared = PREPARE_COMPLETED_SUCCESSFULLY; 89 mPlayerPreparedCondition.signal(); 90 break; 91 92 case MEDIA_SET_VIDEO_SIZE: 93 // only send video size updates if the player was flagged as having video, to avoid 94 // sending video size updates of (0,0) 95 if (mGenericMediaPlayer->mHasVideo) { 96 mGenericMediaPlayer->notify(PLAYEREVENT_VIDEO_SIZE_UPDATE, 97 (int32_t)ext1, (int32_t)ext2, true /*async*/); 98 } 99 break; 100 101 case MEDIA_SEEK_COMPLETE: 102 mGenericMediaPlayer->seekComplete(); 103 break; 104 105 case MEDIA_PLAYBACK_COMPLETE: 106 mGenericMediaPlayer->notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/); 107 break; 108 109 case MEDIA_BUFFERING_UPDATE: 110 // values received from Android framework for buffer fill level use percent, 111 // while SL/XA use permille, so does GenericPlayer 112 mGenericMediaPlayer->bufferingUpdate(ext1 * 10 /*fillLevelPerMille*/); 113 break; 114 115 case MEDIA_ERROR: 116 mPlayerPrepared = PREPARE_COMPLETED_UNSUCCESSFULLY; 117 mPlayerPreparedCondition.signal(); 118 break; 119 120 case MEDIA_NOP: 121 case MEDIA_TIMED_TEXT: 122 case MEDIA_INFO: 123 break; 124 125 default: { } 126 } 127 128} 129 130//-------------------------------------------------- 131void MediaPlayerNotificationClient::beforePrepare() 132{ 133 Mutex::Autolock _l(mLock); 134 assert(mPlayerPrepared == PREPARE_NOT_STARTED); 135 mPlayerPrepared = PREPARE_IN_PROGRESS; 136} 137 138//-------------------------------------------------- 139bool MediaPlayerNotificationClient::blockUntilPlayerPrepared() { 140 Mutex::Autolock _l(mLock); 141 assert(mPlayerPrepared != PREPARE_NOT_STARTED); 142 while (mPlayerPrepared == PREPARE_IN_PROGRESS) { 143 mPlayerPreparedCondition.wait(mLock); 144 } 145 assert(mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY || 146 mPlayerPrepared == PREPARE_COMPLETED_UNSUCCESSFULLY); 147 return mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY; 148} 149 150//-------------------------------------------------------------------------------------------------- 151GenericMediaPlayer::GenericMediaPlayer(const AudioPlayback_Parameters* params, bool hasVideo) : 152 GenericPlayer(params), 153 mHasVideo(hasVideo), 154 mSeekTimeMsec(0), 155 mVideoSurface(0), 156 mVideoSurfaceTexture(0), 157 mPlayer(0), 158 mPlayerClient(0) 159{ 160 SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()"); 161 162 mPlayerClient = new MediaPlayerNotificationClient(this); 163} 164 165GenericMediaPlayer::~GenericMediaPlayer() { 166 SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()"); 167} 168 169void GenericMediaPlayer::preDestroy() { 170 SL_LOGD("GenericMediaPlayer::preDestroy()"); 171 if (mPlayer != 0) { 172 mPlayer->stop(); 173 } 174 GenericPlayer::preDestroy(); 175} 176 177//-------------------------------------------------- 178// overridden from GenericPlayer 179// pre-condition: 180// msec != NULL 181// post-condition 182// *msec == 183// ANDROID_UNKNOWN_TIME if position is unknown at time of query, 184// or the current MediaPlayer position 185void GenericMediaPlayer::getPositionMsec(int* msec) { 186 SL_LOGD("GenericMediaPlayer::getPositionMsec()"); 187 sp<IMediaPlayer> player; 188 getPlayerPrepared(player); 189 // To avoid deadlock, directly call the MediaPlayer object 190 if (player == 0 || player->getCurrentPosition(msec) != NO_ERROR) { 191 *msec = ANDROID_UNKNOWN_TIME; 192 } 193} 194 195//-------------------------------------------------- 196void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) { 197 SL_LOGV("GenericMediaPlayer::setVideoSurface()"); 198 // FIXME bug - race condition, should do in looper 199 if (mVideoSurface.get() == surface.get()) { 200 return; 201 } 202 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) { 203 mPlayer->setVideoSurface(surface); 204 } 205 mVideoSurface = surface; 206 mVideoSurfaceTexture = NULL; 207} 208 209void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) { 210 SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()"); 211 // FIXME bug - race condition, should do in looper 212 if (mVideoSurfaceTexture.get() == surfaceTexture.get()) { 213 return; 214 } 215 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) { 216 mPlayer->setVideoSurfaceTexture(surfaceTexture); 217 } 218 mVideoSurfaceTexture = surfaceTexture; 219 mVideoSurface = NULL; 220} 221 222 223//-------------------------------------------------- 224// Event handlers 225 226// blocks until mPlayer is prepared 227void GenericMediaPlayer::onPrepare() { 228 SL_LOGD("GenericMediaPlayer::onPrepare()"); 229 // Attempt to prepare at most once, and only if there is a MediaPlayer 230 if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) { 231 if (mHasVideo) { 232 if (mVideoSurface != 0) { 233 mPlayer->setVideoSurface(mVideoSurface); 234 } else if (mVideoSurfaceTexture != 0) { 235 mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture); 236 } 237 } 238 mPlayer->setAudioStreamType(mPlaybackParams.streamType); 239 mPlayerClient->beforePrepare(); 240 mPlayer->prepareAsync(); 241 if (mPlayerClient->blockUntilPlayerPrepared()) { 242 mStateFlags |= kFlagPrepared; 243 afterMediaPlayerPreparedSuccessfully(); 244 } else { 245 mStateFlags |= kFlagPreparedUnsuccessfully; 246 } 247 } 248 GenericPlayer::onPrepare(); 249 SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags); 250} 251 252 253void GenericMediaPlayer::onPlay() { 254 SL_LOGD("GenericMediaPlayer::onPlay()"); 255 if (((mStateFlags & (kFlagPrepared | kFlagPlaying)) == kFlagPrepared) && (mPlayer != 0)) { 256 mPlayer->start(); 257 } 258 GenericPlayer::onPlay(); 259} 260 261 262void GenericMediaPlayer::onPause() { 263 SL_LOGD("GenericMediaPlayer::onPause()"); 264 if (!(~mStateFlags & (kFlagPrepared | kFlagPlaying)) && (mPlayer != 0)) { 265 mPlayer->pause(); 266 } 267 GenericPlayer::onPause(); 268} 269 270 271void GenericMediaPlayer::onSeekComplete() { 272 SL_LOGV("GenericMediaPlayer::onSeekComplete()"); 273 // did we initiate the seek? 274 if (!(mStateFlags & kFlagSeeking)) { 275 // no, are we looping? 276 if (mStateFlags & kFlagLooping) { 277 // yes, per OpenSL ES 1.0.1 and 1.1 do NOT report it to client 278 // notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/); 279 // no, well that's surprising, but it's probably just a benign race condition 280 } else { 281 SL_LOGW("Unexpected seek complete event ignored"); 282 } 283 } 284 GenericPlayer::onSeekComplete(); 285} 286 287 288/** 289 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0 290 */ 291void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) { 292 SL_LOGV("GenericMediaPlayer::onSeek"); 293 int64_t timeMsec = ANDROID_UNKNOWN_TIME; 294 if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) { 295 // invalid command, drop it 296 return; 297 } 298 if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec) && 299 (timeMsec != ANDROID_UNKNOWN_TIME)) { 300 // already seeking to the same non-unknown time, cancel this command 301 return; 302 } else if (mStateFlags & kFlagPreparedUnsuccessfully) { 303 // discard seeks after unsuccessful prepare 304 } else if (!(mStateFlags & kFlagPrepared)) { 305 // we are not ready to accept a seek command at this time, retry later 306 msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US); 307 } else { 308 if (msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec) && (mPlayer != 0)) { 309 mStateFlags |= kFlagSeeking; 310 mSeekTimeMsec = (int32_t)timeMsec; 311 // seek to unknown time is used by StreamPlayer after discontinuity 312 if (timeMsec == ANDROID_UNKNOWN_TIME) { 313 // FIXME simulate a MEDIA_SEEK_COMPLETE event in 250 ms; 314 // this is a terrible hack to make up for mediaserver not sending one 315 (new AMessage(kWhatSeekComplete, id()))->post(250000); 316 } else if (OK != mPlayer->seekTo(timeMsec)) { 317 mStateFlags &= ~kFlagSeeking; 318 mSeekTimeMsec = ANDROID_UNKNOWN_TIME; 319 } 320 } 321 } 322} 323 324 325void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) { 326 SL_LOGV("GenericMediaPlayer::onLoop"); 327 int32_t loop = 0; 328 if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) { 329 if (loop) { 330 mStateFlags |= kFlagLooping; 331 } else { 332 mStateFlags &= ~kFlagLooping; 333 } 334 // if we have a MediaPlayer then tell it now, otherwise we'll tell it after it's created 335 if (mPlayer != 0) { 336 (void) mPlayer->setLooping(loop); 337 } 338 } 339} 340 341 342void GenericMediaPlayer::onVolumeUpdate() { 343 SL_LOGD("GenericMediaPlayer::onVolumeUpdate()"); 344 // use settings lock to read the volume settings 345 Mutex::Autolock _l(mSettingsLock); 346 if (mPlayer != 0) { 347 mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0], 348 mAndroidAudioLevels.mFinalVolume[1]); 349 } 350} 351 352 353void GenericMediaPlayer::onAttachAuxEffect(const sp<AMessage> &msg) { 354 SL_LOGD("GenericMediaPlayer::onAttachAuxEffect()"); 355 int32_t effectId = 0; 356 if (msg->findInt32(WHATPARAM_ATTACHAUXEFFECT, &effectId)) { 357 if (mPlayer != 0) { 358 status_t status; 359 status = mPlayer->attachAuxEffect(effectId); 360 // attachAuxEffect returns a status but we have no way to report it back to app 361 (void) status; 362 } 363 } 364} 365 366 367void GenericMediaPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) { 368 SL_LOGD("GenericMediaPlayer::onSetAuxEffectSendLevel()"); 369 float level = 0.0f; 370 if (msg->findFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, &level)) { 371 if (mPlayer != 0) { 372 status_t status; 373 status = mPlayer->setAuxEffectSendLevel(level); 374 // setAuxEffectSendLevel returns a status but we have no way to report it back to app 375 (void) status; 376 } 377 } 378} 379 380 381void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) { 382 int32_t fillLevel = 0; 383 if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) { 384 SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel); 385 386 Mutex::Autolock _l(mSettingsLock); 387 mCacheFill = fillLevel; 388 // handle cache fill update 389 if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) { 390 notifyCacheFill(); 391 } 392 // handle prefetch status update 393 // compute how much time ahead of position is buffered 394 int durationMsec, positionMsec = -1; 395 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0) 396 && (OK == mPlayer->getDuration(&durationMsec)) 397 && (OK == mPlayer->getCurrentPosition(&positionMsec))) { 398 if ((-1 != durationMsec) && (-1 != positionMsec)) { 399 // evaluate prefetch status based on buffer time thresholds 400 int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec; 401 CacheStatus_t newCacheStatus = mCacheStatus; 402 if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) { 403 newCacheStatus = kStatusHigh; 404 } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) { 405 newCacheStatus = kStatusEnough; 406 } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) { 407 newCacheStatus = kStatusIntermediate; 408 } else if (bufferedDurationMsec == 0) { 409 newCacheStatus = kStatusEmpty; 410 } else { 411 newCacheStatus = kStatusLow; 412 } 413 414 if (newCacheStatus != mCacheStatus) { 415 mCacheStatus = newCacheStatus; 416 notifyStatus(); 417 } 418 } 419 } 420 } else { 421 SL_LOGV("GenericMediaPlayer::onBufferingUpdate(fillLevel=unknown)"); 422 } 423} 424 425 426//-------------------------------------------------- 427/** 428 * called from GenericMediaPlayer::onPrepare after the MediaPlayer mPlayer is prepared successfully 429 * pre-conditions: 430 * mPlayer != 0 431 * mPlayer is prepared successfully 432 */ 433void GenericMediaPlayer::afterMediaPlayerPreparedSuccessfully() { 434 SL_LOGV("GenericMediaPlayer::afterMediaPlayerPrepared()"); 435 assert(mPlayer != 0); 436 assert(mStateFlags & kFlagPrepared); 437 // Mark this player as prepared successfully, so safe to directly call getCurrentPosition 438 { 439 Mutex::Autolock _l(mPlayerPreparedLock); 440 assert(mPlayerPrepared == 0); 441 mPlayerPrepared = mPlayer; 442 } 443 // retrieve channel count 444 assert(UNKNOWN_NUMCHANNELS == mChannelCount); 445 Parcel *reply = new Parcel(); 446 status_t status = mPlayer->getParameter(KEY_PARAMETER_AUDIO_CHANNEL_COUNT, reply); 447 if (status == NO_ERROR) { 448 mChannelCount = reply->readInt32(); 449 } else { 450 // FIXME MPEG-2 TS doesn't yet implement this key, so default to stereo 451 mChannelCount = 2; 452 } 453 if (UNKNOWN_NUMCHANNELS != mChannelCount) { 454 // now that we know the channel count, re-calculate the volumes 455 notify(PLAYEREVENT_CHANNEL_COUNT, mChannelCount, true /*async*/); 456 } else { 457 LOGW("channel count is still unknown after prepare"); 458 } 459 delete reply; 460 // retrieve duration 461 { 462 Mutex::Autolock _l(mSettingsLock); 463 int msec = 0; 464 if (OK == mPlayer->getDuration(&msec)) { 465 mDurationMsec = msec; 466 } 467 } 468 // now that we have a MediaPlayer, set the looping flag 469 if (mStateFlags & kFlagLooping) { 470 (void) mPlayer->setLooping(1); 471 } 472 // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers 473 // if the data source was local, and the buffers are considered full so we need to notify that 474 bool isLocalSource = true; 475 if (kDataLocatorUri == mDataLocatorType) { 476 isLocalSource = !isDistantProtocol(mDataLocator.uriRef); 477 } 478 if (isLocalSource) { 479 SL_LOGD("media player prepared on local source"); 480 { 481 Mutex::Autolock _l(mSettingsLock); 482 mCacheStatus = kStatusHigh; 483 mCacheFill = 1000; 484 notifyStatus(); 485 notifyCacheFill(); 486 } 487 } else { 488 SL_LOGD("media player prepared on non-local source"); 489 } 490} 491 492 493//-------------------------------------------------- 494// If player is prepared successfully, set output parameter to that reference, otherwise NULL 495void GenericMediaPlayer::getPlayerPrepared(sp<IMediaPlayer> &playerPrepared) 496{ 497 Mutex::Autolock _l(mPlayerPreparedLock); 498 playerPrepared = mPlayerPrepared; 499} 500 501} // namespace android 502