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