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