android_GenericMediaPlayer.cpp revision 49935c51fddcd0caa0030e2aac0c3a7ba3339e3d
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
42}
43
44MediaPlayerNotificationClient::~MediaPlayerNotificationClient() {
45
46}
47
48//--------------------------------------------------
49// IMediaPlayerClient implementation
50void MediaPlayerNotificationClient::notify(int msg, int ext1, int ext2, const Parcel *obj) {
51    SL_LOGV("MediaPlayerNotificationClient::notify(msg=%d, ext1=%d, ext2=%d)", msg, ext1, ext2);
52
53    switch (msg) {
54      case MEDIA_PREPARED:
55        mPlayerPrepared = PREPARE_COMPLETED_SUCCESSFULLY;
56        mPlayerPreparedCondition.signal();
57        break;
58
59      case MEDIA_SET_VIDEO_SIZE:
60        // only send video size updates if the player was flagged as having video, to avoid
61        // sending video size updates of (0,0)
62        if (mGenericMediaPlayer->mHasVideo) {
63            mGenericMediaPlayer->notify(PLAYEREVENT_VIDEO_SIZE_UPDATE,
64                    (int32_t)ext1, (int32_t)ext2, true /*async*/);
65        }
66        break;
67
68      case MEDIA_SEEK_COMPLETE:
69          mGenericMediaPlayer->seekComplete();
70        break;
71
72      case MEDIA_PLAYBACK_COMPLETE:
73        mGenericMediaPlayer->notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/);
74        break;
75
76      case MEDIA_BUFFERING_UPDATE:
77        // values received from Android framework for buffer fill level use percent,
78        //   while SL/XA use permille, so does GenericPlayer
79        mGenericMediaPlayer->bufferingUpdate(ext1 * 10 /*fillLevelPerMille*/);
80        break;
81
82      case MEDIA_ERROR:
83        mPlayerPrepared = PREPARE_COMPLETED_UNSUCCESSFULLY;
84        mPlayerPreparedCondition.signal();
85        break;
86
87      case MEDIA_NOP:
88      case MEDIA_TIMED_TEXT:
89      case MEDIA_INFO:
90        break;
91
92      default: { }
93    }
94
95}
96
97//--------------------------------------------------
98void MediaPlayerNotificationClient::beforePrepare()
99{
100    Mutex::Autolock _l(mLock);
101    assert(mPlayerPrepared == PREPARE_NOT_STARTED);
102    mPlayerPrepared = PREPARE_IN_PROGRESS;
103}
104
105//--------------------------------------------------
106bool MediaPlayerNotificationClient::blockUntilPlayerPrepared() {
107    Mutex::Autolock _l(mLock);
108    assert(mPlayerPrepared != PREPARE_NOT_STARTED);
109    while (mPlayerPrepared == PREPARE_IN_PROGRESS) {
110        mPlayerPreparedCondition.wait(mLock);
111    }
112    assert(mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY ||
113            mPlayerPrepared == PREPARE_COMPLETED_UNSUCCESSFULLY);
114    return mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY;
115}
116
117//--------------------------------------------------------------------------------------------------
118GenericMediaPlayer::GenericMediaPlayer(const AudioPlayback_Parameters* params, bool hasVideo) :
119    GenericPlayer(params),
120    mHasVideo(hasVideo),
121    mSeekTimeMsec(0),
122    mVideoSurface(0),
123    mVideoSurfaceTexture(0),
124    mPlayer(0),
125    mPlayerClient(0),
126    mGetMediaPlayerInfoGenCount(0)
127{
128    SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()");
129
130    mServiceManager = defaultServiceManager();
131    mBinder = mServiceManager->getService(String16("media.player"));
132    mMediaPlayerService = interface_cast<IMediaPlayerService>(mBinder);
133
134    CHECK(mMediaPlayerService.get() != NULL);
135
136    mPlayerClient = new MediaPlayerNotificationClient(this);
137}
138
139GenericMediaPlayer::~GenericMediaPlayer() {
140    SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()");
141}
142
143void GenericMediaPlayer::preDestroy() {
144    SL_LOGD("GenericMediaPlayer::preDestroy()");
145    // we might be in the middle of blocking for a getXXX call
146    {
147        android::Mutex::Autolock autoLock(mGetMediaPlayerInfoLock);
148        mGetMediaPlayerInfoGenCount++;
149        mGetMediaPlayerInfoCondition.broadcast();
150    }
151    GenericPlayer::preDestroy();
152}
153
154//--------------------------------------------------
155// overridden from GenericPlayer
156// pre-condition:
157//   msec != NULL
158// post-condition
159//   *msec == mPositionMsec ==
160//                  ANDROID_UNKNOWN_TIME if position is unknown at time of query,
161//               or the current MediaPlayer position
162void GenericMediaPlayer::getPositionMsec(int* msec) {
163    SL_LOGD("GenericMediaPlayer::getPositionMsec()");
164    uint32_t currentGen = 0;
165    {
166        android::Mutex::Autolock autoLock(mGetMediaPlayerInfoLock);
167        currentGen = mGetMediaPlayerInfoGenCount;
168    }
169    // send a message to update the MediaPlayer position in the event loop where it's safe to
170    //   access the MediaPlayer. We block until the message kWhatMediaPlayerInfo has been processed
171    (new AMessage(kWhatMediaPlayerInfo, id()))->post();
172    {
173        android::Mutex::Autolock autoLock(mGetMediaPlayerInfoLock);
174        // mGetMediaPlayerInfoGenCount will be incremented when the kWhatMediaPlayerInfo
175        //  gets processed.
176        while (currentGen == mGetMediaPlayerInfoGenCount) {
177            mGetMediaPlayerInfoCondition.wait(mGetMediaPlayerInfoLock);
178            // if multiple GetPosition calls were issued before any got processed on the event queue
179            // then they will all return the same "recent-enough" position
180        }
181        // at this point mPositionMsec has been updated
182        // so now updates msec from mPositionMsec, while holding the lock protecting it
183        GenericPlayer::getPositionMsec(msec);
184    }
185}
186
187//--------------------------------------------------
188void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) {
189    mVideoSurface = surface;
190}
191
192void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
193    mVideoSurfaceTexture = surfaceTexture;
194}
195
196//--------------------------------------------------
197void GenericMediaPlayer::onMessageReceived(const sp<AMessage> &msg) {
198    switch (msg->what()) {
199        case kWhatMediaPlayerInfo:
200            onGetMediaPlayerInfo();
201            break;
202
203        default:
204            GenericPlayer::onMessageReceived(msg);
205            break;
206    }
207}
208
209//--------------------------------------------------
210// Event handlers
211
212void GenericMediaPlayer::onPrepare() {
213    SL_LOGD("GenericMediaPlayer::onPrepare()");
214    // Attempt to prepare at most once, and only if there is a MediaPlayer
215    if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) {
216        if (mHasVideo) {
217            if (mVideoSurface != 0) {
218                mPlayer->setVideoSurface(mVideoSurface);
219            } else if (mVideoSurfaceTexture != 0) {
220                mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture);
221            }
222        }
223        mPlayer->setAudioStreamType(mPlaybackParams.streamType);
224        mPlayerClient->beforePrepare();
225        mPlayer->prepareAsync();
226        mStateFlags |= mPlayerClient->blockUntilPlayerPrepared() ?
227                kFlagPrepared : kFlagPreparedUnsuccessfully;
228        onAfterMediaPlayerPrepared();
229        GenericPlayer::onPrepare();
230    }
231    SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags);
232}
233
234
235void GenericMediaPlayer::onPlay() {
236    SL_LOGD("GenericMediaPlayer::onPlay()");
237    if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
238        SL_LOGD("starting player");
239        mPlayer->start();
240        mStateFlags |= kFlagPlaying;
241    } else {
242        SL_LOGV("NOT starting player mStateFlags=0x%x", mStateFlags);
243    }
244}
245
246
247void GenericMediaPlayer::onPause() {
248    SL_LOGD("GenericMediaPlayer::onPause()");
249    if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
250        mPlayer->pause();
251        mStateFlags &= ~kFlagPlaying;
252    }
253}
254
255/**
256 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0
257 */
258void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) {
259    SL_LOGV("GenericMediaPlayer::onSeek");
260    int64_t timeMsec = ANDROID_UNKNOWN_TIME;
261    if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) {
262        // invalid command, drop it
263        return;
264    }
265    if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec)) {
266        // already seeking to the same time, cancel this command
267        return;
268    } else if (mStateFlags & kFlagPreparedUnsuccessfully) {
269        // discard seeks after unsuccessful prepare
270    } else if (!(mStateFlags & kFlagPrepared)) {
271        // we are not ready to accept a seek command at this time, retry later
272        msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US);
273    } else {
274        if (msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec) && (mPlayer != 0)) {
275            mStateFlags |= kFlagSeeking;
276            mSeekTimeMsec = (int32_t)timeMsec;
277            if (OK != mPlayer->seekTo(timeMsec)) {
278                mStateFlags &= ~kFlagSeeking;
279                mSeekTimeMsec = ANDROID_UNKNOWN_TIME;
280            } else {
281                mPositionMsec = mSeekTimeMsec;
282            }
283        }
284    }
285}
286
287
288void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) {
289    SL_LOGV("GenericMediaPlayer::onLoop");
290    int32_t loop = 0;
291    if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) {
292        if (mPlayer != 0 && OK == mPlayer->setLooping(loop)) {
293            if (loop) {
294                mStateFlags |= kFlagLooping;
295            } else {
296                mStateFlags &= ~kFlagLooping;
297            }
298        }
299    }
300}
301
302
303void GenericMediaPlayer::onVolumeUpdate() {
304    SL_LOGD("GenericMediaPlayer::onVolumeUpdate()");
305    // use settings lock to read the volume settings
306    Mutex::Autolock _l(mSettingsLock);
307    if (mPlayer != 0) {
308        if (mAndroidAudioLevels.mMute) {
309            mPlayer->setVolume(0.0f, 0.0f);
310        } else {
311            mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0],
312                    mAndroidAudioLevels.mFinalVolume[1]);
313        }
314    }
315}
316
317
318void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) {
319    int32_t fillLevel = 0;
320    if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) {
321        SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel);
322
323        Mutex::Autolock _l(mSettingsLock);
324        mCacheFill = fillLevel;
325        // handle cache fill update
326        if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) {
327            notifyCacheFill();
328        }
329        // handle prefetch status update
330        //   compute how much time ahead of position is buffered
331        int durationMsec, positionMsec = -1;
332        if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)
333                && (OK == mPlayer->getDuration(&durationMsec))
334                        && (OK == mPlayer->getCurrentPosition(&positionMsec))) {
335            if ((-1 != durationMsec) && (-1 != positionMsec)) {
336                // evaluate prefetch status based on buffer time thresholds
337                int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec;
338                CacheStatus_t newCacheStatus = mCacheStatus;
339                if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) {
340                    newCacheStatus = kStatusHigh;
341                } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) {
342                    newCacheStatus = kStatusEnough;
343                } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) {
344                    newCacheStatus = kStatusIntermediate;
345                } else if (bufferedDurationMsec == 0) {
346                    newCacheStatus = kStatusEmpty;
347                } else {
348                    newCacheStatus = kStatusLow;
349                }
350
351                if (newCacheStatus != mCacheStatus) {
352                    mCacheStatus = newCacheStatus;
353                    notifyStatus();
354                }
355            }
356        }
357    }
358}
359
360
361void GenericMediaPlayer::onGetMediaPlayerInfo() {
362    SL_LOGD("GenericMediaPlayer::onGetMediaPlayerInfo()");
363    {
364        android::Mutex::Autolock autoLock(mGetMediaPlayerInfoLock);
365
366        if ((!(mStateFlags & kFlagPrepared)) || (mPlayer == 0)) {
367            mPositionMsec = ANDROID_UNKNOWN_TIME;
368        } else {
369            mPlayer->getCurrentPosition(&mPositionMsec);
370        }
371
372        // the MediaPlayer info has been refreshed
373        mGetMediaPlayerInfoGenCount++;
374        // there might be multiple requests for MediaPlayer info, so use broadcast instead of signal
375        mGetMediaPlayerInfoCondition.broadcast();
376    }
377}
378
379
380//--------------------------------------------------
381/**
382 * called from the event handling loop
383 * pre-condition: mPlayer is prepared
384 */
385void GenericMediaPlayer::onAfterMediaPlayerPrepared() {
386    // the MediaPlayer mPlayer is prepared, retrieve its duration
387    // FIXME retrieve channel count
388    {
389        Mutex::Autolock _l(mSettingsLock);
390        int msec = 0;
391        if (OK == mPlayer->getDuration(&msec)) {
392            mDurationMsec = msec;
393        }
394    }
395    // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers
396    // if the data source was local, and the buffers are considered full so we need to notify that
397    bool isLocalSource = true;
398    if (kDataLocatorUri == mDataLocatorType) {
399        for (unsigned int i = 0 ; i < NB_DISTANT_PROTOCOLS ; i++) {
400            if (!strncasecmp(mDataLocator.uriRef,
401                    kDistantProtocolPrefix[i], strlen(kDistantProtocolPrefix[i]))) {
402                isLocalSource = false;
403                break;
404            }
405        }
406    }
407    if (isLocalSource) {
408        SL_LOGD("media player prepared on local source");
409        {
410            Mutex::Autolock _l(mSettingsLock);
411            mCacheStatus = kStatusHigh;
412            mCacheFill = 1000;
413            notifyStatus();
414            notifyCacheFill();
415        }
416    } else {
417        SL_LOGD("media player prepared on non-local source");
418    }
419}
420
421} // namespace android
422