broadcast radio: add wrapper over HAL implementation
Add radio HAL wrapper in radio service to prepare migration to HIDL.
Bug: 31973526
Change-Id: I93fc6f00a2211f7ca425be73090f12b2855c9641
diff --git a/services/radio/Android.mk b/services/radio/Android.mk
index f5d74d3..c3178ea 100644
--- a/services/radio/Android.mk
+++ b/services/radio/Android.mk
@@ -18,7 +18,8 @@
LOCAL_SRC_FILES:= \
- RadioService.cpp
+ RadioService.cpp \
+ RadioHalLegacy.cpp
LOCAL_SHARED_LIBRARIES:= \
libui \
diff --git a/services/radio/RadioHalLegacy.cpp b/services/radio/RadioHalLegacy.cpp
new file mode 100644
index 0000000..d50ccd4
--- /dev/null
+++ b/services/radio/RadioHalLegacy.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2016 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 "RadioHalLegacy"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include "RadioHalLegacy.h"
+
+namespace android {
+
+const char *RadioHalLegacy::sClassModuleNames[] = {
+ RADIO_HARDWARE_MODULE_ID_FM, /* corresponds to RADIO_CLASS_AM_FM */
+ RADIO_HARDWARE_MODULE_ID_SAT, /* corresponds to RADIO_CLASS_SAT */
+ RADIO_HARDWARE_MODULE_ID_DT, /* corresponds to RADIO_CLASS_DT */
+};
+
+/* static */
+sp<RadioInterface> RadioInterface::connectModule(radio_class_t classId)
+{
+ return new RadioHalLegacy(classId);
+}
+
+RadioHalLegacy::RadioHalLegacy(radio_class_t classId)
+ : RadioInterface(), mClassId(classId), mHwDevice(NULL)
+{
+}
+
+void RadioHalLegacy::onFirstRef()
+{
+ const hw_module_t *mod;
+ int rc;
+ ALOGI("%s mClassId %d", __FUNCTION__, mClassId);
+
+ mHwDevice = NULL;
+
+ if ((mClassId < 0) ||
+ (mClassId >= NELEM(sClassModuleNames))) {
+ ALOGE("invalid class ID %d", mClassId);
+ return;
+ }
+
+ ALOGI("%s RADIO_HARDWARE_MODULE_ID %s %s",
+ __FUNCTION__, RADIO_HARDWARE_MODULE_ID, sClassModuleNames[mClassId]);
+
+ rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, sClassModuleNames[mClassId], &mod);
+ if (rc != 0) {
+ ALOGE("couldn't load radio module %s.%s (%s)",
+ RADIO_HARDWARE_MODULE_ID, sClassModuleNames[mClassId], strerror(-rc));
+ return;
+ }
+ rc = radio_hw_device_open(mod, &mHwDevice);
+ if (rc != 0) {
+ ALOGE("couldn't open radio hw device in %s.%s (%s)",
+ RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+ mHwDevice = NULL;
+ return;
+ }
+ if (mHwDevice->common.version != RADIO_DEVICE_API_VERSION_CURRENT) {
+ ALOGE("wrong radio hw device version %04x", mHwDevice->common.version);
+ radio_hw_device_close(mHwDevice);
+ mHwDevice = NULL;
+ }
+}
+
+RadioHalLegacy::~RadioHalLegacy()
+{
+ if (mHwDevice != NULL) {
+ radio_hw_device_close(mHwDevice);
+ }
+}
+
+int RadioHalLegacy::getProperties(radio_hal_properties_t *properties)
+{
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+
+ int rc = mHwDevice->get_properties(mHwDevice, properties);
+ if (rc != 0) {
+ ALOGE("could not read implementation properties");
+ }
+
+ return rc;
+}
+
+int RadioHalLegacy::openTuner(const radio_hal_band_config_t *config,
+ bool audio,
+ sp<TunerCallbackInterface> callback,
+ sp<TunerInterface>& tuner)
+{
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+ sp<Tuner> tunerImpl = new Tuner(callback);
+
+ const struct radio_tuner *halTuner;
+ int rc = mHwDevice->open_tuner(mHwDevice, config, audio,
+ RadioHalLegacy::Tuner::callback, tunerImpl.get(),
+ &halTuner);
+ if (rc == 0) {
+ tunerImpl->setHalTuner(halTuner);
+ tuner = tunerImpl;
+ }
+ return rc;
+}
+
+int RadioHalLegacy::closeTuner(sp<TunerInterface>& tuner)
+{
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+ if (tuner == 0) {
+ return -EINVAL;
+ }
+ sp<Tuner> tunerImpl = (Tuner *)tuner.get();
+ return mHwDevice->close_tuner(mHwDevice, tunerImpl->getHalTuner());
+}
+
+int RadioHalLegacy::Tuner::setConfiguration(const radio_hal_band_config_t *config)
+{
+ if (mHalTuner == NULL) {
+ return -ENODEV;
+ }
+ return mHalTuner->set_configuration(mHalTuner, config);
+}
+
+int RadioHalLegacy::Tuner::getConfiguration(radio_hal_band_config_t *config)
+{
+ if (mHalTuner == NULL) {
+ return -ENODEV;
+ }
+ return mHalTuner->get_configuration(mHalTuner, config);
+}
+
+int RadioHalLegacy::Tuner::scan(radio_direction_t direction, bool skip_sub_channel)
+{
+ if (mHalTuner == NULL) {
+ return -ENODEV;
+ }
+ return mHalTuner->scan(mHalTuner, direction, skip_sub_channel);
+}
+
+int RadioHalLegacy::Tuner::step(radio_direction_t direction, bool skip_sub_channel)
+{
+ if (mHalTuner == NULL) {
+ return -ENODEV;
+ }
+ return mHalTuner->step(mHalTuner, direction, skip_sub_channel);
+}
+
+int RadioHalLegacy::Tuner::tune(unsigned int channel, unsigned int sub_channel)
+{
+ if (mHalTuner == NULL) {
+ return -ENODEV;
+ }
+ return mHalTuner->tune(mHalTuner, channel, sub_channel);
+}
+
+int RadioHalLegacy::Tuner::cancel()
+{
+ if (mHalTuner == NULL) {
+ return -ENODEV;
+ }
+ return mHalTuner->cancel(mHalTuner);
+}
+
+int RadioHalLegacy::Tuner::getProgramInformation(radio_program_info_t *info)
+{
+ if (mHalTuner == NULL) {
+ return -ENODEV;
+ }
+ return mHalTuner->get_program_information(mHalTuner, info);
+}
+
+void RadioHalLegacy::Tuner::onCallback(radio_hal_event_t *halEvent)
+{
+ if (mCallback != 0) {
+ mCallback->onEvent(halEvent);
+ }
+}
+
+//static
+void RadioHalLegacy::Tuner::callback(radio_hal_event_t *halEvent, void *cookie)
+{
+ wp<RadioHalLegacy::Tuner> weak = wp<RadioHalLegacy::Tuner>((RadioHalLegacy::Tuner *)cookie);
+ sp<RadioHalLegacy::Tuner> tuner = weak.promote();
+ if (tuner != 0) {
+ tuner->onCallback(halEvent);
+ }
+}
+
+RadioHalLegacy::Tuner::Tuner(sp<TunerCallbackInterface> callback)
+ : TunerInterface(), mHalTuner(NULL), mCallback(callback)
+{
+}
+
+
+RadioHalLegacy::Tuner::~Tuner()
+{
+}
+
+
+} // namespace android
diff --git a/services/radio/RadioHalLegacy.h b/services/radio/RadioHalLegacy.h
new file mode 100644
index 0000000..7d4831b
--- /dev/null
+++ b/services/radio/RadioHalLegacy.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_RADIO_HAL_LEGACY_H
+#define ANDROID_HARDWARE_RADIO_HAL_LEGACY_H
+
+#include <utils/RefBase.h>
+#include <hardware/radio.h>
+#include "RadioInterface.h"
+#include "TunerInterface.h"
+#include "TunerCallbackInterface.h"
+
+namespace android {
+
+class RadioHalLegacy : public RadioInterface
+{
+public:
+ RadioHalLegacy(radio_class_t classId);
+
+ // RadioInterface
+ virtual int getProperties(radio_hal_properties_t *properties);
+ virtual int openTuner(const radio_hal_band_config_t *config,
+ bool audio,
+ sp<TunerCallbackInterface> callback,
+ sp<TunerInterface>& tuner);
+ virtual int closeTuner(sp<TunerInterface>& tuner);
+
+ // RefBase
+ virtual void onFirstRef();
+
+ class Tuner : public TunerInterface
+ {
+ public:
+ Tuner(sp<TunerCallbackInterface> callback);
+
+ virtual int setConfiguration(const radio_hal_band_config_t *config);
+ virtual int getConfiguration(radio_hal_band_config_t *config);
+ virtual int scan(radio_direction_t direction, bool skip_sub_channel);
+ virtual int step(radio_direction_t direction, bool skip_sub_channel);
+ virtual int tune(unsigned int channel, unsigned int sub_channel);
+ virtual int cancel();
+ virtual int getProgramInformation(radio_program_info_t *info);
+
+ static void callback(radio_hal_event_t *halEvent, void *cookie);
+ void onCallback(radio_hal_event_t *halEvent);
+
+ void setHalTuner(const struct radio_tuner *halTuner) { mHalTuner = halTuner; }
+ const struct radio_tuner *getHalTuner() { return mHalTuner; }
+
+ private:
+ virtual ~Tuner();
+
+ const struct radio_tuner *mHalTuner;
+ sp<TunerCallbackInterface> mCallback;
+ };
+
+protected:
+ virtual ~RadioHalLegacy();
+
+private:
+ static const char * sClassModuleNames[];
+
+ radio_class_t mClassId;
+ struct radio_hw_device *mHwDevice;
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_RADIO_HAL_LEGACY_H
diff --git a/services/radio/RadioInterface.h b/services/radio/RadioInterface.h
new file mode 100644
index 0000000..fcfb4d5
--- /dev/null
+++ b/services/radio/RadioInterface.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_RADIO_INTERFACE_H
+#define ANDROID_HARDWARE_RADIO_INTERFACE_H
+
+#include <utils/RefBase.h>
+#include <system/radio.h>
+#include "TunerInterface.h"
+#include "TunerCallbackInterface.h"
+
+namespace android {
+
+class RadioInterface : public virtual RefBase
+{
+public:
+ /* get a sound trigger HAL instance */
+ static sp<RadioInterface> connectModule(radio_class_t classId);
+
+ /*
+ * Retrieve implementation properties.
+ *
+ * arguments:
+ * - properties: where to return the module properties
+ *
+ * returns:
+ * 0 if no error
+ * -EINVAL if invalid arguments are passed
+ */
+ virtual int getProperties(radio_hal_properties_t *properties) = 0;
+
+ /*
+ * Open a tuner interface for the requested configuration.
+ * If no other tuner is opened, this will activate the radio module.
+ *
+ * arguments:
+ * - config: the band configuration to apply
+ * - audio: this tuner will be used for live radio listening and should be connected to
+ * the radio audio source.
+ * - callback: the event callback
+ * - cookie: the cookie to pass when calling the callback
+ * - tuner: where to return the tuner interface
+ *
+ * returns:
+ * 0 if HW was powered up and configuration could be applied
+ * -EINVAL if configuration requested is invalid
+ * -ENOSYS if called out of sequence
+ *
+ * Callback function with event RADIO_EVENT_CONFIG MUST be called once the
+ * configuration is applied or a failure occurs or after a time out.
+ */
+ virtual int openTuner(const radio_hal_band_config_t *config,
+ bool audio,
+ sp<TunerCallbackInterface> callback,
+ sp<TunerInterface>& tuner) = 0;
+
+ /*
+ * Close a tuner interface.
+ * If the last tuner is closed, the radio module is deactivated.
+ *
+ * arguments:
+ * - tuner: the tuner interface to close
+ *
+ * returns:
+ * 0 if powered down successfully.
+ * -EINVAL if an invalid argument is passed
+ * -ENOSYS if called out of sequence
+ */
+ virtual int closeTuner(sp<TunerInterface>& tuner) = 0;
+
+protected:
+ RadioInterface() {}
+ virtual ~RadioInterface() {}
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_RADIO_INTERFACE_H
diff --git a/services/radio/RadioService.cpp b/services/radio/RadioService.cpp
index 5a3f750..227955d 100644
--- a/services/radio/RadioService.cpp
+++ b/services/radio/RadioService.cpp
@@ -51,31 +51,15 @@
void RadioService::onFirstRef()
{
- const hw_module_t *mod;
- int rc;
- struct radio_hw_device *dev;
-
ALOGI("%s", __FUNCTION__);
- rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, RADIO_HARDWARE_MODULE_ID_FM, &mod);
- if (rc != 0) {
- ALOGE("couldn't load radio module %s.%s (%s)",
- RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
- return;
- }
- rc = radio_hw_device_open(mod, &dev);
- if (rc != 0) {
- ALOGE("couldn't open radio hw device in %s.%s (%s)",
- RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
- return;
- }
- if (dev->common.version != RADIO_DEVICE_API_VERSION_CURRENT) {
- ALOGE("wrong radio hw device version %04x", dev->common.version);
- return;
- }
+ sp<RadioInterface> dev = RadioInterface::connectModule(RADIO_CLASS_AM_FM);
+ if (dev == 0) {
+ return;
+ }
struct radio_hal_properties halProperties;
- rc = dev->get_properties(dev, &halProperties);
+ int rc = dev->getProperties(&halProperties);
if (rc != 0) {
ALOGE("could not read implementation properties");
return;
@@ -94,9 +78,6 @@
RadioService::~RadioService()
{
- for (size_t i = 0; i < mModules.size(); i++) {
- radio_hw_device_close(mModules.valueAt(i)->hwDevice());
- }
}
status_t RadioService::listModules(struct radio_properties *properties,
@@ -108,7 +89,7 @@
if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
return BAD_VALUE;
}
- size_t maxModules = *numModules;
+ uint32_t maxModules = *numModules;
*numModules = mModules.size();
for (size_t i = 0; i < mModules.size() && i < maxModules; i++) {
properties[i] = mModules.valueAt(i)->properties();
@@ -192,16 +173,6 @@
}
-// static
-void RadioService::callback(radio_hal_event_t *halEvent, void *cookie)
-{
- CallbackThread *callbackThread = (CallbackThread *)cookie;
- if (callbackThread == NULL) {
- return;
- }
- callbackThread->sendEvent(halEvent);
-}
-
/* static */
void RadioService::convertProperties(radio_properties_t *properties,
const radio_hal_properties_t *halProperties)
@@ -385,12 +356,13 @@
#undef LOG_TAG
#define LOG_TAG "RadioService::Module"
-RadioService::Module::Module(radio_hw_device* hwDevice, radio_properties properties)
+RadioService::Module::Module(sp<RadioInterface> hwDevice, radio_properties properties)
: mHwDevice(hwDevice), mProperties(properties), mMute(true)
{
}
RadioService::Module::~Module() {
+ mHwDevice.clear();
mModuleClients.clear();
}
@@ -404,10 +376,15 @@
bool audio)
{
ALOGV("addClient() %p config %p product %s", this, config, mProperties.product);
+
AutoMutex lock(mLock);
sp<ModuleClient> moduleClient;
int ret;
+ if (mHwDevice == 0) {
+ return moduleClient;
+ }
+
for (size_t i = 0; i < mModuleClients.size(); i++) {
if (mModuleClients[i]->client() == client) {
// client already connected: reject
@@ -464,7 +441,7 @@
}
}
- const struct radio_tuner *halTuner;
+ sp<TunerInterface> halTuner;
sp<ModuleClient> preemtedClient;
if (audio) {
if (allocatedAudio >= mProperties.num_audio_sources) {
@@ -484,18 +461,19 @@
}
if (preemtedClient != 0) {
halTuner = preemtedClient->getTuner();
- preemtedClient->setTuner(NULL);
- mHwDevice->close_tuner(mHwDevice, halTuner);
+ sp<TunerInterface> clear;
+ preemtedClient->setTuner(clear);
+ mHwDevice->closeTuner(halTuner);
if (preemtedClient->audio()) {
notifyDeviceConnection(false, "");
}
}
- ret = mHwDevice->open_tuner(mHwDevice, &halConfig, audio,
- RadioService::callback, moduleClient->callbackThread().get(),
- &halTuner);
+ ret = mHwDevice->openTuner(&halConfig, audio,
+ moduleClient,
+ halTuner);
if (ret == 0) {
- ALOGV("addClient() setTuner %p", halTuner);
+ ALOGV("addClient() setTuner %p", halTuner.get());
moduleClient->setTuner(halTuner);
mModuleClients.add(moduleClient);
if (audio) {
@@ -527,12 +505,15 @@
}
mModuleClients.removeAt(index);
- const struct radio_tuner *halTuner = moduleClient->getTuner();
+ sp<TunerInterface> halTuner = moduleClient->getTuner();
if (halTuner == NULL) {
return;
}
- mHwDevice->close_tuner(mHwDevice, halTuner);
+ if (mHwDevice != 0) {
+ mHwDevice->closeTuner(halTuner);
+ }
+
if (moduleClient->audio()) {
notifyDeviceConnection(false, "");
}
@@ -543,6 +524,10 @@
return;
}
+ if (mHwDevice == 0) {
+ return;
+ }
+
// Tuner reallocation logic:
// When a client is removed and was controlling a tuner, this tuner will be allocated to a
// previously preempted client. This client will be notified by a callback with
@@ -591,9 +576,9 @@
ALOG_ASSERT(youngestClient != 0, "removeClient() removed client no candidate found for tuner");
struct radio_hal_band_config halConfig = youngestClient->halConfig();
- ret = mHwDevice->open_tuner(mHwDevice, &halConfig, youngestClient->audio(),
- RadioService::callback, moduleClient->callbackThread().get(),
- &halTuner);
+ ret = mHwDevice->openTuner(&halConfig, youngestClient->audio(),
+ moduleClient,
+ halTuner);
if (ret == 0) {
youngestClient->setTuner(halTuner);
@@ -646,7 +631,7 @@
const sp<IRadioClient>& client,
const struct radio_band_config *config,
bool audio)
- : mModule(module), mClient(client), mConfig(*config), mAudio(audio), mTuner(NULL)
+ : mModule(module), mClient(client), mConfig(*config), mAudio(audio), mTuner(0)
{
}
@@ -666,6 +651,11 @@
}
}
+void RadioService::ModuleClient::onEvent(radio_hal_event_t *halEvent)
+{
+ mCallbackThread->sendEvent(halEvent);
+}
+
status_t RadioService::ModuleClient::dump(int fd __unused,
const Vector<String16>& args __unused) {
String8 result;
@@ -696,14 +686,14 @@
return mConfig.band;
}
-const struct radio_tuner *RadioService::ModuleClient::getTuner() const
+sp<TunerInterface>& RadioService::ModuleClient::getTuner()
{
AutoMutex lock(mLock);
ALOGV("%s locked", __FUNCTION__);
return mTuner;
}
-void RadioService::ModuleClient::setTuner(const struct radio_tuner *tuner)
+void RadioService::ModuleClient::setTuner(sp<TunerInterface>& tuner)
{
ALOGV("%s %p", __FUNCTION__, this);
@@ -714,7 +704,7 @@
radio_hal_event_t event;
event.type = RADIO_EVENT_CONTROL;
event.status = 0;
- event.on = mTuner != NULL;
+ event.on = mTuner != 0;
mCallbackThread->sendEvent(&event);
ALOGV("%s DONE", __FUNCTION__);
@@ -726,10 +716,10 @@
status_t status = NO_ERROR;
ALOGV("%s locked", __FUNCTION__);
- if (mTuner != NULL) {
+ if (mTuner != 0) {
struct radio_hal_band_config halConfig;
halConfig = config->band;
- status = (status_t)mTuner->set_configuration(mTuner, &halConfig);
+ status = (status_t)mTuner->setConfiguration(&halConfig);
if (status == NO_ERROR) {
mConfig = *config;
}
@@ -747,9 +737,9 @@
status_t status = NO_ERROR;
ALOGV("%s locked", __FUNCTION__);
- if (mTuner != NULL) {
+ if (mTuner != 0) {
struct radio_hal_band_config halConfig;
- status = (status_t)mTuner->get_configuration(mTuner, &halConfig);
+ status = (status_t)mTuner->getConfiguration(&halConfig);
if (status == NO_ERROR) {
mConfig.band = halConfig;
}
@@ -765,7 +755,7 @@
{
Mutex::Autolock _l(mLock);
ALOGV("%s locked", __FUNCTION__);
- if (mTuner == NULL || !mAudio) {
+ if (mTuner == 0 || !mAudio) {
return INVALID_OPERATION;
}
module = mModule.promote();
@@ -796,8 +786,8 @@
AutoMutex lock(mLock);
ALOGV("%s locked", __FUNCTION__);
status_t status;
- if (mTuner != NULL) {
- status = (status_t)mTuner->scan(mTuner, direction, skipSubChannel);
+ if (mTuner != 0) {
+ status = (status_t)mTuner->scan(direction, skipSubChannel);
} else {
status = INVALID_OPERATION;
}
@@ -809,21 +799,21 @@
AutoMutex lock(mLock);
ALOGV("%s locked", __FUNCTION__);
status_t status;
- if (mTuner != NULL) {
- status = (status_t)mTuner->step(mTuner, direction, skipSubChannel);
+ if (mTuner != 0) {
+ status = (status_t)mTuner->step(direction, skipSubChannel);
} else {
status = INVALID_OPERATION;
}
return status;
}
-status_t RadioService::ModuleClient::tune(unsigned int channel, unsigned int subChannel)
+status_t RadioService::ModuleClient::tune(uint32_t channel, uint32_t subChannel)
{
AutoMutex lock(mLock);
ALOGV("%s locked", __FUNCTION__);
status_t status;
- if (mTuner != NULL) {
- status = (status_t)mTuner->tune(mTuner, channel, subChannel);
+ if (mTuner != 0) {
+ status = (status_t)mTuner->tune(channel, subChannel);
} else {
status = INVALID_OPERATION;
}
@@ -835,8 +825,8 @@
AutoMutex lock(mLock);
ALOGV("%s locked", __FUNCTION__);
status_t status;
- if (mTuner != NULL) {
- status = (status_t)mTuner->cancel(mTuner);
+ if (mTuner != 0) {
+ status = (status_t)mTuner->cancel();
} else {
status = INVALID_OPERATION;
}
@@ -849,7 +839,7 @@
ALOGV("%s locked", __FUNCTION__);
status_t status;
if (mTuner != NULL) {
- status = (status_t)mTuner->get_program_information(mTuner, info);
+ status = (status_t)mTuner->getProgramInformation(info);
} else {
status = INVALID_OPERATION;
}
@@ -860,7 +850,7 @@
{
Mutex::Autolock lock(mLock);
ALOGV("%s locked", __FUNCTION__);
- *hasControl = mTuner != NULL;
+ *hasControl = mTuner != 0;
return NO_ERROR;
}
diff --git a/services/radio/RadioService.h b/services/radio/RadioService.h
index ac3481e..444eb7a 100644
--- a/services/radio/RadioService.h
+++ b/services/radio/RadioService.h
@@ -27,6 +27,9 @@
#include <radio/IRadioClient.h>
#include <system/radio.h>
#include <hardware/radio.h>
+#include "RadioInterface.h"
+#include "TunerInterface.h"
+#include "TunerCallbackInterface.h"
namespace android {
@@ -66,7 +69,7 @@
class Module : public virtual RefBase {
public:
- Module(radio_hw_device* hwDevice,
+ Module(sp<RadioInterface> hwDevice,
struct radio_properties properties);
virtual ~Module();
@@ -83,7 +86,7 @@
virtual status_t dump(int fd, const Vector<String16>& args);
- const struct radio_hw_device *hwDevice() const { return mHwDevice; }
+ sp<RadioInterface> hwDevice() const { return mHwDevice; }
const struct radio_properties properties() const { return mProperties; }
const struct radio_band_config *getDefaultConfig() const ;
@@ -92,7 +95,7 @@
void notifyDeviceConnection(bool connected, const char *address);
Mutex mLock; // protects mModuleClients
- const struct radio_hw_device *mHwDevice; // HAL hardware device
+ sp<RadioInterface> mHwDevice; // HAL hardware device
const struct radio_properties mProperties; // cached hardware module properties
Vector< sp<ModuleClient> > mModuleClients; // list of attached clients
bool mMute; // radio audio source state
@@ -128,7 +131,8 @@
}; // class CallbackThread
class ModuleClient : public BnRadio,
- public IBinder::DeathRecipient {
+ public IBinder::DeathRecipient,
+ public TunerCallbackInterface {
public:
ModuleClient(const sp<Module>& module,
@@ -167,8 +171,8 @@
wp<Module> module() const { return mModule; }
radio_hal_band_config_t halConfig() const;
sp<CallbackThread> callbackThread() const { return mCallbackThread; }
- void setTuner(const struct radio_tuner *tuner);
- const struct radio_tuner *getTuner() const;
+ void setTuner(sp<TunerInterface>& tuner);
+ sp<TunerInterface>& getTuner();
bool audio() const { return mAudio; }
void onCallbackEvent(const sp<IMemory>& event);
@@ -179,6 +183,9 @@
// IBinder::DeathRecipient implementation
virtual void binderDied(const wp<IBinder> &who);
+ // TunerCallbackInterface
+ virtual void onEvent(radio_hal_event_t *event);
+
private:
mutable Mutex mLock; // protects mClient, mConfig and mTuner
@@ -187,7 +194,7 @@
radio_band_config_t mConfig; // current band configuration
sp<CallbackThread> mCallbackThread; // event callback thread
const bool mAudio;
- const struct radio_tuner *mTuner; // HAL tuner interface. NULL indicates that
+ sp<TunerInterface> mTuner; // HAL tuner interface. NULL indicates that
// this client does not have control on any
// tuner
}; // class ModuleClient
diff --git a/services/radio/TunerCallbackInterface.h b/services/radio/TunerCallbackInterface.h
new file mode 100644
index 0000000..4973cce
--- /dev/null
+++ b/services/radio/TunerCallbackInterface.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TUNER_CALLBACK_INTERFACE_H
+#define ANDROID_HARDWARE_TUNER_CALLBACK_INTERFACE_H
+
+#include <utils/RefBase.h>
+#include <system/radio.h>
+
+namespace android {
+
+class TunerCallbackInterface : public virtual RefBase
+{
+public:
+ virtual void onEvent(radio_hal_event_t *event) = 0;
+
+protected:
+ TunerCallbackInterface() {}
+ virtual ~TunerCallbackInterface() {}
+
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TUNER_CALLBACK_INTERFACE_H
diff --git a/services/radio/TunerInterface.h b/services/radio/TunerInterface.h
new file mode 100644
index 0000000..4e657d3
--- /dev/null
+++ b/services/radio/TunerInterface.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TUNER_INTERFACE_H
+#define ANDROID_HARDWARE_TUNER_INTERFACE_H
+
+#include <utils/RefBase.h>
+#include <system/radio.h>
+
+namespace android {
+
+class TunerInterface : public virtual RefBase
+{
+public:
+ /*
+ * Apply current radio band configuration (band, range, channel spacing ...).
+ *
+ * arguments:
+ * - config: the band configuration to apply
+ *
+ * returns:
+ * 0 if configuration could be applied
+ * -EINVAL if configuration requested is invalid
+ *
+ * Automatically cancels pending scan, step or tune.
+ *
+ * Callback function with event RADIO_EVENT_CONFIG MUST be called once the
+ * configuration is applied or a failure occurs or after a time out.
+ */
+ virtual int setConfiguration(const radio_hal_band_config_t *config) = 0;
+
+ /*
+ * Retrieve current radio band configuration.
+ *
+ * arguments:
+ * - config: where to return the band configuration
+ *
+ * returns:
+ * 0 if valid configuration is returned
+ * -EINVAL if invalid arguments are passed
+ */
+ virtual int getConfiguration(radio_hal_band_config_t *config) = 0;
+
+ /*
+ * Start scanning up to next valid station.
+ * Must be called when a valid configuration has been applied.
+ *
+ * arguments:
+ * - direction: RADIO_DIRECTION_UP or RADIO_DIRECTION_DOWN
+ * - skip_sub_channel: valid for HD radio or digital radios only: ignore sub channels
+ * (e.g SPS for HD radio).
+ *
+ * returns:
+ * 0 if scan successfully started
+ * -ENOSYS if called out of sequence
+ * -ENODEV if another error occurs
+ *
+ * Automatically cancels pending scan, step or tune.
+ *
+ * Callback function with event RADIO_EVENT_TUNED MUST be called once
+ * locked on a station or after a time out or full frequency scan if
+ * no station found. The event status should indicate if a valid station
+ * is tuned or not.
+ */
+ virtual int scan(radio_direction_t direction, bool skip_sub_channel) = 0;
+
+ /*
+ * Move one channel spacing up or down.
+ * Must be called when a valid configuration has been applied.
+ *
+ * arguments:
+ * - direction: RADIO_DIRECTION_UP or RADIO_DIRECTION_DOWN
+ * - skip_sub_channel: valid for HD radio or digital radios only: ignore sub channels
+ * (e.g SPS for HD radio).
+ *
+ * returns:
+ * 0 if step successfully started
+ * -ENOSYS if called out of sequence
+ * -ENODEV if another error occurs
+ *
+ * Automatically cancels pending scan, step or tune.
+ *
+ * Callback function with event RADIO_EVENT_TUNED MUST be called once
+ * step completed or after a time out. The event status should indicate
+ * if a valid station is tuned or not.
+ */
+ virtual int step(radio_direction_t direction, bool skip_sub_channel) = 0;
+
+ /*
+ * Tune to specified frequency.
+ * Must be called when a valid configuration has been applied.
+ *
+ * arguments:
+ * - channel: channel to tune to. A frequency in kHz for AM/FM/HD Radio bands.
+ * - sub_channel: valid for HD radio or digital radios only: (e.g SPS number for HD radio).
+ *
+ * returns:
+ * 0 if tune successfully started
+ * -ENOSYS if called out of sequence
+ * -EINVAL if invalid arguments are passed
+ * -ENODEV if another error occurs
+ *
+ * Automatically cancels pending scan, step or tune.
+ *
+ * Callback function with event RADIO_EVENT_TUNED MUST be called once
+ * tuned or after a time out. The event status should indicate
+ * if a valid station is tuned or not.
+ */
+ virtual int tune(unsigned int channel, unsigned int sub_channel) = 0;
+
+ /*
+ * Cancel a scan, step or tune operation.
+ * Must be called while a scan, step or tune operation is pending
+ * (callback not yet sent).
+ *
+ * returns:
+ * 0 if successful
+ * -ENOSYS if called out of sequence
+ * -ENODEV if another error occurs
+ *
+ * The callback is not sent.
+ */
+ virtual int cancel() = 0;
+
+ /*
+ * Retrieve current station information.
+ *
+ * arguments:
+ * - info: where to return the program info.
+ * If info->metadata is NULL. no meta data should be returned.
+ * If meta data must be returned, they should be added to or cloned to
+ * info->metadata, not passed from a newly created meta data buffer.
+ *
+ * returns:
+ * 0 if tuned and information available
+ * -EINVAL if invalid arguments are passed
+ * -ENODEV if another error occurs
+ */
+ virtual int getProgramInformation(radio_program_info_t *info) = 0;
+
+protected:
+ TunerInterface() {}
+ virtual ~TunerInterface() {}
+
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TUNER_INTERFACE_H