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