1/*
2**
3** Copyright 2015, 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_TAG "IRadio"
19#include <utils/Log.h>
20#include <utils/Errors.h>
21#include <binder/IMemory.h>
22#include <radio/IRadio.h>
23#include <radio/IRadioService.h>
24#include <radio/IRadioClient.h>
25#include <system/radio.h>
26#include <system/radio_metadata.h>
27
28namespace android {
29
30enum {
31    DETACH = IBinder::FIRST_CALL_TRANSACTION,
32    SET_CONFIGURATION,
33    GET_CONFIGURATION,
34    SET_MUTE,
35    GET_MUTE,
36    SCAN,
37    STEP,
38    TUNE,
39    CANCEL,
40    GET_PROGRAM_INFORMATION,
41    HAS_CONTROL
42};
43
44class BpRadio: public BpInterface<IRadio>
45{
46public:
47    BpRadio(const sp<IBinder>& impl)
48        : BpInterface<IRadio>(impl)
49    {
50    }
51
52    void detach()
53    {
54        ALOGV("detach");
55        Parcel data, reply;
56        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
57        remote()->transact(DETACH, data, &reply);
58    }
59
60    virtual status_t setConfiguration(const struct radio_band_config *config)
61    {
62        Parcel data, reply;
63        if (config == NULL) {
64            return BAD_VALUE;
65        }
66        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
67        data.write(config, sizeof(struct radio_band_config));
68        status_t status = remote()->transact(SET_CONFIGURATION, data, &reply);
69        if (status == NO_ERROR) {
70            status = (status_t)reply.readInt32();
71        }
72        return status;
73    }
74
75    virtual status_t getConfiguration(struct radio_band_config *config)
76    {
77        Parcel data, reply;
78        if (config == NULL) {
79            return BAD_VALUE;
80        }
81        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
82        status_t status = remote()->transact(GET_CONFIGURATION, data, &reply);
83        if (status == NO_ERROR) {
84            status = (status_t)reply.readInt32();
85            if (status == NO_ERROR) {
86                reply.read(config, sizeof(struct radio_band_config));
87            }
88        }
89        return status;
90    }
91
92    virtual status_t setMute(bool mute)
93    {
94        Parcel data, reply;
95        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
96        data.writeInt32(mute ? 1 : 0);
97        status_t status = remote()->transact(SET_MUTE, data, &reply);
98        if (status == NO_ERROR) {
99            status = (status_t)reply.readInt32();
100        }
101        return status;
102    }
103
104    virtual status_t getMute(bool *mute)
105    {
106        Parcel data, reply;
107        if (mute == NULL) {
108            return BAD_VALUE;
109        }
110        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
111        status_t status = remote()->transact(GET_MUTE, data, &reply);
112        if (status == NO_ERROR) {
113            status = (status_t)reply.readInt32();
114            if (status == NO_ERROR) {
115                int muteread = reply.readInt32();
116                *mute = muteread != 0;
117            }
118        }
119        return status;
120    }
121
122    virtual status_t scan(radio_direction_t direction, bool skipSubChannel)
123    {
124        Parcel data, reply;
125        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
126        data.writeInt32(direction);
127        data.writeInt32(skipSubChannel ? 1 : 0);
128        status_t status = remote()->transact(SCAN, data, &reply);
129        if (status == NO_ERROR) {
130            status = (status_t)reply.readInt32();
131        }
132        return status;
133    }
134
135    virtual status_t step(radio_direction_t direction, bool skipSubChannel)
136    {
137        Parcel data, reply;
138        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
139        data.writeInt32(direction);
140        data.writeInt32(skipSubChannel ? 1 : 0);
141        status_t status = remote()->transact(STEP, data, &reply);
142        if (status == NO_ERROR) {
143            status = (status_t)reply.readInt32();
144        }
145        return status;
146    }
147
148    virtual status_t tune(unsigned int channel, unsigned int subChannel)
149    {
150        Parcel data, reply;
151        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
152        data.writeInt32(channel);
153        data.writeInt32(subChannel);
154        status_t status = remote()->transact(TUNE, data, &reply);
155        if (status == NO_ERROR) {
156            status = (status_t)reply.readInt32();
157        }
158        return status;
159    }
160
161    virtual status_t cancel()
162    {
163        Parcel data, reply;
164        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
165        status_t status = remote()->transact(CANCEL, data, &reply);
166        if (status == NO_ERROR) {
167            status = (status_t)reply.readInt32();
168        }
169        return status;
170    }
171
172    virtual status_t getProgramInformation(struct radio_program_info *info)
173    {
174        Parcel data, reply;
175        if (info == NULL) {
176            return BAD_VALUE;
177        }
178        radio_metadata_t *metadata = info->metadata;
179        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
180        status_t status = remote()->transact(GET_PROGRAM_INFORMATION, data, &reply);
181        if (status == NO_ERROR) {
182            status = (status_t)reply.readInt32();
183            if (status == NO_ERROR) {
184                reply.read(info, sizeof(struct radio_program_info));
185                info->metadata = metadata;
186                if (metadata == NULL) {
187                    return status;
188                }
189                size_t size = (size_t)reply.readInt32();
190                if (size == 0) {
191                    return status;
192                }
193                metadata =
194                    (radio_metadata_t *)calloc(size / sizeof(unsigned int), sizeof(unsigned int));
195                if (metadata == NULL) {
196                    return NO_MEMORY;
197                }
198                reply.read(metadata, size);
199                status = radio_metadata_add_metadata(&info->metadata, metadata);
200                free(metadata);
201            }
202        }
203        return status;
204    }
205
206    virtual status_t hasControl(bool *hasControl)
207    {
208        Parcel data, reply;
209        if (hasControl == NULL) {
210            return BAD_VALUE;
211        }
212        data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
213        status_t status = remote()->transact(HAS_CONTROL, data, &reply);
214        if (status == NO_ERROR) {
215            status = (status_t)reply.readInt32();
216            if (status == NO_ERROR) {
217                *hasControl = reply.readInt32() != 0;
218            }
219        }
220        return status;
221    }
222};
223
224IMPLEMENT_META_INTERFACE(Radio, "android.hardware.IRadio");
225
226// ----------------------------------------------------------------------
227
228status_t BnRadio::onTransact(
229    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
230{
231    switch(code) {
232        case DETACH: {
233            ALOGV("DETACH");
234            CHECK_INTERFACE(IRadio, data, reply);
235            detach();
236            return NO_ERROR;
237        } break;
238        case SET_CONFIGURATION: {
239            CHECK_INTERFACE(IRadio, data, reply);
240            struct radio_band_config config;
241            data.read(&config, sizeof(struct radio_band_config));
242            status_t status = setConfiguration(&config);
243            reply->writeInt32(status);
244            return NO_ERROR;
245        }
246        case GET_CONFIGURATION: {
247            CHECK_INTERFACE(IRadio, data, reply);
248            struct radio_band_config config;
249            status_t status = getConfiguration(&config);
250            reply->writeInt32(status);
251            if (status == NO_ERROR) {
252                reply->write(&config, sizeof(struct radio_band_config));
253            }
254            return NO_ERROR;
255        }
256        case SET_MUTE: {
257            CHECK_INTERFACE(IRadio, data, reply);
258            bool mute = data.readInt32() != 0;
259            status_t status = setMute(mute);
260            reply->writeInt32(status);
261            return NO_ERROR;
262        }
263        case GET_MUTE: {
264            CHECK_INTERFACE(IRadio, data, reply);
265            bool mute;
266            status_t status = getMute(&mute);
267            reply->writeInt32(status);
268            if (status == NO_ERROR) {
269                reply->writeInt32(mute ? 1 : 0);
270            }
271            return NO_ERROR;
272        }
273        case SCAN: {
274            CHECK_INTERFACE(IRadio, data, reply);
275            radio_direction_t direction = (radio_direction_t)data.readInt32();
276            bool skipSubChannel = data.readInt32() == 1;
277            status_t status = scan(direction, skipSubChannel);
278            reply->writeInt32(status);
279            return NO_ERROR;
280        }
281        case STEP: {
282            CHECK_INTERFACE(IRadio, data, reply);
283            radio_direction_t direction = (radio_direction_t)data.readInt32();
284            bool skipSubChannel = data.readInt32() == 1;
285            status_t status = step(direction, skipSubChannel);
286            reply->writeInt32(status);
287            return NO_ERROR;
288        }
289        case TUNE: {
290            CHECK_INTERFACE(IRadio, data, reply);
291            unsigned int channel = (unsigned int)data.readInt32();
292            unsigned int subChannel = (unsigned int)data.readInt32();
293            status_t status = tune(channel, subChannel);
294            reply->writeInt32(status);
295            return NO_ERROR;
296        }
297        case CANCEL: {
298            CHECK_INTERFACE(IRadio, data, reply);
299            status_t status = cancel();
300            reply->writeInt32(status);
301            return NO_ERROR;
302        }
303        case GET_PROGRAM_INFORMATION: {
304            CHECK_INTERFACE(IRadio, data, reply);
305            struct radio_program_info info;
306
307            status_t status = radio_metadata_allocate(&info.metadata, 0, 0);
308            if (status != NO_ERROR) {
309                return status;
310            }
311            status = getProgramInformation(&info);
312            reply->writeInt32(status);
313            if (status == NO_ERROR) {
314                reply->write(&info, sizeof(struct radio_program_info));
315                int count = radio_metadata_get_count(info.metadata);
316                if (count > 0) {
317                    size_t size = radio_metadata_get_size(info.metadata);
318                    reply->writeInt32(size);
319                    reply->write(info.metadata, size);
320                } else {
321                    reply->writeInt32(0);
322                }
323            }
324            radio_metadata_deallocate(info.metadata);
325            return NO_ERROR;
326        }
327        case HAS_CONTROL: {
328            CHECK_INTERFACE(IRadio, data, reply);
329            bool control;
330            status_t status = hasControl(&control);
331            reply->writeInt32(status);
332            if (status == NO_ERROR) {
333                reply->writeInt32(control ? 1 : 0);
334            }
335            return NO_ERROR;
336        }
337        default:
338            return BBinder::onTransact(code, data, reply, flags);
339    }
340}
341
342// ----------------------------------------------------------------------------
343
344}; // namespace android
345