blob: 242df77860274a6581c7e6bcef756612441e082b [file] [log] [blame]
Eric Laurentd73697b2015-03-05 15:09:23 -08001/*
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