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