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: 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 224 IMPLEMENT_META_INTERFACE(Radio, "android.hardware.IRadio"); 225 226 // ---------------------------------------------------------------------- 227 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