blob: c6bbbcc9cf2df9f0033dcd042aae97ef1f8a5f3d [file] [log] [blame]
The Android Open Source Project9066cfe2009-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 Agopian07952722009-05-19 19:08:10 -070027#include <binder/IServiceManager.h>
28#include <binder/IPCThreadState.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
30#include <media/mediaplayer.h>
31#include <media/AudioTrack.h>
32
Mathias Agopian000479f2010-02-09 17:46:37 -080033#include <surfaceflinger/Surface.h>
34
Mathias Agopian07952722009-05-19 19:08:10 -070035#include <binder/MemoryBase.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036
Andreas Huber25643002010-01-28 11:19:57 -080037#include <utils/KeyedVector.h>
38#include <utils/String8.h>
39
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040namespace android {
41
The Android Open Source Project9066cfe2009-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 Samsebb020a2009-03-24 18:45:22 -070057 mLockThreadId = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058}
59
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060MediaPlayer::~MediaPlayer()
61{
62 LOGV("destructor");
The Android Open Source Project9066cfe2009-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
Marco Nelissene44b41b2010-03-10 10:53:16 -0800107 if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
108 (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 LOGE("setDataSource called in state %d", mCurrentState);
110 return INVALID_OPERATION;
111 }
112
113 clear_l();
114 p = mPlayer;
115 mPlayer = player;
116 if (player != 0) {
117 mCurrentState = MEDIA_PLAYER_INITIALIZED;
118 err = NO_ERROR;
119 } else {
120 LOGE("Unable to to create media player");
121 }
122 }
123
124 if (p != 0) {
125 p->disconnect();
126 }
127
128 return err;
129}
130
Andreas Huber25643002010-01-28 11:19:57 -0800131status_t MediaPlayer::setDataSource(
132 const char *url, const KeyedVector<String8, String8> *headers)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133{
134 LOGV("setDataSource(%s)", url);
135 status_t err = BAD_VALUE;
136 if (url != NULL) {
137 const sp<IMediaPlayerService>& service(getMediaPlayerService());
138 if (service != 0) {
Andreas Huber25643002010-01-28 11:19:57 -0800139 sp<IMediaPlayer> player(
140 service->create(getpid(), this, url, headers));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 err = setDataSource(player);
142 }
143 }
144 return err;
145}
146
147status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
148{
149 LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
150 status_t err = UNKNOWN_ERROR;
151 const sp<IMediaPlayerService>& service(getMediaPlayerService());
152 if (service != 0) {
153 sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length));
154 err = setDataSource(player);
155 }
156 return err;
157}
158
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700159status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
160{
161 Mutex::Autolock _l(mLock);
Nicolas Catania7bd3d7d2010-03-10 10:41:04 -0800162 const bool hasBeenInitialized =
163 (mCurrentState != MEDIA_PLAYER_STATE_ERROR) &&
164 ((mCurrentState & MEDIA_PLAYER_IDLE) != MEDIA_PLAYER_IDLE);
165 if ((mPlayer != NULL) && hasBeenInitialized) {
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700166 LOGV("invoke %d", request.dataSize());
167 return mPlayer->invoke(request, reply);
168 }
169 LOGE("invoke failed: wrong state %X", mCurrentState);
170 return INVALID_OPERATION;
171}
172
Andreas Huberfbb38852010-02-12 12:35:58 -0800173status_t MediaPlayer::suspend() {
174 Mutex::Autolock _l(mLock);
175 return mPlayer->suspend();
176}
177
178status_t MediaPlayer::resume() {
179 Mutex::Autolock _l(mLock);
180 return mPlayer->resume();
181}
182
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700183status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
184{
185 LOGD("setMetadataFilter");
Nicolas Catania5d55c712009-07-09 09:21:33 -0700186 Mutex::Autolock lock(mLock);
187 if (mPlayer == NULL) {
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700188 return NO_INIT;
189 }
190 return mPlayer->setMetadataFilter(filter);
191}
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700192
Nicolas Catania5d55c712009-07-09 09:21:33 -0700193status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
194{
195 LOGD("getMetadata");
196 Mutex::Autolock lock(mLock);
197 if (mPlayer == NULL) {
198 return NO_INIT;
199 }
200 return mPlayer->getMetadata(update_only, apply_filter, metadata);
201}
202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
204{
205 LOGV("setVideoSurface");
206 Mutex::Autolock _l(mLock);
207 if (mPlayer == 0) return NO_INIT;
Marco Nelissen0fc736f322009-07-10 09:34:59 -0700208 if (surface != NULL)
209 return mPlayer->setVideoSurface(surface->getISurface());
210 else
211 return mPlayer->setVideoSurface(NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212}
213
214// must call with lock held
215status_t MediaPlayer::prepareAsync_l()
216{
217 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
218 mPlayer->setAudioStreamType(mStreamType);
219 mCurrentState = MEDIA_PLAYER_PREPARING;
220 return mPlayer->prepareAsync();
221 }
222 LOGE("prepareAsync called in state %d", mCurrentState);
223 return INVALID_OPERATION;
224}
225
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700226// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
227// one defined in the Android framework and one provided by the implementation
228// that generated the error. The sync version of prepare returns only 1 error
229// code.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230status_t MediaPlayer::prepare()
231{
232 LOGV("prepare");
233 Mutex::Autolock _l(mLock);
Jason Samsebb020a2009-03-24 18:45:22 -0700234 mLockThreadId = getThreadId();
235 if (mPrepareSync) {
236 mLockThreadId = 0;
237 return -EALREADY;
238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 mPrepareSync = true;
240 status_t ret = prepareAsync_l();
Jason Samsebb020a2009-03-24 18:45:22 -0700241 if (ret != NO_ERROR) {
242 mLockThreadId = 0;
243 return ret;
244 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
246 if (mPrepareSync) {
247 mSignal.wait(mLock); // wait for prepare done
248 mPrepareSync = false;
249 }
250 LOGV("prepare complete - status=%d", mPrepareStatus);
Jason Samsebb020a2009-03-24 18:45:22 -0700251 mLockThreadId = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 return mPrepareStatus;
253}
254
255status_t MediaPlayer::prepareAsync()
256{
257 LOGV("prepareAsync");
258 Mutex::Autolock _l(mLock);
259 return prepareAsync_l();
260}
261
262status_t MediaPlayer::start()
263{
264 LOGV("start");
265 Mutex::Autolock _l(mLock);
266 if (mCurrentState & MEDIA_PLAYER_STARTED)
267 return NO_ERROR;
268 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
269 MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
270 mPlayer->setLooping(mLoop);
271 mPlayer->setVolume(mLeftVolume, mRightVolume);
272 mCurrentState = MEDIA_PLAYER_STARTED;
273 status_t ret = mPlayer->start();
274 if (ret != NO_ERROR) {
275 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
276 } else {
277 if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
278 LOGV("playback completed immediately following start()");
279 }
280 }
281 return ret;
282 }
283 LOGE("start called in state %d", mCurrentState);
284 return INVALID_OPERATION;
285}
286
287status_t MediaPlayer::stop()
288{
289 LOGV("stop");
290 Mutex::Autolock _l(mLock);
291 if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
292 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
293 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
294 status_t ret = mPlayer->stop();
295 if (ret != NO_ERROR) {
296 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
297 } else {
298 mCurrentState = MEDIA_PLAYER_STOPPED;
299 }
300 return ret;
301 }
302 LOGE("stop called in state %d", mCurrentState);
303 return INVALID_OPERATION;
304}
305
306status_t MediaPlayer::pause()
307{
308 LOGV("pause");
309 Mutex::Autolock _l(mLock);
Marco Nelissen465faa92010-02-26 13:16:23 -0800310 if (mCurrentState & (MEDIA_PLAYER_PAUSED|MEDIA_PLAYER_PLAYBACK_COMPLETE))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 return NO_ERROR;
312 if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
313 status_t ret = mPlayer->pause();
314 if (ret != NO_ERROR) {
315 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
316 } else {
317 mCurrentState = MEDIA_PLAYER_PAUSED;
318 }
319 return ret;
320 }
321 LOGE("pause called in state %d", mCurrentState);
322 return INVALID_OPERATION;
323}
324
325bool MediaPlayer::isPlaying()
326{
327 Mutex::Autolock _l(mLock);
328 if (mPlayer != 0) {
329 bool temp = false;
330 mPlayer->isPlaying(&temp);
331 LOGV("isPlaying: %d", temp);
332 if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
333 LOGE("internal/external state mismatch corrected");
334 mCurrentState = MEDIA_PLAYER_PAUSED;
335 }
336 return temp;
337 }
338 LOGV("isPlaying: no active player");
339 return false;
340}
341
342status_t MediaPlayer::getVideoWidth(int *w)
343{
344 LOGV("getVideoWidth");
345 Mutex::Autolock _l(mLock);
346 if (mPlayer == 0) return INVALID_OPERATION;
347 *w = mVideoWidth;
348 return NO_ERROR;
349}
350
351status_t MediaPlayer::getVideoHeight(int *h)
352{
353 LOGV("getVideoHeight");
354 Mutex::Autolock _l(mLock);
355 if (mPlayer == 0) return INVALID_OPERATION;
356 *h = mVideoHeight;
357 return NO_ERROR;
358}
359
360status_t MediaPlayer::getCurrentPosition(int *msec)
361{
362 LOGV("getCurrentPosition");
363 Mutex::Autolock _l(mLock);
364 if (mPlayer != 0) {
365 if (mCurrentPosition >= 0) {
366 LOGV("Using cached seek position: %d", mCurrentPosition);
367 *msec = mCurrentPosition;
368 return NO_ERROR;
369 }
370 return mPlayer->getCurrentPosition(msec);
371 }
372 return INVALID_OPERATION;
373}
374
375status_t MediaPlayer::getDuration_l(int *msec)
376{
377 LOGV("getDuration");
378 bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
379 if (mPlayer != 0 && isValidState) {
380 status_t ret = NO_ERROR;
381 if (mDuration <= 0)
382 ret = mPlayer->getDuration(&mDuration);
383 if (msec)
384 *msec = mDuration;
385 return ret;
386 }
387 LOGE("Attempt to call getDuration without a valid mediaplayer");
388 return INVALID_OPERATION;
389}
390
391status_t MediaPlayer::getDuration(int *msec)
392{
393 Mutex::Autolock _l(mLock);
394 return getDuration_l(msec);
395}
396
397status_t MediaPlayer::seekTo_l(int msec)
398{
399 LOGV("seekTo %d", msec);
400 if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
401 if ( msec < 0 ) {
402 LOGW("Attempt to seek to invalid position: %d", msec);
403 msec = 0;
404 } else if ((mDuration > 0) && (msec > mDuration)) {
405 LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
406 msec = mDuration;
407 }
408 // cache duration
409 mCurrentPosition = msec;
410 if (mSeekPosition < 0) {
411 getDuration_l(NULL);
412 mSeekPosition = msec;
413 return mPlayer->seekTo(msec);
414 }
415 else {
416 LOGV("Seek in progress - queue up seekTo[%d]", msec);
417 return NO_ERROR;
418 }
419 }
420 LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
421 return INVALID_OPERATION;
422}
423
424status_t MediaPlayer::seekTo(int msec)
425{
Andreas Hubereffd8d52009-03-24 20:48:51 -0700426 mLockThreadId = getThreadId();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 Mutex::Autolock _l(mLock);
Andreas Hubereffd8d52009-03-24 20:48:51 -0700428 status_t result = seekTo_l(msec);
429 mLockThreadId = 0;
430
431 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432}
433
434status_t MediaPlayer::reset()
435{
436 LOGV("reset");
437 Mutex::Autolock _l(mLock);
438 mLoop = false;
439 if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
440 mPrepareSync = false;
441 if (mPlayer != 0) {
442 status_t ret = mPlayer->reset();
443 if (ret != NO_ERROR) {
444 LOGE("reset() failed with return code (%d)", ret);
445 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
446 } else {
447 mCurrentState = MEDIA_PLAYER_IDLE;
448 }
449 return ret;
450 }
451 clear_l();
452 return NO_ERROR;
453}
454
455status_t MediaPlayer::setAudioStreamType(int type)
456{
457 LOGV("MediaPlayer::setAudioStreamType");
458 Mutex::Autolock _l(mLock);
459 if (mStreamType == type) return NO_ERROR;
460 if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
461 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
462 // Can't change the stream type after prepare
463 LOGE("setAudioStream called in state %d", mCurrentState);
464 return INVALID_OPERATION;
465 }
466 // cache
467 mStreamType = type;
468 return OK;
469}
470
471status_t MediaPlayer::setLooping(int loop)
472{
473 LOGV("MediaPlayer::setLooping");
474 Mutex::Autolock _l(mLock);
475 mLoop = (loop != 0);
476 if (mPlayer != 0) {
477 return mPlayer->setLooping(loop);
478 }
479 return OK;
480}
481
482bool MediaPlayer::isLooping() {
483 LOGV("isLooping");
484 Mutex::Autolock _l(mLock);
485 if (mPlayer != 0) {
486 return mLoop;
487 }
488 LOGV("isLooping: no active player");
489 return false;
490}
491
492status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
493{
494 LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
495 Mutex::Autolock _l(mLock);
496 mLeftVolume = leftVolume;
497 mRightVolume = rightVolume;
498 if (mPlayer != 0) {
499 return mPlayer->setVolume(leftVolume, rightVolume);
500 }
501 return OK;
502}
503
504void MediaPlayer::notify(int msg, int ext1, int ext2)
505{
506 LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
507 bool send = true;
Jason Samsebb020a2009-03-24 18:45:22 -0700508 bool locked = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509
510 // TODO: In the future, we might be on the same thread if the app is
511 // running in the same process as the media server. In that case,
512 // this will deadlock.
Nicolas Catania32f82772009-06-11 16:33:49 -0700513 //
Jason Samsebb020a2009-03-24 18:45:22 -0700514 // The threadId hack below works around this for the care of prepare
Andreas Hubereffd8d52009-03-24 20:48:51 -0700515 // and seekTo within the same process.
516 // FIXME: Remember, this is a hack, it's not even a hack that is applied
517 // consistently for all use-cases, this needs to be revisited.
Jason Samsebb020a2009-03-24 18:45:22 -0700518 if (mLockThreadId != getThreadId()) {
519 mLock.lock();
520 locked = true;
Nicolas Catania32f82772009-06-11 16:33:49 -0700521 }
Jason Samsebb020a2009-03-24 18:45:22 -0700522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 if (mPlayer == 0) {
524 LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
Jason Samsebb020a2009-03-24 18:45:22 -0700525 if (locked) mLock.unlock(); // release the lock when done.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 return;
527 }
528
529 switch (msg) {
530 case MEDIA_NOP: // interface test message
531 break;
532 case MEDIA_PREPARED:
533 LOGV("prepared");
534 mCurrentState = MEDIA_PLAYER_PREPARED;
535 if (mPrepareSync) {
536 LOGV("signal application thread");
537 mPrepareSync = false;
538 mPrepareStatus = NO_ERROR;
539 mSignal.signal();
540 }
541 break;
542 case MEDIA_PLAYBACK_COMPLETE:
543 LOGV("playback complete");
544 if (!mLoop) {
545 mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
546 }
547 break;
548 case MEDIA_ERROR:
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700549 // Always log errors.
550 // ext1: Media framework error code.
551 // ext2: Implementation dependant error code.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 LOGE("error (%d, %d)", ext1, ext2);
553 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
554 if (mPrepareSync)
555 {
556 LOGV("signal application thread");
557 mPrepareSync = false;
558 mPrepareStatus = ext1;
559 mSignal.signal();
560 send = false;
561 }
562 break;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700563 case MEDIA_INFO:
564 // ext1: Media framework error code.
565 // ext2: Implementation dependant error code.
566 LOGW("info/warning (%d, %d)", ext1, ext2);
567 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 case MEDIA_SEEK_COMPLETE:
569 LOGV("Received seek complete");
570 if (mSeekPosition != mCurrentPosition) {
571 LOGV("Executing queued seekTo(%d)", mSeekPosition);
572 mSeekPosition = -1;
573 seekTo_l(mCurrentPosition);
574 }
575 else {
576 LOGV("All seeks complete - return to regularly scheduled program");
577 mCurrentPosition = mSeekPosition = -1;
578 }
579 break;
580 case MEDIA_BUFFERING_UPDATE:
581 LOGV("buffering %d", ext1);
582 break;
583 case MEDIA_SET_VIDEO_SIZE:
584 LOGV("New video size %d x %d", ext1, ext2);
585 mVideoWidth = ext1;
586 mVideoHeight = ext2;
587 break;
588 default:
589 LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
590 break;
591 }
592
593 sp<MediaPlayerListener> listener = mListener;
Jason Samsebb020a2009-03-24 18:45:22 -0700594 if (locked) mLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595
596 // this prevents re-entrant calls into client code
597 if ((listener != 0) && send) {
598 Mutex::Autolock _l(mNotifyLock);
599 LOGV("callback application");
600 listener->notify(msg, ext1, ext2);
601 LOGV("back from callback");
602 }
603}
604
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
606{
607 LOGV("decode(%s)", url);
608 sp<IMemory> p;
609 const sp<IMediaPlayerService>& service = getMediaPlayerService();
610 if (service != 0) {
James Dong34bbc222010-01-15 18:13:58 -0800611 p = service->decode(url, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 } else {
613 LOGE("Unable to locate media service");
614 }
615 return p;
616
617}
618
James Dong34bbc222010-01-15 18:13:58 -0800619void MediaPlayer::died()
620{
621 LOGV("died");
622 notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
623}
624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
626{
627 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
628 sp<IMemory> p;
629 const sp<IMediaPlayerService>& service = getMediaPlayerService();
630 if (service != 0) {
James Dong34bbc222010-01-15 18:13:58 -0800631 p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 } else {
633 LOGE("Unable to locate media service");
634 }
635 return p;
636
637}
638
Marco Nelissenc39d2e32009-09-20 10:42:13 -0700639extern "C" {
640#define FLOATING_POINT 1
641#include "fftwrap.h"
642}
643
644static void *ffttable = NULL;
645
646// peeks at the audio data and fills 'data' with the requested kind
647// (currently kind=0 returns mono 16 bit PCM data, and kind=1 returns
648// 256 point FFT data). Return value is number of samples returned,
649// which may be 0.
650/*static*/ int MediaPlayer::snoop(short* data, int len, int kind) {
651
652 sp<IMemory> p;
653 const sp<IMediaPlayerService>& service = getMediaPlayerService();
654 if (service != 0) {
655 // Take a peek at the waveform. The returned data consists of 16 bit mono PCM data.
656 p = service->snoop();
657
658 if (p == NULL) {
659 return 0;
660 }
661
662 if (kind == 0) { // return waveform data
663 int plen = p->size();
664 len *= 2; // number of shorts -> number of bytes
665 short *src = (short*) p->pointer();
666 if (plen > len) {
667 plen = len;
668 }
669 memcpy(data, src, plen);
670 return plen / sizeof(short); // return number of samples
671 } else if (kind == 1) {
672 // TODO: use a more efficient FFT
673 // Right now this uses the speex library, which is compiled to do a float FFT
674 if (!ffttable) ffttable = spx_fft_init(512);
675 short *usrc = (short*) p->pointer();
676 float fsrc[512];
677 for (int i=0;i<512;i++)
678 fsrc[i] = usrc[i];
679 float fdst[512];
680 spx_fft_float(ffttable, fsrc, fdst);
681 if (len > 512) {
682 len = 512;
683 }
684 len /= 2; // only half the output data is valid
685 for (int i=0; i < len; i++)
686 data[i] = fdst[i];
687 return len;
688 }
689
690 } else {
691 LOGE("Unable to locate media service");
692 }
693 return 0;
694}
695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696}; // namespace android