• 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     (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