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