android_GenericMediaPlayer.cpp revision a9f22e6f5f53e90daa779e38b22f88e4faa35c95
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
27// default delay in Us used when reposting an event when the player is not ready to accept
28// the command yet. This is for instance used when seeking on a MediaPlayer that's still preparing
29#define DEFAULT_COMMAND_DELAY_FOR_REPOST_US (100*1000) // 100ms
30
31// table of prefixes for known distant protocols; these are immediately dispatched to mediaserver
32static const char* const kDistantProtocolPrefix[] = { "http://", "https://", "rtsp://"};
33#define NB_DISTANT_PROTOCOLS (sizeof(kDistantProtocolPrefix)/sizeof(kDistantProtocolPrefix[0]))
34
35// is the specified URI a known distant protocol?
36bool isDistantProtocol(const char *uri)
37{
38    for (unsigned int i = 0; i < NB_DISTANT_PROTOCOLS; i++) {
39        if (!strncasecmp(uri, kDistantProtocolPrefix[i], strlen(kDistantProtocolPrefix[i]))) {
40            return true;
41        }
42    }
43    return false;
44}
45
46namespace android {
47
48//--------------------------------------------------------------------------------------------------
49MediaPlayerNotificationClient::MediaPlayerNotificationClient(GenericMediaPlayer* gmp) :
50    mGenericMediaPlayer(gmp),
51    mPlayerPrepared(PREPARE_NOT_STARTED)
52{
53    SL_LOGV("MediaPlayerNotificationClient::MediaPlayerNotificationClient()");
54}
55
56MediaPlayerNotificationClient::~MediaPlayerNotificationClient() {
57    SL_LOGV("MediaPlayerNotificationClient::~MediaPlayerNotificationClient()");
58}
59
60// Map a MEDIA_* enum to a string
61static const char *media_to_string(int msg)
62{
63    switch (msg) {
64#define _(x) case MEDIA_##x: return "MEDIA_" #x;
65      _(PREPARED)
66      _(SET_VIDEO_SIZE)
67      _(SEEK_COMPLETE)
68      _(PLAYBACK_COMPLETE)
69      _(BUFFERING_UPDATE)
70      _(ERROR)
71      _(NOP)
72      _(TIMED_TEXT)
73      _(INFO)
74#undef _
75    default:
76        return NULL;
77    }
78}
79
80//--------------------------------------------------
81// IMediaPlayerClient implementation
82void MediaPlayerNotificationClient::notify(int msg, int ext1, int ext2, const Parcel *obj) {
83    SL_LOGV("MediaPlayerNotificationClient::notify(msg=%s (%d), ext1=%d, ext2=%d)",
84            media_to_string(msg), msg, ext1, ext2);
85
86    switch (msg) {
87      case MEDIA_PREPARED:
88        mPlayerPrepared = PREPARE_COMPLETED_SUCCESSFULLY;
89        mPlayerPreparedCondition.signal();
90        break;
91
92      case MEDIA_SET_VIDEO_SIZE:
93        // only send video size updates if the player was flagged as having video, to avoid
94        // sending video size updates of (0,0)
95        if (mGenericMediaPlayer->mHasVideo) {
96            mGenericMediaPlayer->notify(PLAYEREVENT_VIDEO_SIZE_UPDATE,
97                    (int32_t)ext1, (int32_t)ext2, true /*async*/);
98        }
99        break;
100
101      case MEDIA_SEEK_COMPLETE:
102        mGenericMediaPlayer->seekComplete();
103        break;
104
105      case MEDIA_PLAYBACK_COMPLETE:
106        mGenericMediaPlayer->notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/);
107        break;
108
109      case MEDIA_BUFFERING_UPDATE:
110        // values received from Android framework for buffer fill level use percent,
111        //   while SL/XA use permille, so does GenericPlayer
112        mGenericMediaPlayer->bufferingUpdate(ext1 * 10 /*fillLevelPerMille*/);
113        break;
114
115      case MEDIA_ERROR:
116        mPlayerPrepared = PREPARE_COMPLETED_UNSUCCESSFULLY;
117        mPlayerPreparedCondition.signal();
118        break;
119
120      case MEDIA_NOP:
121      case MEDIA_TIMED_TEXT:
122      case MEDIA_INFO:
123        break;
124
125      default: { }
126    }
127
128}
129
130//--------------------------------------------------
131void MediaPlayerNotificationClient::beforePrepare()
132{
133    Mutex::Autolock _l(mLock);
134    assert(mPlayerPrepared == PREPARE_NOT_STARTED);
135    mPlayerPrepared = PREPARE_IN_PROGRESS;
136}
137
138//--------------------------------------------------
139bool MediaPlayerNotificationClient::blockUntilPlayerPrepared() {
140    Mutex::Autolock _l(mLock);
141    assert(mPlayerPrepared != PREPARE_NOT_STARTED);
142    while (mPlayerPrepared == PREPARE_IN_PROGRESS) {
143        mPlayerPreparedCondition.wait(mLock);
144    }
145    assert(mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY ||
146            mPlayerPrepared == PREPARE_COMPLETED_UNSUCCESSFULLY);
147    return mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY;
148}
149
150//--------------------------------------------------------------------------------------------------
151GenericMediaPlayer::GenericMediaPlayer(const AudioPlayback_Parameters* params, bool hasVideo) :
152    GenericPlayer(params),
153    mHasVideo(hasVideo),
154    mSeekTimeMsec(0),
155    mVideoSurface(0),
156    mVideoSurfaceTexture(0),
157    mPlayer(0),
158    mPlayerClient(0)
159{
160    SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()");
161
162    mPlayerClient = new MediaPlayerNotificationClient(this);
163}
164
165GenericMediaPlayer::~GenericMediaPlayer() {
166    SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()");
167}
168
169void GenericMediaPlayer::preDestroy() {
170    SL_LOGD("GenericMediaPlayer::preDestroy()");
171    if (mPlayer != 0) {
172        mPlayer->stop();
173    }
174    GenericPlayer::preDestroy();
175}
176
177//--------------------------------------------------
178// overridden from GenericPlayer
179// pre-condition:
180//   msec != NULL
181// post-condition
182//   *msec ==
183//                  ANDROID_UNKNOWN_TIME if position is unknown at time of query,
184//               or the current MediaPlayer position
185void GenericMediaPlayer::getPositionMsec(int* msec) {
186    SL_LOGD("GenericMediaPlayer::getPositionMsec()");
187    sp<IMediaPlayer> player;
188    getPlayerPrepared(player);
189    // To avoid deadlock, directly call the MediaPlayer object
190    if (player == 0 || player->getCurrentPosition(msec) != NO_ERROR) {
191        *msec = ANDROID_UNKNOWN_TIME;
192    }
193}
194
195//--------------------------------------------------
196void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) {
197    SL_LOGV("GenericMediaPlayer::setVideoSurface()");
198    // FIXME bug - race condition, should do in looper
199    if (mVideoSurface.get() == surface.get()) {
200        return;
201    }
202    if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
203        mPlayer->setVideoSurface(surface);
204    }
205    mVideoSurface = surface;
206    mVideoSurfaceTexture = NULL;
207}
208
209void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
210    SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()");
211    // FIXME bug - race condition, should do in looper
212    if (mVideoSurfaceTexture.get() == surfaceTexture.get()) {
213        return;
214    }
215    if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
216        mPlayer->setVideoSurfaceTexture(surfaceTexture);
217    }
218    mVideoSurfaceTexture = surfaceTexture;
219    mVideoSurface = NULL;
220}
221
222
223//--------------------------------------------------
224// Event handlers
225
226// blocks until mPlayer is prepared
227void GenericMediaPlayer::onPrepare() {
228    SL_LOGD("GenericMediaPlayer::onPrepare()");
229    // Attempt to prepare at most once, and only if there is a MediaPlayer
230    if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) {
231        if (mHasVideo) {
232            if (mVideoSurface != 0) {
233                mPlayer->setVideoSurface(mVideoSurface);
234            } else if (mVideoSurfaceTexture != 0) {
235                mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture);
236            }
237        }
238        mPlayer->setAudioStreamType(mPlaybackParams.streamType);
239        mPlayerClient->beforePrepare();
240        mPlayer->prepareAsync();
241        if (mPlayerClient->blockUntilPlayerPrepared()) {
242            mStateFlags |= kFlagPrepared;
243            afterMediaPlayerPreparedSuccessfully();
244        } else {
245            mStateFlags |= kFlagPreparedUnsuccessfully;
246        }
247    }
248    GenericPlayer::onPrepare();
249    SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags);
250}
251
252
253void GenericMediaPlayer::onPlay() {
254    SL_LOGD("GenericMediaPlayer::onPlay()");
255    if (((mStateFlags & (kFlagPrepared | kFlagPlaying)) == kFlagPrepared) && (mPlayer != 0)) {
256        mPlayer->start();
257    }
258    GenericPlayer::onPlay();
259}
260
261
262void GenericMediaPlayer::onPause() {
263    SL_LOGD("GenericMediaPlayer::onPause()");
264    if (!(~mStateFlags & (kFlagPrepared | kFlagPlaying)) && (mPlayer != 0)) {
265        mPlayer->pause();
266    }
267    GenericPlayer::onPause();
268}
269
270
271void GenericMediaPlayer::onSeekComplete() {
272    SL_LOGV("GenericMediaPlayer::onSeekComplete()");
273    // did we initiate the seek?
274    if (!(mStateFlags & kFlagSeeking)) {
275        // no, are we looping?
276        if (mStateFlags & kFlagLooping) {
277            // yes, per OpenSL ES 1.0.1 and 1.1 do NOT report it to client
278            // notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/);
279        // no, well that's surprising, but it's probably just a benign race condition
280        } else {
281            SL_LOGW("Unexpected seek complete event ignored");
282        }
283    }
284    GenericPlayer::onSeekComplete();
285}
286
287
288/**
289 * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0
290 */
291void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) {
292    SL_LOGV("GenericMediaPlayer::onSeek");
293    int64_t timeMsec = ANDROID_UNKNOWN_TIME;
294    if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) {
295        // invalid command, drop it
296        return;
297    }
298    if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec) &&
299            (timeMsec != ANDROID_UNKNOWN_TIME)) {
300        // already seeking to the same non-unknown time, cancel this command
301        return;
302    } else if (mStateFlags & kFlagPreparedUnsuccessfully) {
303        // discard seeks after unsuccessful prepare
304    } else if (!(mStateFlags & kFlagPrepared)) {
305        // we are not ready to accept a seek command at this time, retry later
306        msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US);
307    } else {
308        if (msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec) && (mPlayer != 0)) {
309            mStateFlags |= kFlagSeeking;
310            mSeekTimeMsec = (int32_t)timeMsec;
311            // seek to unknown time is used by StreamPlayer after discontinuity
312            if (timeMsec == ANDROID_UNKNOWN_TIME) {
313                // FIXME simulate a MEDIA_SEEK_COMPLETE event in 250 ms;
314                // this is a terrible hack to make up for mediaserver not sending one
315                (new AMessage(kWhatSeekComplete, id()))->post(250000);
316            } else if (OK != mPlayer->seekTo(timeMsec)) {
317                mStateFlags &= ~kFlagSeeking;
318                mSeekTimeMsec = ANDROID_UNKNOWN_TIME;
319            }
320        }
321    }
322}
323
324
325void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) {
326    SL_LOGV("GenericMediaPlayer::onLoop");
327    int32_t loop = 0;
328    if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) {
329        if (loop) {
330            mStateFlags |= kFlagLooping;
331        } else {
332            mStateFlags &= ~kFlagLooping;
333        }
334        // if we have a MediaPlayer then tell it now, otherwise we'll tell it after it's created
335        if (mPlayer != 0) {
336            (void) mPlayer->setLooping(loop);
337        }
338    }
339}
340
341
342void GenericMediaPlayer::onVolumeUpdate() {
343    SL_LOGD("GenericMediaPlayer::onVolumeUpdate()");
344    // use settings lock to read the volume settings
345    Mutex::Autolock _l(mSettingsLock);
346    if (mPlayer != 0) {
347        mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0],
348                mAndroidAudioLevels.mFinalVolume[1]);
349    }
350}
351
352
353void GenericMediaPlayer::onAttachAuxEffect(const sp<AMessage> &msg) {
354    SL_LOGD("GenericMediaPlayer::onAttachAuxEffect()");
355    int32_t effectId = 0;
356    if (msg->findInt32(WHATPARAM_ATTACHAUXEFFECT, &effectId)) {
357        if (mPlayer != 0) {
358            status_t status;
359            status = mPlayer->attachAuxEffect(effectId);
360            // attachAuxEffect returns a status but we have no way to report it back to app
361            (void) status;
362        }
363    }
364}
365
366
367void GenericMediaPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) {
368    SL_LOGD("GenericMediaPlayer::onSetAuxEffectSendLevel()");
369    float level = 0.0f;
370    if (msg->findFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, &level)) {
371        if (mPlayer != 0) {
372            status_t status;
373            status = mPlayer->setAuxEffectSendLevel(level);
374            // setAuxEffectSendLevel returns a status but we have no way to report it back to app
375            (void) status;
376        }
377    }
378}
379
380
381void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) {
382    int32_t fillLevel = 0;
383    if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) {
384        SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel);
385
386        Mutex::Autolock _l(mSettingsLock);
387        mCacheFill = fillLevel;
388        // handle cache fill update
389        if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) {
390            notifyCacheFill();
391        }
392        // handle prefetch status update
393        //   compute how much time ahead of position is buffered
394        int durationMsec, positionMsec = -1;
395        if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)
396                && (OK == mPlayer->getDuration(&durationMsec))
397                        && (OK == mPlayer->getCurrentPosition(&positionMsec))) {
398            if ((-1 != durationMsec) && (-1 != positionMsec)) {
399                // evaluate prefetch status based on buffer time thresholds
400                int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec;
401                CacheStatus_t newCacheStatus = mCacheStatus;
402                if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) {
403                    newCacheStatus = kStatusHigh;
404                } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) {
405                    newCacheStatus = kStatusEnough;
406                } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) {
407                    newCacheStatus = kStatusIntermediate;
408                } else if (bufferedDurationMsec == 0) {
409                    newCacheStatus = kStatusEmpty;
410                } else {
411                    newCacheStatus = kStatusLow;
412                }
413
414                if (newCacheStatus != mCacheStatus) {
415                    mCacheStatus = newCacheStatus;
416                    notifyStatus();
417                }
418            }
419        }
420    } else {
421        SL_LOGV("GenericMediaPlayer::onBufferingUpdate(fillLevel=unknown)");
422    }
423}
424
425
426//--------------------------------------------------
427/**
428 * called from GenericMediaPlayer::onPrepare after the MediaPlayer mPlayer is prepared successfully
429 * pre-conditions:
430 *  mPlayer != 0
431 *  mPlayer is prepared successfully
432 */
433void GenericMediaPlayer::afterMediaPlayerPreparedSuccessfully() {
434    SL_LOGV("GenericMediaPlayer::afterMediaPlayerPrepared()");
435    assert(mPlayer != 0);
436    assert(mStateFlags & kFlagPrepared);
437    // Mark this player as prepared successfully, so safe to directly call getCurrentPosition
438    {
439        Mutex::Autolock _l(mPlayerPreparedLock);
440        assert(mPlayerPrepared == 0);
441        mPlayerPrepared = mPlayer;
442    }
443    // retrieve channel count
444    assert(UNKNOWN_NUMCHANNELS == mChannelCount);
445    Parcel *reply = new Parcel();
446    status_t status = mPlayer->getParameter(KEY_PARAMETER_AUDIO_CHANNEL_COUNT, reply);
447    if (status == NO_ERROR) {
448        mChannelCount = reply->readInt32();
449    } else {
450        // FIXME MPEG-2 TS doesn't yet implement this key, so default to stereo
451        mChannelCount = 2;
452    }
453    if (UNKNOWN_NUMCHANNELS != mChannelCount) {
454        // now that we know the channel count, re-calculate the volumes
455        notify(PLAYEREVENT_CHANNEL_COUNT, mChannelCount, true /*async*/);
456    } else {
457        LOGW("channel count is still unknown after prepare");
458    }
459    delete reply;
460    // retrieve duration
461    {
462        Mutex::Autolock _l(mSettingsLock);
463        int msec = 0;
464        if (OK == mPlayer->getDuration(&msec)) {
465            mDurationMsec = msec;
466        }
467    }
468    // now that we have a MediaPlayer, set the looping flag
469    if (mStateFlags & kFlagLooping) {
470        (void) mPlayer->setLooping(1);
471    }
472    // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers
473    // if the data source was local, and the buffers are considered full so we need to notify that
474    bool isLocalSource = true;
475    if (kDataLocatorUri == mDataLocatorType) {
476        isLocalSource = !isDistantProtocol(mDataLocator.uriRef);
477    }
478    if (isLocalSource) {
479        SL_LOGD("media player prepared on local source");
480        {
481            Mutex::Autolock _l(mSettingsLock);
482            mCacheStatus = kStatusHigh;
483            mCacheFill = 1000;
484            notifyStatus();
485            notifyCacheFill();
486        }
487    } else {
488        SL_LOGD("media player prepared on non-local source");
489    }
490}
491
492
493//--------------------------------------------------
494// If player is prepared successfully, set output parameter to that reference, otherwise NULL
495void GenericMediaPlayer::getPlayerPrepared(sp<IMediaPlayer> &playerPrepared)
496{
497    Mutex::Autolock _l(mPlayerPreparedLock);
498    playerPrepared = mPlayerPrepared;
499}
500
501} // namespace android
502