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//#define LOG_NDEBUG 0 20#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> 27#include <system/RadioMetadataWrapper.h> 28 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: 48 explicit BpRadio(const sp<IBinder>& impl) 49 : 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) { 116 int32_t muteread = reply.readInt32(); 117 *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 149 virtual status_t tune(uint32_t channel, uint32_t subChannel) 150 { 151 Parcel data, reply; 152 data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); 153 data.writeUint32(channel); 154 data.writeUint32(subChannel); 155 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; 176 if (info == nullptr || info->metadata == nullptr) { 177 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)); 186 // restore local metadata pointer 187 info->metadata = metadata; 188 189 uint32_t metadataSize = reply.readUint32(); 190 if (metadataSize != 0) { 191 radio_metadata_t *newMetadata = (radio_metadata_t *)malloc(metadataSize); 192 if (newMetadata == NULL) { 193 return NO_MEMORY; 194 } 195 reply.read(newMetadata, metadataSize); 196 status = radio_metadata_add_metadata(&info->metadata, newMetadata); 197 free(newMetadata); 198 } 199 } 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); 289 uint32_t channel = data.readUint32(); 290 uint32_t subChannel = data.readUint32(); 291 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; 304 RadioMetadataWrapper metadataWrapper(&info.metadata); 305 306 status_t status = getProgramInformation(&info); 307 reply->writeInt32(status); 308 if (status == NO_ERROR) { 309 reply->write(&info, sizeof(struct radio_program_info)); 310 if (radio_metadata_get_count(info.metadata) > 0) { 311 size_t size = radio_metadata_get_size(info.metadata); 312 reply->writeUint32((uint32_t)size); 313 reply->write(info.metadata, size); 314 } else { 315 reply->writeUint32(0); 316 } 317 } 318 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 338