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