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