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