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