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