blob: 9d459071f3f9019607c3983fca41dc450554d41c [file] [log] [blame]
Glenn Kasten99e53b82012-01-19 08:59:58 -08001/*
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08002**
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
Jamie Gennis61c7ef52011-07-13 12:59:34 -070030#include <gui/SurfaceTextureClient.h>
31
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080032#include <media/mediaplayer.h>
Glenn Kastena3f1fa32012-01-18 14:54:46 -080033#include <media/AudioSystem.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080034
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
Dima Zavin64760242011-05-11 14:15:23 -070040#include <system/audio.h>
Jamie Gennis61c7ef52011-07-13 12:59:34 -070041#include <system/window.h>
Dima Zavinfce7a472011-04-19 22:30:36 -070042
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080043namespace android {
44
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080045MediaPlayer::MediaPlayer()
46{
Steve Block3856b092011-10-20 11:56:00 +010047 ALOGV("constructor");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080048 mListener = NULL;
49 mCookie = NULL;
50 mDuration = -1;
Dima Zavinfce7a472011-04-19 22:30:36 -070051 mStreamType = AUDIO_STREAM_MUSIC;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080052 mCurrentPosition = -1;
53 mSeekPosition = -1;
54 mCurrentState = MEDIA_PLAYER_IDLE;
55 mPrepareSync = false;
56 mPrepareStatus = NO_ERROR;
57 mLoop = false;
58 mLeftVolume = mRightVolume = 1.0;
59 mVideoWidth = mVideoHeight = 0;
Jason Sams1af452f2009-03-24 18:45:22 -070060 mLockThreadId = 0;
Eric Laurenta514bdb2010-06-21 09:27:30 -070061 mAudioSessionId = AudioSystem::newAudioSessionId();
Marco Nelissen3a34bef2011-08-02 13:33:41 -070062 AudioSystem::acquireAudioSessionId(mAudioSessionId);
Eric Laurent8c563ed2010-10-07 18:23:03 -070063 mSendLevel = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080064}
65
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080066MediaPlayer::~MediaPlayer()
67{
Steve Block3856b092011-10-20 11:56:00 +010068 ALOGV("destructor");
Marco Nelissen3a34bef2011-08-02 13:33:41 -070069 AudioSystem::releaseAudioSessionId(mAudioSessionId);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080070 disconnect();
71 IPCThreadState::self()->flushCommands();
72}
73
74void MediaPlayer::disconnect()
75{
Steve Block3856b092011-10-20 11:56:00 +010076 ALOGV("disconnect");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080077 sp<IMediaPlayer> p;
78 {
79 Mutex::Autolock _l(mLock);
80 p = mPlayer;
81 mPlayer.clear();
82 }
83
84 if (p != 0) {
85 p->disconnect();
86 }
87}
88
89// always call with lock held
90void MediaPlayer::clear_l()
91{
92 mDuration = -1;
93 mCurrentPosition = -1;
94 mSeekPosition = -1;
95 mVideoWidth = mVideoHeight = 0;
96}
97
98status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
99{
Steve Block3856b092011-10-20 11:56:00 +0100100 ALOGV("setListener");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800101 Mutex::Autolock _l(mLock);
102 mListener = listener;
103 return NO_ERROR;
104}
105
106
Dave Burked681bbb2011-08-30 14:39:17 +0100107status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800108{
109 status_t err = UNKNOWN_ERROR;
110 sp<IMediaPlayer> p;
111 { // scope for the lock
112 Mutex::Autolock _l(mLock);
113
Marco Nelissen83ff1432010-03-10 10:53:16 -0800114 if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
115 (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
Steve Block29357bc2012-01-06 19:20:56 +0000116 ALOGE("attachNewPlayer called in state %d", mCurrentState);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800117 return INVALID_OPERATION;
118 }
119
120 clear_l();
121 p = mPlayer;
122 mPlayer = player;
123 if (player != 0) {
124 mCurrentState = MEDIA_PLAYER_INITIALIZED;
125 err = NO_ERROR;
126 } else {
Steve Block29357bc2012-01-06 19:20:56 +0000127 ALOGE("Unable to to create media player");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800128 }
129 }
130
131 if (p != 0) {
132 p->disconnect();
133 }
134
135 return err;
136}
137
Andreas Huber2db84552010-01-28 11:19:57 -0800138status_t MediaPlayer::setDataSource(
139 const char *url, const KeyedVector<String8, String8> *headers)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800140{
Steve Block3856b092011-10-20 11:56:00 +0100141 ALOGV("setDataSource(%s)", url);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800142 status_t err = BAD_VALUE;
143 if (url != NULL) {
144 const sp<IMediaPlayerService>& service(getMediaPlayerService());
145 if (service != 0) {
Dave Burked681bbb2011-08-30 14:39:17 +0100146 sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
Dave Burke06620672011-09-06 20:39:47 +0100147 if (NO_ERROR != player->setDataSource(url, headers)) {
148 player.clear();
Dave Burked681bbb2011-08-30 14:39:17 +0100149 }
Dave Burke06620672011-09-06 20:39:47 +0100150 err = attachNewPlayer(player);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800151 }
152 }
153 return err;
154}
155
156status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
157{
Steve Block3856b092011-10-20 11:56:00 +0100158 ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800159 status_t err = UNKNOWN_ERROR;
160 const sp<IMediaPlayerService>& service(getMediaPlayerService());
161 if (service != 0) {
Dave Burked681bbb2011-08-30 14:39:17 +0100162 sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
Dave Burke06620672011-09-06 20:39:47 +0100163 if (NO_ERROR != player->setDataSource(fd, offset, length)) {
164 player.clear();
Dave Burked681bbb2011-08-30 14:39:17 +0100165 }
Dave Burke06620672011-09-06 20:39:47 +0100166 err = attachNewPlayer(player);
Dave Burked681bbb2011-08-30 14:39:17 +0100167 }
168 return err;
169}
170
171status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
172{
Steve Block3856b092011-10-20 11:56:00 +0100173 ALOGV("setDataSource");
Dave Burked681bbb2011-08-30 14:39:17 +0100174 status_t err = UNKNOWN_ERROR;
175 const sp<IMediaPlayerService>& service(getMediaPlayerService());
176 if (service != 0) {
177 sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
Dave Burke06620672011-09-06 20:39:47 +0100178 if (NO_ERROR != player->setDataSource(source)) {
179 player.clear();
Dave Burked681bbb2011-08-30 14:39:17 +0100180 }
Dave Burke06620672011-09-06 20:39:47 +0100181 err = attachNewPlayer(player);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800182 }
183 return err;
184}
185
Nicolas Catania1d187f12009-05-12 23:25:55 -0700186status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
187{
188 Mutex::Autolock _l(mLock);
Nicolas Catania40234932010-03-10 10:41:04 -0800189 const bool hasBeenInitialized =
190 (mCurrentState != MEDIA_PLAYER_STATE_ERROR) &&
191 ((mCurrentState & MEDIA_PLAYER_IDLE) != MEDIA_PLAYER_IDLE);
192 if ((mPlayer != NULL) && hasBeenInitialized) {
Steve Block3856b092011-10-20 11:56:00 +0100193 ALOGV("invoke %d", request.dataSize());
Nicolas Catania1d187f12009-05-12 23:25:55 -0700194 return mPlayer->invoke(request, reply);
195 }
Steve Block29357bc2012-01-06 19:20:56 +0000196 ALOGE("invoke failed: wrong state %X", mCurrentState);
Nicolas Catania1d187f12009-05-12 23:25:55 -0700197 return INVALID_OPERATION;
198}
199
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700200status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
201{
Steve Blockb8a80522011-12-20 16:23:08 +0000202 ALOGD("setMetadataFilter");
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700203 Mutex::Autolock lock(mLock);
204 if (mPlayer == NULL) {
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700205 return NO_INIT;
206 }
207 return mPlayer->setMetadataFilter(filter);
208}
Nicolas Catania1d187f12009-05-12 23:25:55 -0700209
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700210status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
211{
Steve Blockb8a80522011-12-20 16:23:08 +0000212 ALOGD("getMetadata");
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700213 Mutex::Autolock lock(mLock);
214 if (mPlayer == NULL) {
215 return NO_INIT;
216 }
217 return mPlayer->getMetadata(update_only, apply_filter, metadata);
218}
219
Glenn Kasten11731182011-02-08 17:26:17 -0800220status_t MediaPlayer::setVideoSurfaceTexture(
221 const sp<ISurfaceTexture>& surfaceTexture)
222{
Steve Block3856b092011-10-20 11:56:00 +0100223 ALOGV("setVideoSurfaceTexture");
Glenn Kasten11731182011-02-08 17:26:17 -0800224 Mutex::Autolock _l(mLock);
225 if (mPlayer == 0) return NO_INIT;
Jamie Gennis7dae00b2011-10-26 18:36:31 -0700226 return mPlayer->setVideoSurfaceTexture(surfaceTexture);
Glenn Kasten11731182011-02-08 17:26:17 -0800227}
228
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800229// must call with lock held
230status_t MediaPlayer::prepareAsync_l()
231{
232 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
233 mPlayer->setAudioStreamType(mStreamType);
234 mCurrentState = MEDIA_PLAYER_PREPARING;
235 return mPlayer->prepareAsync();
236 }
Steve Block29357bc2012-01-06 19:20:56 +0000237 ALOGE("prepareAsync called in state %d", mCurrentState);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800238 return INVALID_OPERATION;
239}
240
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700241// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
242// one defined in the Android framework and one provided by the implementation
243// that generated the error. The sync version of prepare returns only 1 error
244// code.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800245status_t MediaPlayer::prepare()
246{
Steve Block3856b092011-10-20 11:56:00 +0100247 ALOGV("prepare");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800248 Mutex::Autolock _l(mLock);
Jason Sams1af452f2009-03-24 18:45:22 -0700249 mLockThreadId = getThreadId();
250 if (mPrepareSync) {
251 mLockThreadId = 0;
252 return -EALREADY;
253 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800254 mPrepareSync = true;
255 status_t ret = prepareAsync_l();
Jason Sams1af452f2009-03-24 18:45:22 -0700256 if (ret != NO_ERROR) {
257 mLockThreadId = 0;
258 return ret;
259 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800260
261 if (mPrepareSync) {
262 mSignal.wait(mLock); // wait for prepare done
263 mPrepareSync = false;
264 }
Steve Block3856b092011-10-20 11:56:00 +0100265 ALOGV("prepare complete - status=%d", mPrepareStatus);
Jason Sams1af452f2009-03-24 18:45:22 -0700266 mLockThreadId = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800267 return mPrepareStatus;
268}
269
270status_t MediaPlayer::prepareAsync()
271{
Steve Block3856b092011-10-20 11:56:00 +0100272 ALOGV("prepareAsync");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800273 Mutex::Autolock _l(mLock);
274 return prepareAsync_l();
275}
276
277status_t MediaPlayer::start()
278{
Steve Block3856b092011-10-20 11:56:00 +0100279 ALOGV("start");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800280 Mutex::Autolock _l(mLock);
281 if (mCurrentState & MEDIA_PLAYER_STARTED)
282 return NO_ERROR;
283 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
284 MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
285 mPlayer->setLooping(mLoop);
286 mPlayer->setVolume(mLeftVolume, mRightVolume);
Eric Laurent2beeb502010-07-16 07:43:46 -0700287 mPlayer->setAuxEffectSendLevel(mSendLevel);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800288 mCurrentState = MEDIA_PLAYER_STARTED;
289 status_t ret = mPlayer->start();
290 if (ret != NO_ERROR) {
291 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
292 } else {
293 if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
Steve Block3856b092011-10-20 11:56:00 +0100294 ALOGV("playback completed immediately following start()");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800295 }
296 }
297 return ret;
298 }
Steve Block29357bc2012-01-06 19:20:56 +0000299 ALOGE("start called in state %d", mCurrentState);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800300 return INVALID_OPERATION;
301}
302
303status_t MediaPlayer::stop()
304{
Steve Block3856b092011-10-20 11:56:00 +0100305 ALOGV("stop");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800306 Mutex::Autolock _l(mLock);
307 if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
308 if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
309 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
310 status_t ret = mPlayer->stop();
311 if (ret != NO_ERROR) {
312 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
313 } else {
314 mCurrentState = MEDIA_PLAYER_STOPPED;
315 }
316 return ret;
317 }
Steve Block29357bc2012-01-06 19:20:56 +0000318 ALOGE("stop called in state %d", mCurrentState);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800319 return INVALID_OPERATION;
320}
321
322status_t MediaPlayer::pause()
323{
Steve Block3856b092011-10-20 11:56:00 +0100324 ALOGV("pause");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800325 Mutex::Autolock _l(mLock);
Marco Nelissen698f4762010-02-26 13:16:23 -0800326 if (mCurrentState & (MEDIA_PLAYER_PAUSED|MEDIA_PLAYER_PLAYBACK_COMPLETE))
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800327 return NO_ERROR;
328 if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
329 status_t ret = mPlayer->pause();
330 if (ret != NO_ERROR) {
331 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
332 } else {
333 mCurrentState = MEDIA_PLAYER_PAUSED;
334 }
335 return ret;
336 }
Steve Block29357bc2012-01-06 19:20:56 +0000337 ALOGE("pause called in state %d", mCurrentState);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800338 return INVALID_OPERATION;
339}
340
341bool MediaPlayer::isPlaying()
342{
343 Mutex::Autolock _l(mLock);
344 if (mPlayer != 0) {
345 bool temp = false;
346 mPlayer->isPlaying(&temp);
Steve Block3856b092011-10-20 11:56:00 +0100347 ALOGV("isPlaying: %d", temp);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800348 if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
Steve Block29357bc2012-01-06 19:20:56 +0000349 ALOGE("internal/external state mismatch corrected");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800350 mCurrentState = MEDIA_PLAYER_PAUSED;
351 }
352 return temp;
353 }
Steve Block3856b092011-10-20 11:56:00 +0100354 ALOGV("isPlaying: no active player");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800355 return false;
356}
357
358status_t MediaPlayer::getVideoWidth(int *w)
359{
Steve Block3856b092011-10-20 11:56:00 +0100360 ALOGV("getVideoWidth");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800361 Mutex::Autolock _l(mLock);
362 if (mPlayer == 0) return INVALID_OPERATION;
363 *w = mVideoWidth;
364 return NO_ERROR;
365}
366
367status_t MediaPlayer::getVideoHeight(int *h)
368{
Steve Block3856b092011-10-20 11:56:00 +0100369 ALOGV("getVideoHeight");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800370 Mutex::Autolock _l(mLock);
371 if (mPlayer == 0) return INVALID_OPERATION;
372 *h = mVideoHeight;
373 return NO_ERROR;
374}
375
376status_t MediaPlayer::getCurrentPosition(int *msec)
377{
Steve Block3856b092011-10-20 11:56:00 +0100378 ALOGV("getCurrentPosition");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800379 Mutex::Autolock _l(mLock);
380 if (mPlayer != 0) {
381 if (mCurrentPosition >= 0) {
Steve Block3856b092011-10-20 11:56:00 +0100382 ALOGV("Using cached seek position: %d", mCurrentPosition);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800383 *msec = mCurrentPosition;
384 return NO_ERROR;
385 }
386 return mPlayer->getCurrentPosition(msec);
387 }
388 return INVALID_OPERATION;
389}
390
391status_t MediaPlayer::getDuration_l(int *msec)
392{
Steve Block3856b092011-10-20 11:56:00 +0100393 ALOGV("getDuration");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800394 bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
395 if (mPlayer != 0 && isValidState) {
396 status_t ret = NO_ERROR;
397 if (mDuration <= 0)
398 ret = mPlayer->getDuration(&mDuration);
399 if (msec)
400 *msec = mDuration;
401 return ret;
402 }
Steve Block29357bc2012-01-06 19:20:56 +0000403 ALOGE("Attempt to call getDuration without a valid mediaplayer");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800404 return INVALID_OPERATION;
405}
406
407status_t MediaPlayer::getDuration(int *msec)
408{
409 Mutex::Autolock _l(mLock);
410 return getDuration_l(msec);
411}
412
413status_t MediaPlayer::seekTo_l(int msec)
414{
Steve Block3856b092011-10-20 11:56:00 +0100415 ALOGV("seekTo %d", msec);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800416 if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
417 if ( msec < 0 ) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000418 ALOGW("Attempt to seek to invalid position: %d", msec);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800419 msec = 0;
420 } else if ((mDuration > 0) && (msec > mDuration)) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000421 ALOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800422 msec = mDuration;
423 }
424 // cache duration
425 mCurrentPosition = msec;
426 if (mSeekPosition < 0) {
427 getDuration_l(NULL);
428 mSeekPosition = msec;
429 return mPlayer->seekTo(msec);
430 }
431 else {
Steve Block3856b092011-10-20 11:56:00 +0100432 ALOGV("Seek in progress - queue up seekTo[%d]", msec);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800433 return NO_ERROR;
434 }
435 }
Steve Block29357bc2012-01-06 19:20:56 +0000436 ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800437 return INVALID_OPERATION;
438}
439
440status_t MediaPlayer::seekTo(int msec)
441{
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700442 mLockThreadId = getThreadId();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800443 Mutex::Autolock _l(mLock);
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700444 status_t result = seekTo_l(msec);
445 mLockThreadId = 0;
446
447 return result;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800448}
449
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700450status_t MediaPlayer::reset_l()
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800451{
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800452 mLoop = false;
453 if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
454 mPrepareSync = false;
455 if (mPlayer != 0) {
456 status_t ret = mPlayer->reset();
457 if (ret != NO_ERROR) {
Steve Block29357bc2012-01-06 19:20:56 +0000458 ALOGE("reset() failed with return code (%d)", ret);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800459 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
460 } else {
461 mCurrentState = MEDIA_PLAYER_IDLE;
462 }
James Donga1680bc2010-11-18 12:23:58 -0800463 // setDataSource has to be called again to create a
464 // new mediaplayer.
465 mPlayer = 0;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800466 return ret;
467 }
468 clear_l();
469 return NO_ERROR;
470}
471
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700472status_t MediaPlayer::reset()
473{
Steve Block3856b092011-10-20 11:56:00 +0100474 ALOGV("reset");
Jamie Gennis61c7ef52011-07-13 12:59:34 -0700475 Mutex::Autolock _l(mLock);
476 return reset_l();
477}
478
Glenn Kastenfff6d712012-01-12 16:38:12 -0800479status_t MediaPlayer::setAudioStreamType(audio_stream_type_t type)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800480{
Steve Block3856b092011-10-20 11:56:00 +0100481 ALOGV("MediaPlayer::setAudioStreamType");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800482 Mutex::Autolock _l(mLock);
483 if (mStreamType == type) return NO_ERROR;
484 if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
485 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
486 // Can't change the stream type after prepare
Steve Block29357bc2012-01-06 19:20:56 +0000487 ALOGE("setAudioStream called in state %d", mCurrentState);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800488 return INVALID_OPERATION;
489 }
490 // cache
491 mStreamType = type;
492 return OK;
493}
494
495status_t MediaPlayer::setLooping(int loop)
496{
Steve Block3856b092011-10-20 11:56:00 +0100497 ALOGV("MediaPlayer::setLooping");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800498 Mutex::Autolock _l(mLock);
499 mLoop = (loop != 0);
500 if (mPlayer != 0) {
501 return mPlayer->setLooping(loop);
502 }
503 return OK;
504}
505
506bool MediaPlayer::isLooping() {
Steve Block3856b092011-10-20 11:56:00 +0100507 ALOGV("isLooping");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800508 Mutex::Autolock _l(mLock);
509 if (mPlayer != 0) {
510 return mLoop;
511 }
Steve Block3856b092011-10-20 11:56:00 +0100512 ALOGV("isLooping: no active player");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800513 return false;
514}
515
516status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
517{
Steve Block3856b092011-10-20 11:56:00 +0100518 ALOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800519 Mutex::Autolock _l(mLock);
520 mLeftVolume = leftVolume;
521 mRightVolume = rightVolume;
522 if (mPlayer != 0) {
523 return mPlayer->setVolume(leftVolume, rightVolume);
524 }
525 return OK;
526}
527
Eric Laurenta514bdb2010-06-21 09:27:30 -0700528status_t MediaPlayer::setAudioSessionId(int sessionId)
529{
Steve Block3856b092011-10-20 11:56:00 +0100530 ALOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);
Eric Laurenta514bdb2010-06-21 09:27:30 -0700531 Mutex::Autolock _l(mLock);
532 if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {
Steve Block29357bc2012-01-06 19:20:56 +0000533 ALOGE("setAudioSessionId called in state %d", mCurrentState);
Eric Laurenta514bdb2010-06-21 09:27:30 -0700534 return INVALID_OPERATION;
535 }
536 if (sessionId < 0) {
537 return BAD_VALUE;
538 }
Marco Nelissen3a34bef2011-08-02 13:33:41 -0700539 if (sessionId != mAudioSessionId) {
540 AudioSystem::releaseAudioSessionId(mAudioSessionId);
541 AudioSystem::acquireAudioSessionId(sessionId);
542 mAudioSessionId = sessionId;
543 }
Eric Laurenta514bdb2010-06-21 09:27:30 -0700544 return NO_ERROR;
545}
546
547int MediaPlayer::getAudioSessionId()
548{
549 Mutex::Autolock _l(mLock);
550 return mAudioSessionId;
551}
552
Eric Laurent2beeb502010-07-16 07:43:46 -0700553status_t MediaPlayer::setAuxEffectSendLevel(float level)
554{
Steve Block3856b092011-10-20 11:56:00 +0100555 ALOGV("MediaPlayer::setAuxEffectSendLevel(%f)", level);
Eric Laurent2beeb502010-07-16 07:43:46 -0700556 Mutex::Autolock _l(mLock);
557 mSendLevel = level;
558 if (mPlayer != 0) {
559 return mPlayer->setAuxEffectSendLevel(level);
560 }
561 return OK;
562}
563
564status_t MediaPlayer::attachAuxEffect(int effectId)
565{
Steve Block3856b092011-10-20 11:56:00 +0100566 ALOGV("MediaPlayer::attachAuxEffect(%d)", effectId);
Eric Laurent2beeb502010-07-16 07:43:46 -0700567 Mutex::Autolock _l(mLock);
568 if (mPlayer == 0 ||
569 (mCurrentState & MEDIA_PLAYER_IDLE) ||
570 (mCurrentState == MEDIA_PLAYER_STATE_ERROR )) {
Steve Block29357bc2012-01-06 19:20:56 +0000571 ALOGE("attachAuxEffect called in state %d", mCurrentState);
Eric Laurent2beeb502010-07-16 07:43:46 -0700572 return INVALID_OPERATION;
573 }
574
575 return mPlayer->attachAuxEffect(effectId);
576}
577
Gloria Wang4f9e47f2011-04-25 17:28:22 -0700578status_t MediaPlayer::setParameter(int key, const Parcel& request)
579{
Steve Block3856b092011-10-20 11:56:00 +0100580 ALOGV("MediaPlayer::setParameter(%d)", key);
Gloria Wang4f9e47f2011-04-25 17:28:22 -0700581 Mutex::Autolock _l(mLock);
582 if (mPlayer != NULL) {
583 return mPlayer->setParameter(key, request);
584 }
Steve Block3856b092011-10-20 11:56:00 +0100585 ALOGV("setParameter: no active player");
Gloria Wang4f9e47f2011-04-25 17:28:22 -0700586 return INVALID_OPERATION;
587}
588
589status_t MediaPlayer::getParameter(int key, Parcel *reply)
590{
Steve Block3856b092011-10-20 11:56:00 +0100591 ALOGV("MediaPlayer::getParameter(%d)", key);
Gloria Wang4f9e47f2011-04-25 17:28:22 -0700592 Mutex::Autolock _l(mLock);
593 if (mPlayer != NULL) {
594 return mPlayer->getParameter(key, reply);
595 }
Steve Block3856b092011-10-20 11:56:00 +0100596 ALOGV("getParameter: no active player");
Gloria Wang4f9e47f2011-04-25 17:28:22 -0700597 return INVALID_OPERATION;
598}
599
Gloria Wangb483c472011-04-11 17:23:27 -0700600void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800601{
Steve Block3856b092011-10-20 11:56:00 +0100602 ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800603 bool send = true;
Jason Sams1af452f2009-03-24 18:45:22 -0700604 bool locked = false;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800605
606 // TODO: In the future, we might be on the same thread if the app is
607 // running in the same process as the media server. In that case,
608 // this will deadlock.
Nicolas Catania66095182009-06-11 16:33:49 -0700609 //
Jason Sams1af452f2009-03-24 18:45:22 -0700610 // The threadId hack below works around this for the care of prepare
Andreas Huber5cb07aa2009-03-24 20:48:51 -0700611 // and seekTo within the same process.
612 // FIXME: Remember, this is a hack, it's not even a hack that is applied
613 // consistently for all use-cases, this needs to be revisited.
Jason Sams1af452f2009-03-24 18:45:22 -0700614 if (mLockThreadId != getThreadId()) {
615 mLock.lock();
616 locked = true;
Nicolas Catania66095182009-06-11 16:33:49 -0700617 }
Jason Sams1af452f2009-03-24 18:45:22 -0700618
Eric Laurent3b268442010-08-03 07:49:49 -0700619 // Allows calls from JNI in idle state to notify errors
620 if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
Steve Block3856b092011-10-20 11:56:00 +0100621 ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
Jason Sams1af452f2009-03-24 18:45:22 -0700622 if (locked) mLock.unlock(); // release the lock when done.
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800623 return;
624 }
625
626 switch (msg) {
627 case MEDIA_NOP: // interface test message
628 break;
629 case MEDIA_PREPARED:
Steve Block3856b092011-10-20 11:56:00 +0100630 ALOGV("prepared");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800631 mCurrentState = MEDIA_PLAYER_PREPARED;
632 if (mPrepareSync) {
Steve Block3856b092011-10-20 11:56:00 +0100633 ALOGV("signal application thread");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800634 mPrepareSync = false;
635 mPrepareStatus = NO_ERROR;
636 mSignal.signal();
637 }
638 break;
639 case MEDIA_PLAYBACK_COMPLETE:
Steve Block3856b092011-10-20 11:56:00 +0100640 ALOGV("playback complete");
Marco Nelissen1c1503c2010-09-17 15:04:01 -0700641 if (mCurrentState == MEDIA_PLAYER_IDLE) {
Steve Block29357bc2012-01-06 19:20:56 +0000642 ALOGE("playback complete in idle state");
Marco Nelissen1c1503c2010-09-17 15:04:01 -0700643 }
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800644 if (!mLoop) {
645 mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
646 }
647 break;
648 case MEDIA_ERROR:
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700649 // Always log errors.
650 // ext1: Media framework error code.
651 // ext2: Implementation dependant error code.
Steve Block29357bc2012-01-06 19:20:56 +0000652 ALOGE("error (%d, %d)", ext1, ext2);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800653 mCurrentState = MEDIA_PLAYER_STATE_ERROR;
654 if (mPrepareSync)
655 {
Steve Block3856b092011-10-20 11:56:00 +0100656 ALOGV("signal application thread");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800657 mPrepareSync = false;
658 mPrepareStatus = ext1;
659 mSignal.signal();
660 send = false;
661 }
662 break;
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700663 case MEDIA_INFO:
664 // ext1: Media framework error code.
665 // ext2: Implementation dependant error code.
Andreas Huber145e68f2011-01-11 15:05:28 -0800666 if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000667 ALOGW("info/warning (%d, %d)", ext1, ext2);
Andreas Huber145e68f2011-01-11 15:05:28 -0800668 }
The Android Open Source Project65e731f2009-03-11 12:11:56 -0700669 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800670 case MEDIA_SEEK_COMPLETE:
Steve Block3856b092011-10-20 11:56:00 +0100671 ALOGV("Received seek complete");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800672 if (mSeekPosition != mCurrentPosition) {
Steve Block3856b092011-10-20 11:56:00 +0100673 ALOGV("Executing queued seekTo(%d)", mSeekPosition);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800674 mSeekPosition = -1;
675 seekTo_l(mCurrentPosition);
676 }
677 else {
Steve Block3856b092011-10-20 11:56:00 +0100678 ALOGV("All seeks complete - return to regularly scheduled program");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800679 mCurrentPosition = mSeekPosition = -1;
680 }
681 break;
682 case MEDIA_BUFFERING_UPDATE:
Steve Block3856b092011-10-20 11:56:00 +0100683 ALOGV("buffering %d", ext1);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800684 break;
685 case MEDIA_SET_VIDEO_SIZE:
Steve Block3856b092011-10-20 11:56:00 +0100686 ALOGV("New video size %d x %d", ext1, ext2);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800687 mVideoWidth = ext1;
688 mVideoHeight = ext2;
689 break;
Gloria Wangb483c472011-04-11 17:23:27 -0700690 case MEDIA_TIMED_TEXT:
Steve Block3856b092011-10-20 11:56:00 +0100691 ALOGV("Received timed text message");
Gloria Wangb483c472011-04-11 17:23:27 -0700692 break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800693 default:
Steve Block3856b092011-10-20 11:56:00 +0100694 ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800695 break;
696 }
697
698 sp<MediaPlayerListener> listener = mListener;
Jason Sams1af452f2009-03-24 18:45:22 -0700699 if (locked) mLock.unlock();
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800700
701 // this prevents re-entrant calls into client code
702 if ((listener != 0) && send) {
703 Mutex::Autolock _l(mNotifyLock);
Steve Block3856b092011-10-20 11:56:00 +0100704 ALOGV("callback application");
Gloria Wangb483c472011-04-11 17:23:27 -0700705 listener->notify(msg, ext1, ext2, obj);
Steve Block3856b092011-10-20 11:56:00 +0100706 ALOGV("back from callback");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800707 }
708}
709
Glenn Kastene1c39622012-01-04 09:36:37 -0800710/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800711{
Steve Block3856b092011-10-20 11:56:00 +0100712 ALOGV("decode(%s)", url);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800713 sp<IMemory> p;
714 const sp<IMediaPlayerService>& service = getMediaPlayerService();
715 if (service != 0) {
James Dongdd172fc2010-01-15 18:13:58 -0800716 p = service->decode(url, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800717 } else {
Steve Block29357bc2012-01-06 19:20:56 +0000718 ALOGE("Unable to locate media service");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800719 }
720 return p;
721
722}
723
James Dongdd172fc2010-01-15 18:13:58 -0800724void MediaPlayer::died()
725{
Steve Block3856b092011-10-20 11:56:00 +0100726 ALOGV("died");
James Dongdd172fc2010-01-15 18:13:58 -0800727 notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
728}
729
Glenn Kastene1c39622012-01-04 09:36:37 -0800730/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat)
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800731{
Steve Block3856b092011-10-20 11:56:00 +0100732 ALOGV("decode(%d, %lld, %lld)", fd, offset, length);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800733 sp<IMemory> p;
734 const sp<IMediaPlayerService>& service = getMediaPlayerService();
735 if (service != 0) {
James Dongdd172fc2010-01-15 18:13:58 -0800736 p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800737 } else {
Steve Block29357bc2012-01-06 19:20:56 +0000738 ALOGE("Unable to locate media service");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800739 }
740 return p;
741
742}
743
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800744}; // namespace android