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