android_GenericMediaPlayer.cpp revision 2f6d462d89356cdaa77299ca27b60c5cca198d98
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{
104    SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()");
105
106    mServiceManager = defaultServiceManager();
107    mBinder = mServiceManager->getService(String16("media.player"));
108    mMediaPlayerService = interface_cast<IMediaPlayerService>(mBinder);
109
110    CHECK(mMediaPlayerService.get() != NULL);
111
112    mPlayerClient = new MediaPlayerNotificationClient(this);
113}
114
115GenericMediaPlayer::~GenericMediaPlayer() {
116    SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()");
117
118}
119
120//--------------------------------------------------
121void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) {
122    mVideoSurface = surface;
123}
124
125void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
126    mVideoSurfaceTexture = surfaceTexture;
127}
128
129
130//--------------------------------------------------
131// Event handlers
132
133void GenericMediaPlayer::onPrepare() {
134    SL_LOGD("GenericMediaPlayer::onPrepare()");
135    if (!(mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
136        if (mHasVideo) {
137            if (mVideoSurface != 0) {
138                mPlayer->setVideoSurface(mVideoSurface);
139            } else if (mVideoSurfaceTexture != 0) {
140                mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture);
141            }
142        }
143        mPlayer->setAudioStreamType(mPlaybackParams.streamType);
144        mPlayer->prepareAsync();
145        mPlayerClient->blockUntilPlayerPrepared();
146        onAfterMediaPlayerPrepared();
147        GenericPlayer::onPrepare();
148    }
149    SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags);
150}
151
152
153void GenericMediaPlayer::onPlay() {
154    SL_LOGD("GenericMediaPlayer::onPlay()");
155    if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
156        SL_LOGD("starting player");
157        mPlayer->start();
158        mStateFlags |= kFlagPlaying;
159    } else {
160        SL_LOGV("NOT starting player mStateFlags=0x%x", mStateFlags);
161    }
162}
163
164
165void GenericMediaPlayer::onPause() {
166    SL_LOGD("GenericMediaPlayer::onPause()");
167    if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
168        mPlayer->pause();
169        mStateFlags &= ~kFlagPlaying;
170    }
171}
172
173/**
174 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0
175 */
176void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) {
177    SL_LOGV("GenericMediaPlayer::onSeek");
178    int64_t timeMsec = ANDROID_UNKNOWN_TIME;
179    if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) {
180        // invalid command, drop it
181        return;
182    }
183    if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec)) {
184        // already seeking to the same time, cancel this command
185        return;
186    } else if (!(mStateFlags & kFlagPrepared)) {
187        // we are not ready to accept a seek command at this time, retry later
188        msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US);
189    } else {
190        if (msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec) && (mPlayer != 0)) {
191            mStateFlags |= kFlagSeeking;
192            mSeekTimeMsec = (int32_t)timeMsec;
193            if (OK != mPlayer->seekTo(timeMsec)) {
194                mStateFlags &= ~kFlagSeeking;
195                mSeekTimeMsec = ANDROID_UNKNOWN_TIME;
196            } else {
197                mPositionMsec = mSeekTimeMsec;
198            }
199        }
200    }
201}
202
203
204void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) {
205    SL_LOGV("GenericMediaPlayer::onLoop");
206    int32_t loop = 0;
207    if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) {
208        if (mPlayer != 0 && OK == mPlayer->setLooping(loop)) {
209            if (loop) {
210                mStateFlags |= kFlagLooping;
211            } else {
212                mStateFlags &= ~kFlagLooping;
213            }
214        }
215    }
216}
217
218
219void GenericMediaPlayer::onVolumeUpdate() {
220    SL_LOGD("GenericMediaPlayer::onVolumeUpdate()");
221    // use settings lock to read the volume settings
222    Mutex::Autolock _l(mSettingsLock);
223    if (mPlayer != 0) {
224        if (mAndroidAudioLevels.mMute) {
225            mPlayer->setVolume(0.0f, 0.0f);
226        } else {
227            mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0],
228                    mAndroidAudioLevels.mFinalVolume[1]);
229        }
230    }
231}
232
233
234void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) {
235    int32_t fillLevel = 0;
236    if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) {
237        SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel);
238
239        Mutex::Autolock _l(mSettingsLock);
240        mCacheFill = fillLevel;
241        // handle cache fill update
242        if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) {
243            notifyCacheFill();
244        }
245        // handle prefetch status update
246        //   compute how much time ahead of position is buffered
247        int durationMsec, positionMsec = -1;
248        if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)
249                && (OK == mPlayer->getDuration(&durationMsec))
250                        && (OK == mPlayer->getCurrentPosition(&positionMsec))) {
251            if ((-1 != durationMsec) && (-1 != positionMsec)) {
252                // evaluate prefetch status based on buffer time thresholds
253                int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec;
254                CacheStatus_t newCacheStatus = mCacheStatus;
255                if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) {
256                    newCacheStatus = kStatusHigh;
257                } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) {
258                    newCacheStatus = kStatusEnough;
259                } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) {
260                    newCacheStatus = kStatusIntermediate;
261                } else if (bufferedDurationMsec == 0) {
262                    newCacheStatus = kStatusEmpty;
263                } else {
264                    newCacheStatus = kStatusLow;
265                }
266
267                if (newCacheStatus != mCacheStatus) {
268                    mCacheStatus = newCacheStatus;
269                    notifyStatus();
270                }
271            }
272        }
273    }
274}
275
276
277//--------------------------------------------------
278/**
279 * called from the event handling loop
280 * pre-condition: mPlayer is prepared
281 */
282void GenericMediaPlayer::onAfterMediaPlayerPrepared() {
283    // the MediaPlayer mPlayer is prepared, retrieve its duration
284    // FIXME retrieve channel count
285    {
286        Mutex::Autolock _l(mSettingsLock);
287        int msec = 0;
288        if (OK == mPlayer->getDuration(&msec)) {
289            mDurationMsec = msec;
290        }
291    }
292    // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers
293    // if the data source was local, and the buffers are considered full so we need to notify that
294    bool isLocalSource = true;
295    if (kDataLocatorUri == mDataLocatorType) {
296        for (unsigned int i = 0 ; i < NB_DISTANT_PROTOCOLS ; i++) {
297            if (!strncasecmp(mDataLocator.uriRef,
298                    kDistantProtocolPrefix[i], strlen(kDistantProtocolPrefix[i]))) {
299                isLocalSource = false;
300                break;
301            }
302        }
303    }
304    if (isLocalSource) {
305        SL_LOGD("media player prepared on local source");
306        {
307            Mutex::Autolock _l(mSettingsLock);
308            mCacheStatus = kStatusHigh;
309            mCacheFill = 1000;
310            notifyStatus();
311            notifyCacheFill();
312        }
313    } else {
314        SL_LOGD("media player prepared on non-local source");
315    }
316}
317
318} // namespace android
319