blob: ebf385964efefec002bf7fa4948b73360365c9de [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:
Chih-Hung Hsieh090ef602016-04-27 10:39:54 -070047 explicit BpRadio(const sp<IBinder>& impl)
Eric Laurentd73697b2015-03-05 15:09:23 -080048 : 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) {
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700115 int32_t muteread = reply.readInt32();
Eric Laurentd73697b2015-03-05 15:09:23 -0800116 *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
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700148 virtual status_t tune(uint32_t channel, uint32_t subChannel)
Eric Laurentd73697b2015-03-05 15:09:23 -0800149 {
150 Parcel data, reply;
151 data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700152 data.writeUint32(channel);
153 data.writeUint32(subChannel);
Eric Laurentd73697b2015-03-05 15:09:23 -0800154 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());
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700180 if (metadata != NULL) {
181 data.writeUint32(1);
182 } else {
183 data.writeUint32(0);
184 }
Eric Laurentd73697b2015-03-05 15:09:23 -0800185 status_t status = remote()->transact(GET_PROGRAM_INFORMATION, data, &reply);
186 if (status == NO_ERROR) {
187 status = (status_t)reply.readInt32();
188 if (status == NO_ERROR) {
189 reply.read(info, sizeof(struct radio_program_info));
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700190 // restore local metadata pointer
Eric Laurentd73697b2015-03-05 15:09:23 -0800191 info->metadata = metadata;
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700192
193 uint32_t metatataSize = reply.readUint32();
194 if ((metadata != NULL) && (metatataSize != 0)) {
195 radio_metadata_t *newMetadata = (radio_metadata_t *)malloc(metatataSize);
196 if (newMetadata == NULL) {
197 return NO_MEMORY;
198 }
199 reply.read(newMetadata, metatataSize);
200 status = radio_metadata_add_metadata(&info->metadata, newMetadata);
201 free(newMetadata);
Eric Laurentd73697b2015-03-05 15:09:23 -0800202 }
Eric Laurentd73697b2015-03-05 15:09:23 -0800203 }
204 }
205 return status;
206 }
207
208 virtual status_t hasControl(bool *hasControl)
209 {
210 Parcel data, reply;
211 if (hasControl == NULL) {
212 return BAD_VALUE;
213 }
214 data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
215 status_t status = remote()->transact(HAS_CONTROL, data, &reply);
216 if (status == NO_ERROR) {
217 status = (status_t)reply.readInt32();
218 if (status == NO_ERROR) {
219 *hasControl = reply.readInt32() != 0;
220 }
221 }
222 return status;
223 }
224};
225
226IMPLEMENT_META_INTERFACE(Radio, "android.hardware.IRadio");
227
228// ----------------------------------------------------------------------
229
230status_t BnRadio::onTransact(
231 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
232{
233 switch(code) {
234 case DETACH: {
235 ALOGV("DETACH");
236 CHECK_INTERFACE(IRadio, data, reply);
237 detach();
238 return NO_ERROR;
239 } break;
240 case SET_CONFIGURATION: {
241 CHECK_INTERFACE(IRadio, data, reply);
242 struct radio_band_config config;
243 data.read(&config, sizeof(struct radio_band_config));
244 status_t status = setConfiguration(&config);
245 reply->writeInt32(status);
246 return NO_ERROR;
247 }
248 case GET_CONFIGURATION: {
249 CHECK_INTERFACE(IRadio, data, reply);
250 struct radio_band_config config;
251 status_t status = getConfiguration(&config);
252 reply->writeInt32(status);
253 if (status == NO_ERROR) {
254 reply->write(&config, sizeof(struct radio_band_config));
255 }
256 return NO_ERROR;
257 }
258 case SET_MUTE: {
259 CHECK_INTERFACE(IRadio, data, reply);
260 bool mute = data.readInt32() != 0;
261 status_t status = setMute(mute);
262 reply->writeInt32(status);
263 return NO_ERROR;
264 }
265 case GET_MUTE: {
266 CHECK_INTERFACE(IRadio, data, reply);
267 bool mute;
268 status_t status = getMute(&mute);
269 reply->writeInt32(status);
270 if (status == NO_ERROR) {
271 reply->writeInt32(mute ? 1 : 0);
272 }
273 return NO_ERROR;
274 }
275 case SCAN: {
276 CHECK_INTERFACE(IRadio, data, reply);
277 radio_direction_t direction = (radio_direction_t)data.readInt32();
278 bool skipSubChannel = data.readInt32() == 1;
279 status_t status = scan(direction, skipSubChannel);
280 reply->writeInt32(status);
281 return NO_ERROR;
282 }
283 case STEP: {
284 CHECK_INTERFACE(IRadio, data, reply);
285 radio_direction_t direction = (radio_direction_t)data.readInt32();
286 bool skipSubChannel = data.readInt32() == 1;
287 status_t status = step(direction, skipSubChannel);
288 reply->writeInt32(status);
289 return NO_ERROR;
290 }
291 case TUNE: {
292 CHECK_INTERFACE(IRadio, data, reply);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700293 uint32_t channel = data.readUint32();
294 uint32_t subChannel = data.readUint32();
Eric Laurentd73697b2015-03-05 15:09:23 -0800295 status_t status = tune(channel, subChannel);
296 reply->writeInt32(status);
297 return NO_ERROR;
298 }
299 case CANCEL: {
300 CHECK_INTERFACE(IRadio, data, reply);
301 status_t status = cancel();
302 reply->writeInt32(status);
303 return NO_ERROR;
304 }
305 case GET_PROGRAM_INFORMATION: {
306 CHECK_INTERFACE(IRadio, data, reply);
307 struct radio_program_info info;
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700308 status_t status;
309 // query metadata only if requested by remote side
310 if (data.readUint32() == 1) {
311 status = radio_metadata_allocate(&info.metadata, 0, 0);
312 if (status != NO_ERROR) {
313 return status;
314 }
315 } else {
316 info.metadata = NULL;
Eric Laurentd73697b2015-03-05 15:09:23 -0800317 }
318 status = getProgramInformation(&info);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700319
Eric Laurentd73697b2015-03-05 15:09:23 -0800320 reply->writeInt32(status);
321 if (status == NO_ERROR) {
322 reply->write(&info, sizeof(struct radio_program_info));
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700323 if ((info.metadata != NULL) && (radio_metadata_get_count(info.metadata) > 0)) {
Eric Laurentd73697b2015-03-05 15:09:23 -0800324 size_t size = radio_metadata_get_size(info.metadata);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700325 reply->writeUint32((uint32_t)size);
Eric Laurentd73697b2015-03-05 15:09:23 -0800326 reply->write(info.metadata, size);
327 } else {
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700328 reply->writeUint32(0);
Eric Laurentd73697b2015-03-05 15:09:23 -0800329 }
330 }
331 radio_metadata_deallocate(info.metadata);
332 return NO_ERROR;
333 }
334 case HAS_CONTROL: {
335 CHECK_INTERFACE(IRadio, data, reply);
336 bool control;
337 status_t status = hasControl(&control);
338 reply->writeInt32(status);
339 if (status == NO_ERROR) {
340 reply->writeInt32(control ? 1 : 0);
341 }
342 return NO_ERROR;
343 }
344 default:
345 return BBinder::onTransact(code, data, reply, flags);
346 }
347}
348
349// ----------------------------------------------------------------------------
350
351}; // namespace android