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