android_GenericMediaPlayer.cpp revision 35ac702ee1ad91e5c8748c12450222d50b366a52
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{
148    SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()");
149
150    mServiceManager = defaultServiceManager();
151    mBinder = mServiceManager->getService(String16("media.player"));
152    mMediaPlayerService = interface_cast<IMediaPlayerService>(mBinder);
153
154    CHECK(mMediaPlayerService.get() != NULL);
155
156    mPlayerClient = new MediaPlayerNotificationClient(this);
157}
158
159GenericMediaPlayer::~GenericMediaPlayer() {
160    SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()");
161}
162
163void GenericMediaPlayer::preDestroy() {
164    SL_LOGD("GenericMediaPlayer::preDestroy()");
165    GenericPlayer::preDestroy();
166}
167
168//--------------------------------------------------
169// overridden from GenericPlayer
170// pre-condition:
171//   msec != NULL
172// post-condition
173//   *msec ==
174//                  ANDROID_UNKNOWN_TIME if position is unknown at time of query,
175//               or the current MediaPlayer position
176void GenericMediaPlayer::getPositionMsec(int* msec) {
177    SL_LOGD("GenericMediaPlayer::getPositionMsec()");
178    sp<IMediaPlayer> player;
179    getPlayerPrepared(player);
180    // To avoid deadlock, directly call the MediaPlayer object
181    if (player == 0 || player->getCurrentPosition(msec) != NO_ERROR) {
182        *msec = ANDROID_UNKNOWN_TIME;
183    }
184}
185
186//--------------------------------------------------
187void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) {
188    SL_LOGV("GenericMediaPlayer::setVideoSurface()");
189    // FIXME bug - race condition, should do in looper
190    if (mVideoSurface.get() == surface.get()) {
191        return;
192    }
193    if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
194        mPlayer->setVideoSurface(surface);
195    }
196    mVideoSurface = surface;
197    mVideoSurfaceTexture = NULL;
198}
199
200void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
201    SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()");
202    // FIXME bug - race condition, should do in looper
203    if (mVideoSurfaceTexture.get() == surfaceTexture.get()) {
204        return;
205    }
206    if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
207        mPlayer->setVideoSurfaceTexture(surfaceTexture);
208    }
209    mVideoSurfaceTexture = surfaceTexture;
210    mVideoSurface = NULL;
211}
212
213
214//--------------------------------------------------
215// Event handlers
216
217void GenericMediaPlayer::onPrepare() {
218    SL_LOGD("GenericMediaPlayer::onPrepare()");
219    // Attempt to prepare at most once, and only if there is a MediaPlayer
220    if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) {
221        if (mHasVideo) {
222            if (mVideoSurface != 0) {
223                mPlayer->setVideoSurface(mVideoSurface);
224            } else if (mVideoSurfaceTexture != 0) {
225                mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture);
226            }
227        }
228        mPlayer->setAudioStreamType(mPlaybackParams.streamType);
229        mPlayerClient->beforePrepare();
230        mPlayer->prepareAsync();
231        if (mPlayerClient->blockUntilPlayerPrepared()) {
232            mStateFlags |= kFlagPrepared;
233            afterMediaPlayerPreparedSuccessfully();
234        } else {
235            mStateFlags |= kFlagPreparedUnsuccessfully;
236        }
237        GenericPlayer::onPrepare();
238    }
239    SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags);
240}
241
242
243void GenericMediaPlayer::onPlay() {
244    SL_LOGD("GenericMediaPlayer::onPlay()");
245    if (((mStateFlags & (kFlagPrepared | kFlagPlaying)) == kFlagPrepared) && (mPlayer != 0)) {
246        mPlayer->start();
247    }
248    GenericPlayer::onPlay();
249}
250
251
252void GenericMediaPlayer::onPause() {
253    SL_LOGD("GenericMediaPlayer::onPause()");
254    if (!(~mStateFlags & (kFlagPrepared | kFlagPlaying)) && (mPlayer != 0)) {
255        mPlayer->pause();
256    }
257    GenericPlayer::onPause();
258}
259
260
261void GenericMediaPlayer::onSeekComplete() {
262    SL_LOGV("GenericMediaPlayer::onSeekComplete()");
263    // did we initiate the seek?
264    if (!(mStateFlags & kFlagSeeking)) {
265        // no, are we looping?
266        if (mStateFlags & kFlagLooping) {
267            // yes, per OpenSL ES 1.0.1 and 1.1 do NOT report it to client
268            // notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/);
269        // no, well that's surprising, but it's probably just a benign race condition
270        } else {
271            SL_LOGW("Unexpected seek complete event ignored");
272        }
273    }
274    GenericPlayer::onSeekComplete();
275}
276
277
278/**
279 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0
280 */
281void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) {
282    SL_LOGV("GenericMediaPlayer::onSeek");
283    int64_t timeMsec = ANDROID_UNKNOWN_TIME;
284    if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) {
285        // invalid command, drop it
286        return;
287    }
288    if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec)) {
289        // already seeking to the same time, cancel this command
290        return;
291    } else if (mStateFlags & kFlagPreparedUnsuccessfully) {
292        // discard seeks after unsuccessful prepare
293    } else if (!(mStateFlags & kFlagPrepared)) {
294        // we are not ready to accept a seek command at this time, retry later
295        msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US);
296    } else {
297        if (msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec) && (mPlayer != 0)) {
298            mStateFlags |= kFlagSeeking;
299            mSeekTimeMsec = (int32_t)timeMsec;
300            if (OK != mPlayer->seekTo(timeMsec)) {
301                mStateFlags &= ~kFlagSeeking;
302                mSeekTimeMsec = ANDROID_UNKNOWN_TIME;
303            }
304        }
305    }
306}
307
308
309void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) {
310    SL_LOGV("GenericMediaPlayer::onLoop");
311    int32_t loop = 0;
312    if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) {
313        if (loop) {
314            mStateFlags |= kFlagLooping;
315        } else {
316            mStateFlags &= ~kFlagLooping;
317        }
318        // if we have a MediaPlayer then tell it now, otherwise we'll tell it after it's created
319        if (mPlayer != 0) {
320            (void) mPlayer->setLooping(loop);
321        }
322    }
323}
324
325
326void GenericMediaPlayer::onVolumeUpdate() {
327    SL_LOGD("GenericMediaPlayer::onVolumeUpdate()");
328    // use settings lock to read the volume settings
329    Mutex::Autolock _l(mSettingsLock);
330    if (mPlayer != 0) {
331        mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0],
332                mAndroidAudioLevels.mFinalVolume[1]);
333    }
334}
335
336
337void GenericMediaPlayer::onAttachAuxEffect(const sp<AMessage> &msg) {
338    SL_LOGD("GenericMediaPlayer::onAttachAuxEffect()");
339    int32_t effectId = 0;
340    if (msg->findInt32(WHATPARAM_ATTACHAUXEFFECT, &effectId)) {
341        if (mPlayer != 0) {
342            status_t status;
343            status = mPlayer->attachAuxEffect(effectId);
344            // attachAuxEffect returns a status but we have no way to report it back to app
345            (void) status;
346        }
347    }
348}
349
350
351void GenericMediaPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) {
352    SL_LOGD("GenericMediaPlayer::onSetAuxEffectSendLevel()");
353    float level = 0.0f;
354    if (msg->findFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, &level)) {
355        if (mPlayer != 0) {
356            status_t status;
357            status = mPlayer->setAuxEffectSendLevel(level);
358            // setAuxEffectSendLevel returns a status but we have no way to report it back to app
359            (void) status;
360        }
361    }
362}
363
364
365void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) {
366    int32_t fillLevel = 0;
367    if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) {
368        SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel);
369
370        Mutex::Autolock _l(mSettingsLock);
371        mCacheFill = fillLevel;
372        // handle cache fill update
373        if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) {
374            notifyCacheFill();
375        }
376        // handle prefetch status update
377        //   compute how much time ahead of position is buffered
378        int durationMsec, positionMsec = -1;
379        if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)
380                && (OK == mPlayer->getDuration(&durationMsec))
381                        && (OK == mPlayer->getCurrentPosition(&positionMsec))) {
382            if ((-1 != durationMsec) && (-1 != positionMsec)) {
383                // evaluate prefetch status based on buffer time thresholds
384                int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec;
385                CacheStatus_t newCacheStatus = mCacheStatus;
386                if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) {
387                    newCacheStatus = kStatusHigh;
388                } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) {
389                    newCacheStatus = kStatusEnough;
390                } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) {
391                    newCacheStatus = kStatusIntermediate;
392                } else if (bufferedDurationMsec == 0) {
393                    newCacheStatus = kStatusEmpty;
394                } else {
395                    newCacheStatus = kStatusLow;
396                }
397
398                if (newCacheStatus != mCacheStatus) {
399                    mCacheStatus = newCacheStatus;
400                    notifyStatus();
401                }
402            }
403        }
404    } else {
405        SL_LOGV("GenericMediaPlayer::onBufferingUpdate(fillLevel=unknown)");
406    }
407}
408
409
410//--------------------------------------------------
411/**
412 * called from GenericMediaPlayer::onPrepare after the MediaPlayer mPlayer is prepared successfully
413 * pre-conditions:
414 *  mPlayer != 0
415 *  mPlayer is prepared successfully
416 */
417void GenericMediaPlayer::afterMediaPlayerPreparedSuccessfully() {
418    SL_LOGV("GenericMediaPlayer::afterMediaPlayerPrepared()");
419    assert(mPlayer != 0);
420    assert(mStateFlags & kFlagPrepared);
421    // Mark this player as prepared successfully, so safe to directly call getCurrentPosition
422    {
423        Mutex::Autolock _l(mPlayerPreparedLock);
424        assert(mPlayerPrepared == 0);
425        mPlayerPrepared = mPlayer;
426    }
427    // retrieve channel count
428    assert(UNKNOWN_NUMCHANNELS == mChannelCount);
429    Parcel *reply = new Parcel();
430    status_t status = mPlayer->getParameter(KEY_PARAMETER_AUDIO_CHANNEL_COUNT, reply);
431    if (status == NO_ERROR) {
432        mChannelCount = reply->readInt32();
433    } else {
434        // FIXME MPEG-2 TS doesn't yet implement this key, so default to stereo
435        mChannelCount = 2;
436    }
437    if (UNKNOWN_NUMCHANNELS != mChannelCount) {
438        // now that we know the channel count, re-calculate the volumes
439        notify(PLAYEREVENT_CHANNEL_COUNT, mChannelCount, true /*async*/);
440    } else {
441        LOGW("channel count is still unknown after prepare");
442    }
443    delete reply;
444    // retrieve duration
445    {
446        Mutex::Autolock _l(mSettingsLock);
447        int msec = 0;
448        if (OK == mPlayer->getDuration(&msec)) {
449            mDurationMsec = msec;
450        }
451    }
452    // now that we have a MediaPlayer, set the looping flag
453    if (mStateFlags & kFlagLooping) {
454        (void) mPlayer->setLooping(1);
455    }
456    // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers
457    // if the data source was local, and the buffers are considered full so we need to notify that
458    bool isLocalSource = true;
459    if (kDataLocatorUri == mDataLocatorType) {
460        for (unsigned int i = 0 ; i < NB_DISTANT_PROTOCOLS ; i++) {
461            if (!strncasecmp(mDataLocator.uriRef,
462                    kDistantProtocolPrefix[i], strlen(kDistantProtocolPrefix[i]))) {
463                isLocalSource = false;
464                break;
465            }
466        }
467    }
468    if (isLocalSource) {
469        SL_LOGD("media player prepared on local source");
470        {
471            Mutex::Autolock _l(mSettingsLock);
472            mCacheStatus = kStatusHigh;
473            mCacheFill = 1000;
474            notifyStatus();
475            notifyCacheFill();
476        }
477    } else {
478        SL_LOGD("media player prepared on non-local source");
479    }
480}
481
482
483//--------------------------------------------------
484// If player is prepared successfully, set output parameter to that reference, otherwise NULL
485void GenericMediaPlayer::getPlayerPrepared(sp<IMediaPlayer> &playerPrepared)
486{
487    Mutex::Autolock _l(mPlayerPreparedLock);
488    playerPrepared = mPlayerPrepared;
489}
490
491} // namespace android
492