Initial Broadcast Radio HAL 1.1 default implementation.

The new implementation does not rely on legacy HAL, it implements
HAL 1.1 directly instead.

This is not a full implementation yet, but passes all existing tests.

Bug: b/36864090
Test: VTS, instrumentalization, Unit
Change-Id: Ic8eddd19d0bf6777b4086d099183d71e05d7da0e
diff --git a/broadcastradio/1.1/default/BroadcastRadio.cpp b/broadcastradio/1.1/default/BroadcastRadio.cpp
index d65fe6d..3aac127 100644
--- a/broadcastradio/1.1/default/BroadcastRadio.cpp
+++ b/broadcastradio/1.1/default/BroadcastRadio.cpp
@@ -13,14 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "BroadcastRadio"
-//#define LOG_NDEBUG 0
-
-#include <log/log.h>
+#define LOG_TAG "BroadcastRadioDefault.module"
+#define LOG_NDEBUG 0
 
 #include "BroadcastRadio.h"
-#include "Tuner.h"
-#include "Utils.h"
+
+#include <log/log.h>
 
 namespace android {
 namespace hardware {
@@ -28,125 +26,126 @@
 namespace V1_1 {
 namespace implementation {
 
-using ::android::sp;
+using V1_0::Band;
+using V1_0::BandConfig;
+using V1_0::Class;
+using V1_0::Deemphasis;
+using V1_0::Rds;
+
+using std::lock_guard;
+using std::map;
+using std::mutex;
+using std::vector;
+
+// clang-format off
+static const map<Class, ModuleConfig> gModuleConfigs{
+    {Class::AM_FM, ModuleConfig({
+        "Digital radio mock",
+        {  // amFmBands
+            AmFmBandConfig({
+                Band::AM_HD,
+                540,   // lowerLimit
+                1610,  // upperLimit
+                10,    // spacing
+            }),
+            AmFmBandConfig({
+                Band::FM_HD,
+                87900,   // lowerLimit
+                107900,  // upperLimit
+                200,     // spacing
+            }),
+        },
+    })},
+
+    {Class::SAT, ModuleConfig({
+        "Satellite radio mock",
+        {},  // amFmBands
+    })},
+};
+// clang-format on
 
 BroadcastRadio::BroadcastRadio(Class classId)
-        : mStatus(Result::NOT_INITIALIZED), mClassId(classId), mHwDevice(NULL)
-{
+    : mClassId(classId), mConfig(gModuleConfigs.at(classId)) {}
+
+bool BroadcastRadio::isSupported(Class classId) {
+    return gModuleConfigs.find(classId) != gModuleConfigs.end();
 }
 
-BroadcastRadio::~BroadcastRadio()
-{
-    if (mHwDevice != NULL) {
-        radio_hw_device_close(mHwDevice);
-    }
-}
-
-void BroadcastRadio::onFirstRef()
-{
-    const hw_module_t *mod;
-    int rc;
-    ALOGI("%s mClassId %d", __FUNCTION__, mClassId);
-
-    mHwDevice = NULL;
-    const char *classString = Utils::getClassString(mClassId);
-    if (classString == NULL) {
-        ALOGE("invalid class ID %d", mClassId);
-        mStatus = Result::INVALID_ARGUMENTS;
-        return;
-    }
-
-    ALOGI("%s RADIO_HARDWARE_MODULE_ID %s %s",
-            __FUNCTION__, RADIO_HARDWARE_MODULE_ID, classString);
-
-    rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, classString, &mod);
-    if (rc != 0) {
-        ALOGE("couldn't load radio module %s.%s (%s)",
-                RADIO_HARDWARE_MODULE_ID, classString, 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;
-    } else {
-        mStatus = Result::OK;
-    }
-}
-
-int BroadcastRadio::closeHalTuner(const struct radio_tuner *halTuner)
-{
-    ALOGV("%s", __FUNCTION__);
-    if (mHwDevice == NULL) {
-        return -ENODEV;
-    }
-    if (halTuner == 0) {
-        return -EINVAL;
-    }
-    return mHwDevice->close_tuner(mHwDevice, halTuner);
-}
-
-
-// Methods from ::android::hardware::broadcastradio::V1_1::IBroadcastRadio follow.
-Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb)
-{
-    int rc;
-    radio_hal_properties_t halProperties;
-    Properties properties;
-
-    if (mHwDevice == NULL) {
-        rc = -ENODEV;
-        goto exit;
-    }
-    rc = mHwDevice->get_properties(mHwDevice, &halProperties);
-    if (rc == 0) {
-        Utils::convertPropertiesFromHal(&properties, &halProperties);
-    }
-
-exit:
-    _hidl_cb(Utils::convertHalResult(rc), properties);
-    return Void();
+Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+    return getProperties_1_1(
+        [&](const Properties& properties) { _hidl_cb(Result::OK, properties.base); });
 }
 
 Return<void> BroadcastRadio::getProperties_1_1(getProperties_1_1_cb _hidl_cb) {
-    radio_hal_properties_t halProperties;
-    V1_1::Properties properties = {};
+    ALOGV("%s", __func__);
+    Properties prop11 = {};
+    auto& prop10 = prop11.base;
 
-    LOG_ALWAYS_FATAL_IF(mHwDevice == nullptr, "HW device is not set");
-    int rc = mHwDevice->get_properties(mHwDevice, &halProperties);
-    LOG_ALWAYS_FATAL_IF(rc != 0, "Couldn't get device properties");
-    Utils::convertPropertiesFromHal(&properties.base, &halProperties);
+    prop10.classId = mClassId;
+    prop10.implementor = "Google";
+    prop10.product = mConfig.productName;
+    prop10.numTuners = 1;
+    prop10.numAudioSources = 1;
+    prop10.supportsCapture = false;
+    prop11.supportsBackgroundScanning = false;
+    prop11.vendorExension = "dummy";
 
-    _hidl_cb(properties);
-    return Void();
-}
+    prop10.bands.resize(mConfig.amFmBands.size());
+    for (size_t i = 0; i < mConfig.amFmBands.size(); i++) {
+        auto& src = mConfig.amFmBands[i];
+        auto& dst = prop10.bands[i];
 
-Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio,
-    const sp<V1_0::ITunerCallback>& callback, openTuner_cb _hidl_cb)
-{
-    sp<Tuner> tunerImpl = new Tuner(callback, this);
+        dst.type = src.type;
+        dst.antennaConnected = true;
+        dst.lowerLimit = src.lowerLimit;
+        dst.upperLimit = src.upperLimit;
+        dst.spacings = vector<uint32_t>({src.spacing});
 
-    radio_hal_band_config_t halConfig;
-    const struct radio_tuner *halTuner;
-    Utils::convertBandConfigToHal(&halConfig, &config);
-    int rc = mHwDevice->open_tuner(mHwDevice, &halConfig, audio, Tuner::callback,
-            tunerImpl.get(), &halTuner);
-    if (rc == 0) {
-        tunerImpl->setHalTuner(halTuner);
+        if (src.type == Band::AM) {
+            dst.ext.am.stereo = true;
+        } else if (src.type == Band::FM) {
+            dst.ext.fm.deemphasis = Deemphasis::D75;
+            dst.ext.fm.stereo = true;
+            dst.ext.fm.rds = Rds::US;
+            dst.ext.fm.ta = true;
+            dst.ext.fm.af = true;
+            dst.ext.fm.ea = true;
+        }
     }
 
-    _hidl_cb(Utils::convertHalResult(rc), tunerImpl);
+    _hidl_cb(prop11);
     return Void();
 }
 
-} // namespace implementation
+Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio __unused,
+                                       const sp<V1_0::ITunerCallback>& callback,
+                                       openTuner_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+
+    auto oldTuner = mTuner.promote();
+    if (oldTuner != nullptr) {
+        ALOGI("Force-closing previously opened tuner");
+        oldTuner->forceClose();
+        mTuner = nullptr;
+    }
+
+    sp<Tuner> newTuner = new Tuner(callback);
+    mTuner = newTuner;
+    if (mClassId == Class::AM_FM) {
+        auto ret = newTuner->setConfiguration(config);
+        if (ret != Result::OK) {
+            _hidl_cb(Result::INVALID_ARGUMENTS, {});
+            return Void();
+        }
+    }
+
+    _hidl_cb(Result::OK, newTuner);
+    return Void();
+}
+
+}  // namespace implementation
 }  // namespace V1_1
 }  // namespace broadcastradio
 }  // namespace hardware