blob: 72f3b68614694d3d898b33395e5f0893613432e4 [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"
Tomasz Wasilczyk302ea572017-01-23 14:36:15 -080019//#define LOG_NDEBUG 0
Eric Laurentd73697b2015-03-05 15:09:23 -080020#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>
Tomasz Wasilczyk302ea572017-01-23 14:36:15 -080027#include <system/RadioMetadataWrapper.h>
Eric Laurentd73697b2015-03-05 15:09:23 -080028
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:
Chih-Hung Hsieh090ef602016-04-27 10:39:54 -070048 explicit BpRadio(const sp<IBinder>& impl)
Eric Laurentd73697b2015-03-05 15:09:23 -080049 : 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) {
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700116 int32_t muteread = reply.readInt32();
Eric Laurentd73697b2015-03-05 15:09:23 -0800117 *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
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700149 virtual status_t tune(uint32_t channel, uint32_t subChannel)
Eric Laurentd73697b2015-03-05 15:09:23 -0800150 {
151 Parcel data, reply;
152 data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700153 data.writeUint32(channel);
154 data.writeUint32(subChannel);
Eric Laurentd73697b2015-03-05 15:09:23 -0800155 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;
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800176 if (info == nullptr || info->metadata == nullptr) {
Eric Laurentd73697b2015-03-05 15:09:23 -0800177 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));
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700186 // restore local metadata pointer
Eric Laurentd73697b2015-03-05 15:09:23 -0800187 info->metadata = metadata;
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700188
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800189 uint32_t metadataSize = reply.readUint32();
190 if (metadataSize != 0) {
191 radio_metadata_t *newMetadata = (radio_metadata_t *)malloc(metadataSize);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700192 if (newMetadata == NULL) {
193 return NO_MEMORY;
194 }
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800195 reply.read(newMetadata, metadataSize);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700196 status = radio_metadata_add_metadata(&info->metadata, newMetadata);
197 free(newMetadata);
Eric Laurentd73697b2015-03-05 15:09:23 -0800198 }
Eric Laurentd73697b2015-03-05 15:09:23 -0800199 }
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);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700289 uint32_t channel = data.readUint32();
290 uint32_t subChannel = data.readUint32();
Eric Laurentd73697b2015-03-05 15:09:23 -0800291 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;
Tomasz Wasilczyk302ea572017-01-23 14:36:15 -0800304 RadioMetadataWrapper metadataWrapper(&info.metadata);
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800305
Tomasz Wasilczyk302ea572017-01-23 14:36:15 -0800306 status_t status = getProgramInformation(&info);
Eric Laurentd73697b2015-03-05 15:09:23 -0800307 reply->writeInt32(status);
308 if (status == NO_ERROR) {
309 reply->write(&info, sizeof(struct radio_program_info));
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800310 if (radio_metadata_get_count(info.metadata) > 0) {
Eric Laurentd73697b2015-03-05 15:09:23 -0800311 size_t size = radio_metadata_get_size(info.metadata);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700312 reply->writeUint32((uint32_t)size);
Eric Laurentd73697b2015-03-05 15:09:23 -0800313 reply->write(info.metadata, size);
314 } else {
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700315 reply->writeUint32(0);
Eric Laurentd73697b2015-03-05 15:09:23 -0800316 }
317 }
Eric Laurentd73697b2015-03-05 15:09:23 -0800318 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