From dedc86dcb6d63e93518c8974c077e50912d15e9c Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 5 Mar 2015 15:10:52 -0800 Subject: radio client Added implementation of native broadcast radio client class and callback. Change-Id: I82478448e32a5b9be5165e7eb53b99b6289884ed --- radio/Android.mk | 1 + radio/Radio.cpp | 283 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 284 insertions(+) create mode 100644 radio/Radio.cpp (limited to 'radio') diff --git a/radio/Android.mk b/radio/Android.mk index bddc3c2..ecbb8fd 100644 --- a/radio/Android.mk +++ b/radio/Android.mk @@ -17,6 +17,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + Radio.cpp \ IRadio.cpp \ IRadioClient.cpp \ IRadioService.cpp diff --git a/radio/Radio.cpp b/radio/Radio.cpp new file mode 100644 index 0000000..e3554c2 --- /dev/null +++ b/radio/Radio.cpp @@ -0,0 +1,283 @@ +/* +** +** Copyright (C) 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 "Radio" +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace android { + +namespace { + sp gRadioService; + const int kRadioServicePollDelay = 500000; // 0.5s + const char* kRadioServiceName = "media.radio"; + Mutex gLock; + + class DeathNotifier : public IBinder::DeathRecipient + { + public: + DeathNotifier() { + } + + virtual void binderDied(const wp& who __unused) { + ALOGV("binderDied"); + Mutex::Autolock _l(gLock); + gRadioService.clear(); + ALOGW("Radio service died!"); + } + }; + + sp gDeathNotifier; +}; // namespace anonymous + +const sp& Radio::getRadioService() +{ + Mutex::Autolock _l(gLock); + if (gRadioService.get() == 0) { + sp sm = defaultServiceManager(); + sp binder; + do { + binder = sm->getService(String16(kRadioServiceName)); + if (binder != 0) { + break; + } + ALOGW("RadioService not published, waiting..."); + usleep(kRadioServicePollDelay); + } while(true); + if (gDeathNotifier == NULL) { + gDeathNotifier = new DeathNotifier(); + } + binder->linkToDeath(gDeathNotifier); + gRadioService = interface_cast(binder); + } + ALOGE_IF(gRadioService == 0, "no RadioService!?"); + return gRadioService; +} + +// Static methods +status_t Radio::listModules(struct radio_properties *properties, + uint32_t *numModules) +{ + ALOGV("listModules()"); + const sp& service = getRadioService(); + if (service == 0) { + return NO_INIT; + } + return service->listModules(properties, numModules); +} + +sp Radio::attach(radio_handle_t handle, + const struct radio_band_config *config, + bool withAudio, + const sp& callback) +{ + ALOGV("attach()"); + sp radio; + const sp& service = getRadioService(); + if (service == 0) { + return radio; + } + radio = new Radio(handle, callback); + status_t status = service->attach(handle, radio, config, withAudio, radio->mIRadio); + + if (status == NO_ERROR && radio->mIRadio != 0) { + IInterface::asBinder(radio->mIRadio)->linkToDeath(radio); + } else { + ALOGW("Error %d connecting to radio service", status); + radio.clear(); + } + return radio; +} + + + +// Radio +Radio::Radio(radio_handle_t handle, const sp& callback) + : mHandle(handle), mCallback(callback) +{ +} + +Radio::~Radio() +{ + if (mIRadio != 0) { + mIRadio->detach(); + } +} + + +void Radio::detach() { + ALOGV("detach()"); + Mutex::Autolock _l(mLock); + mCallback.clear(); + if (mIRadio != 0) { + mIRadio->detach(); + IInterface::asBinder(mIRadio)->unlinkToDeath(this); + mIRadio = 0; + } +} + +status_t Radio::setConfiguration(const struct radio_band_config *config) +{ + Mutex::Autolock _l(mLock); + if (mIRadio == 0) { + return NO_INIT; + } + return mIRadio->setConfiguration(config); +} + +status_t Radio::getConfiguration(struct radio_band_config *config) +{ + Mutex::Autolock _l(mLock); + if (mIRadio == 0) { + return NO_INIT; + } + return mIRadio->getConfiguration(config); +} + +status_t Radio::setMute(bool mute) +{ + Mutex::Autolock _l(mLock); + if (mIRadio == 0) { + return NO_INIT; + } + return mIRadio->setMute(mute); +} + +status_t Radio::getMute(bool *mute) +{ + Mutex::Autolock _l(mLock); + if (mIRadio == 0) { + return NO_INIT; + } + return mIRadio->getMute(mute); +} + +status_t Radio::scan(radio_direction_t direction, bool skipSubchannel) +{ + Mutex::Autolock _l(mLock); + if (mIRadio == 0) { + return NO_INIT; + } + return mIRadio->scan(direction, skipSubchannel); +} + +status_t Radio::step(radio_direction_t direction, bool skipSubchannel) +{ + Mutex::Autolock _l(mLock); + if (mIRadio == 0) { + return NO_INIT; + } + return mIRadio->step(direction, skipSubchannel); +} + +status_t Radio::tune(unsigned int channel, unsigned int subChannel) +{ + Mutex::Autolock _l(mLock); + if (mIRadio == 0) { + return NO_INIT; + } + return mIRadio->tune(channel, subChannel); +} + +status_t Radio::cancel() +{ + Mutex::Autolock _l(mLock); + if (mIRadio == 0) { + return NO_INIT; + } + return mIRadio->cancel(); +} + +status_t Radio::getProgramInformation(struct radio_program_info *info) +{ + Mutex::Autolock _l(mLock); + if (mIRadio == 0) { + return NO_INIT; + } + return mIRadio->getProgramInformation(info); +} + +status_t Radio::hasControl(bool *hasControl) +{ + Mutex::Autolock _l(mLock); + if (mIRadio == 0) { + return NO_INIT; + } + return mIRadio->hasControl(hasControl); +} + + +// BpRadioClient +void Radio::onEvent(const sp& eventMemory) +{ + Mutex::Autolock _l(mLock); + if (eventMemory == 0 || eventMemory->pointer() == NULL) { + return; + } + + struct radio_event *event = (struct radio_event *)eventMemory->pointer(); + // restore local metadata pointer from offset + switch (event->type) { + case RADIO_EVENT_TUNED: + case RADIO_EVENT_AF_SWITCH: + if (event->info.metadata != NULL) { + event->info.metadata = + (radio_metadata_t *)((char *)event + (size_t)event->info.metadata); + } + break; + case RADIO_EVENT_METADATA: + if (event->metadata != NULL) { + event->metadata = + (radio_metadata_t *)((char *)event + (size_t)event->metadata); + } + break; + default: + break; + } + + if (mCallback != 0) { + mCallback->onEvent(event); + } +} + + +//IBinder::DeathRecipient +void Radio::binderDied(const wp& who __unused) { + Mutex::Autolock _l(mLock); + ALOGW("Radio server binder Died "); + mIRadio = 0; + struct radio_event event; + memset(&event, 0, sizeof(struct radio_event)); + event.type = RADIO_EVENT_SERVER_DIED; + event.status = DEAD_OBJECT; + if (mCallback != 0) { + mCallback->onEvent(&event); + } +} + +}; // namespace android -- cgit v1.1