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