mediaplayer.cpp revision 7dae00baa6e8957be15523c46bb948bd1dde64c3
1/* mediaplayer.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "MediaPlayer"
20#include <utils/Log.h>
21
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <fcntl.h>
26
27#include <binder/IServiceManager.h>
28#include <binder/IPCThreadState.h>
29
30#include <gui/SurfaceTextureClient.h>
31
32#include <media/mediaplayer.h>
33#include <media/AudioTrack.h>
34
35#include <surfaceflinger/Surface.h>
36
37#include <binder/MemoryBase.h>
38
39#include <utils/KeyedVector.h>
40#include <utils/String8.h>
41
42#include <system/audio.h>
43#include <system/window.h>
44
45namespace android {
46
47MediaPlayer::MediaPlayer()
48{
49    LOGV("constructor");
50    mListener = NULL;
51    mCookie = NULL;
52    mDuration = -1;
53    mStreamType = AUDIO_STREAM_MUSIC;
54    mCurrentPosition = -1;
55    mSeekPosition = -1;
56    mCurrentState = MEDIA_PLAYER_IDLE;
57    mPrepareSync = false;
58    mPrepareStatus = NO_ERROR;
59    mLoop = false;
60    mLeftVolume = mRightVolume = 1.0;
61    mVideoWidth = mVideoHeight = 0;
62    mLockThreadId = 0;
63    mAudioSessionId = AudioSystem::newAudioSessionId();
64    AudioSystem::acquireAudioSessionId(mAudioSessionId);
65    mSendLevel = 0;
66}
67
68MediaPlayer::~MediaPlayer()
69{
70    LOGV("destructor");
71    AudioSystem::releaseAudioSessionId(mAudioSessionId);
72    disconnect();
73    IPCThreadState::self()->flushCommands();
74}
75
76void MediaPlayer::disconnect()
77{
78    LOGV("disconnect");
79    sp<IMediaPlayer> p;
80    {
81        Mutex::Autolock _l(mLock);
82        p = mPlayer;
83        mPlayer.clear();
84    }
85
86    if (p != 0) {
87        p->disconnect();
88    }
89}
90
91// always call with lock held
92void MediaPlayer::clear_l()
93{
94    mDuration = -1;
95    mCurrentPosition = -1;
96    mSeekPosition = -1;
97    mVideoWidth = mVideoHeight = 0;
98}
99
100status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
101{
102    LOGV("setListener");
103    Mutex::Autolock _l(mLock);
104    mListener = listener;
105    return NO_ERROR;
106}
107
108
109status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
110{
111    status_t err = UNKNOWN_ERROR;
112    sp<IMediaPlayer> p;
113    { // scope for the lock
114        Mutex::Autolock _l(mLock);
115
116        if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
117                (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
118            LOGE("attachNewPlayer called in state %d", mCurrentState);
119            return INVALID_OPERATION;
120        }
121
122        clear_l();
123        p = mPlayer;
124        mPlayer = player;
125        if (player != 0) {
126            mCurrentState = MEDIA_PLAYER_INITIALIZED;
127            err = NO_ERROR;
128        } else {
129            LOGE("Unable to to create media player");
130        }
131    }
132
133    if (p != 0) {
134        p->disconnect();
135    }
136
137    return err;
138}
139
140status_t MediaPlayer::setDataSource(
141        const char *url, const KeyedVector<String8, String8> *headers)
142{
143    LOGV("setDataSource(%s)", url);
144    status_t err = BAD_VALUE;
145    if (url != NULL) {
146        const sp<IMediaPlayerService>& service(getMediaPlayerService());
147        if (service != 0) {
148            sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
149            if (NO_ERROR != player->setDataSource(url, headers)) {
150                player.clear();
151            }
152            err = attachNewPlayer(player);
153        }
154    }
155    return err;
156}
157
158status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
159{
160    LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
161    status_t err = UNKNOWN_ERROR;
162    const sp<IMediaPlayerService>& service(getMediaPlayerService());
163    if (service != 0) {
164        sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
165        if (NO_ERROR != player->setDataSource(fd, offset, length)) {
166            player.clear();
167        }
168        err = attachNewPlayer(player);
169    }
170    return err;
171}
172
173status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
174{
175    LOGV("setDataSource");
176    status_t err = UNKNOWN_ERROR;
177    const sp<IMediaPlayerService>& service(getMediaPlayerService());
178    if (service != 0) {
179        sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
180        if (NO_ERROR != player->setDataSource(source)) {
181            player.clear();
182        }
183        err = attachNewPlayer(player);
184    }
185    return err;
186}
187
188status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
189{
190    Mutex::Autolock _l(mLock);
191    const bool hasBeenInitialized =
192            (mCurrentState != MEDIA_PLAYER_STATE_ERROR) &&
193            ((mCurrentState & MEDIA_PLAYER_IDLE) != MEDIA_PLAYER_IDLE);
194    if ((mPlayer != NULL) && hasBeenInitialized) {
195         LOGV("invoke %d", request.dataSize());
196         return  mPlayer->invoke(request, reply);
197    }
198    LOGE("invoke failed: wrong state %X", mCurrentState);
199    return INVALID_OPERATION;
200}
201
202status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
203{
204    LOGD("setMetadataFilter");
205    Mutex::Autolock lock(mLock);
206    if (mPlayer == NULL) {
207        return NO_INIT;
208    }
209    return mPlayer->setMetadataFilter(filter);
210}
211
212status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
213{
214    LOGD("getMetadata");
215    Mutex::Autolock lock(mLock);
216    if (mPlayer == NULL) {
217        return NO_INIT;
218    }
219    return mPlayer->getMetadata(update_only, apply_filter, metadata);
220}
221
222status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
223{
224    LOGV("setVideoSurface");
225    Mutex::Autolock _l(mLock);
226    if (mPlayer == 0) return NO_INIT;
227    return mPlayer->setVideoSurface(surface);
228}
229
230status_t MediaPlayer::setVideoSurfaceTexture(
231        const sp<ISurfaceTexture>& surfaceTexture)
232{
233    LOGV("setVideoSurfaceTexture");
234    Mutex::Autolock _l(mLock);
235    if (mPlayer == 0) return NO_INIT;
236    return mPlayer->setVideoSurfaceTexture(surfaceTexture);
237}
238
239// must call with lock held
240status_t MediaPlayer::prepareAsync_l()
241{
242    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
243        mPlayer->setAudioStreamType(mStreamType);
244        mCurrentState = MEDIA_PLAYER_PREPARING;
245        return mPlayer->prepareAsync();
246    }
247    LOGE("prepareAsync called in state %d", mCurrentState);
248    return INVALID_OPERATION;
249}
250
251// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
252// one defined in the Android framework and one provided by the implementation
253// that generated the error. The sync version of prepare returns only 1 error
254// code.
255status_t MediaPlayer::prepare()
256{
257    LOGV("prepare");
258    Mutex::Autolock _l(mLock);
259    mLockThreadId = getThreadId();
260    if (mPrepareSync) {
261        mLockThreadId = 0;
262        return -EALREADY;
263    }
264    mPrepareSync = true;
265    status_t ret = prepareAsync_l();
266    if (ret != NO_ERROR) {
267        mLockThreadId = 0;
268        return ret;
269    }
270
271    if (mPrepareSync) {
272        mSignal.wait(mLock);  // wait for prepare done
273        mPrepareSync = false;
274    }
275    LOGV("prepare complete - status=%d", mPrepareStatus);
276    mLockThreadId = 0;
277    return mPrepareStatus;
278}
279
280status_t MediaPlayer::prepareAsync()
281{
282    LOGV("prepareAsync");
283    Mutex::Autolock _l(mLock);
284    return prepareAsync_l();
285}
286
287status_t MediaPlayer::start()
288{
289    LOGV("start");
290    Mutex::Autolock _l(mLock);
291    if (mCurrentState & MEDIA_PLAYER_STARTED)
292        return NO_ERROR;
293    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
294                    MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
295        mPlayer->setLooping(mLoop);
296        mPlayer->setVolume(mLeftVolume, mRightVolume);
297        mPlayer->setAuxEffectSendLevel(mSendLevel);
298        mCurrentState = MEDIA_PLAYER_STARTED;
299        status_t ret = mPlayer->start();
300        if (ret != NO_ERROR) {
301            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
302        } else {
303            if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
304                LOGV("playback completed immediately following start()");
305            }
306        }
307        return ret;
308    }
309    LOGE("start called in state %d", mCurrentState);
310    return INVALID_OPERATION;
311}
312
313status_t MediaPlayer::stop()
314{
315    LOGV("stop");
316    Mutex::Autolock _l(mLock);
317    if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
318    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
319                    MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
320        status_t ret = mPlayer->stop();
321        if (ret != NO_ERROR) {
322            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
323        } else {
324            mCurrentState = MEDIA_PLAYER_STOPPED;
325        }
326        return ret;
327    }
328    LOGE("stop called in state %d", mCurrentState);
329    return INVALID_OPERATION;
330}
331
332status_t MediaPlayer::pause()
333{
334    LOGV("pause");
335    Mutex::Autolock _l(mLock);
336    if (mCurrentState & (MEDIA_PLAYER_PAUSED|MEDIA_PLAYER_PLAYBACK_COMPLETE))
337        return NO_ERROR;
338    if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
339        status_t ret = mPlayer->pause();
340        if (ret != NO_ERROR) {
341            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
342        } else {
343            mCurrentState = MEDIA_PLAYER_PAUSED;
344        }
345        return ret;
346    }
347    LOGE("pause called in state %d", mCurrentState);
348    return INVALID_OPERATION;
349}
350
351bool MediaPlayer::isPlaying()
352{
353    Mutex::Autolock _l(mLock);
354    if (mPlayer != 0) {
355        bool temp = false;
356        mPlayer->isPlaying(&temp);
357        LOGV("isPlaying: %d", temp);
358        if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
359            LOGE("internal/external state mismatch corrected");
360            mCurrentState = MEDIA_PLAYER_PAUSED;
361        }
362        return temp;
363    }
364    LOGV("isPlaying: no active player");
365    return false;
366}
367
368status_t MediaPlayer::getVideoWidth(int *w)
369{
370    LOGV("getVideoWidth");
371    Mutex::Autolock _l(mLock);
372    if (mPlayer == 0) return INVALID_OPERATION;
373    *w = mVideoWidth;
374    return NO_ERROR;
375}
376
377status_t MediaPlayer::getVideoHeight(int *h)
378{
379    LOGV("getVideoHeight");
380    Mutex::Autolock _l(mLock);
381    if (mPlayer == 0) return INVALID_OPERATION;
382    *h = mVideoHeight;
383    return NO_ERROR;
384}
385
386status_t MediaPlayer::getCurrentPosition(int *msec)
387{
388    LOGV("getCurrentPosition");
389    Mutex::Autolock _l(mLock);
390    if (mPlayer != 0) {
391        if (mCurrentPosition >= 0) {
392            LOGV("Using cached seek position: %d", mCurrentPosition);
393            *msec = mCurrentPosition;
394            return NO_ERROR;
395        }
396        return mPlayer->getCurrentPosition(msec);
397    }
398    return INVALID_OPERATION;
399}
400
401status_t MediaPlayer::getDuration_l(int *msec)
402{
403    LOGV("getDuration");
404    bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
405    if (mPlayer != 0 && isValidState) {
406        status_t ret = NO_ERROR;
407        if (mDuration <= 0)
408            ret = mPlayer->getDuration(&mDuration);
409        if (msec)
410            *msec = mDuration;
411        return ret;
412    }
413    LOGE("Attempt to call getDuration without a valid mediaplayer");
414    return INVALID_OPERATION;
415}
416
417status_t MediaPlayer::getDuration(int *msec)
418{
419    Mutex::Autolock _l(mLock);
420    return getDuration_l(msec);
421}
422
423status_t MediaPlayer::seekTo_l(int msec)
424{
425    LOGV("seekTo %d", msec);
426    if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED |  MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
427        if ( msec < 0 ) {
428            LOGW("Attempt to seek to invalid position: %d", msec);
429            msec = 0;
430        } else if ((mDuration > 0) && (msec > mDuration)) {
431            LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
432            msec = mDuration;
433        }
434        // cache duration
435        mCurrentPosition = msec;
436        if (mSeekPosition < 0) {
437            getDuration_l(NULL);
438            mSeekPosition = msec;
439            return mPlayer->seekTo(msec);
440        }
441        else {
442            LOGV("Seek in progress - queue up seekTo[%d]", msec);
443            return NO_ERROR;
444        }
445    }
446    LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
447    return INVALID_OPERATION;
448}
449
450status_t MediaPlayer::seekTo(int msec)
451{
452    mLockThreadId = getThreadId();
453    Mutex::Autolock _l(mLock);
454    status_t result = seekTo_l(msec);
455    mLockThreadId = 0;
456
457    return result;
458}
459
460status_t MediaPlayer::reset_l()
461{
462    mLoop = false;
463    if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
464    mPrepareSync = false;
465    if (mPlayer != 0) {
466        status_t ret = mPlayer->reset();
467        if (ret != NO_ERROR) {
468            LOGE("reset() failed with return code (%d)", ret);
469            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
470        } else {
471            mCurrentState = MEDIA_PLAYER_IDLE;
472        }
473        // setDataSource has to be called again to create a
474        // new mediaplayer.
475        mPlayer = 0;
476        return ret;
477    }
478    clear_l();
479    return NO_ERROR;
480}
481
482status_t MediaPlayer::reset()
483{
484    LOGV("reset");
485    Mutex::Autolock _l(mLock);
486    return reset_l();
487}
488
489status_t MediaPlayer::setAudioStreamType(int type)
490{
491    LOGV("MediaPlayer::setAudioStreamType");
492    Mutex::Autolock _l(mLock);
493    if (mStreamType == type) return NO_ERROR;
494    if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
495                MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
496        // Can't change the stream type after prepare
497        LOGE("setAudioStream called in state %d", mCurrentState);
498        return INVALID_OPERATION;
499    }
500    // cache
501    mStreamType = type;
502    return OK;
503}
504
505status_t MediaPlayer::setLooping(int loop)
506{
507    LOGV("MediaPlayer::setLooping");
508    Mutex::Autolock _l(mLock);
509    mLoop = (loop != 0);
510    if (mPlayer != 0) {
511        return mPlayer->setLooping(loop);
512    }
513    return OK;
514}
515
516bool MediaPlayer::isLooping() {
517    LOGV("isLooping");
518    Mutex::Autolock _l(mLock);
519    if (mPlayer != 0) {
520        return mLoop;
521    }
522    LOGV("isLooping: no active player");
523    return false;
524}
525
526status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
527{
528    LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
529    Mutex::Autolock _l(mLock);
530    mLeftVolume = leftVolume;
531    mRightVolume = rightVolume;
532    if (mPlayer != 0) {
533        return mPlayer->setVolume(leftVolume, rightVolume);
534    }
535    return OK;
536}
537
538status_t MediaPlayer::setAudioSessionId(int sessionId)
539{
540    LOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);
541    Mutex::Autolock _l(mLock);
542    if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {
543        LOGE("setAudioSessionId called in state %d", mCurrentState);
544        return INVALID_OPERATION;
545    }
546    if (sessionId < 0) {
547        return BAD_VALUE;
548    }
549    if (sessionId != mAudioSessionId) {
550      AudioSystem::releaseAudioSessionId(mAudioSessionId);
551      AudioSystem::acquireAudioSessionId(sessionId);
552      mAudioSessionId = sessionId;
553    }
554    return NO_ERROR;
555}
556
557int MediaPlayer::getAudioSessionId()
558{
559    Mutex::Autolock _l(mLock);
560    return mAudioSessionId;
561}
562
563status_t MediaPlayer::setAuxEffectSendLevel(float level)
564{
565    LOGV("MediaPlayer::setAuxEffectSendLevel(%f)", level);
566    Mutex::Autolock _l(mLock);
567    mSendLevel = level;
568    if (mPlayer != 0) {
569        return mPlayer->setAuxEffectSendLevel(level);
570    }
571    return OK;
572}
573
574status_t MediaPlayer::attachAuxEffect(int effectId)
575{
576    LOGV("MediaPlayer::attachAuxEffect(%d)", effectId);
577    Mutex::Autolock _l(mLock);
578    if (mPlayer == 0 ||
579        (mCurrentState & MEDIA_PLAYER_IDLE) ||
580        (mCurrentState == MEDIA_PLAYER_STATE_ERROR )) {
581        LOGE("attachAuxEffect called in state %d", mCurrentState);
582        return INVALID_OPERATION;
583    }
584
585    return mPlayer->attachAuxEffect(effectId);
586}
587
588status_t MediaPlayer::setParameter(int key, const Parcel& request)
589{
590    LOGV("MediaPlayer::setParameter(%d)", key);
591    Mutex::Autolock _l(mLock);
592    if (mPlayer != NULL) {
593        return  mPlayer->setParameter(key, request);
594    }
595    LOGV("setParameter: no active player");
596    return INVALID_OPERATION;
597}
598
599status_t MediaPlayer::getParameter(int key, Parcel *reply)
600{
601    LOGV("MediaPlayer::getParameter(%d)", key);
602    Mutex::Autolock _l(mLock);
603    if (mPlayer != NULL) {
604         return  mPlayer->getParameter(key, reply);
605    }
606    LOGV("getParameter: no active player");
607    return INVALID_OPERATION;
608}
609
610void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
611{
612    LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
613    bool send = true;
614    bool locked = false;
615
616    // TODO: In the future, we might be on the same thread if the app is
617    // running in the same process as the media server. In that case,
618    // this will deadlock.
619    //
620    // The threadId hack below works around this for the care of prepare
621    // and seekTo within the same process.
622    // FIXME: Remember, this is a hack, it's not even a hack that is applied
623    // consistently for all use-cases, this needs to be revisited.
624     if (mLockThreadId != getThreadId()) {
625        mLock.lock();
626        locked = true;
627    }
628
629    // Allows calls from JNI in idle state to notify errors
630    if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
631        LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
632        if (locked) mLock.unlock();   // release the lock when done.
633        return;
634    }
635
636    switch (msg) {
637    case MEDIA_NOP: // interface test message
638        break;
639    case MEDIA_PREPARED:
640        LOGV("prepared");
641        mCurrentState = MEDIA_PLAYER_PREPARED;
642        if (mPrepareSync) {
643            LOGV("signal application thread");
644            mPrepareSync = false;
645            mPrepareStatus = NO_ERROR;
646            mSignal.signal();
647        }
648        break;
649    case MEDIA_PLAYBACK_COMPLETE:
650        LOGV("playback complete");
651        if (mCurrentState == MEDIA_PLAYER_IDLE) {
652            LOGE("playback complete in idle state");
653        }
654        if (!mLoop) {
655            mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
656        }
657        break;
658    case MEDIA_ERROR:
659        // Always log errors.
660        // ext1: Media framework error code.
661        // ext2: Implementation dependant error code.
662        LOGE("error (%d, %d)", ext1, ext2);
663        mCurrentState = MEDIA_PLAYER_STATE_ERROR;
664        if (mPrepareSync)
665        {
666            LOGV("signal application thread");
667            mPrepareSync = false;
668            mPrepareStatus = ext1;
669            mSignal.signal();
670            send = false;
671        }
672        break;
673    case MEDIA_INFO:
674        // ext1: Media framework error code.
675        // ext2: Implementation dependant error code.
676        if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
677            LOGW("info/warning (%d, %d)", ext1, ext2);
678        }
679        break;
680    case MEDIA_SEEK_COMPLETE:
681        LOGV("Received seek complete");
682        if (mSeekPosition != mCurrentPosition) {
683            LOGV("Executing queued seekTo(%d)", mSeekPosition);
684            mSeekPosition = -1;
685            seekTo_l(mCurrentPosition);
686        }
687        else {
688            LOGV("All seeks complete - return to regularly scheduled program");
689            mCurrentPosition = mSeekPosition = -1;
690        }
691        break;
692    case MEDIA_BUFFERING_UPDATE:
693        LOGV("buffering %d", ext1);
694        break;
695    case MEDIA_SET_VIDEO_SIZE:
696        LOGV("New video size %d x %d", ext1, ext2);
697        mVideoWidth = ext1;
698        mVideoHeight = ext2;
699        break;
700    case MEDIA_TIMED_TEXT:
701        LOGV("Received timed text message");
702        break;
703    default:
704        LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
705        break;
706    }
707
708    sp<MediaPlayerListener> listener = mListener;
709    if (locked) mLock.unlock();
710
711    // this prevents re-entrant calls into client code
712    if ((listener != 0) && send) {
713        Mutex::Autolock _l(mNotifyLock);
714        LOGV("callback application");
715        listener->notify(msg, ext1, ext2, obj);
716        LOGV("back from callback");
717    }
718}
719
720/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
721{
722    LOGV("decode(%s)", url);
723    sp<IMemory> p;
724    const sp<IMediaPlayerService>& service = getMediaPlayerService();
725    if (service != 0) {
726        p = service->decode(url, pSampleRate, pNumChannels, pFormat);
727    } else {
728        LOGE("Unable to locate media service");
729    }
730    return p;
731
732}
733
734void MediaPlayer::died()
735{
736    LOGV("died");
737    notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
738}
739
740/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
741{
742    LOGV("decode(%d, %lld, %lld)", fd, offset, length);
743    sp<IMemory> p;
744    const sp<IMediaPlayerService>& service = getMediaPlayerService();
745    if (service != 0) {
746        p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
747    } else {
748        LOGE("Unable to locate media service");
749    }
750    return p;
751
752}
753
754}; // namespace android
755