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