blob: c0664f3cda92525307fb91092fcb7186e8654864 [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 Agopian75624082009-05-19 19:08:10 -070033#include <binder/MemoryBase.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080034
35namespace android {
36
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080037MediaPlayer::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;
Jason Sams1af452f2009-03-24 18:45:22 -070052 mLockThreadId = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080053}
54
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080055MediaPlayer::~MediaPlayer()
56{
57 LOGV("destructor");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080058 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
Nicolas Catania1d187f12009-05-12 23:25:55 -0700151status_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
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700163status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
164{
165 LOGD("setMetadataFilter");
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700166 Mutex::Autolock lock(mLock);
167 if (mPlayer == NULL) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700168 return NO_INIT;
169 }
170 return mPlayer->setMetadataFilter(filter);
171}
Nicolas Catania1d187f12009-05-12 23:25:55 -0700172
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700173status_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
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800183status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
184{
185 LOGV("setVideoSurface");
186 Mutex::Autolock _l(mLock);
187 if (mPlayer == 0) return NO_INIT;
Marco Nelissenaa371732009-07-10 09:34:59 -0700188 if (surface != NULL)
189 return mPlayer->setVideoSurface(surface->getISurface());
190 else
191 return mPlayer->setVideoSurface(NULL);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800192}
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
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700206// 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.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800210status_t MediaPlayer::prepare()
211{
212 LOGV("prepare");
213 Mutex::Autolock _l(mLock);
Jason Sams1af452f2009-03-24 18:45:22 -0700214 mLockThreadId = getThreadId();
215 if (mPrepareSync) {
216 mLockThreadId = 0;
217 return -EALREADY;
218 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800219 mPrepareSync = true;
220 status_t ret = prepareAsync_l();
Jason Sams1af452f2009-03-24 18:45:22 -0700221 if (ret != NO_ERROR) {
222 mLockThreadId = 0;
223 return ret;
224 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800225
226 if (mPrepareSync) {
227 mSignal.wait(mLock); // wait for prepare done
228 mPrepareSync = false;
229 }
230 LOGV("prepare complete - status=%d", mPrepareStatus);
Jason Sams1af452f2009-03-24 18:45:22 -0700231 mLockThreadId = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800232 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{
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700406 mLockThreadId = getThreadId();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800407 Mutex::Autolock _l(mLock);
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700408 status_t result = seekTo_l(msec);
409 mLockThreadId = 0;
410
411 return result;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800412}
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;
Jason Sams1af452f2009-03-24 18:45:22 -0700488 bool locked = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800489
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.
Nicolas Catania66095182009-06-11 16:33:49 -0700493 //
Jason Sams1af452f2009-03-24 18:45:22 -0700494 // The threadId hack below works around this for the care of prepare
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700495 // 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.
Jason Sams1af452f2009-03-24 18:45:22 -0700498 if (mLockThreadId != getThreadId()) {
499 mLock.lock();
500 locked = true;
Nicolas Catania66095182009-06-11 16:33:49 -0700501 }
Jason Sams1af452f2009-03-24 18:45:22 -0700502
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800503 if (mPlayer == 0) {
504 LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
Jason Sams1af452f2009-03-24 18:45:22 -0700505 if (locked) mLock.unlock(); // release the lock when done.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800506 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:
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700529 // Always log errors.
530 // ext1: Media framework error code.
531 // ext2: Implementation dependant error code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800532 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;
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700543 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;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800548 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;
Jason Sams1af452f2009-03-24 18:45:22 -0700574 if (locked) mLock.unlock();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800575
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
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800585/*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) {
James Dongdd172fc2010-01-15 18:13:58 -0800591 p = service->decode(url, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800592 } else {
593 LOGE("Unable to locate media service");
594 }
595 return p;
596
597}
598
James Dongdd172fc2010-01-15 18:13:58 -0800599void MediaPlayer::died()
600{
601 LOGV("died");
602 notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
603}
604
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800605/*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) {
James Dongdd172fc2010-01-15 18:13:58 -0800611 p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800612 } else {
613 LOGE("Unable to locate media service");
614 }
615 return p;
616
617}
618
Marco Nelissen10dbb8e2009-09-20 10:42:13 -0700619extern "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
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800676}; // namespace android