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