1/*
2**
3** Copyright 2010, 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 "IEffect"
20#include <utils/Log.h>
21#include <stdint.h>
22#include <sys/types.h>
23#include <binder/Parcel.h>
24#include <media/IEffect.h>
25
26namespace android {
27
28// Maximum command/reply size expected
29#define EFFECT_PARAM_SIZE_MAX       65536
30
31enum {
32    ENABLE = IBinder::FIRST_CALL_TRANSACTION,
33    DISABLE,
34    COMMAND,
35    DISCONNECT,
36    GET_CBLK
37};
38
39class BpEffect: public BpInterface<IEffect>
40{
41public:
42    explicit BpEffect(const sp<IBinder>& impl)
43        : BpInterface<IEffect>(impl)
44    {
45    }
46
47    status_t enable()
48    {
49        ALOGV("enable");
50        Parcel data, reply;
51        data.writeInterfaceToken(IEffect::getInterfaceDescriptor());
52        remote()->transact(ENABLE, data, &reply);
53        return reply.readInt32();
54    }
55
56    status_t disable()
57    {
58        ALOGV("disable");
59        Parcel data, reply;
60        data.writeInterfaceToken(IEffect::getInterfaceDescriptor());
61        remote()->transact(DISABLE, data, &reply);
62        return reply.readInt32();
63    }
64
65    status_t command(uint32_t cmdCode,
66                     uint32_t cmdSize,
67                     void *pCmdData,
68                     uint32_t *pReplySize,
69                     void *pReplyData)
70    {
71        ALOGV("command");
72        Parcel data, reply;
73        data.writeInterfaceToken(IEffect::getInterfaceDescriptor());
74        data.writeInt32(cmdCode);
75        int size = cmdSize;
76        if (pCmdData == NULL) {
77            size = 0;
78        }
79        data.writeInt32(size);
80        if (size) {
81            data.write(pCmdData, size);
82        }
83        if (pReplySize == NULL) {
84            size = 0;
85        } else {
86            size = *pReplySize;
87        }
88        data.writeInt32(size);
89
90        status_t status = remote()->transact(COMMAND, data, &reply);
91        if (status == NO_ERROR) {
92            status = reply.readInt32();
93        }
94        if (status != NO_ERROR) {
95            if (pReplySize != NULL)
96                *pReplySize = 0;
97            return status;
98        }
99
100        size = reply.readInt32();
101        if (size != 0 && pReplyData != NULL && pReplySize != NULL) {
102            reply.read(pReplyData, size);
103            *pReplySize = size;
104        }
105        return status;
106    }
107
108    void disconnect()
109    {
110        ALOGV("disconnect");
111        Parcel data, reply;
112        data.writeInterfaceToken(IEffect::getInterfaceDescriptor());
113        remote()->transact(DISCONNECT, data, &reply);
114        return;
115    }
116
117    virtual sp<IMemory> getCblk() const
118    {
119        Parcel data, reply;
120        sp<IMemory> cblk;
121        data.writeInterfaceToken(IEffect::getInterfaceDescriptor());
122        status_t status = remote()->transact(GET_CBLK, data, &reply);
123        if (status == NO_ERROR) {
124            cblk = interface_cast<IMemory>(reply.readStrongBinder());
125            if (cblk != 0 && cblk->pointer() == NULL) {
126                cblk.clear();
127            }
128        }
129        return cblk;
130    }
131 };
132
133IMPLEMENT_META_INTERFACE(Effect, "android.media.IEffect");
134
135// ----------------------------------------------------------------------
136
137status_t BnEffect::onTransact(
138    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
139{
140    switch (code) {
141        case ENABLE: {
142            ALOGV("ENABLE");
143            CHECK_INTERFACE(IEffect, data, reply);
144            reply->writeInt32(enable());
145            return NO_ERROR;
146        } break;
147
148        case DISABLE: {
149            ALOGV("DISABLE");
150            CHECK_INTERFACE(IEffect, data, reply);
151            reply->writeInt32(disable());
152            return NO_ERROR;
153        } break;
154
155        case COMMAND: {
156            ALOGV("COMMAND");
157            CHECK_INTERFACE(IEffect, data, reply);
158            uint32_t cmdCode = data.readInt32();
159            uint32_t cmdSize = data.readInt32();
160            char *cmd = NULL;
161            if (cmdSize) {
162                if (cmdSize > EFFECT_PARAM_SIZE_MAX) {
163                    reply->writeInt32(NO_MEMORY);
164                    return NO_ERROR;
165                }
166                cmd = (char *)calloc(cmdSize, 1);
167                if (cmd == NULL) {
168                    reply->writeInt32(NO_MEMORY);
169                    return NO_ERROR;
170                }
171                data.read(cmd, cmdSize);
172            }
173            uint32_t replySize = data.readInt32();
174            uint32_t replySz = replySize;
175            char *resp = NULL;
176            if (replySize) {
177                if (replySize > EFFECT_PARAM_SIZE_MAX) {
178                    free(cmd);
179                    reply->writeInt32(NO_MEMORY);
180                    return NO_ERROR;
181                }
182                resp = (char *)calloc(replySize, 1);
183                if (resp == NULL) {
184                    free(cmd);
185                    reply->writeInt32(NO_MEMORY);
186                    return NO_ERROR;
187                }
188            }
189            status_t status = command(cmdCode, cmdSize, cmd, &replySz, resp);
190            reply->writeInt32(status);
191            if (status == NO_ERROR) {
192                if (replySz < replySize) {
193                    replySize = replySz;
194                }
195                reply->writeInt32(replySize);
196                if (replySize) {
197                    reply->write(resp, replySize);
198                }
199            }
200            if (cmd) {
201                free(cmd);
202            }
203            if (resp) {
204                free(resp);
205            }
206            return NO_ERROR;
207        } break;
208
209        case DISCONNECT: {
210            ALOGV("DISCONNECT");
211            CHECK_INTERFACE(IEffect, data, reply);
212            disconnect();
213            return NO_ERROR;
214        } break;
215
216        case GET_CBLK: {
217            CHECK_INTERFACE(IEffect, data, reply);
218            reply->writeStrongBinder(IInterface::asBinder(getCblk()));
219            return NO_ERROR;
220        } break;
221
222        default:
223            return BBinder::onTransact(code, data, reply, flags);
224    }
225}
226
227// ----------------------------------------------------------------------------
228
229} // namespace android
230