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