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 <system/window.h>
23
24 #include <media/IMediaPlayerService.h>
25 #include <media/stagefright/foundation/ADebug.h>
26 #include <media/mediaplayer.h> // media_event_type media_error_type media_info_type
27
28 // default delay in Us used when reposting an event when the player is not ready to accept
29 // the command yet. This is for instance used when seeking on a MediaPlayer that's still preparing
30 #define DEFAULT_COMMAND_DELAY_FOR_REPOST_US (100*1000) // 100ms
31
32 // table of prefixes for known distant protocols; these are immediately dispatched to mediaserver
33 static const char* const kDistantProtocolPrefix[] = { "http://", "https://", "rtsp://"};
34 #define NB_DISTANT_PROTOCOLS (sizeof(kDistantProtocolPrefix)/sizeof(kDistantProtocolPrefix[0]))
35
36 // is the specified URI a known distant protocol?
isDistantProtocol(const char * uri)37 bool isDistantProtocol(const char *uri)
38 {
39 for (unsigned int i = 0; i < NB_DISTANT_PROTOCOLS; i++) {
40 if (!strncasecmp(uri, kDistantProtocolPrefix[i], strlen(kDistantProtocolPrefix[i]))) {
41 return true;
42 }
43 }
44 return false;
45 }
46
47 namespace android {
48
49 //--------------------------------------------------------------------------------------------------
MediaPlayerNotificationClient(GenericMediaPlayer * gmp)50 MediaPlayerNotificationClient::MediaPlayerNotificationClient(GenericMediaPlayer* gmp) :
51 mGenericMediaPlayer(gmp),
52 mPlayerPrepared(PREPARE_NOT_STARTED)
53 {
54 SL_LOGV("MediaPlayerNotificationClient::MediaPlayerNotificationClient()");
55 }
56
~MediaPlayerNotificationClient()57 MediaPlayerNotificationClient::~MediaPlayerNotificationClient() {
58 SL_LOGV("MediaPlayerNotificationClient::~MediaPlayerNotificationClient()");
59 }
60
61 // Map a media_event_type enum (the msg of an IMediaPlayerClient::notify) to a string or NULL
media_event_type_to_string(media_event_type msg)62 static const char *media_event_type_to_string(media_event_type msg)
63 {
64 switch (msg) {
65 #define _(code) case code: return #code;
66 _(MEDIA_NOP)
67 _(MEDIA_PREPARED)
68 _(MEDIA_PLAYBACK_COMPLETE)
69 _(MEDIA_BUFFERING_UPDATE)
70 _(MEDIA_SEEK_COMPLETE)
71 _(MEDIA_SET_VIDEO_SIZE)
72 _(MEDIA_TIMED_TEXT)
73 _(MEDIA_ERROR)
74 _(MEDIA_INFO)
75 #undef _
76 default:
77 return NULL;
78 }
79 }
80
81 // Map a media_error_type enum (the ext1 of a MEDIA_ERROR event) to a string or NULL
media_error_type_to_string(media_error_type err)82 static const char *media_error_type_to_string(media_error_type err)
83 {
84 switch (err) {
85 #define _(code, msg) case code: return msg;
86 _(MEDIA_ERROR_UNKNOWN, "Unknown media error")
87 _(MEDIA_ERROR_SERVER_DIED, "Server died")
88 _(MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK, "Not valid for progressive playback")
89 #undef _
90 default:
91 return NULL;
92 }
93 }
94
95 // Map a media_info_type enum (the ext1 of a MEDIA_INFO event) to a string or NULL
media_info_type_to_string(media_info_type info)96 static const char *media_info_type_to_string(media_info_type info)
97 {
98 switch (info) {
99 #define _(code, msg) case code: return msg;
100 _(MEDIA_INFO_UNKNOWN, "Unknown info")
101 _(MEDIA_INFO_VIDEO_TRACK_LAGGING, "Video track lagging")
102 _(MEDIA_INFO_BUFFERING_START, "Buffering start")
103 _(MEDIA_INFO_BUFFERING_END, "Buffering end")
104 _(MEDIA_INFO_NETWORK_BANDWIDTH, "Network bandwidth")
105 _(MEDIA_INFO_BAD_INTERLEAVING, "Bad interleaving")
106 _(MEDIA_INFO_NOT_SEEKABLE, "Not seekable")
107 _(MEDIA_INFO_METADATA_UPDATE, "Metadata update")
108 #undef _
109 default:
110 return NULL;
111 }
112 }
113
114 //--------------------------------------------------
115 // IMediaPlayerClient implementation
notify(int msg,int ext1,int ext2,const Parcel * obj)116 void MediaPlayerNotificationClient::notify(int msg, int ext1, int ext2, const Parcel *obj) {
117 (void)media_event_type_to_string; // Suppresses -Wunused-function.
118 SL_LOGV("MediaPlayerNotificationClient::notify(msg=%s (%d), ext1=%d, ext2=%d)",
119 media_event_type_to_string((enum media_event_type) msg), msg, ext1, ext2);
120
121 sp<GenericMediaPlayer> genericMediaPlayer(mGenericMediaPlayer.promote());
122 if (genericMediaPlayer == NULL) {
123 SL_LOGW("MediaPlayerNotificationClient::notify after GenericMediaPlayer destroyed");
124 return;
125 }
126
127 switch ((media_event_type) msg) {
128 case MEDIA_PREPARED:
129 {
130 Mutex::Autolock _l(mLock);
131 if (PREPARE_IN_PROGRESS == mPlayerPrepared) {
132 mPlayerPrepared = PREPARE_COMPLETED_SUCCESSFULLY;
133 mPlayerPreparedCondition.signal();
134 } else {
135 SL_LOGE("Unexpected MEDIA_PREPARED");
136 }
137 }
138 break;
139
140 case MEDIA_SET_VIDEO_SIZE:
141 // only send video size updates if the player was flagged as having video, to avoid
142 // sending video size updates of (0,0)
143 // We're running on a different thread than genericMediaPlayer's ALooper thread,
144 // so it would normally be racy to access fields within genericMediaPlayer.
145 // But in this case mHasVideo is const, so it is safe to access.
146 // Or alternatively, we could notify unconditionally and let it decide whether to handle.
147 if (genericMediaPlayer->mHasVideo && (ext1 != 0 || ext2 != 0)) {
148 genericMediaPlayer->notify(PLAYEREVENT_VIDEO_SIZE_UPDATE,
149 (int32_t)ext1 /*width*/, (int32_t)ext2 /*height*/, true /*async*/);
150 }
151 break;
152
153 case MEDIA_SEEK_COMPLETE:
154 genericMediaPlayer->seekComplete();
155 break;
156
157 case MEDIA_PLAYBACK_COMPLETE:
158 genericMediaPlayer->notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/);
159 break;
160
161 case MEDIA_BUFFERING_UPDATE:
162 // if we receive any out-of-range data, then clamp it to reduce further harm
163 if (ext1 < 0) {
164 SL_LOGE("MEDIA_BUFFERING_UPDATE %d%% < 0", ext1);
165 ext1 = 0;
166 } else if (ext1 > 100) {
167 SL_LOGE("MEDIA_BUFFERING_UPDATE %d%% > 100", ext1);
168 ext1 = 100;
169 }
170 // values received from Android framework for buffer fill level use percent,
171 // while SL/XA use permille, so does GenericPlayer
172 genericMediaPlayer->bufferingUpdate(ext1 * 10 /*fillLevelPerMille*/);
173 break;
174
175 case MEDIA_ERROR:
176 {
177 (void)media_error_type_to_string; // Suppresses -Wunused-function.
178 SL_LOGV("MediaPlayerNotificationClient::notify(msg=MEDIA_ERROR, ext1=%s (%d), ext2=%d)",
179 media_error_type_to_string((media_error_type) ext1), ext1, ext2);
180 Mutex::Autolock _l(mLock);
181 if (PREPARE_IN_PROGRESS == mPlayerPrepared) {
182 mPlayerPrepared = PREPARE_COMPLETED_UNSUCCESSFULLY;
183 mPlayerPreparedCondition.signal();
184 } else {
185 // inform client of errors after preparation
186 genericMediaPlayer->notify(PLAYEREVENT_ERRORAFTERPREPARE, ext1, true /*async*/);
187 }
188 }
189 break;
190
191 case MEDIA_NOP:
192 case MEDIA_TIMED_TEXT:
193 break;
194
195 case MEDIA_INFO:
196 (void)media_info_type_to_string; // Suppresses -Wunused-function.
197 SL_LOGV("MediaPlayerNotificationClient::notify(msg=MEDIA_INFO, ext1=%s (%d), ext2=%d)",
198 media_info_type_to_string((media_info_type) ext1), ext1, ext2);
199 switch (ext1) {
200 case MEDIA_INFO_VIDEO_TRACK_LAGGING:
201 SL_LOGV("MEDIA_INFO_VIDEO_TRACK_LAGGING by %d ms", ext1);
202 break;
203 case MEDIA_INFO_NETWORK_BANDWIDTH:
204 SL_LOGV("MEDIA_INFO_NETWORK_BANDWIDTH %d kbps", ext2);
205 break;
206 case MEDIA_INFO_UNKNOWN:
207 case MEDIA_INFO_BUFFERING_START:
208 case MEDIA_INFO_BUFFERING_END:
209 case MEDIA_INFO_BAD_INTERLEAVING:
210 case MEDIA_INFO_NOT_SEEKABLE:
211 case MEDIA_INFO_METADATA_UPDATE:
212 default:
213 break;
214 }
215 break;
216
217 default:
218 break;
219 }
220
221 }
222
223 //--------------------------------------------------
beforePrepare()224 void MediaPlayerNotificationClient::beforePrepare()
225 {
226 Mutex::Autolock _l(mLock);
227 assert(mPlayerPrepared == PREPARE_NOT_STARTED);
228 mPlayerPrepared = PREPARE_IN_PROGRESS;
229 }
230
231 //--------------------------------------------------
blockUntilPlayerPrepared()232 bool MediaPlayerNotificationClient::blockUntilPlayerPrepared() {
233 Mutex::Autolock _l(mLock);
234 assert(mPlayerPrepared != PREPARE_NOT_STARTED);
235 while (mPlayerPrepared == PREPARE_IN_PROGRESS) {
236 mPlayerPreparedCondition.wait(mLock);
237 }
238 assert(mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY ||
239 mPlayerPrepared == PREPARE_COMPLETED_UNSUCCESSFULLY);
240 return mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY;
241 }
242
243 //--------------------------------------------------------------------------------------------------
GenericMediaPlayer(const AudioPlayback_Parameters * params,bool hasVideo)244 GenericMediaPlayer::GenericMediaPlayer(const AudioPlayback_Parameters* params, bool hasVideo) :
245 GenericPlayer(params),
246 mHasVideo(hasVideo),
247 mSeekTimeMsec(0),
248 mVideoSurfaceTexture(0),
249 mPlayer(0),
250 mPlayerClient(new MediaPlayerNotificationClient(this)),
251 mPlayerDeathNotifier(new MediaPlayerDeathNotifier(mPlayerClient))
252 {
253 SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()");
254
255 }
256
~GenericMediaPlayer()257 GenericMediaPlayer::~GenericMediaPlayer() {
258 SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()");
259 }
260
preDestroy()261 void GenericMediaPlayer::preDestroy() {
262 // FIXME can't access mPlayer from outside the looper (no mutex!) so using mPreparedPlayer
263 sp<IMediaPlayer> player;
264 getPreparedPlayer(player);
265 if (player != NULL) {
266 player->stop();
267 // causes CHECK failure in Nuplayer, but commented out in the subclass preDestroy
268 // randomly causes a NPE in StagefrightPlayer, heap corruption, or app hang
269 //player->setDataSource(NULL);
270 player->setVideoSurfaceTexture(NULL);
271 player->disconnect();
272 // release all references to the IMediaPlayer
273 // FIXME illegal if not on looper
274 //mPlayer.clear();
275 {
276 Mutex::Autolock _l(mPreparedPlayerLock);
277 mPreparedPlayer.clear();
278 }
279 }
280 GenericPlayer::preDestroy();
281 }
282
283 //--------------------------------------------------
284 // overridden from GenericPlayer
285 // pre-condition:
286 // msec != NULL
287 // post-condition
288 // *msec ==
289 // ANDROID_UNKNOWN_TIME if position is unknown at time of query,
290 // or the current MediaPlayer position
getPositionMsec(int * msec)291 void GenericMediaPlayer::getPositionMsec(int* msec) {
292 SL_LOGD("GenericMediaPlayer::getPositionMsec()");
293 sp<IMediaPlayer> player;
294 getPreparedPlayer(player);
295 // To avoid deadlock, directly call the MediaPlayer object
296 if (player == 0 || player->getCurrentPosition(msec) != NO_ERROR) {
297 *msec = ANDROID_UNKNOWN_TIME;
298 }
299 }
300
301 //--------------------------------------------------
setVideoSurfaceTexture(const sp<IGraphicBufferProducer> & bufferProducer)302 void GenericMediaPlayer::setVideoSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer) {
303 SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()");
304 // FIXME bug - race condition, should do in looper
305 if (mVideoSurfaceTexture.get() == bufferProducer.get()) {
306 return;
307 }
308 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
309 mPlayer->setVideoSurfaceTexture(bufferProducer);
310 }
311 mVideoSurfaceTexture = bufferProducer;
312 }
313
314 //--------------------------------------------------
setPlaybackRate(int32_t ratePermille)315 void GenericMediaPlayer::setPlaybackRate(int32_t ratePermille) {
316 SL_LOGV("GenericMediaPlayer::setPlaybackRate(%d)", ratePermille);
317 GenericPlayer::setPlaybackRate(ratePermille);
318 sp<IMediaPlayer> player;
319 getPreparedPlayer(player);
320 if (player != 0) {
321 Parcel rateParcel;
322 if (rateParcel.writeInt32(ratePermille) == OK) {
323 player->setParameter(KEY_PARAMETER_PLAYBACK_RATE_PERMILLE, rateParcel);
324 }
325 }
326 }
327
328
329 //--------------------------------------------------
330 // Event handlers
331
332 // blocks until mPlayer is prepared
onPrepare()333 void GenericMediaPlayer::onPrepare() {
334 SL_LOGD("GenericMediaPlayer::onPrepare()");
335 // Attempt to prepare at most once, and only if there is a MediaPlayer
336 if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) {
337 if (mHasVideo) {
338 if (mVideoSurfaceTexture != 0) {
339 mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture);
340 }
341 }
342 mPlayer->setAudioStreamType(mPlaybackParams.streamType);
343 mPlayerClient->beforePrepare();
344 mPlayer->prepareAsync();
345 if (mPlayerClient->blockUntilPlayerPrepared()) {
346 mStateFlags |= kFlagPrepared;
347 afterMediaPlayerPreparedSuccessfully();
348 } else {
349 mStateFlags |= kFlagPreparedUnsuccessfully;
350 }
351 }
352 GenericPlayer::onPrepare();
353 SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags);
354 }
355
356
onPlay()357 void GenericMediaPlayer::onPlay() {
358 SL_LOGD("GenericMediaPlayer::onPlay()");
359 if (((mStateFlags & (kFlagPrepared | kFlagPlaying)) == kFlagPrepared) && (mPlayer != 0)) {
360 mPlayer->start();
361 }
362 GenericPlayer::onPlay();
363 }
364
365
onPause()366 void GenericMediaPlayer::onPause() {
367 SL_LOGD("GenericMediaPlayer::onPause()");
368 if (!(~mStateFlags & (kFlagPrepared | kFlagPlaying)) && (mPlayer != 0)) {
369 mPlayer->pause();
370 }
371 GenericPlayer::onPause();
372 }
373
374
onSeekComplete()375 void GenericMediaPlayer::onSeekComplete() {
376 SL_LOGV("GenericMediaPlayer::onSeekComplete()");
377 // did we initiate the seek?
378 if (!(mStateFlags & kFlagSeeking)) {
379 // no, are we looping?
380 if (mStateFlags & kFlagLooping) {
381 // yes, per OpenSL ES 1.0.1 and 1.1 do NOT report it to client
382 // notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/);
383 // no, well that's surprising, but it's probably just a benign race condition
384 } else {
385 SL_LOGW("Unexpected seek complete event ignored");
386 }
387 }
388 GenericPlayer::onSeekComplete();
389 }
390
391
392 /**
393 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0
394 */
onSeek(const sp<AMessage> & msg)395 void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) {
396 SL_LOGV("GenericMediaPlayer::onSeek");
397 int64_t timeMsec = ANDROID_UNKNOWN_TIME;
398 if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) {
399 // invalid command, drop it
400 return;
401 }
402 if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec) &&
403 (timeMsec != ANDROID_UNKNOWN_TIME)) {
404 // already seeking to the same non-unknown time, cancel this command
405 return;
406 } else if (mStateFlags & kFlagPreparedUnsuccessfully) {
407 // discard seeks after unsuccessful prepare
408 } else if (!(mStateFlags & kFlagPrepared)) {
409 // we are not ready to accept a seek command at this time, retry later
410 msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US);
411 } else {
412 if (mPlayer != 0) {
413 mStateFlags |= kFlagSeeking;
414 mSeekTimeMsec = (int32_t)timeMsec;
415 // seek to unknown time is used by StreamPlayer after discontinuity
416 if (timeMsec == ANDROID_UNKNOWN_TIME) {
417 // FIXME simulate a MEDIA_SEEK_COMPLETE event in 250 ms;
418 // this is a terrible hack to make up for mediaserver not sending one
419 (new AMessage(kWhatSeekComplete, this))->post(250000);
420 } else if (OK != mPlayer->seekTo(timeMsec)) {
421 mStateFlags &= ~kFlagSeeking;
422 mSeekTimeMsec = ANDROID_UNKNOWN_TIME;
423 // don't call updateOneShot because seek not yet done
424 }
425 }
426 }
427 }
428
429
onLoop(const sp<AMessage> & msg)430 void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) {
431 SL_LOGV("GenericMediaPlayer::onLoop");
432 int32_t loop = 0;
433 if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) {
434 if (loop) {
435 mStateFlags |= kFlagLooping;
436 } else {
437 mStateFlags &= ~kFlagLooping;
438 }
439 // if we have a MediaPlayer then tell it now, otherwise we'll tell it after it's created
440 if (mPlayer != 0) {
441 (void) mPlayer->setLooping(loop);
442 }
443 }
444 }
445
446
onVolumeUpdate()447 void GenericMediaPlayer::onVolumeUpdate() {
448 SL_LOGD("GenericMediaPlayer::onVolumeUpdate()");
449 if (mPlayer != 0) {
450 // use settings lock to read the volume settings
451 Mutex::Autolock _l(mSettingsLock);
452 mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0],
453 mAndroidAudioLevels.mFinalVolume[1]);
454 }
455 }
456
457
onAttachAuxEffect(const sp<AMessage> & msg)458 void GenericMediaPlayer::onAttachAuxEffect(const sp<AMessage> &msg) {
459 SL_LOGD("GenericMediaPlayer::onAttachAuxEffect()");
460 int32_t effectId = 0;
461 if (msg->findInt32(WHATPARAM_ATTACHAUXEFFECT, &effectId)) {
462 if (mPlayer != 0) {
463 status_t status;
464 status = mPlayer->attachAuxEffect(effectId);
465 // attachAuxEffect returns a status but we have no way to report it back to app
466 (void) status;
467 }
468 }
469 }
470
471
onSetAuxEffectSendLevel(const sp<AMessage> & msg)472 void GenericMediaPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) {
473 SL_LOGD("GenericMediaPlayer::onSetAuxEffectSendLevel()");
474 float level = 0.0f;
475 if (msg->findFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, &level)) {
476 if (mPlayer != 0) {
477 status_t status;
478 status = mPlayer->setAuxEffectSendLevel(level);
479 // setAuxEffectSendLevel returns a status but we have no way to report it back to app
480 (void) status;
481 }
482 }
483 }
484
485
onBufferingUpdate(const sp<AMessage> & msg)486 void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) {
487 int32_t fillLevel = 0;
488 if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) {
489 SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel);
490
491 Mutex::Autolock _l(mSettingsLock);
492 mCacheFill = fillLevel;
493 // handle cache fill update
494 if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) {
495 notifyCacheFill();
496 }
497 // handle prefetch status update
498 // compute how much time ahead of position is buffered
499 int durationMsec, positionMsec = -1;
500 if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)
501 && (OK == mPlayer->getDuration(&durationMsec))
502 && (OK == mPlayer->getCurrentPosition(&positionMsec))) {
503 if ((-1 != durationMsec) && (-1 != positionMsec)) {
504 // evaluate prefetch status based on buffer time thresholds
505 int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec;
506 CacheStatus_t newCacheStatus = mCacheStatus;
507 if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) {
508 newCacheStatus = kStatusHigh;
509 } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) {
510 newCacheStatus = kStatusEnough;
511 } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) {
512 newCacheStatus = kStatusIntermediate;
513 } else if (bufferedDurationMsec == 0) {
514 newCacheStatus = kStatusEmpty;
515 } else {
516 newCacheStatus = kStatusLow;
517 }
518
519 if (newCacheStatus != mCacheStatus) {
520 mCacheStatus = newCacheStatus;
521 notifyStatus();
522 }
523 }
524 }
525 } else {
526 SL_LOGV("GenericMediaPlayer::onBufferingUpdate(fillLevel=unknown)");
527 }
528 }
529
530
531 //--------------------------------------------------
532 /**
533 * called from GenericMediaPlayer::onPrepare after the MediaPlayer mPlayer is prepared successfully
534 * pre-conditions:
535 * mPlayer != 0
536 * mPlayer is prepared successfully
537 */
afterMediaPlayerPreparedSuccessfully()538 void GenericMediaPlayer::afterMediaPlayerPreparedSuccessfully() {
539 SL_LOGV("GenericMediaPlayer::afterMediaPlayerPrepared()");
540 assert(mPlayer != 0);
541 assert(mStateFlags & kFlagPrepared);
542 // Mark this player as prepared successfully, so safe to directly call getCurrentPosition
543 {
544 Mutex::Autolock _l(mPreparedPlayerLock);
545 assert(mPreparedPlayer == 0);
546 mPreparedPlayer = mPlayer;
547 }
548 // retrieve channel count
549 int32_t channelCount;
550 Parcel *reply = new Parcel();
551 status_t status = mPlayer->getParameter(KEY_PARAMETER_AUDIO_CHANNEL_COUNT, reply);
552 if (status == NO_ERROR) {
553 channelCount = reply->readInt32();
554 } else {
555 // FIXME MPEG-2 TS doesn't yet implement this key, so default to stereo
556 channelCount = 2;
557 }
558 if (UNKNOWN_NUMCHANNELS != channelCount) {
559 // now that we know the channel count, re-calculate the volumes
560 notify(PLAYEREVENT_CHANNEL_COUNT, channelCount, true /*async*/);
561 } else {
562 ALOGW("channel count is still unknown after prepare");
563 }
564 delete reply;
565 // retrieve duration
566 {
567 int msec = 0;
568 if (OK == mPlayer->getDuration(&msec)) {
569 Mutex::Autolock _l(mSettingsLock);
570 mDurationMsec = msec;
571 }
572 }
573 // now that we have a MediaPlayer, set the looping flag
574 if (mStateFlags & kFlagLooping) {
575 (void) mPlayer->setLooping(1);
576 }
577 // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers
578 // if the data source was local, and the buffers are considered full so we need to notify that
579 bool isLocalSource = true;
580 if (kDataLocatorUri == mDataLocatorType) {
581 isLocalSource = !isDistantProtocol(mDataLocator.uriRef);
582 }
583 if (isLocalSource) {
584 SL_LOGD("media player prepared on local source");
585 {
586 Mutex::Autolock _l(mSettingsLock);
587 mCacheStatus = kStatusHigh;
588 mCacheFill = 1000;
589 notifyStatus();
590 notifyCacheFill();
591 }
592 } else {
593 SL_LOGD("media player prepared on non-local source");
594 }
595 // when the MediaPlayer mPlayer is prepared, apply the playback rate
596 Parcel rateParcel;
597 if (rateParcel.writeInt32((int32_t)mPlaybackRatePermille) == OK) {
598 mPlayer->setParameter(KEY_PARAMETER_PLAYBACK_RATE_PERMILLE, rateParcel);
599 }
600 }
601
602
603 //--------------------------------------------------
604 // If player is prepared successfully, set output parameter to that reference, otherwise NULL
getPreparedPlayer(sp<IMediaPlayer> & preparedPlayer)605 void GenericMediaPlayer::getPreparedPlayer(sp<IMediaPlayer> &preparedPlayer)
606 {
607 Mutex::Autolock _l(mPreparedPlayerLock);
608 preparedPlayer = mPreparedPlayer;
609 }
610
611 } // namespace android
612