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 
28 namespace android {
29 
30 enum {
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 
44 class BpRadio: public BpInterface<IRadio>
45 {
46 public:
BpRadio(const sp<IBinder> & impl)47     BpRadio(const sp<IBinder>& impl)
48         : BpInterface<IRadio>(impl)
49     {
50     }
51 
detach()52     void detach()
53     {
54         ALOGV("detach");
55         Parcel data, reply;
56         data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
57         remote()->transact(DETACH, data, &reply);
58     }
59 
setConfiguration(const struct radio_band_config * config)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 
getConfiguration(struct radio_band_config * config)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 
setMute(bool mute)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 
getMute(bool * mute)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 
scan(radio_direction_t direction,bool skipSubChannel)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 
step(radio_direction_t direction,bool skipSubChannel)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 
tune(unsigned int channel,unsigned int subChannel)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 
cancel()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 
getProgramInformation(struct radio_program_info * info)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 
hasControl(bool * hasControl)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 
224 IMPLEMENT_META_INTERFACE(Radio, "android.hardware.IRadio");
225 
226 // ----------------------------------------------------------------------
227 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)228 status_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