• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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<ISurfaceTexture> & surfaceTexture)299 void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
300     SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()");
301     // FIXME bug - race condition, should do in looper
302     if (mVideoSurfaceTexture.get() == surfaceTexture.get()) {
303         return;
304     }
305     if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
306         mPlayer->setVideoSurfaceTexture(surfaceTexture);
307     }
308     mVideoSurfaceTexture = surfaceTexture;
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, id()))->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