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