blob: 5bbe7cbf932e9d4423196f859348a54e5a5e65ae [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;
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800175 if (info == nullptr || info->metadata == nullptr) {
Eric Laurentd73697b2015-03-05 15:09:23 -0800176 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));
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700185 // restore local metadata pointer
Eric Laurentd73697b2015-03-05 15:09:23 -0800186 info->metadata = metadata;
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700187
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800188 uint32_t metadataSize = reply.readUint32();
189 if (metadataSize != 0) {
190 radio_metadata_t *newMetadata = (radio_metadata_t *)malloc(metadataSize);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700191 if (newMetadata == NULL) {
192 return NO_MEMORY;
193 }
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800194 reply.read(newMetadata, metadataSize);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700195 status = radio_metadata_add_metadata(&info->metadata, newMetadata);
196 free(newMetadata);
Eric Laurentd73697b2015-03-05 15:09:23 -0800197 }
Eric Laurentd73697b2015-03-05 15:09:23 -0800198 }
199 }
200 return status;
201 }
202
203 virtual status_t hasControl(bool *hasControl)
204 {
205 Parcel data, reply;
206 if (hasControl == NULL) {
207 return BAD_VALUE;
208 }
209 data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
210 status_t status = remote()->transact(HAS_CONTROL, data, &reply);
211 if (status == NO_ERROR) {
212 status = (status_t)reply.readInt32();
213 if (status == NO_ERROR) {
214 *hasControl = reply.readInt32() != 0;
215 }
216 }
217 return status;
218 }
219};
220
221IMPLEMENT_META_INTERFACE(Radio, "android.hardware.IRadio");
222
223// ----------------------------------------------------------------------
224
225status_t BnRadio::onTransact(
226 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
227{
228 switch(code) {
229 case DETACH: {
230 ALOGV("DETACH");
231 CHECK_INTERFACE(IRadio, data, reply);
232 detach();
233 return NO_ERROR;
234 } break;
235 case SET_CONFIGURATION: {
236 CHECK_INTERFACE(IRadio, data, reply);
237 struct radio_band_config config;
238 data.read(&config, sizeof(struct radio_band_config));
239 status_t status = setConfiguration(&config);
240 reply->writeInt32(status);
241 return NO_ERROR;
242 }
243 case GET_CONFIGURATION: {
244 CHECK_INTERFACE(IRadio, data, reply);
245 struct radio_band_config config;
246 status_t status = getConfiguration(&config);
247 reply->writeInt32(status);
248 if (status == NO_ERROR) {
249 reply->write(&config, sizeof(struct radio_band_config));
250 }
251 return NO_ERROR;
252 }
253 case SET_MUTE: {
254 CHECK_INTERFACE(IRadio, data, reply);
255 bool mute = data.readInt32() != 0;
256 status_t status = setMute(mute);
257 reply->writeInt32(status);
258 return NO_ERROR;
259 }
260 case GET_MUTE: {
261 CHECK_INTERFACE(IRadio, data, reply);
262 bool mute;
263 status_t status = getMute(&mute);
264 reply->writeInt32(status);
265 if (status == NO_ERROR) {
266 reply->writeInt32(mute ? 1 : 0);
267 }
268 return NO_ERROR;
269 }
270 case SCAN: {
271 CHECK_INTERFACE(IRadio, data, reply);
272 radio_direction_t direction = (radio_direction_t)data.readInt32();
273 bool skipSubChannel = data.readInt32() == 1;
274 status_t status = scan(direction, skipSubChannel);
275 reply->writeInt32(status);
276 return NO_ERROR;
277 }
278 case STEP: {
279 CHECK_INTERFACE(IRadio, data, reply);
280 radio_direction_t direction = (radio_direction_t)data.readInt32();
281 bool skipSubChannel = data.readInt32() == 1;
282 status_t status = step(direction, skipSubChannel);
283 reply->writeInt32(status);
284 return NO_ERROR;
285 }
286 case TUNE: {
287 CHECK_INTERFACE(IRadio, data, reply);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700288 uint32_t channel = data.readUint32();
289 uint32_t subChannel = data.readUint32();
Eric Laurentd73697b2015-03-05 15:09:23 -0800290 status_t status = tune(channel, subChannel);
291 reply->writeInt32(status);
292 return NO_ERROR;
293 }
294 case CANCEL: {
295 CHECK_INTERFACE(IRadio, data, reply);
296 status_t status = cancel();
297 reply->writeInt32(status);
298 return NO_ERROR;
299 }
300 case GET_PROGRAM_INFORMATION: {
301 CHECK_INTERFACE(IRadio, data, reply);
302 struct radio_program_info info;
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700303 status_t status;
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800304
305 status = radio_metadata_allocate(&info.metadata, 0, 0);
306 if (status != NO_ERROR) {
307 return status;
Eric Laurentd73697b2015-03-05 15:09:23 -0800308 }
309 status = getProgramInformation(&info);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700310
Eric Laurentd73697b2015-03-05 15:09:23 -0800311 reply->writeInt32(status);
312 if (status == NO_ERROR) {
313 reply->write(&info, sizeof(struct radio_program_info));
Tomasz Wasilczyk049475c2017-01-06 14:17:04 -0800314 if (radio_metadata_get_count(info.metadata) > 0) {
Eric Laurentd73697b2015-03-05 15:09:23 -0800315 size_t size = radio_metadata_get_size(info.metadata);
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700316 reply->writeUint32((uint32_t)size);
Eric Laurentd73697b2015-03-05 15:09:23 -0800317 reply->write(info.metadata, size);
318 } else {
Eric Laurentaebf5fb2016-10-25 11:08:53 -0700319 reply->writeUint32(0);
Eric Laurentd73697b2015-03-05 15:09:23 -0800320 }
321 }
322 radio_metadata_deallocate(info.metadata);
323 return NO_ERROR;
324 }
325 case HAS_CONTROL: {
326 CHECK_INTERFACE(IRadio, data, reply);
327 bool control;
328 status_t status = hasControl(&control);
329 reply->writeInt32(status);
330 if (status == NO_ERROR) {
331 reply->writeInt32(control ? 1 : 0);
332 }
333 return NO_ERROR;
334 }
335 default:
336 return BBinder::onTransact(code, data, reply, flags);
337 }
338}
339
340// ----------------------------------------------------------------------------
341
342}; // namespace android