mediaplayer.cpp revision fff6d715a8db0daf08a50634f242c40268de3d49
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    ALOGV("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    ALOGV("destructor");
71    AudioSystem::releaseAudioSessionId(mAudioSessionId);
72    disconnect();
73    IPCThreadState::self()->flushCommands();
74}
75
76void MediaPlayer::disconnect()
77{
78    ALOGV("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    ALOGV("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            ALOGE("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            ALOGE("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    ALOGV("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    ALOGV("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    ALOGV("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         ALOGV("invoke %d", request.dataSize());
196         return  mPlayer->invoke(request, reply);
197    }
198    ALOGE("invoke failed: wrong state %X", mCurrentState);
199    return INVALID_OPERATION;
200}
201
202status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
203{
204    ALOGD("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    ALOGD("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::setVideoSurfaceTexture(
223        const sp<ISurfaceTexture>& surfaceTexture)
224{
225    ALOGV("setVideoSurfaceTexture");
226    Mutex::Autolock _l(mLock);
227    if (mPlayer == 0) return NO_INIT;
228    return mPlayer->setVideoSurfaceTexture(surfaceTexture);
229}
230
231// must call with lock held
232status_t MediaPlayer::prepareAsync_l()
233{
234    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
235        mPlayer->setAudioStreamType(mStreamType);
236        mCurrentState = MEDIA_PLAYER_PREPARING;
237        return mPlayer->prepareAsync();
238    }
239    ALOGE("prepareAsync called in state %d", mCurrentState);
240    return INVALID_OPERATION;
241}
242
243// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
244// one defined in the Android framework and one provided by the implementation
245// that generated the error. The sync version of prepare returns only 1 error
246// code.
247status_t MediaPlayer::prepare()
248{
249    ALOGV("prepare");
250    Mutex::Autolock _l(mLock);
251    mLockThreadId = getThreadId();
252    if (mPrepareSync) {
253        mLockThreadId = 0;
254        return -EALREADY;
255    }
256    mPrepareSync = true;
257    status_t ret = prepareAsync_l();
258    if (ret != NO_ERROR) {
259        mLockThreadId = 0;
260        return ret;
261    }
262
263    if (mPrepareSync) {
264        mSignal.wait(mLock);  // wait for prepare done
265        mPrepareSync = false;
266    }
267    ALOGV("prepare complete - status=%d", mPrepareStatus);
268    mLockThreadId = 0;
269    return mPrepareStatus;
270}
271
272status_t MediaPlayer::prepareAsync()
273{
274    ALOGV("prepareAsync");
275    Mutex::Autolock _l(mLock);
276    return prepareAsync_l();
277}
278
279status_t MediaPlayer::start()
280{
281    ALOGV("start");
282    Mutex::Autolock _l(mLock);
283    if (mCurrentState & MEDIA_PLAYER_STARTED)
284        return NO_ERROR;
285    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
286                    MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
287        mPlayer->setLooping(mLoop);
288        mPlayer->setVolume(mLeftVolume, mRightVolume);
289        mPlayer->setAuxEffectSendLevel(mSendLevel);
290        mCurrentState = MEDIA_PLAYER_STARTED;
291        status_t ret = mPlayer->start();
292        if (ret != NO_ERROR) {
293            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
294        } else {
295            if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
296                ALOGV("playback completed immediately following start()");
297            }
298        }
299        return ret;
300    }
301    ALOGE("start called in state %d", mCurrentState);
302    return INVALID_OPERATION;
303}
304
305status_t MediaPlayer::stop()
306{
307    ALOGV("stop");
308    Mutex::Autolock _l(mLock);
309    if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
310    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
311                    MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
312        status_t ret = mPlayer->stop();
313        if (ret != NO_ERROR) {
314            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
315        } else {
316            mCurrentState = MEDIA_PLAYER_STOPPED;
317        }
318        return ret;
319    }
320    ALOGE("stop called in state %d", mCurrentState);
321    return INVALID_OPERATION;
322}
323
324status_t MediaPlayer::pause()
325{
326    ALOGV("pause");
327    Mutex::Autolock _l(mLock);
328    if (mCurrentState & (MEDIA_PLAYER_PAUSED|MEDIA_PLAYER_PLAYBACK_COMPLETE))
329        return NO_ERROR;
330    if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
331        status_t ret = mPlayer->pause();
332        if (ret != NO_ERROR) {
333            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
334        } else {
335            mCurrentState = MEDIA_PLAYER_PAUSED;
336        }
337        return ret;
338    }
339    ALOGE("pause called in state %d", mCurrentState);
340    return INVALID_OPERATION;
341}
342
343bool MediaPlayer::isPlaying()
344{
345    Mutex::Autolock _l(mLock);
346    if (mPlayer != 0) {
347        bool temp = false;
348        mPlayer->isPlaying(&temp);
349        ALOGV("isPlaying: %d", temp);
350        if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
351            ALOGE("internal/external state mismatch corrected");
352            mCurrentState = MEDIA_PLAYER_PAUSED;
353        }
354        return temp;
355    }
356    ALOGV("isPlaying: no active player");
357    return false;
358}
359
360status_t MediaPlayer::getVideoWidth(int *w)
361{
362    ALOGV("getVideoWidth");
363    Mutex::Autolock _l(mLock);
364    if (mPlayer == 0) return INVALID_OPERATION;
365    *w = mVideoWidth;
366    return NO_ERROR;
367}
368
369status_t MediaPlayer::getVideoHeight(int *h)
370{
371    ALOGV("getVideoHeight");
372    Mutex::Autolock _l(mLock);
373    if (mPlayer == 0) return INVALID_OPERATION;
374    *h = mVideoHeight;
375    return NO_ERROR;
376}
377
378status_t MediaPlayer::getCurrentPosition(int *msec)
379{
380    ALOGV("getCurrentPosition");
381    Mutex::Autolock _l(mLock);
382    if (mPlayer != 0) {
383        if (mCurrentPosition >= 0) {
384            ALOGV("Using cached seek position: %d", mCurrentPosition);
385            *msec = mCurrentPosition;
386            return NO_ERROR;
387        }
388        return mPlayer->getCurrentPosition(msec);
389    }
390    return INVALID_OPERATION;
391}
392
393status_t MediaPlayer::getDuration_l(int *msec)
394{
395    ALOGV("getDuration");
396    bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
397    if (mPlayer != 0 && isValidState) {
398        status_t ret = NO_ERROR;
399        if (mDuration <= 0)
400            ret = mPlayer->getDuration(&mDuration);
401        if (msec)
402            *msec = mDuration;
403        return ret;
404    }
405    ALOGE("Attempt to call getDuration without a valid mediaplayer");
406    return INVALID_OPERATION;
407}
408
409status_t MediaPlayer::getDuration(int *msec)
410{
411    Mutex::Autolock _l(mLock);
412    return getDuration_l(msec);
413}
414
415status_t MediaPlayer::seekTo_l(int msec)
416{
417    ALOGV("seekTo %d", msec);
418    if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED |  MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
419        if ( msec < 0 ) {
420            ALOGW("Attempt to seek to invalid position: %d", msec);
421            msec = 0;
422        } else if ((mDuration > 0) && (msec > mDuration)) {
423            ALOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
424            msec = mDuration;
425        }
426        // cache duration
427        mCurrentPosition = msec;
428        if (mSeekPosition < 0) {
429            getDuration_l(NULL);
430            mSeekPosition = msec;
431            return mPlayer->seekTo(msec);
432        }
433        else {
434            ALOGV("Seek in progress - queue up seekTo[%d]", msec);
435            return NO_ERROR;
436        }
437    }
438    ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
439    return INVALID_OPERATION;
440}
441
442status_t MediaPlayer::seekTo(int msec)
443{
444    mLockThreadId = getThreadId();
445    Mutex::Autolock _l(mLock);
446    status_t result = seekTo_l(msec);
447    mLockThreadId = 0;
448
449    return result;
450}
451
452status_t MediaPlayer::reset_l()
453{
454    mLoop = false;
455    if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
456    mPrepareSync = false;
457    if (mPlayer != 0) {
458        status_t ret = mPlayer->reset();
459        if (ret != NO_ERROR) {
460            ALOGE("reset() failed with return code (%d)", ret);
461            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
462        } else {
463            mCurrentState = MEDIA_PLAYER_IDLE;
464        }
465        // setDataSource has to be called again to create a
466        // new mediaplayer.
467        mPlayer = 0;
468        return ret;
469    }
470    clear_l();
471    return NO_ERROR;
472}
473
474status_t MediaPlayer::reset()
475{
476    ALOGV("reset");
477    Mutex::Autolock _l(mLock);
478    return reset_l();
479}
480
481status_t MediaPlayer::setAudioStreamType(audio_stream_type_t type)
482{
483    ALOGV("MediaPlayer::setAudioStreamType");
484    Mutex::Autolock _l(mLock);
485    if (mStreamType == type) return NO_ERROR;
486    if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
487                MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
488        // Can't change the stream type after prepare
489        ALOGE("setAudioStream called in state %d", mCurrentState);
490        return INVALID_OPERATION;
491    }
492    // cache
493    mStreamType = type;
494    return OK;
495}
496
497status_t MediaPlayer::setLooping(int loop)
498{
499    ALOGV("MediaPlayer::setLooping");
500    Mutex::Autolock _l(mLock);
501    mLoop = (loop != 0);
502    if (mPlayer != 0) {
503        return mPlayer->setLooping(loop);
504    }
505    return OK;
506}
507
508bool MediaPlayer::isLooping() {
509    ALOGV("isLooping");
510    Mutex::Autolock _l(mLock);
511    if (mPlayer != 0) {
512        return mLoop;
513    }
514    ALOGV("isLooping: no active player");
515    return false;
516}
517
518status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
519{
520    ALOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
521    Mutex::Autolock _l(mLock);
522    mLeftVolume = leftVolume;
523    mRightVolume = rightVolume;
524    if (mPlayer != 0) {
525        return mPlayer->setVolume(leftVolume, rightVolume);
526    }
527    return OK;
528}
529
530status_t MediaPlayer::setAudioSessionId(int sessionId)
531{
532    ALOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);
533    Mutex::Autolock _l(mLock);
534    if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {
535        ALOGE("setAudioSessionId called in state %d", mCurrentState);
536        return INVALID_OPERATION;
537    }
538    if (sessionId < 0) {
539        return BAD_VALUE;
540    }
541    if (sessionId != mAudioSessionId) {
542      AudioSystem::releaseAudioSessionId(mAudioSessionId);
543      AudioSystem::acquireAudioSessionId(sessionId);
544      mAudioSessionId = sessionId;
545    }
546    return NO_ERROR;
547}
548
549int MediaPlayer::getAudioSessionId()
550{
551    Mutex::Autolock _l(mLock);
552    return mAudioSessionId;
553}
554
555status_t MediaPlayer::setAuxEffectSendLevel(float level)
556{
557    ALOGV("MediaPlayer::setAuxEffectSendLevel(%f)", level);
558    Mutex::Autolock _l(mLock);
559    mSendLevel = level;
560    if (mPlayer != 0) {
561        return mPlayer->setAuxEffectSendLevel(level);
562    }
563    return OK;
564}
565
566status_t MediaPlayer::attachAuxEffect(int effectId)
567{
568    ALOGV("MediaPlayer::attachAuxEffect(%d)", effectId);
569    Mutex::Autolock _l(mLock);
570    if (mPlayer == 0 ||
571        (mCurrentState & MEDIA_PLAYER_IDLE) ||
572        (mCurrentState == MEDIA_PLAYER_STATE_ERROR )) {
573        ALOGE("attachAuxEffect called in state %d", mCurrentState);
574        return INVALID_OPERATION;
575    }
576
577    return mPlayer->attachAuxEffect(effectId);
578}
579
580status_t MediaPlayer::setParameter(int key, const Parcel& request)
581{
582    ALOGV("MediaPlayer::setParameter(%d)", key);
583    Mutex::Autolock _l(mLock);
584    if (mPlayer != NULL) {
585        return  mPlayer->setParameter(key, request);
586    }
587    ALOGV("setParameter: no active player");
588    return INVALID_OPERATION;
589}
590
591status_t MediaPlayer::getParameter(int key, Parcel *reply)
592{
593    ALOGV("MediaPlayer::getParameter(%d)", key);
594    Mutex::Autolock _l(mLock);
595    if (mPlayer != NULL) {
596         return  mPlayer->getParameter(key, reply);
597    }
598    ALOGV("getParameter: no active player");
599    return INVALID_OPERATION;
600}
601
602void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
603{
604    ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
605    bool send = true;
606    bool locked = false;
607
608    // TODO: In the future, we might be on the same thread if the app is
609    // running in the same process as the media server. In that case,
610    // this will deadlock.
611    //
612    // The threadId hack below works around this for the care of prepare
613    // and seekTo within the same process.
614    // FIXME: Remember, this is a hack, it's not even a hack that is applied
615    // consistently for all use-cases, this needs to be revisited.
616     if (mLockThreadId != getThreadId()) {
617        mLock.lock();
618        locked = true;
619    }
620
621    // Allows calls from JNI in idle state to notify errors
622    if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
623        ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
624        if (locked) mLock.unlock();   // release the lock when done.
625        return;
626    }
627
628    switch (msg) {
629    case MEDIA_NOP: // interface test message
630        break;
631    case MEDIA_PREPARED:
632        ALOGV("prepared");
633        mCurrentState = MEDIA_PLAYER_PREPARED;
634        if (mPrepareSync) {
635            ALOGV("signal application thread");
636            mPrepareSync = false;
637            mPrepareStatus = NO_ERROR;
638            mSignal.signal();
639        }
640        break;
641    case MEDIA_PLAYBACK_COMPLETE:
642        ALOGV("playback complete");
643        if (mCurrentState == MEDIA_PLAYER_IDLE) {
644            ALOGE("playback complete in idle state");
645        }
646        if (!mLoop) {
647            mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
648        }
649        break;
650    case MEDIA_ERROR:
651        // Always log errors.
652        // ext1: Media framework error code.
653        // ext2: Implementation dependant error code.
654        ALOGE("error (%d, %d)", ext1, ext2);
655        mCurrentState = MEDIA_PLAYER_STATE_ERROR;
656        if (mPrepareSync)
657        {
658            ALOGV("signal application thread");
659            mPrepareSync = false;
660            mPrepareStatus = ext1;
661            mSignal.signal();
662            send = false;
663        }
664        break;
665    case MEDIA_INFO:
666        // ext1: Media framework error code.
667        // ext2: Implementation dependant error code.
668        if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
669            ALOGW("info/warning (%d, %d)", ext1, ext2);
670        }
671        break;
672    case MEDIA_SEEK_COMPLETE:
673        ALOGV("Received seek complete");
674        if (mSeekPosition != mCurrentPosition) {
675            ALOGV("Executing queued seekTo(%d)", mSeekPosition);
676            mSeekPosition = -1;
677            seekTo_l(mCurrentPosition);
678        }
679        else {
680            ALOGV("All seeks complete - return to regularly scheduled program");
681            mCurrentPosition = mSeekPosition = -1;
682        }
683        break;
684    case MEDIA_BUFFERING_UPDATE:
685        ALOGV("buffering %d", ext1);
686        break;
687    case MEDIA_SET_VIDEO_SIZE:
688        ALOGV("New video size %d x %d", ext1, ext2);
689        mVideoWidth = ext1;
690        mVideoHeight = ext2;
691        break;
692    case MEDIA_TIMED_TEXT:
693        ALOGV("Received timed text message");
694        break;
695    default:
696        ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
697        break;
698    }
699
700    sp<MediaPlayerListener> listener = mListener;
701    if (locked) mLock.unlock();
702
703    // this prevents re-entrant calls into client code
704    if ((listener != 0) && send) {
705        Mutex::Autolock _l(mNotifyLock);
706        ALOGV("callback application");
707        listener->notify(msg, ext1, ext2, obj);
708        ALOGV("back from callback");
709    }
710}
711
712/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat)
713{
714    ALOGV("decode(%s)", url);
715    sp<IMemory> p;
716    const sp<IMediaPlayerService>& service = getMediaPlayerService();
717    if (service != 0) {
718        p = service->decode(url, pSampleRate, pNumChannels, pFormat);
719    } else {
720        ALOGE("Unable to locate media service");
721    }
722    return p;
723
724}
725
726void MediaPlayer::died()
727{
728    ALOGV("died");
729    notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
730}
731
732/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat)
733{
734    ALOGV("decode(%d, %lld, %lld)", fd, offset, length);
735    sp<IMemory> p;
736    const sp<IMediaPlayerService>& service = getMediaPlayerService();
737    if (service != 0) {
738        p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
739    } else {
740        ALOGE("Unable to locate media service");
741    }
742    return p;
743
744}
745
746}; // namespace android
747