blob: bd89ad824e99aecf1e11eb8c2c4d33312984ceec [file] [log] [blame]
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -08001/*
2**
3** Copyright 2008, 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#include <stdint.h>
19#include <sys/types.h>
20
Mathias Agopian75624082009-05-19 19:08:10 -070021#include <binder/Parcel.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080022
23#include <media/IMediaPlayer.h>
Dave Burked681bbb2011-08-30 14:39:17 +010024#include <media/IStreamSource.h>
25
Mathias Agopian3cf61352010-02-09 17:46:37 -080026#include <surfaceflinger/ISurface.h>
Andreas Huber5daeb122010-08-16 08:49:37 -070027#include <surfaceflinger/Surface.h>
Glenn Kasten11731182011-02-08 17:26:17 -080028#include <gui/ISurfaceTexture.h>
Dave Burked681bbb2011-08-30 14:39:17 +010029#include <utils/String8.h>
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080030
31namespace android {
32
33enum {
34 DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
Dave Burked681bbb2011-08-30 14:39:17 +010035 SET_DATA_SOURCE_URL,
36 SET_DATA_SOURCE_FD,
37 SET_DATA_SOURCE_STREAM,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080038 SET_VIDEO_SURFACE,
39 PREPARE_ASYNC,
40 START,
41 STOP,
42 IS_PLAYING,
43 PAUSE,
44 SEEK_TO,
45 GET_CURRENT_POSITION,
46 GET_DURATION,
47 RESET,
48 SET_AUDIO_STREAM_TYPE,
49 SET_LOOPING,
Nicolas Catania1d187f12009-05-12 23:25:55 -070050 SET_VOLUME,
51 INVOKE,
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -070052 SET_METADATA_FILTER,
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -070053 GET_METADATA,
Eric Laurent2beeb502010-07-16 07:43:46 -070054 SET_AUX_EFFECT_SEND_LEVEL,
Glenn Kasten11731182011-02-08 17:26:17 -080055 ATTACH_AUX_EFFECT,
56 SET_VIDEO_SURFACETEXTURE,
Gloria Wang4f9e47f2011-04-25 17:28:22 -070057 SET_PARAMETER,
58 GET_PARAMETER,
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -080059};
60
61class BpMediaPlayer: public BpInterface<IMediaPlayer>
62{
63public:
64 BpMediaPlayer(const sp<IBinder>& impl)
65 : BpInterface<IMediaPlayer>(impl)
66 {
67 }
68
69 // disconnect from media player service
70 void disconnect()
71 {
72 Parcel data, reply;
73 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
74 remote()->transact(DISCONNECT, data, &reply);
75 }
76
Dave Burked681bbb2011-08-30 14:39:17 +010077 status_t setDataSource(const char* url,
78 const KeyedVector<String8, String8>* headers)
79 {
80 Parcel data, reply;
81 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
82 data.writeCString(url);
83 if (headers == NULL) {
84 data.writeInt32(0);
85 } else {
86 // serialize the headers
87 data.writeInt32(headers->size());
88 for (size_t i = 0; i < headers->size(); ++i) {
89 data.writeString8(headers->keyAt(i));
90 data.writeString8(headers->valueAt(i));
91 }
92 }
93 remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
94 return reply.readInt32();
95 }
96
97 status_t setDataSource(int fd, int64_t offset, int64_t length) {
98 Parcel data, reply;
99 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
100 data.writeFileDescriptor(fd);
101 data.writeInt64(offset);
102 data.writeInt64(length);
103 remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
104 return reply.readInt32();
105 }
106
107 status_t setDataSource(const sp<IStreamSource> &source) {
108 Parcel data, reply;
109 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
110 data.writeStrongBinder(source->asBinder());
111 return reply.readInt32();
112 }
113
Glenn Kasten11731182011-02-08 17:26:17 -0800114 // pass the buffered Surface to the media player service
Andreas Huber5daeb122010-08-16 08:49:37 -0700115 status_t setVideoSurface(const sp<Surface>& surface)
116 {
117 Parcel data, reply;
118 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
119 Surface::writeToParcel(surface, &data);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800120 remote()->transact(SET_VIDEO_SURFACE, data, &reply);
121 return reply.readInt32();
122 }
123
Glenn Kasten11731182011-02-08 17:26:17 -0800124 // pass the buffered ISurfaceTexture to the media player service
125 status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture)
126 {
127 Parcel data, reply;
128 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
129 sp<IBinder> b(surfaceTexture->asBinder());
130 data.writeStrongBinder(b);
131 remote()->transact(SET_VIDEO_SURFACETEXTURE, data, &reply);
132 return reply.readInt32();
133 }
134
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800135 status_t prepareAsync()
136 {
137 Parcel data, reply;
138 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
139 remote()->transact(PREPARE_ASYNC, data, &reply);
140 return reply.readInt32();
141 }
142
143 status_t start()
144 {
145 Parcel data, reply;
146 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
147 remote()->transact(START, data, &reply);
148 return reply.readInt32();
149 }
150
151 status_t stop()
152 {
153 Parcel data, reply;
154 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
155 remote()->transact(STOP, data, &reply);
156 return reply.readInt32();
157 }
158
159 status_t isPlaying(bool* state)
160 {
161 Parcel data, reply;
162 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
163 remote()->transact(IS_PLAYING, data, &reply);
164 *state = reply.readInt32();
165 return reply.readInt32();
166 }
167
168 status_t pause()
169 {
170 Parcel data, reply;
171 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
172 remote()->transact(PAUSE, data, &reply);
173 return reply.readInt32();
174 }
175
176 status_t seekTo(int msec)
177 {
178 Parcel data, reply;
179 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
180 data.writeInt32(msec);
181 remote()->transact(SEEK_TO, data, &reply);
182 return reply.readInt32();
183 }
184
185 status_t getCurrentPosition(int* msec)
186 {
187 Parcel data, reply;
188 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
189 remote()->transact(GET_CURRENT_POSITION, data, &reply);
190 *msec = reply.readInt32();
191 return reply.readInt32();
192 }
193
194 status_t getDuration(int* msec)
195 {
196 Parcel data, reply;
197 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
198 remote()->transact(GET_DURATION, data, &reply);
199 *msec = reply.readInt32();
200 return reply.readInt32();
201 }
202
203 status_t reset()
204 {
205 Parcel data, reply;
206 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
207 remote()->transact(RESET, data, &reply);
208 return reply.readInt32();
209 }
210
211 status_t setAudioStreamType(int type)
212 {
213 Parcel data, reply;
214 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
215 data.writeInt32(type);
216 remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply);
217 return reply.readInt32();
218 }
219
220 status_t setLooping(int loop)
221 {
222 Parcel data, reply;
223 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
224 data.writeInt32(loop);
225 remote()->transact(SET_LOOPING, data, &reply);
226 return reply.readInt32();
227 }
228
229 status_t setVolume(float leftVolume, float rightVolume)
230 {
231 Parcel data, reply;
Dave Sparks172fb9a2009-05-26 14:39:29 -0700232 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800233 data.writeFloat(leftVolume);
234 data.writeFloat(rightVolume);
235 remote()->transact(SET_VOLUME, data, &reply);
236 return reply.readInt32();
237 }
Nicolas Catania1d187f12009-05-12 23:25:55 -0700238
239 status_t invoke(const Parcel& request, Parcel *reply)
James Dong040e4a12011-04-06 18:29:01 -0700240 {
241 // Avoid doing any extra copy. The interface descriptor should
242 // have been set by MediaPlayer.java.
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700243 return remote()->transact(INVOKE, request, reply);
Nicolas Catania1d187f12009-05-12 23:25:55 -0700244 }
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700245
246 status_t setMetadataFilter(const Parcel& request)
247 {
248 Parcel reply;
249 // Avoid doing any extra copy of the request. The interface
250 // descriptor should have been set by MediaPlayer.java.
251 remote()->transact(SET_METADATA_FILTER, request, &reply);
252 return reply.readInt32();
253 }
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700254
255 status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply)
256 {
257 Parcel request;
258 request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
259 // TODO: Burning 2 ints for 2 boolean. Should probably use flags in an int here.
260 request.writeInt32(update_only);
261 request.writeInt32(apply_filter);
262 remote()->transact(GET_METADATA, request, reply);
263 return reply->readInt32();
264 }
Andreas Huber4e92c7e2010-02-12 12:35:58 -0800265
Eric Laurent2beeb502010-07-16 07:43:46 -0700266 status_t setAuxEffectSendLevel(float level)
267 {
268 Parcel data, reply;
269 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
270 data.writeFloat(level);
271 remote()->transact(SET_AUX_EFFECT_SEND_LEVEL, data, &reply);
272 return reply.readInt32();
273 }
274
275 status_t attachAuxEffect(int effectId)
276 {
277 Parcel data, reply;
278 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
279 data.writeInt32(effectId);
280 remote()->transact(ATTACH_AUX_EFFECT, data, &reply);
281 return reply.readInt32();
282 }
Glenn Kasten11731182011-02-08 17:26:17 -0800283
Gloria Wang4f9e47f2011-04-25 17:28:22 -0700284 status_t setParameter(int key, const Parcel& request)
285 {
286 Parcel data, reply;
287 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
288 data.writeInt32(key);
289 if (request.dataSize() > 0) {
290 data.appendFrom(const_cast<Parcel *>(&request), 0, request.dataSize());
291 }
292 remote()->transact(SET_PARAMETER, data, &reply);
293 return reply.readInt32();
294 }
295
296 status_t getParameter(int key, Parcel *reply)
297 {
298 Parcel data;
299 data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
300 data.writeInt32(key);
301 return remote()->transact(GET_PARAMETER, data, reply);
302 }
303
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800304};
305
niko56f0cc52009-06-22 08:49:52 -0700306IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800307
308// ----------------------------------------------------------------------
309
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800310status_t BnMediaPlayer::onTransact(
311 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
312{
313 switch(code) {
314 case DISCONNECT: {
315 CHECK_INTERFACE(IMediaPlayer, data, reply);
316 disconnect();
317 return NO_ERROR;
318 } break;
Dave Burked681bbb2011-08-30 14:39:17 +0100319 case SET_DATA_SOURCE_URL: {
320 CHECK_INTERFACE(IMediaPlayer, data, reply);
321 const char* url = data.readCString();
322 KeyedVector<String8, String8> headers;
323 int32_t numHeaders = data.readInt32();
324 for (int i = 0; i < numHeaders; ++i) {
325 String8 key = data.readString8();
326 String8 value = data.readString8();
327 headers.add(key, value);
328 }
329 reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL));
330 return NO_ERROR;
331 } break;
332 case SET_DATA_SOURCE_FD: {
333 CHECK_INTERFACE(IMediaPlayer, data, reply);
334 int fd = data.readFileDescriptor();
335 int64_t offset = data.readInt64();
336 int64_t length = data.readInt64();
337 reply->writeInt32(setDataSource(fd, offset, length));
338 return NO_ERROR;
339 }
340 case SET_DATA_SOURCE_STREAM: {
341 CHECK_INTERFACE(IMediaPlayer, data, reply);
342 sp<IStreamSource> source =
343 interface_cast<IStreamSource>(data.readStrongBinder());
344 reply->writeInt32(setDataSource(source));
345 return NO_ERROR;
346 }
Andreas Huber5daeb122010-08-16 08:49:37 -0700347 case SET_VIDEO_SURFACE: {
348 CHECK_INTERFACE(IMediaPlayer, data, reply);
349 sp<Surface> surface = Surface::readFromParcel(data);
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800350 reply->writeInt32(setVideoSurface(surface));
351 return NO_ERROR;
352 } break;
Glenn Kasten11731182011-02-08 17:26:17 -0800353 case SET_VIDEO_SURFACETEXTURE: {
354 CHECK_INTERFACE(IMediaPlayer, data, reply);
355 sp<ISurfaceTexture> surfaceTexture =
356 interface_cast<ISurfaceTexture>(data.readStrongBinder());
357 reply->writeInt32(setVideoSurfaceTexture(surfaceTexture));
358 return NO_ERROR;
359 } break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800360 case PREPARE_ASYNC: {
361 CHECK_INTERFACE(IMediaPlayer, data, reply);
362 reply->writeInt32(prepareAsync());
363 return NO_ERROR;
364 } break;
365 case START: {
366 CHECK_INTERFACE(IMediaPlayer, data, reply);
367 reply->writeInt32(start());
368 return NO_ERROR;
369 } break;
370 case STOP: {
371 CHECK_INTERFACE(IMediaPlayer, data, reply);
372 reply->writeInt32(stop());
373 return NO_ERROR;
374 } break;
375 case IS_PLAYING: {
376 CHECK_INTERFACE(IMediaPlayer, data, reply);
377 bool state;
378 status_t ret = isPlaying(&state);
379 reply->writeInt32(state);
380 reply->writeInt32(ret);
381 return NO_ERROR;
382 } break;
383 case PAUSE: {
384 CHECK_INTERFACE(IMediaPlayer, data, reply);
385 reply->writeInt32(pause());
386 return NO_ERROR;
387 } break;
388 case SEEK_TO: {
389 CHECK_INTERFACE(IMediaPlayer, data, reply);
390 reply->writeInt32(seekTo(data.readInt32()));
391 return NO_ERROR;
392 } break;
393 case GET_CURRENT_POSITION: {
394 CHECK_INTERFACE(IMediaPlayer, data, reply);
395 int msec;
396 status_t ret = getCurrentPosition(&msec);
397 reply->writeInt32(msec);
398 reply->writeInt32(ret);
399 return NO_ERROR;
400 } break;
401 case GET_DURATION: {
402 CHECK_INTERFACE(IMediaPlayer, data, reply);
403 int msec;
404 status_t ret = getDuration(&msec);
405 reply->writeInt32(msec);
406 reply->writeInt32(ret);
407 return NO_ERROR;
408 } break;
409 case RESET: {
410 CHECK_INTERFACE(IMediaPlayer, data, reply);
411 reply->writeInt32(reset());
412 return NO_ERROR;
413 } break;
414 case SET_AUDIO_STREAM_TYPE: {
415 CHECK_INTERFACE(IMediaPlayer, data, reply);
416 reply->writeInt32(setAudioStreamType(data.readInt32()));
417 return NO_ERROR;
418 } break;
419 case SET_LOOPING: {
420 CHECK_INTERFACE(IMediaPlayer, data, reply);
421 reply->writeInt32(setLooping(data.readInt32()));
422 return NO_ERROR;
423 } break;
424 case SET_VOLUME: {
Dave Sparks172fb9a2009-05-26 14:39:29 -0700425 CHECK_INTERFACE(IMediaPlayer, data, reply);
Gloria Wangde162ff2011-08-01 14:01:29 -0700426 float leftVolume = data.readFloat();
427 float rightVolume = data.readFloat();
428 reply->writeInt32(setVolume(leftVolume, rightVolume));
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800429 return NO_ERROR;
430 } break;
Nicolas Catania1d187f12009-05-12 23:25:55 -0700431 case INVOKE: {
432 CHECK_INTERFACE(IMediaPlayer, data, reply);
James Dong040e4a12011-04-06 18:29:01 -0700433 status_t result = invoke(data, reply);
434 return result;
Nicolas Catania1d187f12009-05-12 23:25:55 -0700435 } break;
Nicolas Cataniaa7e0e8b2009-07-08 08:57:42 -0700436 case SET_METADATA_FILTER: {
437 CHECK_INTERFACE(IMediaPlayer, data, reply);
438 reply->writeInt32(setMetadataFilter(data));
439 return NO_ERROR;
440 } break;
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700441 case GET_METADATA: {
442 CHECK_INTERFACE(IMediaPlayer, data, reply);
Gloria Wangde162ff2011-08-01 14:01:29 -0700443 bool update_only = static_cast<bool>(data.readInt32());
444 bool apply_filter = static_cast<bool>(data.readInt32());
445 const status_t retcode = getMetadata(update_only, apply_filter, reply);
Nicolas Catania8e1b6cc2009-07-09 09:21:33 -0700446 reply->setDataPosition(0);
447 reply->writeInt32(retcode);
448 reply->setDataPosition(0);
449 return NO_ERROR;
450 } break;
Eric Laurent2beeb502010-07-16 07:43:46 -0700451 case SET_AUX_EFFECT_SEND_LEVEL: {
452 CHECK_INTERFACE(IMediaPlayer, data, reply);
453 reply->writeInt32(setAuxEffectSendLevel(data.readFloat()));
454 return NO_ERROR;
455 } break;
456 case ATTACH_AUX_EFFECT: {
457 CHECK_INTERFACE(IMediaPlayer, data, reply);
458 reply->writeInt32(attachAuxEffect(data.readInt32()));
459 return NO_ERROR;
460 } break;
Gloria Wang4f9e47f2011-04-25 17:28:22 -0700461 case SET_PARAMETER: {
462 CHECK_INTERFACE(IMediaPlayer, data, reply);
463 int key = data.readInt32();
464
465 Parcel request;
466 if (data.dataAvail() > 0) {
467 request.appendFrom(
468 const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
469 }
470 request.setDataPosition(0);
471 reply->writeInt32(setParameter(key, request));
472 return NO_ERROR;
473 } break;
474 case GET_PARAMETER: {
475 CHECK_INTERFACE(IMediaPlayer, data, reply);
476 return getParameter(data.readInt32(), reply);
477 } break;
The Android Open Source Project89fa4ad2009-03-03 19:31:44 -0800478 default:
479 return BBinder::onTransact(code, data, reply, flags);
480 }
481}
482
483// ----------------------------------------------------------------------------
484
485}; // namespace android