mediaplayer.cpp revision dd172fce75b2a1c3cb3a5d3b3bbb5020b1ae8675
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 <media/mediaplayer.h>
31#include <media/AudioTrack.h>
32
33#include <binder/MemoryBase.h>
34
35namespace android {
36
37MediaPlayer::MediaPlayer()
38{
39    LOGV("constructor");
40    mListener = NULL;
41    mCookie = NULL;
42    mDuration = -1;
43    mStreamType = AudioSystem::MUSIC;
44    mCurrentPosition = -1;
45    mSeekPosition = -1;
46    mCurrentState = MEDIA_PLAYER_IDLE;
47    mPrepareSync = false;
48    mPrepareStatus = NO_ERROR;
49    mLoop = false;
50    mLeftVolume = mRightVolume = 1.0;
51    mVideoWidth = mVideoHeight = 0;
52    mLockThreadId = 0;
53}
54
55MediaPlayer::~MediaPlayer()
56{
57    LOGV("destructor");
58    disconnect();
59    IPCThreadState::self()->flushCommands();
60}
61
62void MediaPlayer::disconnect()
63{
64    LOGV("disconnect");
65    sp<IMediaPlayer> p;
66    {
67        Mutex::Autolock _l(mLock);
68        p = mPlayer;
69        mPlayer.clear();
70    }
71
72    if (p != 0) {
73        p->disconnect();
74    }
75}
76
77// always call with lock held
78void MediaPlayer::clear_l()
79{
80    mDuration = -1;
81    mCurrentPosition = -1;
82    mSeekPosition = -1;
83    mVideoWidth = mVideoHeight = 0;
84}
85
86status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
87{
88    LOGV("setListener");
89    Mutex::Autolock _l(mLock);
90    mListener = listener;
91    return NO_ERROR;
92}
93
94
95status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
96{
97    status_t err = UNKNOWN_ERROR;
98    sp<IMediaPlayer> p;
99    { // scope for the lock
100        Mutex::Autolock _l(mLock);
101
102        if ( !( mCurrentState & ( MEDIA_PLAYER_IDLE | MEDIA_PLAYER_STATE_ERROR ) ) ) {
103            LOGE("setDataSource called in state %d", mCurrentState);
104            return INVALID_OPERATION;
105        }
106
107        clear_l();
108        p = mPlayer;
109        mPlayer = player;
110        if (player != 0) {
111            mCurrentState = MEDIA_PLAYER_INITIALIZED;
112            err = NO_ERROR;
113        } else {
114            LOGE("Unable to to create media player");
115        }
116    }
117
118    if (p != 0) {
119        p->disconnect();
120    }
121
122    return err;
123}
124
125status_t MediaPlayer::setDataSource(const char *url)
126{
127    LOGV("setDataSource(%s)", url);
128    status_t err = BAD_VALUE;
129    if (url != NULL) {
130        const sp<IMediaPlayerService>& service(getMediaPlayerService());
131        if (service != 0) {
132            sp<IMediaPlayer> player(service->create(getpid(), this, url));
133            err = setDataSource(player);
134        }
135    }
136    return err;
137}
138
139status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
140{
141    LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
142    status_t err = UNKNOWN_ERROR;
143    const sp<IMediaPlayerService>& service(getMediaPlayerService());
144    if (service != 0) {
145        sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length));
146        err = setDataSource(player);
147    }
148    return err;
149}
150
151status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
152{
153    Mutex::Autolock _l(mLock);
154    if ((mPlayer != NULL) && ( mCurrentState & MEDIA_PLAYER_INITIALIZED ))
155    {
156         LOGV("invoke %d", request.dataSize());
157         return  mPlayer->invoke(request, reply);
158    }
159    LOGE("invoke failed: wrong state %X", mCurrentState);
160    return INVALID_OPERATION;
161}
162
163status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
164{
165    LOGD("setMetadataFilter");
166    Mutex::Autolock lock(mLock);
167    if (mPlayer == NULL) {
168        return NO_INIT;
169    }
170    return mPlayer->setMetadataFilter(filter);
171}
172
173status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
174{
175    LOGD("getMetadata");
176    Mutex::Autolock lock(mLock);
177    if (mPlayer == NULL) {
178        return NO_INIT;
179    }
180    return mPlayer->getMetadata(update_only, apply_filter, metadata);
181}
182
183status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
184{
185    LOGV("setVideoSurface");
186    Mutex::Autolock _l(mLock);
187    if (mPlayer == 0) return NO_INIT;
188    if (surface != NULL)
189        return  mPlayer->setVideoSurface(surface->getISurface());
190    else
191        return  mPlayer->setVideoSurface(NULL);
192}
193
194// must call with lock held
195status_t MediaPlayer::prepareAsync_l()
196{
197    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
198        mPlayer->setAudioStreamType(mStreamType);
199        mCurrentState = MEDIA_PLAYER_PREPARING;
200        return mPlayer->prepareAsync();
201    }
202    LOGE("prepareAsync called in state %d", mCurrentState);
203    return INVALID_OPERATION;
204}
205
206// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
207// one defined in the Android framework and one provided by the implementation
208// that generated the error. The sync version of prepare returns only 1 error
209// code.
210status_t MediaPlayer::prepare()
211{
212    LOGV("prepare");
213    Mutex::Autolock _l(mLock);
214    mLockThreadId = getThreadId();
215    if (mPrepareSync) {
216        mLockThreadId = 0;
217        return -EALREADY;
218    }
219    mPrepareSync = true;
220    status_t ret = prepareAsync_l();
221    if (ret != NO_ERROR) {
222        mLockThreadId = 0;
223        return ret;
224    }
225
226    if (mPrepareSync) {
227        mSignal.wait(mLock);  // wait for prepare done
228        mPrepareSync = false;
229    }
230    LOGV("prepare complete - status=%d", mPrepareStatus);
231    mLockThreadId = 0;
232    return mPrepareStatus;
233}
234
235status_t MediaPlayer::prepareAsync()
236{
237    LOGV("prepareAsync");
238    Mutex::Autolock _l(mLock);
239    return prepareAsync_l();
240}
241
242status_t MediaPlayer::start()
243{
244    LOGV("start");
245    Mutex::Autolock _l(mLock);
246    if (mCurrentState & MEDIA_PLAYER_STARTED)
247        return NO_ERROR;
248    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
249                    MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
250        mPlayer->setLooping(mLoop);
251        mPlayer->setVolume(mLeftVolume, mRightVolume);
252        mCurrentState = MEDIA_PLAYER_STARTED;
253        status_t ret = mPlayer->start();
254        if (ret != NO_ERROR) {
255            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
256        } else {
257            if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
258                LOGV("playback completed immediately following start()");
259            }
260        }
261        return ret;
262    }
263    LOGE("start called in state %d", mCurrentState);
264    return INVALID_OPERATION;
265}
266
267status_t MediaPlayer::stop()
268{
269    LOGV("stop");
270    Mutex::Autolock _l(mLock);
271    if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
272    if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
273                    MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
274        status_t ret = mPlayer->stop();
275        if (ret != NO_ERROR) {
276            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
277        } else {
278            mCurrentState = MEDIA_PLAYER_STOPPED;
279        }
280        return ret;
281    }
282    LOGE("stop called in state %d", mCurrentState);
283    return INVALID_OPERATION;
284}
285
286status_t MediaPlayer::pause()
287{
288    LOGV("pause");
289    Mutex::Autolock _l(mLock);
290    if (mCurrentState & MEDIA_PLAYER_PAUSED)
291        return NO_ERROR;
292    if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
293        status_t ret = mPlayer->pause();
294        if (ret != NO_ERROR) {
295            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
296        } else {
297            mCurrentState = MEDIA_PLAYER_PAUSED;
298        }
299        return ret;
300    }
301    LOGE("pause called in state %d", mCurrentState);
302    return INVALID_OPERATION;
303}
304
305bool MediaPlayer::isPlaying()
306{
307    Mutex::Autolock _l(mLock);
308    if (mPlayer != 0) {
309        bool temp = false;
310        mPlayer->isPlaying(&temp);
311        LOGV("isPlaying: %d", temp);
312        if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
313            LOGE("internal/external state mismatch corrected");
314            mCurrentState = MEDIA_PLAYER_PAUSED;
315        }
316        return temp;
317    }
318    LOGV("isPlaying: no active player");
319    return false;
320}
321
322status_t MediaPlayer::getVideoWidth(int *w)
323{
324    LOGV("getVideoWidth");
325    Mutex::Autolock _l(mLock);
326    if (mPlayer == 0) return INVALID_OPERATION;
327    *w = mVideoWidth;
328    return NO_ERROR;
329}
330
331status_t MediaPlayer::getVideoHeight(int *h)
332{
333    LOGV("getVideoHeight");
334    Mutex::Autolock _l(mLock);
335    if (mPlayer == 0) return INVALID_OPERATION;
336    *h = mVideoHeight;
337    return NO_ERROR;
338}
339
340status_t MediaPlayer::getCurrentPosition(int *msec)
341{
342    LOGV("getCurrentPosition");
343    Mutex::Autolock _l(mLock);
344    if (mPlayer != 0) {
345        if (mCurrentPosition >= 0) {
346            LOGV("Using cached seek position: %d", mCurrentPosition);
347            *msec = mCurrentPosition;
348            return NO_ERROR;
349        }
350        return mPlayer->getCurrentPosition(msec);
351    }
352    return INVALID_OPERATION;
353}
354
355status_t MediaPlayer::getDuration_l(int *msec)
356{
357    LOGV("getDuration");
358    bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
359    if (mPlayer != 0 && isValidState) {
360        status_t ret = NO_ERROR;
361        if (mDuration <= 0)
362            ret = mPlayer->getDuration(&mDuration);
363        if (msec)
364            *msec = mDuration;
365        return ret;
366    }
367    LOGE("Attempt to call getDuration without a valid mediaplayer");
368    return INVALID_OPERATION;
369}
370
371status_t MediaPlayer::getDuration(int *msec)
372{
373    Mutex::Autolock _l(mLock);
374    return getDuration_l(msec);
375}
376
377status_t MediaPlayer::seekTo_l(int msec)
378{
379    LOGV("seekTo %d", msec);
380    if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED |  MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
381        if ( msec < 0 ) {
382            LOGW("Attempt to seek to invalid position: %d", msec);
383            msec = 0;
384        } else if ((mDuration > 0) && (msec > mDuration)) {
385            LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
386            msec = mDuration;
387        }
388        // cache duration
389        mCurrentPosition = msec;
390        if (mSeekPosition < 0) {
391            getDuration_l(NULL);
392            mSeekPosition = msec;
393            return mPlayer->seekTo(msec);
394        }
395        else {
396            LOGV("Seek in progress - queue up seekTo[%d]", msec);
397            return NO_ERROR;
398        }
399    }
400    LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
401    return INVALID_OPERATION;
402}
403
404status_t MediaPlayer::seekTo(int msec)
405{
406    mLockThreadId = getThreadId();
407    Mutex::Autolock _l(mLock);
408    status_t result = seekTo_l(msec);
409    mLockThreadId = 0;
410
411    return result;
412}
413
414status_t MediaPlayer::reset()
415{
416    LOGV("reset");
417    Mutex::Autolock _l(mLock);
418    mLoop = false;
419    if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
420    mPrepareSync = false;
421    if (mPlayer != 0) {
422        status_t ret = mPlayer->reset();
423        if (ret != NO_ERROR) {
424            LOGE("reset() failed with return code (%d)", ret);
425            mCurrentState = MEDIA_PLAYER_STATE_ERROR;
426        } else {
427            mCurrentState = MEDIA_PLAYER_IDLE;
428        }
429        return ret;
430    }
431    clear_l();
432    return NO_ERROR;
433}
434
435status_t MediaPlayer::setAudioStreamType(int type)
436{
437    LOGV("MediaPlayer::setAudioStreamType");
438    Mutex::Autolock _l(mLock);
439    if (mStreamType == type) return NO_ERROR;
440    if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
441                MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
442        // Can't change the stream type after prepare
443        LOGE("setAudioStream called in state %d", mCurrentState);
444        return INVALID_OPERATION;
445    }
446    // cache
447    mStreamType = type;
448    return OK;
449}
450
451status_t MediaPlayer::setLooping(int loop)
452{
453    LOGV("MediaPlayer::setLooping");
454    Mutex::Autolock _l(mLock);
455    mLoop = (loop != 0);
456    if (mPlayer != 0) {
457        return mPlayer->setLooping(loop);
458    }
459    return OK;
460}
461
462bool MediaPlayer::isLooping() {
463    LOGV("isLooping");
464    Mutex::Autolock _l(mLock);
465    if (mPlayer != 0) {
466        return mLoop;
467    }
468    LOGV("isLooping: no active player");
469    return false;
470}
471
472status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
473{
474    LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
475    Mutex::Autolock _l(mLock);
476    mLeftVolume = leftVolume;
477    mRightVolume = rightVolume;
478    if (mPlayer != 0) {
479        return mPlayer->setVolume(leftVolume, rightVolume);
480    }
481    return OK;
482}
483
484void MediaPlayer::notify(int msg, int ext1, int ext2)
485{
486    LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
487    bool send = true;
488    bool locked = false;
489
490    // TODO: In the future, we might be on the same thread if the app is
491    // running in the same process as the media server. In that case,
492    // this will deadlock.
493    //
494    // The threadId hack below works around this for the care of prepare
495    // and seekTo within the same process.
496    // FIXME: Remember, this is a hack, it's not even a hack that is applied
497    // consistently for all use-cases, this needs to be revisited.
498     if (mLockThreadId != getThreadId()) {
499        mLock.lock();
500        locked = true;
501    }
502
503    if (mPlayer == 0) {
504        LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
505        if (locked) mLock.unlock();   // release the lock when done.
506        return;
507    }
508
509    switch (msg) {
510    case MEDIA_NOP: // interface test message
511        break;
512    case MEDIA_PREPARED:
513        LOGV("prepared");
514        mCurrentState = MEDIA_PLAYER_PREPARED;
515        if (mPrepareSync) {
516            LOGV("signal application thread");
517            mPrepareSync = false;
518            mPrepareStatus = NO_ERROR;
519            mSignal.signal();
520        }
521        break;
522    case MEDIA_PLAYBACK_COMPLETE:
523        LOGV("playback complete");
524        if (!mLoop) {
525            mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
526        }
527        break;
528    case MEDIA_ERROR:
529        // Always log errors.
530        // ext1: Media framework error code.
531        // ext2: Implementation dependant error code.
532        LOGE("error (%d, %d)", ext1, ext2);
533        mCurrentState = MEDIA_PLAYER_STATE_ERROR;
534        if (mPrepareSync)
535        {
536            LOGV("signal application thread");
537            mPrepareSync = false;
538            mPrepareStatus = ext1;
539            mSignal.signal();
540            send = false;
541        }
542        break;
543    case MEDIA_INFO:
544        // ext1: Media framework error code.
545        // ext2: Implementation dependant error code.
546        LOGW("info/warning (%d, %d)", ext1, ext2);
547        break;
548    case MEDIA_SEEK_COMPLETE:
549        LOGV("Received seek complete");
550        if (mSeekPosition != mCurrentPosition) {
551            LOGV("Executing queued seekTo(%d)", mSeekPosition);
552            mSeekPosition = -1;
553            seekTo_l(mCurrentPosition);
554        }
555        else {
556            LOGV("All seeks complete - return to regularly scheduled program");
557            mCurrentPosition = mSeekPosition = -1;
558        }
559        break;
560    case MEDIA_BUFFERING_UPDATE:
561        LOGV("buffering %d", ext1);
562        break;
563    case MEDIA_SET_VIDEO_SIZE:
564        LOGV("New video size %d x %d", ext1, ext2);
565        mVideoWidth = ext1;
566        mVideoHeight = ext2;
567        break;
568    default:
569        LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
570        break;
571    }
572
573    sp<MediaPlayerListener> listener = mListener;
574    if (locked) mLock.unlock();
575
576    // this prevents re-entrant calls into client code
577    if ((listener != 0) && send) {
578        Mutex::Autolock _l(mNotifyLock);
579        LOGV("callback application");
580        listener->notify(msg, ext1, ext2);
581        LOGV("back from callback");
582    }
583}
584
585/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
586{
587    LOGV("decode(%s)", url);
588    sp<IMemory> p;
589    const sp<IMediaPlayerService>& service = getMediaPlayerService();
590    if (service != 0) {
591        p = service->decode(url, pSampleRate, pNumChannels, pFormat);
592    } else {
593        LOGE("Unable to locate media service");
594    }
595    return p;
596
597}
598
599void MediaPlayer::died()
600{
601    LOGV("died");
602    notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
603}
604
605/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
606{
607    LOGV("decode(%d, %lld, %lld)", fd, offset, length);
608    sp<IMemory> p;
609    const sp<IMediaPlayerService>& service = getMediaPlayerService();
610    if (service != 0) {
611        p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
612    } else {
613        LOGE("Unable to locate media service");
614    }
615    return p;
616
617}
618
619extern "C" {
620#define FLOATING_POINT 1
621#include "fftwrap.h"
622}
623
624static void *ffttable = NULL;
625
626// peeks at the audio data and fills 'data' with the requested kind
627// (currently kind=0 returns mono 16 bit PCM data, and kind=1 returns
628// 256 point FFT data). Return value is number of samples returned,
629// which may be 0.
630/*static*/ int MediaPlayer::snoop(short* data, int len, int kind) {
631
632    sp<IMemory> p;
633    const sp<IMediaPlayerService>& service = getMediaPlayerService();
634    if (service != 0) {
635        // Take a peek at the waveform. The returned data consists of 16 bit mono PCM data.
636        p = service->snoop();
637
638        if (p == NULL) {
639            return 0;
640        }
641
642        if (kind == 0) { // return waveform data
643            int plen = p->size();
644            len *= 2; // number of shorts -> number of bytes
645            short *src = (short*) p->pointer();
646            if (plen > len) {
647                plen = len;
648            }
649            memcpy(data, src, plen);
650            return plen / sizeof(short); // return number of samples
651        } else if (kind == 1) {
652            // TODO: use a more efficient FFT
653            // Right now this uses the speex library, which is compiled to do a float FFT
654            if (!ffttable) ffttable = spx_fft_init(512);
655            short *usrc = (short*) p->pointer();
656            float fsrc[512];
657            for (int i=0;i<512;i++)
658                fsrc[i] = usrc[i];
659            float fdst[512];
660            spx_fft_float(ffttable, fsrc, fdst);
661            if (len > 512) {
662                len = 512;
663            }
664            len /= 2; // only half the output data is valid
665            for (int i=0; i < len; i++)
666                data[i] = fdst[i];
667            return len;
668        }
669
670    } else {
671        LOGE("Unable to locate media service");
672    }
673    return 0;
674}
675
676}; // namespace android
677