blob: f623295be76e76d62fef0e4b461ddcc48f2ca077 [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
Marco Nelissen83ff1432010-03-10 10:53:16 -0800107 if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
108 (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
The Android Open Source Project89fa4ad2009-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 Huber2db84552010-01-28 11:19:57 -0800131status_t MediaPlayer::setDataSource(
132 const char *url, const KeyedVector<String8, String8> *headers)
The Android Open Source Project89fa4ad2009-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 Huber2db84552010-01-28 11:19:57 -0800139 sp<IMediaPlayer> player(
140 service->create(getpid(), this, url, headers));
The Android Open Source Project89fa4ad2009-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 Catania1d187f12009-05-12 23:25:55 -0700159status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
160{
161 Mutex::Autolock _l(mLock);
Nicolas Catania64fb06f2010-03-11 08:16:26 -0800162 if ((mPlayer != NULL) && ( mCurrentState & MEDIA_PLAYER_INITIALIZED ))
163 {
Nicolas Catania1d187f12009-05-12 23:25:55 -0700164 LOGV("invoke %d", request.dataSize());
165 return mPlayer->invoke(request, reply);
166 }
167 LOGE("invoke failed: wrong state %X", mCurrentState);
168 return INVALID_OPERATION;
169}
170
Andreas Huber4e92c7e2010-02-12 12:35:58 -0800171status_t MediaPlayer::suspend() {
172 Mutex::Autolock _l(mLock);
173 return mPlayer->suspend();
174}
175
176status_t MediaPlayer::resume() {
177 Mutex::Autolock _l(mLock);
178 return mPlayer->resume();
179}
180
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700181status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
182{
183 LOGD("setMetadataFilter");
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700184 Mutex::Autolock lock(mLock);
185 if (mPlayer == NULL) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700186 return NO_INIT;
187 }
188 return mPlayer->setMetadataFilter(filter);
189}
Nicolas Catania1d187f12009-05-12 23:25:55 -0700190
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700191status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
192{
193 LOGD("getMetadata");
194 Mutex::Autolock lock(mLock);
195 if (mPlayer == NULL) {
196 return NO_INIT;
197 }
198 return mPlayer->getMetadata(update_only, apply_filter, metadata);
199}
200
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800201status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
202{
203 LOGV("setVideoSurface");
204 Mutex::Autolock _l(mLock);
205 if (mPlayer == 0) return NO_INIT;
Marco Nelissenaa371732009-07-10 09:34:59 -0700206 if (surface != NULL)
207 return mPlayer->setVideoSurface(surface->getISurface());
208 else
209 return mPlayer->setVideoSurface(NULL);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800210}
211
212// must call with lock held
213status_t MediaPlayer::prepareAsync_l()
214{
215 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
216 mPlayer->setAudioStreamType(mStreamType);
217 mCurrentState = MEDIA_PLAYER_PREPARING;
218 return mPlayer->prepareAsync();
219 }
220 LOGE("prepareAsync called in state %d", mCurrentState);
221 return INVALID_OPERATION;
222}
223
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700224// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
225// one defined in the Android framework and one provided by the implementation
226// that generated the error. The sync version of prepare returns only 1 error
227// code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800228status_t MediaPlayer::prepare()
229{
230 LOGV("prepare");
231 Mutex::Autolock _l(mLock);
Jason Sams1af452f2009-03-24 18:45:22 -0700232 mLockThreadId = getThreadId();
233 if (mPrepareSync) {
234 mLockThreadId = 0;
235 return -EALREADY;
236 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800237 mPrepareSync = true;
238 status_t ret = prepareAsync_l();
Jason Sams1af452f2009-03-24 18:45:22 -0700239 if (ret != NO_ERROR) {
240 mLockThreadId = 0;
241 return ret;
242 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800243
244 if (mPrepareSync) {
245 mSignal.wait(mLock); // wait for prepare done
246 mPrepareSync = false;
247 }
248 LOGV("prepare complete - status=%d", mPrepareStatus);
Jason Sams1af452f2009-03-24 18:45:22 -0700249 mLockThreadId = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800250 return mPrepareStatus;
251}
252
253status_t MediaPlayer::prepareAsync()
254{
255 LOGV("prepareAsync");
256 Mutex::Autolock _l(mLock);
257 return prepareAsync_l();
258}
259
260status_t MediaPlayer::start()
261{
262 LOGV("start");
263 Mutex::Autolock _l(mLock);
264 if (mCurrentState & MEDIA_PLAYER_STARTED)
265 return NO_ERROR;
266 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
267 MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
268 mPlayer->setLooping(mLoop);
269 mPlayer->setVolume(mLeftVolume, mRightVolume);
270 mCurrentState = MEDIA_PLAYER_STARTED;
271 status_t ret = mPlayer->start();
272 if (ret != NO_ERROR) {
273 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
274 } else {
275 if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
276 LOGV("playback completed immediately following start()");
277 }
278 }
279 return ret;
280 }
281 LOGE("start called in state %d", mCurrentState);
282 return INVALID_OPERATION;
283}
284
285status_t MediaPlayer::stop()
286{
287 LOGV("stop");
288 Mutex::Autolock _l(mLock);
289 if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
290 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
291 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
292 status_t ret = mPlayer->stop();
293 if (ret != NO_ERROR) {
294 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
295 } else {
296 mCurrentState = MEDIA_PLAYER_STOPPED;
297 }
298 return ret;
299 }
300 LOGE("stop called in state %d", mCurrentState);
301 return INVALID_OPERATION;
302}
303
304status_t MediaPlayer::pause()
305{
306 LOGV("pause");
307 Mutex::Autolock _l(mLock);
Marco Nelissen698f4762010-02-26 13:16:23 -0800308 if (mCurrentState & (MEDIA_PLAYER_PAUSED|MEDIA_PLAYER_PLAYBACK_COMPLETE))
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800309 return NO_ERROR;
310 if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
311 status_t ret = mPlayer->pause();
312 if (ret != NO_ERROR) {
313 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
314 } else {
315 mCurrentState = MEDIA_PLAYER_PAUSED;
316 }
317 return ret;
318 }
319 LOGE("pause called in state %d", mCurrentState);
320 return INVALID_OPERATION;
321}
322
323bool MediaPlayer::isPlaying()
324{
325 Mutex::Autolock _l(mLock);
326 if (mPlayer != 0) {
327 bool temp = false;
328 mPlayer->isPlaying(&temp);
329 LOGV("isPlaying: %d", temp);
330 if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
331 LOGE("internal/external state mismatch corrected");
332 mCurrentState = MEDIA_PLAYER_PAUSED;
333 }
334 return temp;
335 }
336 LOGV("isPlaying: no active player");
337 return false;
338}
339
340status_t MediaPlayer::getVideoWidth(int *w)
341{
342 LOGV("getVideoWidth");
343 Mutex::Autolock _l(mLock);
344 if (mPlayer == 0) return INVALID_OPERATION;
345 *w = mVideoWidth;
346 return NO_ERROR;
347}
348
349status_t MediaPlayer::getVideoHeight(int *h)
350{
351 LOGV("getVideoHeight");
352 Mutex::Autolock _l(mLock);
353 if (mPlayer == 0) return INVALID_OPERATION;
354 *h = mVideoHeight;
355 return NO_ERROR;
356}
357
358status_t MediaPlayer::getCurrentPosition(int *msec)
359{
360 LOGV("getCurrentPosition");
361 Mutex::Autolock _l(mLock);
362 if (mPlayer != 0) {
363 if (mCurrentPosition >= 0) {
364 LOGV("Using cached seek position: %d", mCurrentPosition);
365 *msec = mCurrentPosition;
366 return NO_ERROR;
367 }
368 return mPlayer->getCurrentPosition(msec);
369 }
370 return INVALID_OPERATION;
371}
372
373status_t MediaPlayer::getDuration_l(int *msec)
374{
375 LOGV("getDuration");
376 bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
377 if (mPlayer != 0 && isValidState) {
378 status_t ret = NO_ERROR;
379 if (mDuration <= 0)
380 ret = mPlayer->getDuration(&mDuration);
381 if (msec)
382 *msec = mDuration;
383 return ret;
384 }
385 LOGE("Attempt to call getDuration without a valid mediaplayer");
386 return INVALID_OPERATION;
387}
388
389status_t MediaPlayer::getDuration(int *msec)
390{
391 Mutex::Autolock _l(mLock);
392 return getDuration_l(msec);
393}
394
395status_t MediaPlayer::seekTo_l(int msec)
396{
397 LOGV("seekTo %d", msec);
398 if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
399 if ( msec < 0 ) {
400 LOGW("Attempt to seek to invalid position: %d", msec);
401 msec = 0;
402 } else if ((mDuration > 0) && (msec > mDuration)) {
403 LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
404 msec = mDuration;
405 }
406 // cache duration
407 mCurrentPosition = msec;
408 if (mSeekPosition < 0) {
409 getDuration_l(NULL);
410 mSeekPosition = msec;
411 return mPlayer->seekTo(msec);
412 }
413 else {
414 LOGV("Seek in progress - queue up seekTo[%d]", msec);
415 return NO_ERROR;
416 }
417 }
418 LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
419 return INVALID_OPERATION;
420}
421
422status_t MediaPlayer::seekTo(int msec)
423{
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700424 mLockThreadId = getThreadId();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800425 Mutex::Autolock _l(mLock);
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700426 status_t result = seekTo_l(msec);
427 mLockThreadId = 0;
428
429 return result;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800430}
431
432status_t MediaPlayer::reset()
433{
434 LOGV("reset");
435 Mutex::Autolock _l(mLock);
436 mLoop = false;
437 if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
438 mPrepareSync = false;
439 if (mPlayer != 0) {
440 status_t ret = mPlayer->reset();
441 if (ret != NO_ERROR) {
442 LOGE("reset() failed with return code (%d)", ret);
443 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
444 } else {
445 mCurrentState = MEDIA_PLAYER_IDLE;
446 }
447 return ret;
448 }
449 clear_l();
450 return NO_ERROR;
451}
452
453status_t MediaPlayer::setAudioStreamType(int type)
454{
455 LOGV("MediaPlayer::setAudioStreamType");
456 Mutex::Autolock _l(mLock);
457 if (mStreamType == type) return NO_ERROR;
458 if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
459 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
460 // Can't change the stream type after prepare
461 LOGE("setAudioStream called in state %d", mCurrentState);
462 return INVALID_OPERATION;
463 }
464 // cache
465 mStreamType = type;
466 return OK;
467}
468
469status_t MediaPlayer::setLooping(int loop)
470{
471 LOGV("MediaPlayer::setLooping");
472 Mutex::Autolock _l(mLock);
473 mLoop = (loop != 0);
474 if (mPlayer != 0) {
475 return mPlayer->setLooping(loop);
476 }
477 return OK;
478}
479
480bool MediaPlayer::isLooping() {
481 LOGV("isLooping");
482 Mutex::Autolock _l(mLock);
483 if (mPlayer != 0) {
484 return mLoop;
485 }
486 LOGV("isLooping: no active player");
487 return false;
488}
489
490status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
491{
492 LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
493 Mutex::Autolock _l(mLock);
494 mLeftVolume = leftVolume;
495 mRightVolume = rightVolume;
496 if (mPlayer != 0) {
497 return mPlayer->setVolume(leftVolume, rightVolume);
498 }
499 return OK;
500}
501
502void MediaPlayer::notify(int msg, int ext1, int ext2)
503{
504 LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
505 bool send = true;
Jason Sams1af452f2009-03-24 18:45:22 -0700506 bool locked = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800507
508 // TODO: In the future, we might be on the same thread if the app is
509 // running in the same process as the media server. In that case,
510 // this will deadlock.
Nicolas Catania66095182009-06-11 16:33:49 -0700511 //
Jason Sams1af452f2009-03-24 18:45:22 -0700512 // The threadId hack below works around this for the care of prepare
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700513 // and seekTo within the same process.
514 // FIXME: Remember, this is a hack, it's not even a hack that is applied
515 // consistently for all use-cases, this needs to be revisited.
Jason Sams1af452f2009-03-24 18:45:22 -0700516 if (mLockThreadId != getThreadId()) {
517 mLock.lock();
518 locked = true;
Nicolas Catania66095182009-06-11 16:33:49 -0700519 }
Jason Sams1af452f2009-03-24 18:45:22 -0700520
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800521 if (mPlayer == 0) {
522 LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
Jason Sams1af452f2009-03-24 18:45:22 -0700523 if (locked) mLock.unlock(); // release the lock when done.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800524 return;
525 }
526
527 switch (msg) {
528 case MEDIA_NOP: // interface test message
529 break;
530 case MEDIA_PREPARED:
531 LOGV("prepared");
532 mCurrentState = MEDIA_PLAYER_PREPARED;
533 if (mPrepareSync) {
534 LOGV("signal application thread");
535 mPrepareSync = false;
536 mPrepareStatus = NO_ERROR;
537 mSignal.signal();
538 }
539 break;
540 case MEDIA_PLAYBACK_COMPLETE:
541 LOGV("playback complete");
542 if (!mLoop) {
543 mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
544 }
545 break;
546 case MEDIA_ERROR:
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700547 // Always log errors.
548 // ext1: Media framework error code.
549 // ext2: Implementation dependant error code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800550 LOGE("error (%d, %d)", ext1, ext2);
551 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
552 if (mPrepareSync)
553 {
554 LOGV("signal application thread");
555 mPrepareSync = false;
556 mPrepareStatus = ext1;
557 mSignal.signal();
558 send = false;
559 }
560 break;
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700561 case MEDIA_INFO:
562 // ext1: Media framework error code.
563 // ext2: Implementation dependant error code.
564 LOGW("info/warning (%d, %d)", ext1, ext2);
565 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800566 case MEDIA_SEEK_COMPLETE:
567 LOGV("Received seek complete");
568 if (mSeekPosition != mCurrentPosition) {
569 LOGV("Executing queued seekTo(%d)", mSeekPosition);
570 mSeekPosition = -1;
571 seekTo_l(mCurrentPosition);
572 }
573 else {
574 LOGV("All seeks complete - return to regularly scheduled program");
575 mCurrentPosition = mSeekPosition = -1;
576 }
577 break;
578 case MEDIA_BUFFERING_UPDATE:
579 LOGV("buffering %d", ext1);
580 break;
581 case MEDIA_SET_VIDEO_SIZE:
582 LOGV("New video size %d x %d", ext1, ext2);
583 mVideoWidth = ext1;
584 mVideoHeight = ext2;
585 break;
586 default:
587 LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
588 break;
589 }
590
591 sp<MediaPlayerListener> listener = mListener;
Jason Sams1af452f2009-03-24 18:45:22 -0700592 if (locked) mLock.unlock();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800593
594 // this prevents re-entrant calls into client code
595 if ((listener != 0) && send) {
596 Mutex::Autolock _l(mNotifyLock);
597 LOGV("callback application");
598 listener->notify(msg, ext1, ext2);
599 LOGV("back from callback");
600 }
601}
602
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800603/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
604{
605 LOGV("decode(%s)", url);
606 sp<IMemory> p;
607 const sp<IMediaPlayerService>& service = getMediaPlayerService();
608 if (service != 0) {
James Dongdd172fc2010-01-15 18:13:58 -0800609 p = service->decode(url, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800610 } else {
611 LOGE("Unable to locate media service");
612 }
613 return p;
614
615}
616
James Dongdd172fc2010-01-15 18:13:58 -0800617void MediaPlayer::died()
618{
619 LOGV("died");
620 notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
621}
622
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800623/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
624{
625 LOGV("decode(%d, %lld, %lld)", fd, offset, length);
626 sp<IMemory> p;
627 const sp<IMediaPlayerService>& service = getMediaPlayerService();
628 if (service != 0) {
James Dongdd172fc2010-01-15 18:13:58 -0800629 p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800630 } else {
631 LOGE("Unable to locate media service");
632 }
633 return p;
634
635}
636
Marco Nelissen10dbb8e2009-09-20 10:42:13 -0700637extern "C" {
638#define FLOATING_POINT 1
639#include "fftwrap.h"
640}
641
642static void *ffttable = NULL;
643
644// peeks at the audio data and fills 'data' with the requested kind
645// (currently kind=0 returns mono 16 bit PCM data, and kind=1 returns
646// 256 point FFT data). Return value is number of samples returned,
647// which may be 0.
648/*static*/ int MediaPlayer::snoop(short* data, int len, int kind) {
649
650 sp<IMemory> p;
651 const sp<IMediaPlayerService>& service = getMediaPlayerService();
652 if (service != 0) {
653 // Take a peek at the waveform. The returned data consists of 16 bit mono PCM data.
654 p = service->snoop();
655
656 if (p == NULL) {
657 return 0;
658 }
659
660 if (kind == 0) { // return waveform data
661 int plen = p->size();
662 len *= 2; // number of shorts -> number of bytes
663 short *src = (short*) p->pointer();
664 if (plen > len) {
665 plen = len;
666 }
667 memcpy(data, src, plen);
668 return plen / sizeof(short); // return number of samples
669 } else if (kind == 1) {
670 // TODO: use a more efficient FFT
671 // Right now this uses the speex library, which is compiled to do a float FFT
672 if (!ffttable) ffttable = spx_fft_init(512);
673 short *usrc = (short*) p->pointer();
674 float fsrc[512];
675 for (int i=0;i<512;i++)
676 fsrc[i] = usrc[i];
677 float fdst[512];
678 spx_fft_float(ffttable, fsrc, fdst);
679 if (len > 512) {
680 len = 512;
681 }
682 len /= 2; // only half the output data is valid
683 for (int i=0; i < len; i++)
684 data[i] = fdst[i];
685 return len;
686 }
687
688 } else {
689 LOGE("Unable to locate media service");
690 }
691 return 0;
692}
693
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800694}; // namespace android