blob: f2a657aa03572c9a055129d2b40c9750e29748b3 [file] [log] [blame]
Andreas Huber20111aa2009-07-14 16:56:47 -07001//#define LOG_NDEBUG 0
2#define LOG_TAG "IOMX"
3#include <utils/Log.h>
4
5#include <binder/IMemory.h>
6#include <binder/Parcel.h>
7#include <media/IOMX.h>
8
9namespace android {
10
11enum {
12 CONNECT = IBinder::FIRST_CALL_TRANSACTION,
13 LIST_NODES,
14 ALLOCATE_NODE,
15 FREE_NODE,
16 SEND_COMMAND,
17 GET_PARAMETER,
18 SET_PARAMETER,
19 USE_BUFFER,
20 ALLOC_BUFFER,
21 ALLOC_BUFFER_WITH_BACKUP,
22 FREE_BUFFER,
23 OBSERVE_NODE,
24 FILL_BUFFER,
25 EMPTY_BUFFER,
26 OBSERVER_ON_MSG,
27};
28
29static void *readVoidStar(const Parcel *parcel) {
30 // FIX if sizeof(void *) != sizeof(int32)
31 return (void *)parcel->readInt32();
32}
33
34static void writeVoidStar(void *x, Parcel *parcel) {
35 // FIX if sizeof(void *) != sizeof(int32)
36 parcel->writeInt32((int32_t)x);
37}
38
39class BpOMX : public BpInterface<IOMX> {
40public:
41 BpOMX(const sp<IBinder> &impl)
42 : BpInterface<IOMX>(impl) {
43 }
44
45#if IOMX_USES_SOCKETS
46 virtual status_t connect(int *sd) {
47 Parcel data, reply;
48 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
49 remote()->transact(CONNECT, data, &reply);
50
51 status_t err = reply.readInt32();
52 if (err == OK) {
53 *sd = dup(reply.readFileDescriptor());
54 } else {
55 *sd = -1;
56 }
57
58 return reply.readInt32();
59 }
60#endif
61
62 virtual status_t list_nodes(List<String8> *list) {
63 list->clear();
64
65 Parcel data, reply;
66 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
67 remote()->transact(LIST_NODES, data, &reply);
68
69 int32_t n = reply.readInt32();
70 for (int32_t i = 0; i < n; ++i) {
71 String8 s = reply.readString8();
72
73 list->push_back(s);
74 }
75
76 return OK;
77 }
78
79 virtual status_t allocate_node(const char *name, node_id *node) {
80 Parcel data, reply;
81 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
82 data.writeCString(name);
83 remote()->transact(ALLOCATE_NODE, data, &reply);
84
85 status_t err = reply.readInt32();
86 if (err == OK) {
87 *node = readVoidStar(&reply);
88 } else {
89 *node = 0;
90 }
91
92 return err;
93 }
94
95 virtual status_t free_node(node_id node) {
96 Parcel data, reply;
97 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
98 writeVoidStar(node, &data);
99 remote()->transact(FREE_NODE, data, &reply);
100
101 return reply.readInt32();
102 }
103
104 virtual status_t send_command(
105 node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
106 Parcel data, reply;
107 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
108 writeVoidStar(node, &data);
109 data.writeInt32(cmd);
110 data.writeInt32(param);
111 remote()->transact(SEND_COMMAND, data, &reply);
112
113 return reply.readInt32();
114 }
115
116 virtual status_t get_parameter(
117 node_id node, OMX_INDEXTYPE index,
118 void *params, size_t size) {
119 Parcel data, reply;
120 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
121 writeVoidStar(node, &data);
122 data.writeInt32(index);
123 data.writeInt32(size);
124 data.write(params, size);
125 remote()->transact(GET_PARAMETER, data, &reply);
126
127 status_t err = reply.readInt32();
128 if (err != OK) {
129 return err;
130 }
131
132 reply.read(params, size);
133
134 return OK;
135 }
136
137 virtual status_t set_parameter(
138 node_id node, OMX_INDEXTYPE index,
139 const void *params, size_t size) {
140 Parcel data, reply;
141 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
142 writeVoidStar(node, &data);
143 data.writeInt32(index);
144 data.writeInt32(size);
145 data.write(params, size);
146 remote()->transact(SET_PARAMETER, data, &reply);
147
148 return reply.readInt32();
149 }
150
151 virtual status_t use_buffer(
152 node_id node, OMX_U32 port_index, const sp<IMemory> &params,
153 buffer_id *buffer) {
154 Parcel data, reply;
155 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
156 writeVoidStar(node, &data);
157 data.writeInt32(port_index);
158 data.writeStrongBinder(params->asBinder());
159 remote()->transact(USE_BUFFER, data, &reply);
160
161 status_t err = reply.readInt32();
162 if (err != OK) {
163 *buffer = 0;
164
165 return err;
166 }
167
168 *buffer = readVoidStar(&reply);
169
170 return err;
171 }
172
173 virtual status_t allocate_buffer(
174 node_id node, OMX_U32 port_index, size_t size,
175 buffer_id *buffer) {
176 Parcel data, reply;
177 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
178 writeVoidStar(node, &data);
179 data.writeInt32(port_index);
180 data.writeInt32(size);
181 remote()->transact(ALLOC_BUFFER, data, &reply);
182
183 status_t err = reply.readInt32();
184 if (err != OK) {
185 *buffer = 0;
186
187 return err;
188 }
189
190 *buffer = readVoidStar(&reply);
191
192 return err;
193 }
194
195 virtual status_t allocate_buffer_with_backup(
196 node_id node, OMX_U32 port_index, const sp<IMemory> &params,
197 buffer_id *buffer) {
198 Parcel data, reply;
199 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
200 writeVoidStar(node, &data);
201 data.writeInt32(port_index);
202 data.writeStrongBinder(params->asBinder());
203 remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply);
204
205 status_t err = reply.readInt32();
206 if (err != OK) {
207 *buffer = 0;
208
209 return err;
210 }
211
212 *buffer = readVoidStar(&reply);
213
214 return err;
215 }
216
217 virtual status_t free_buffer(
218 node_id node, OMX_U32 port_index, buffer_id buffer) {
219 Parcel data, reply;
220 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
221 writeVoidStar(node, &data);
222 data.writeInt32(port_index);
223 writeVoidStar(buffer, &data);
224 remote()->transact(FREE_BUFFER, data, &reply);
225
226 return reply.readInt32();
227 }
228
229#if !IOMX_USES_SOCKETS
230 virtual status_t observe_node(
231 node_id node, const sp<IOMXObserver> &observer) {
232 Parcel data, reply;
233 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
234 writeVoidStar(node, &data);
235 data.writeStrongBinder(observer->asBinder());
236 remote()->transact(OBSERVE_NODE, data, &reply);
237
238 return reply.readInt32();
239 }
240
241 virtual void fill_buffer(node_id node, buffer_id buffer) {
242 Parcel data, reply;
243 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
244 writeVoidStar(node, &data);
245 writeVoidStar(buffer, &data);
246 remote()->transact(FILL_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
247 }
248
249 virtual void empty_buffer(
250 node_id node,
251 buffer_id buffer,
252 OMX_U32 range_offset, OMX_U32 range_length,
253 OMX_U32 flags, OMX_TICKS timestamp) {
254 Parcel data, reply;
255 data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
256 writeVoidStar(node, &data);
257 writeVoidStar(buffer, &data);
258 data.writeInt32(range_offset);
259 data.writeInt32(range_length);
260 data.writeInt32(flags);
261 data.writeInt64(timestamp);
262 remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
263 }
264#endif
265};
266
267IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
268
269////////////////////////////////////////////////////////////////////////////////
270
271#define CHECK_INTERFACE(interface, data, reply) \
272 do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
273 LOGW("Call incorrectly routed to " #interface); \
274 return PERMISSION_DENIED; \
275 } } while (0)
276
277status_t BnOMX::onTransact(
278 uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
279 switch (code) {
280#if IOMX_USES_SOCKETS
281 case CONNECT:
282 {
283 CHECK_INTERFACE(IOMX, data, reply);
284
285 int s;
286 status_t err = connect(&s);
287
288 reply->writeInt32(err);
289 if (err == OK) {
290 assert(s >= 0);
291 reply->writeDupFileDescriptor(s);
292 close(s);
293 s = -1;
294 } else {
295 assert(s == -1);
296 }
297
298 return NO_ERROR;
299 }
300#endif
301
302 case LIST_NODES:
303 {
304 CHECK_INTERFACE(IOMX, data, reply);
305
306 List<String8> list;
307 list_nodes(&list);
308
309 reply->writeInt32(list.size());
310 for (List<String8>::iterator it = list.begin();
311 it != list.end(); ++it) {
312 reply->writeString8(*it);
313 }
314
315 return NO_ERROR;
316 }
317
318 case ALLOCATE_NODE:
319 {
320 CHECK_INTERFACE(IOMX, data, reply);
321
322 node_id node;
323 status_t err = allocate_node(data.readCString(), &node);
324 reply->writeInt32(err);
325 if (err == OK) {
326 writeVoidStar(node, reply);
327 }
328
329 return NO_ERROR;
330 }
331
332 case FREE_NODE:
333 {
334 CHECK_INTERFACE(IOMX, data, reply);
335
336 node_id node = readVoidStar(&data);
337
338 reply->writeInt32(free_node(node));
339
340 return NO_ERROR;
341 }
342
343 case SEND_COMMAND:
344 {
345 CHECK_INTERFACE(IOMX, data, reply);
346
347 node_id node = readVoidStar(&data);
348
349 OMX_COMMANDTYPE cmd =
350 static_cast<OMX_COMMANDTYPE>(data.readInt32());
351
352 OMX_S32 param = data.readInt32();
353 reply->writeInt32(send_command(node, cmd, param));
354
355 return NO_ERROR;
356 }
357
358 case GET_PARAMETER:
359 {
360 CHECK_INTERFACE(IOMX, data, reply);
361
362 node_id node = readVoidStar(&data);
363 OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
364
365 size_t size = data.readInt32();
366
367 // XXX I am not happy with this but Parcel::readInplace didn't work.
368 void *params = malloc(size);
369 data.read(params, size);
370
371 status_t err = get_parameter(node, index, params, size);
372
373 reply->writeInt32(err);
374
375 if (err == OK) {
376 reply->write(params, size);
377 }
378
379 free(params);
380 params = NULL;
381
382 return NO_ERROR;
383 }
384
385 case SET_PARAMETER:
386 {
387 CHECK_INTERFACE(IOMX, data, reply);
388
389 node_id node = readVoidStar(&data);
390 OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
391
392 size_t size = data.readInt32();
393 void *params = const_cast<void *>(data.readInplace(size));
394
395 reply->writeInt32(set_parameter(node, index, params, size));
396
397 return NO_ERROR;
398 }
399
400 case USE_BUFFER:
401 {
402 CHECK_INTERFACE(IOMX, data, reply);
403
404 node_id node = readVoidStar(&data);
405 OMX_U32 port_index = data.readInt32();
406 sp<IMemory> params =
407 interface_cast<IMemory>(data.readStrongBinder());
408
409 buffer_id buffer;
410 status_t err = use_buffer(node, port_index, params, &buffer);
411 reply->writeInt32(err);
412
413 if (err == OK) {
414 writeVoidStar(buffer, reply);
415 }
416
417 return NO_ERROR;
418 }
419
420 case ALLOC_BUFFER:
421 {
422 CHECK_INTERFACE(IOMX, data, reply);
423
424 node_id node = readVoidStar(&data);
425 OMX_U32 port_index = data.readInt32();
426 size_t size = data.readInt32();
427
428 buffer_id buffer;
429 status_t err = allocate_buffer(node, port_index, size, &buffer);
430 reply->writeInt32(err);
431
432 if (err == OK) {
433 writeVoidStar(buffer, reply);
434 }
435
436 return NO_ERROR;
437 }
438
439 case ALLOC_BUFFER_WITH_BACKUP:
440 {
441 CHECK_INTERFACE(IOMX, data, reply);
442
443 node_id node = readVoidStar(&data);
444 OMX_U32 port_index = data.readInt32();
445 sp<IMemory> params =
446 interface_cast<IMemory>(data.readStrongBinder());
447
448 buffer_id buffer;
449 status_t err = allocate_buffer_with_backup(
450 node, port_index, params, &buffer);
451
452 reply->writeInt32(err);
453
454 if (err == OK) {
455 writeVoidStar(buffer, reply);
456 }
457
458 return NO_ERROR;
459 }
460
461 case FREE_BUFFER:
462 {
463 CHECK_INTERFACE(IOMX, data, reply);
464
465 node_id node = readVoidStar(&data);
466 OMX_U32 port_index = data.readInt32();
467 buffer_id buffer = readVoidStar(&data);
468 reply->writeInt32(free_buffer(node, port_index, buffer));
469
470 return NO_ERROR;
471 }
472
473#if !IOMX_USES_SOCKETS
474 case OBSERVE_NODE:
475 {
476 CHECK_INTERFACE(IOMX, data, reply);
477
478 node_id node = readVoidStar(&data);
479 sp<IOMXObserver> observer =
480 interface_cast<IOMXObserver>(data.readStrongBinder());
481 reply->writeInt32(observe_node(node, observer));
482
483 return NO_ERROR;
484 }
485
486 case FILL_BUFFER:
487 {
488 CHECK_INTERFACE(IOMX, data, reply);
489
490 node_id node = readVoidStar(&data);
491 buffer_id buffer = readVoidStar(&data);
492 fill_buffer(node, buffer);
493
494 return NO_ERROR;
495 }
496
497 case EMPTY_BUFFER:
498 {
499 CHECK_INTERFACE(IOMX, data, reply);
500
501 node_id node = readVoidStar(&data);
502 buffer_id buffer = readVoidStar(&data);
503 OMX_U32 range_offset = data.readInt32();
504 OMX_U32 range_length = data.readInt32();
505 OMX_U32 flags = data.readInt32();
506 OMX_TICKS timestamp = data.readInt64();
507
508 empty_buffer(
509 node, buffer, range_offset, range_length,
510 flags, timestamp);
511
512 return NO_ERROR;
513 }
514#endif
515
516 default:
517 return BBinder::onTransact(code, data, reply, flags);
518 }
519}
520
521////////////////////////////////////////////////////////////////////////////////
522
523class BpOMXObserver : public BpInterface<IOMXObserver> {
524public:
525 BpOMXObserver(const sp<IBinder> &impl)
526 : BpInterface<IOMXObserver>(impl) {
527 }
528
529 virtual void on_message(const omx_message &msg) {
530 Parcel data, reply;
531 data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor());
532 data.write(&msg, sizeof(msg));
533
534 remote()->transact(OBSERVER_ON_MSG, data, &reply, IBinder::FLAG_ONEWAY);
535 }
536};
537
538IMPLEMENT_META_INTERFACE(OMXObserver, "android.hardware.IOMXObserver");
539
540status_t BnOMXObserver::onTransact(
541 uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
542 switch (code) {
543 case OBSERVER_ON_MSG:
544 {
545 CHECK_INTERFACE(IOMXObserver, data, reply);
546
547 omx_message msg;
548 data.read(&msg, sizeof(msg));
549
550 // XXX Could use readInplace maybe?
551 on_message(msg);
552
553 return NO_ERROR;
554 }
555
556 default:
557 return BBinder::onTransact(code, data, reply, flags);
558 }
559}
560
561} // namespace android