summaryrefslogtreecommitdiffstats
path: root/radio/Radio.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'radio/Radio.cpp')
-rw-r--r--radio/Radio.cpp283
1 files changed, 283 insertions, 0 deletions
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 <utils/Log.h>
+#include <utils/threads.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IMemory.h>
+
+#include <radio/Radio.h>
+#include <radio/IRadio.h>
+#include <radio/IRadioService.h>
+#include <radio/IRadioClient.h>
+#include <radio/RadioCallback.h>
+
+namespace android {
+
+namespace {
+ sp<IRadioService> 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<IBinder>& who __unused) {
+ ALOGV("binderDied");
+ Mutex::Autolock _l(gLock);
+ gRadioService.clear();
+ ALOGW("Radio service died!");
+ }
+ };
+
+ sp<DeathNotifier> gDeathNotifier;
+}; // namespace anonymous
+
+const sp<IRadioService>& Radio::getRadioService()
+{
+ Mutex::Autolock _l(gLock);
+ if (gRadioService.get() == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> 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<IRadioService>(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<IRadioService>& service = getRadioService();
+ if (service == 0) {
+ return NO_INIT;
+ }
+ return service->listModules(properties, numModules);
+}
+
+sp<Radio> Radio::attach(radio_handle_t handle,
+ const struct radio_band_config *config,
+ bool withAudio,
+ const sp<RadioCallback>& callback)
+{
+ ALOGV("attach()");
+ sp<Radio> radio;
+ const sp<IRadioService>& 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<RadioCallback>& 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<IMemory>& 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<IBinder>& 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