/* ** ** Copyright 2015, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #define LOG_TAG "IRadio" //#define LOG_NDEBUG 0 #include <utils/Log.h> #include <utils/Errors.h> #include <binder/IMemory.h> #include <radio/IRadio.h> #include <radio/IRadioService.h> #include <radio/IRadioClient.h> #include <system/radio.h> #include <system/RadioMetadataWrapper.h> namespace android { enum { DETACH = IBinder::FIRST_CALL_TRANSACTION, SET_CONFIGURATION, GET_CONFIGURATION, SET_MUTE, GET_MUTE, SCAN, STEP, TUNE, CANCEL, GET_PROGRAM_INFORMATION, HAS_CONTROL }; class BpRadio: public BpInterface<IRadio> { public: explicit BpRadio(const sp<IBinder>& impl) : BpInterface<IRadio>(impl) { } void detach() { ALOGV("detach"); Parcel data, reply; data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); remote()->transact(DETACH, data, &reply); } virtual status_t setConfiguration(const struct radio_band_config *config) { Parcel data, reply; if (config == NULL) { return BAD_VALUE; } data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); data.write(config, sizeof(struct radio_band_config)); status_t status = remote()->transact(SET_CONFIGURATION, data, &reply); if (status == NO_ERROR) { status = (status_t)reply.readInt32(); } return status; } virtual status_t getConfiguration(struct radio_band_config *config) { Parcel data, reply; if (config == NULL) { return BAD_VALUE; } data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); status_t status = remote()->transact(GET_CONFIGURATION, data, &reply); if (status == NO_ERROR) { status = (status_t)reply.readInt32(); if (status == NO_ERROR) { reply.read(config, sizeof(struct radio_band_config)); } } return status; } virtual status_t setMute(bool mute) { Parcel data, reply; data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); data.writeInt32(mute ? 1 : 0); status_t status = remote()->transact(SET_MUTE, data, &reply); if (status == NO_ERROR) { status = (status_t)reply.readInt32(); } return status; } virtual status_t getMute(bool *mute) { Parcel data, reply; if (mute == NULL) { return BAD_VALUE; } data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); status_t status = remote()->transact(GET_MUTE, data, &reply); if (status == NO_ERROR) { status = (status_t)reply.readInt32(); if (status == NO_ERROR) { int32_t muteread = reply.readInt32(); *mute = muteread != 0; } } return status; } virtual status_t scan(radio_direction_t direction, bool skipSubChannel) { Parcel data, reply; data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); data.writeInt32(direction); data.writeInt32(skipSubChannel ? 1 : 0); status_t status = remote()->transact(SCAN, data, &reply); if (status == NO_ERROR) { status = (status_t)reply.readInt32(); } return status; } virtual status_t step(radio_direction_t direction, bool skipSubChannel) { Parcel data, reply; data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); data.writeInt32(direction); data.writeInt32(skipSubChannel ? 1 : 0); status_t status = remote()->transact(STEP, data, &reply); if (status == NO_ERROR) { status = (status_t)reply.readInt32(); } return status; } virtual status_t tune(uint32_t channel, uint32_t subChannel) { Parcel data, reply; data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); data.writeUint32(channel); data.writeUint32(subChannel); status_t status = remote()->transact(TUNE, data, &reply); if (status == NO_ERROR) { status = (status_t)reply.readInt32(); } return status; } virtual status_t cancel() { Parcel data, reply; data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); status_t status = remote()->transact(CANCEL, data, &reply); if (status == NO_ERROR) { status = (status_t)reply.readInt32(); } return status; } virtual status_t getProgramInformation(struct radio_program_info *info) { Parcel data, reply; if (info == nullptr || info->metadata == nullptr) { return BAD_VALUE; } radio_metadata_t *metadata = info->metadata; data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); status_t status = remote()->transact(GET_PROGRAM_INFORMATION, data, &reply); if (status == NO_ERROR) { status = (status_t)reply.readInt32(); if (status == NO_ERROR) { reply.read(info, sizeof(struct radio_program_info)); // restore local metadata pointer info->metadata = metadata; uint32_t metadataSize = reply.readUint32(); if (metadataSize != 0) { radio_metadata_t *newMetadata = (radio_metadata_t *)malloc(metadataSize); if (newMetadata == NULL) { return NO_MEMORY; } reply.read(newMetadata, metadataSize); status = radio_metadata_add_metadata(&info->metadata, newMetadata); free(newMetadata); } } } return status; } virtual status_t hasControl(bool *hasControl) { Parcel data, reply; if (hasControl == NULL) { return BAD_VALUE; } data.writeInterfaceToken(IRadio::getInterfaceDescriptor()); status_t status = remote()->transact(HAS_CONTROL, data, &reply); if (status == NO_ERROR) { status = (status_t)reply.readInt32(); if (status == NO_ERROR) { *hasControl = reply.readInt32() != 0; } } return status; } }; IMPLEMENT_META_INTERFACE(Radio, "android.hardware.IRadio"); // ---------------------------------------------------------------------- status_t BnRadio::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case DETACH: { ALOGV("DETACH"); CHECK_INTERFACE(IRadio, data, reply); detach(); return NO_ERROR; } break; case SET_CONFIGURATION: { CHECK_INTERFACE(IRadio, data, reply); struct radio_band_config config; data.read(&config, sizeof(struct radio_band_config)); status_t status = setConfiguration(&config); reply->writeInt32(status); return NO_ERROR; } case GET_CONFIGURATION: { CHECK_INTERFACE(IRadio, data, reply); struct radio_band_config config; status_t status = getConfiguration(&config); reply->writeInt32(status); if (status == NO_ERROR) { reply->write(&config, sizeof(struct radio_band_config)); } return NO_ERROR; } case SET_MUTE: { CHECK_INTERFACE(IRadio, data, reply); bool mute = data.readInt32() != 0; status_t status = setMute(mute); reply->writeInt32(status); return NO_ERROR; } case GET_MUTE: { CHECK_INTERFACE(IRadio, data, reply); bool mute; status_t status = getMute(&mute); reply->writeInt32(status); if (status == NO_ERROR) { reply->writeInt32(mute ? 1 : 0); } return NO_ERROR; } case SCAN: { CHECK_INTERFACE(IRadio, data, reply); radio_direction_t direction = (radio_direction_t)data.readInt32(); bool skipSubChannel = data.readInt32() == 1; status_t status = scan(direction, skipSubChannel); reply->writeInt32(status); return NO_ERROR; } case STEP: { CHECK_INTERFACE(IRadio, data, reply); radio_direction_t direction = (radio_direction_t)data.readInt32(); bool skipSubChannel = data.readInt32() == 1; status_t status = step(direction, skipSubChannel); reply->writeInt32(status); return NO_ERROR; } case TUNE: { CHECK_INTERFACE(IRadio, data, reply); uint32_t channel = data.readUint32(); uint32_t subChannel = data.readUint32(); status_t status = tune(channel, subChannel); reply->writeInt32(status); return NO_ERROR; } case CANCEL: { CHECK_INTERFACE(IRadio, data, reply); status_t status = cancel(); reply->writeInt32(status); return NO_ERROR; } case GET_PROGRAM_INFORMATION: { CHECK_INTERFACE(IRadio, data, reply); struct radio_program_info info; RadioMetadataWrapper metadataWrapper(&info.metadata); status_t status = getProgramInformation(&info); reply->writeInt32(status); if (status == NO_ERROR) { reply->write(&info, sizeof(struct radio_program_info)); if (radio_metadata_get_count(info.metadata) > 0) { size_t size = radio_metadata_get_size(info.metadata); reply->writeUint32((uint32_t)size); reply->write(info.metadata, size); } else { reply->writeUint32(0); } } return NO_ERROR; } case HAS_CONTROL: { CHECK_INTERFACE(IRadio, data, reply); bool control; status_t status = hasControl(&control); reply->writeInt32(status); if (status == NO_ERROR) { reply->writeInt32(control ? 1 : 0); } return NO_ERROR; } default: return BBinder::onTransact(code, data, reply, flags); } } // ---------------------------------------------------------------------------- }; // namespace android