android_GenericMediaPlayer.cpp revision 7c40d3b78c609b2a84acd0dd6e874ab24a73f8d7
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
32static 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?
36bool 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
46namespace android {
47
48//--------------------------------------------------------------------------------------------------
49MediaPlayerNotificationClient::MediaPlayerNotificationClient(GenericMediaPlayer* gmp) :
50    mGenericMediaPlayer(gmp),
51    mPlayerPrepared(PREPARE_NOT_STARTED)
52{
53    SL_LOGV("MediaPlayerNotificationClient::MediaPlayerNotificationClient()");
54}
55
56MediaPlayerNotificationClient::~MediaPlayerNotificationClient() {
57    SL_LOGV("MediaPlayerNotificationClient::~MediaPlayerNotificationClient()");
58}
59
60// Map a MEDIA_* enum to a string
61static 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
82void 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            // FIXME Currently no mechanism to inform client of errors after preparation
140        }
141        }
142        break;
143
144      case MEDIA_NOP:
145      case MEDIA_TIMED_TEXT:
146      case MEDIA_INFO:
147        break;
148
149      default: { }
150    }
151
152}
153
154//--------------------------------------------------
155void MediaPlayerNotificationClient::beforePrepare()
156{
157    Mutex::Autolock _l(mLock);
158    assert(mPlayerPrepared == PREPARE_NOT_STARTED);
159    mPlayerPrepared = PREPARE_IN_PROGRESS;
160}
161
162//--------------------------------------------------
163bool MediaPlayerNotificationClient::blockUntilPlayerPrepared() {
164    Mutex::Autolock _l(mLock);
165    assert(mPlayerPrepared != PREPARE_NOT_STARTED);
166    while (mPlayerPrepared == PREPARE_IN_PROGRESS) {
167        mPlayerPreparedCondition.wait(mLock);
168    }
169    assert(mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY ||
170            mPlayerPrepared == PREPARE_COMPLETED_UNSUCCESSFULLY);
171    return mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY;
172}
173
174//--------------------------------------------------------------------------------------------------
175GenericMediaPlayer::GenericMediaPlayer(const AudioPlayback_Parameters* params, bool hasVideo) :
176    GenericPlayer(params),
177    mHasVideo(hasVideo),
178    mSeekTimeMsec(0),
179    mVideoSurface(0),
180    mVideoSurfaceTexture(0),
181    mPlayer(0),
182    mPlayerClient(new MediaPlayerNotificationClient(this))
183{
184    SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()");
185
186}
187
188GenericMediaPlayer::~GenericMediaPlayer() {
189    SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()");
190}
191
192void GenericMediaPlayer::preDestroy() {
193    // FIXME can't access mPlayer from outside the looper (no mutex!) so using mPreparedPlayer
194    sp<IMediaPlayer> player;
195    getPreparedPlayer(player);
196    if (player != NULL) {
197        player->stop();
198        // causes CHECK failure in Nuplayer, but commented out in the subclass preDestroy
199        // randomly causes a NPE in StagefrightPlayer, heap corruption, or app hang
200        //player->setDataSource(NULL);
201        player->setVideoSurface(NULL);
202        player->disconnect();
203        // release all references to the IMediaPlayer
204        // FIXME illegal if not on looper
205        //mPlayer.clear();
206        {
207            Mutex::Autolock _l(mPreparedPlayerLock);
208            mPreparedPlayer.clear();
209        }
210    }
211    GenericPlayer::preDestroy();
212}
213
214//--------------------------------------------------
215// overridden from GenericPlayer
216// pre-condition:
217//   msec != NULL
218// post-condition
219//   *msec ==
220//                  ANDROID_UNKNOWN_TIME if position is unknown at time of query,
221//               or the current MediaPlayer position
222void GenericMediaPlayer::getPositionMsec(int* msec) {
223    SL_LOGD("GenericMediaPlayer::getPositionMsec()");
224    sp<IMediaPlayer> player;
225    getPreparedPlayer(player);
226    // To avoid deadlock, directly call the MediaPlayer object
227    if (player == 0 || player->getCurrentPosition(msec) != NO_ERROR) {
228        *msec = ANDROID_UNKNOWN_TIME;
229    }
230}
231
232//--------------------------------------------------
233void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) {
234    SL_LOGV("GenericMediaPlayer::setVideoSurface()");
235    // FIXME bug - race condition, should do in looper
236    if (mVideoSurface.get() == surface.get()) {
237        return;
238    }
239    if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
240        mPlayer->setVideoSurface(surface);
241    }
242    mVideoSurface = surface;
243    mVideoSurfaceTexture = NULL;
244}
245
246void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
247    SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()");
248    // FIXME bug - race condition, should do in looper
249    if (mVideoSurfaceTexture.get() == surfaceTexture.get()) {
250        return;
251    }
252    if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
253        mPlayer->setVideoSurfaceTexture(surfaceTexture);
254    }
255    mVideoSurfaceTexture = surfaceTexture;
256    mVideoSurface = NULL;
257}
258
259
260//--------------------------------------------------
261// Event handlers
262
263// blocks until mPlayer is prepared
264void GenericMediaPlayer::onPrepare() {
265    SL_LOGD("GenericMediaPlayer::onPrepare()");
266    // Attempt to prepare at most once, and only if there is a MediaPlayer
267    if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) {
268        if (mHasVideo) {
269            if (mVideoSurface != 0) {
270                mPlayer->setVideoSurface(mVideoSurface);
271            } else if (mVideoSurfaceTexture != 0) {
272                mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture);
273            }
274        }
275        mPlayer->setAudioStreamType(mPlaybackParams.streamType);
276        mPlayerClient->beforePrepare();
277        mPlayer->prepareAsync();
278        if (mPlayerClient->blockUntilPlayerPrepared()) {
279            mStateFlags |= kFlagPrepared;
280            afterMediaPlayerPreparedSuccessfully();
281        } else {
282            mStateFlags |= kFlagPreparedUnsuccessfully;
283        }
284    }
285    GenericPlayer::onPrepare();
286    SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags);
287}
288
289
290void GenericMediaPlayer::onPlay() {
291    SL_LOGD("GenericMediaPlayer::onPlay()");
292    if (((mStateFlags & (kFlagPrepared | kFlagPlaying)) == kFlagPrepared) && (mPlayer != 0)) {
293        mPlayer->start();
294    }
295    GenericPlayer::onPlay();
296}
297
298
299void GenericMediaPlayer::onPause() {
300    SL_LOGD("GenericMediaPlayer::onPause()");
301    if (!(~mStateFlags & (kFlagPrepared | kFlagPlaying)) && (mPlayer != 0)) {
302        mPlayer->pause();
303    }
304    GenericPlayer::onPause();
305}
306
307
308void GenericMediaPlayer::onSeekComplete() {
309    SL_LOGV("GenericMediaPlayer::onSeekComplete()");
310    // did we initiate the seek?
311    if (!(mStateFlags & kFlagSeeking)) {
312        // no, are we looping?
313        if (mStateFlags & kFlagLooping) {
314            // yes, per OpenSL ES 1.0.1 and 1.1 do NOT report it to client
315            // notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/);
316        // no, well that's surprising, but it's probably just a benign race condition
317        } else {
318            SL_LOGW("Unexpected seek complete event ignored");
319        }
320    }
321    GenericPlayer::onSeekComplete();
322}
323
324
325/**
326 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0
327 */
328void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) {
329    SL_LOGV("GenericMediaPlayer::onSeek");
330    int64_t timeMsec = ANDROID_UNKNOWN_TIME;
331    if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) {
332        // invalid command, drop it
333        return;
334    }
335    if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec) &&
336            (timeMsec != ANDROID_UNKNOWN_TIME)) {
337        // already seeking to the same non-unknown time, cancel this command
338        return;
339    } else if (mStateFlags & kFlagPreparedUnsuccessfully) {
340        // discard seeks after unsuccessful prepare
341    } else if (!(mStateFlags & kFlagPrepared)) {
342        // we are not ready to accept a seek command at this time, retry later
343        msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US);
344    } else {
345        if (mPlayer != 0) {
346            mStateFlags |= kFlagSeeking;
347            mSeekTimeMsec = (int32_t)timeMsec;
348            // seek to unknown time is used by StreamPlayer after discontinuity
349            if (timeMsec == ANDROID_UNKNOWN_TIME) {
350                // FIXME simulate a MEDIA_SEEK_COMPLETE event in 250 ms;
351                // this is a terrible hack to make up for mediaserver not sending one
352                (new AMessage(kWhatSeekComplete, id()))->post(250000);
353            } else if (OK != mPlayer->seekTo(timeMsec)) {
354                mStateFlags &= ~kFlagSeeking;
355                mSeekTimeMsec = ANDROID_UNKNOWN_TIME;
356            }
357        }
358    }
359}
360
361
362void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) {
363    SL_LOGV("GenericMediaPlayer::onLoop");
364    int32_t loop = 0;
365    if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) {
366        if (loop) {
367            mStateFlags |= kFlagLooping;
368        } else {
369            mStateFlags &= ~kFlagLooping;
370        }
371        // if we have a MediaPlayer then tell it now, otherwise we'll tell it after it's created
372        if (mPlayer != 0) {
373            (void) mPlayer->setLooping(loop);
374        }
375    }
376}
377
378
379void GenericMediaPlayer::onVolumeUpdate() {
380    SL_LOGD("GenericMediaPlayer::onVolumeUpdate()");
381    // use settings lock to read the volume settings
382    Mutex::Autolock _l(mSettingsLock);
383    if (mPlayer != 0) {
384        mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0],
385                mAndroidAudioLevels.mFinalVolume[1]);
386    }
387}
388
389
390void GenericMediaPlayer::onAttachAuxEffect(const sp<AMessage> &msg) {
391    SL_LOGD("GenericMediaPlayer::onAttachAuxEffect()");
392    int32_t effectId = 0;
393    if (msg->findInt32(WHATPARAM_ATTACHAUXEFFECT, &effectId)) {
394        if (mPlayer != 0) {
395            status_t status;
396            status = mPlayer->attachAuxEffect(effectId);
397            // attachAuxEffect returns a status but we have no way to report it back to app
398            (void) status;
399        }
400    }
401}
402
403
404void GenericMediaPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) {
405    SL_LOGD("GenericMediaPlayer::onSetAuxEffectSendLevel()");
406    float level = 0.0f;
407    if (msg->findFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, &level)) {
408        if (mPlayer != 0) {
409            status_t status;
410            status = mPlayer->setAuxEffectSendLevel(level);
411            // setAuxEffectSendLevel returns a status but we have no way to report it back to app
412            (void) status;
413        }
414    }
415}
416
417
418void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) {
419    int32_t fillLevel = 0;
420    if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) {
421        SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel);
422
423        Mutex::Autolock _l(mSettingsLock);
424        mCacheFill = fillLevel;
425        // handle cache fill update
426        if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) {
427            notifyCacheFill();
428        }
429        // handle prefetch status update
430        //   compute how much time ahead of position is buffered
431        int durationMsec, positionMsec = -1;
432        if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)
433                && (OK == mPlayer->getDuration(&durationMsec))
434                        && (OK == mPlayer->getCurrentPosition(&positionMsec))) {
435            if ((-1 != durationMsec) && (-1 != positionMsec)) {
436                // evaluate prefetch status based on buffer time thresholds
437                int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec;
438                CacheStatus_t newCacheStatus = mCacheStatus;
439                if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) {
440                    newCacheStatus = kStatusHigh;
441                } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) {
442                    newCacheStatus = kStatusEnough;
443                } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) {
444                    newCacheStatus = kStatusIntermediate;
445                } else if (bufferedDurationMsec == 0) {
446                    newCacheStatus = kStatusEmpty;
447                } else {
448                    newCacheStatus = kStatusLow;
449                }
450
451                if (newCacheStatus != mCacheStatus) {
452                    mCacheStatus = newCacheStatus;
453                    notifyStatus();
454                }
455            }
456        }
457    } else {
458        SL_LOGV("GenericMediaPlayer::onBufferingUpdate(fillLevel=unknown)");
459    }
460}
461
462
463//--------------------------------------------------
464/**
465 * called from GenericMediaPlayer::onPrepare after the MediaPlayer mPlayer is prepared successfully
466 * pre-conditions:
467 *  mPlayer != 0
468 *  mPlayer is prepared successfully
469 */
470void GenericMediaPlayer::afterMediaPlayerPreparedSuccessfully() {
471    SL_LOGV("GenericMediaPlayer::afterMediaPlayerPrepared()");
472    assert(mPlayer != 0);
473    assert(mStateFlags & kFlagPrepared);
474    // Mark this player as prepared successfully, so safe to directly call getCurrentPosition
475    {
476        Mutex::Autolock _l(mPreparedPlayerLock);
477        assert(mPreparedPlayer == 0);
478        mPreparedPlayer = mPlayer;
479    }
480    // retrieve channel count
481    int32_t channelCount;
482    Parcel *reply = new Parcel();
483    status_t status = mPlayer->getParameter(KEY_PARAMETER_AUDIO_CHANNEL_COUNT, reply);
484    if (status == NO_ERROR) {
485        channelCount = reply->readInt32();
486    } else {
487        // FIXME MPEG-2 TS doesn't yet implement this key, so default to stereo
488        channelCount = 2;
489    }
490    if (UNKNOWN_NUMCHANNELS != channelCount) {
491        // now that we know the channel count, re-calculate the volumes
492        notify(PLAYEREVENT_CHANNEL_COUNT, channelCount, true /*async*/);
493    } else {
494        LOGW("channel count is still unknown after prepare");
495    }
496    delete reply;
497    // retrieve duration
498    {
499        Mutex::Autolock _l(mSettingsLock);
500        int msec = 0;
501        if (OK == mPlayer->getDuration(&msec)) {
502            mDurationMsec = msec;
503        }
504    }
505    // now that we have a MediaPlayer, set the looping flag
506    if (mStateFlags & kFlagLooping) {
507        (void) mPlayer->setLooping(1);
508    }
509    // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers
510    // if the data source was local, and the buffers are considered full so we need to notify that
511    bool isLocalSource = true;
512    if (kDataLocatorUri == mDataLocatorType) {
513        isLocalSource = !isDistantProtocol(mDataLocator.uriRef);
514    }
515    if (isLocalSource) {
516        SL_LOGD("media player prepared on local source");
517        {
518            Mutex::Autolock _l(mSettingsLock);
519            mCacheStatus = kStatusHigh;
520            mCacheFill = 1000;
521            notifyStatus();
522            notifyCacheFill();
523        }
524    } else {
525        SL_LOGD("media player prepared on non-local source");
526    }
527}
528
529
530//--------------------------------------------------
531// If player is prepared successfully, set output parameter to that reference, otherwise NULL
532void GenericMediaPlayer::getPreparedPlayer(sp<IMediaPlayer> &preparedPlayer)
533{
534    Mutex::Autolock _l(mPreparedPlayerLock);
535    preparedPlayer = mPreparedPlayer;
536}
537
538} // namespace android
539