OSDN Git Service

Implement region guessing.
authorTomasz Wasilczyk <twasilczyk@google.com>
Thu, 10 Aug 2017 19:30:31 +0000 (12:30 -0700)
committerTomasz Wasilczyk <twasilczyk@google.com>
Thu, 10 Aug 2017 23:07:25 +0000 (16:07 -0700)
Bug: b/64115131
Test: instrumentation
Change-Id: I80a03b4e8614de18cebd9c4bd1f5f9922b8da59b

core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
services/core/jni/Android.mk
services/core/jni/BroadcastRadio/convert.cpp
services/core/jni/BroadcastRadio/regions.cpp [new file with mode: 0644]
services/core/jni/BroadcastRadio/regions.h [new file with mode: 0644]

index 29b6fd0..c707240 100644 (file)
@@ -131,7 +131,9 @@ public class RadioTunerTest {
 
         // find FM band and build its config
         mModule = mModules.get(0);
+
         for (RadioManager.BandDescriptor band : mModule.getBands()) {
+            Log.d(TAG, "Band: " + band);
             int bandType = band.getType();
             if (bandType == RadioManager.BAND_AM || bandType == RadioManager.BAND_AM_HD) {
                 mAmBandDescriptor = (RadioManager.AmBandDescriptor)band;
index 651cc7d..bf9f941 100644 (file)
@@ -11,6 +11,7 @@ LOCAL_SRC_FILES += \
     $(LOCAL_REL_DIR)/BroadcastRadio/Tuner.cpp \
     $(LOCAL_REL_DIR)/BroadcastRadio/TunerCallback.cpp \
     $(LOCAL_REL_DIR)/BroadcastRadio/convert.cpp \
+    $(LOCAL_REL_DIR)/BroadcastRadio/regions.cpp \
     $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
index 3e0bc63..ae278de 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "convert.h"
 
+#include "regions.h"
+
 #include <broadcastradio-utils/Utils.h>
 #include <core_jni_helpers.h>
 #include <nativehelper/JNIHelp.h>
@@ -29,8 +31,11 @@ namespace server {
 namespace BroadcastRadio {
 namespace convert {
 
+namespace utils = V1_1::utils;
+
 using hardware::Return;
 using hardware::hidl_vec;
+using regions::RegionalBandConfig;
 
 using V1_0::Band;
 using V1_0::Deemphasis;
@@ -43,6 +48,7 @@ using V1_1::ProgramListResult;
 using V1_1::ProgramSelector;
 using V1_1::VendorKeyValue;
 
+static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const RegionalBandConfig &config);
 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region);
 
 static struct {
@@ -334,9 +340,10 @@ static JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Propert
     auto jSerial = make_javastr(env, prop10.serial);
     bool isBgScanSupported = prop11 ? prop11->supportsBackgroundScanning : false;
     auto jVendorInfo = prop11 ? VendorInfoFromHal(env, prop11->vendorInfo) : nullptr;
-    // ITU_1 is the default region just because its index is 0.
-    auto jBands = ArrayFromHal<V1_0::BandConfig>(env, prop10.bands, gjni.BandDescriptor.clazz,
-        std::bind(BandDescriptorFromHal, _1, _2, Region::ITU_1));
+
+    auto regionalBands = regions::mapRegions(prop10.bands);
+    auto jBands = ArrayFromHal<RegionalBandConfig>(env, regionalBands,
+            gjni.BandDescriptor.clazz, BandDescriptorFromHal);
     auto jSupportedProgramTypes =
             prop11 ? ArrayFromHal(env, prop11->supportedProgramTypes) : nullptr;
     auto jSupportedIdentifierTypes =
@@ -359,32 +366,31 @@ JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_1::Properties &pr
     return ModulePropertiesFromHal(env, properties.base, &properties, moduleId, serviceName);
 }
 
+static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const RegionalBandConfig &config) {
+    return BandDescriptorFromHal(env, config.bandConfig, config.region);
+}
+
 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region) {
     ALOGV("%s", __func__);
 
     jint spacing = config.spacings.size() > 0 ? config.spacings[0] : 0;
+    ALOGW_IF(config.spacings.size() > 1, "Multiple spacings - not a regional config");
     ALOGW_IF(config.spacings.size() == 0, "No channel spacing specified");
 
-    switch (config.type) {
-        case Band::FM:
-        case Band::FM_HD: {
-            auto& fm = config.ext.fm;
-            return make_javaref(env, env->NewObject(
-                    gjni.FmBandDescriptor.clazz, gjni.FmBandDescriptor.cstor,
-                    region, config.type, config.lowerLimit, config.upperLimit, spacing,
-                    fm.stereo, fm.rds != Rds::NONE, fm.ta, fm.af, fm.ea));
-        }
-        case Band::AM:
-        case Band::AM_HD: {
-            auto& am = config.ext.am;
-            return make_javaref(env, env->NewObject(
-                    gjni.AmBandDescriptor.clazz, gjni.AmBandDescriptor.cstor,
-                    region, config.type, config.lowerLimit, config.upperLimit, spacing,
-                    am.stereo));
-        }
-        default:
-            ALOGE("Unsupported band type: %d", config.type);
-            return nullptr;
+    if (utils::isFm(config.type)) {
+        auto& fm = config.ext.fm;
+        return make_javaref(env, env->NewObject(
+                gjni.FmBandDescriptor.clazz, gjni.FmBandDescriptor.cstor,
+                region, config.type, config.lowerLimit, config.upperLimit, spacing,
+                fm.stereo, fm.rds != Rds::NONE, fm.ta, fm.af, fm.ea));
+    } else if (utils::isAm(config.type)) {
+        auto& am = config.ext.am;
+        return make_javaref(env, env->NewObject(
+                gjni.AmBandDescriptor.clazz, gjni.AmBandDescriptor.cstor,
+                region, config.type, config.lowerLimit, config.upperLimit, spacing, am.stereo));
+    } else {
+        ALOGE("Unsupported band type: %d", config.type);
+        return nullptr;
     }
 }
 
@@ -394,20 +400,15 @@ JavaRef<jobject> BandConfigFromHal(JNIEnv *env, const V1_0::BandConfig &config,
     auto descriptor = BandDescriptorFromHal(env, config, region);
     if (descriptor == nullptr) return nullptr;
 
-    switch (config.type) {
-        case Band::FM:
-        case Band::FM_HD: {
-            return make_javaref(env, env->NewObject(
-                    gjni.FmBandConfig.clazz, gjni.FmBandConfig.cstor, descriptor.get()));
-        }
-        case Band::AM:
-        case Band::AM_HD: {
-            return make_javaref(env, env->NewObject(
-                    gjni.AmBandConfig.clazz, gjni.AmBandConfig.cstor, descriptor.get()));
-        }
-        default:
-            ALOGE("Unsupported band type: %d", config.type);
-            return nullptr;
+    if (utils::isFm(config.type)) {
+        return make_javaref(env, env->NewObject(
+                gjni.FmBandConfig.clazz, gjni.FmBandConfig.cstor, descriptor.get()));
+    } else if (utils::isAm(config.type)) {
+        return make_javaref(env, env->NewObject(
+                gjni.AmBandConfig.clazz, gjni.AmBandConfig.cstor, descriptor.get()));
+    } else {
+        ALOGE("Unsupported band type: %d", config.type);
+        return nullptr;
     }
 }
 
@@ -583,7 +584,7 @@ static JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo
 }
 
 JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo &info, V1_0::Band band) {
-    auto selector = V1_1::utils::make_selector(band, info.channel, info.subChannel);
+    auto selector = utils::make_selector(band, info.channel, info.subChannel);
     return ProgramInfoFromHal(env, info, nullptr, selector);
 }
 
diff --git a/services/core/jni/BroadcastRadio/regions.cpp b/services/core/jni/BroadcastRadio/regions.cpp
new file mode 100644 (file)
index 0000000..e313521
--- /dev/null
@@ -0,0 +1,196 @@
+/**
+ * Copyright (C) 2017 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 "BroadcastRadioService.regions.jni"
+#define LOG_NDEBUG 0
+
+#include "regions.h"
+
+#include <broadcastradio-utils/Utils.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace server {
+namespace BroadcastRadio {
+namespace regions {
+
+namespace utils = hardware::broadcastradio::V1_1::utils;
+
+using hardware::hidl_vec;
+
+using V1_0::Band;
+using V1_0::BandConfig;
+using V1_0::Deemphasis;
+using V1_0::Rds;
+
+class RegionalBandDefinition {
+public:
+    std::vector<Region> mRegions;
+    std::vector<Band> mTypes;
+    uint32_t mLowerLimit;
+    uint32_t mUpperLimit;
+    uint32_t mSpacing;
+
+    Deemphasis mFmDeemphasis = {};
+    Rds mFmRds = Rds::NONE;
+
+    bool fitsInsideBand(const BandConfig &bandConfig) const;
+    std::vector<RegionalBandConfig> withConfig(BandConfig bandConfig) const;
+};
+
+static const RegionalBandDefinition kKnownRegionConfigs[] = {
+    {
+        { Region::ITU_1 },
+        { Band::FM },
+        87500,
+        108000,
+        100,
+        Deemphasis::D50,
+        Rds::WORLD,
+    },
+    {
+        { Region::ITU_2 },
+        { Band::FM, Band::FM_HD },
+        87900,
+        107900,
+        200,
+        Deemphasis::D75,
+        Rds::US,
+    },
+    {
+        { Region::OIRT },
+        { Band::FM },
+        65800,
+        74000,
+        10,
+        Deemphasis::D50,
+        Rds::WORLD,
+    },
+    {
+        { Region::JAPAN },
+        { Band::FM },
+        76000,
+        90000,
+        100,
+        Deemphasis::D50,
+        Rds::WORLD,
+    },
+    {
+        { Region::KOREA },
+        { Band::FM },
+        87500,
+        108000,
+        100,
+        Deemphasis::D75,
+        Rds::WORLD,
+    },
+    {  // AM LW
+        { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
+        { Band::AM },
+        153,
+        279,
+        9,
+    },
+    {  // AM MW
+        { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
+        { Band::AM },
+        531,
+        1611,
+        9,
+    },
+    {  // AM SW
+        { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
+        { Band::AM },
+        2300,
+        26100,
+        5,
+    },
+    {  // AM LW ITU2
+        { Region::ITU_2 },
+        { Band::AM, Band::AM_HD },
+        153,
+        279,
+        9,
+    },
+    {  // AM MW ITU2
+        { Region::ITU_2 },
+        { Band::AM, Band::AM_HD },
+        540,
+        1610,
+        10,
+    },
+    {  // AM SW ITU2
+        { Region::ITU_2 },
+        { Band::AM, Band::AM_HD },
+        2300,
+        26100,
+        5,
+    },
+};
+
+bool RegionalBandDefinition::fitsInsideBand(const BandConfig &bandConfig) const {
+    if (std::find(mTypes.begin(), mTypes.end(), bandConfig.type) == mTypes.end()) return false;
+    if (mLowerLimit < bandConfig.lowerLimit) return false;
+    if (mUpperLimit > bandConfig.upperLimit) return false;
+    auto&& spacings = bandConfig.spacings;
+    if (std::find(spacings.begin(), spacings.end(), mSpacing) == spacings.end()) return false;
+    if (utils::isFm(bandConfig.type)) {
+        if (0 == (mFmDeemphasis & bandConfig.ext.fm.deemphasis)) return false;
+    }
+
+    return true;
+}
+
+std::vector<RegionalBandConfig> RegionalBandDefinition::withConfig(BandConfig config) const {
+    config.lowerLimit = mLowerLimit;
+    config.upperLimit = mUpperLimit;
+    config.spacings = hidl_vec<uint32_t>({ mSpacing });
+    if (utils::isFm(config.type)) {
+        auto&& fm = config.ext.fm;
+        fm.deemphasis = mFmDeemphasis;
+        fm.rds = static_cast<Rds>(mFmRds & fm.rds);
+    }
+
+    std::vector<RegionalBandConfig> configs;
+    for (auto region : mRegions) {
+        configs.push_back({region, config});
+    }
+
+    return configs;
+}
+
+std::vector<RegionalBandConfig> mapRegions(const hidl_vec<BandConfig>& bands) {
+    ALOGV("%s", __func__);
+
+    std::vector<RegionalBandConfig> out;
+
+    for (auto&& regionalBand : kKnownRegionConfigs) {
+        for (auto&& tunerBand : bands) {
+            if (regionalBand.fitsInsideBand(tunerBand)) {
+                auto mapped = regionalBand.withConfig(tunerBand);
+                out.insert(out.end(), mapped.begin(), mapped.end());
+            }
+        }
+    }
+
+    ALOGI("Mapped %zu tuner bands to %zu regional bands", bands.size(), out.size());
+    return out;
+}
+
+} // namespace regions
+} // namespace BroadcastRadio
+} // namespace server
+} // namespace android
diff --git a/services/core/jni/BroadcastRadio/regions.h b/services/core/jni/BroadcastRadio/regions.h
new file mode 100644 (file)
index 0000000..45a32ea
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2017 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_SERVER_BROADCASTRADIO_REGIONS_H
+#define _ANDROID_SERVER_BROADCASTRADIO_REGIONS_H
+
+#include "types.h"
+
+#include <android/hardware/broadcastradio/1.1/types.h>
+
+namespace android {
+namespace server {
+namespace BroadcastRadio {
+namespace regions {
+
+namespace V1_0 = hardware::broadcastradio::V1_0;
+
+struct RegionalBandConfig {
+    Region region;
+    V1_0::BandConfig bandConfig;
+};
+
+std::vector<RegionalBandConfig>
+mapRegions(const hardware::hidl_vec<V1_0::BandConfig>& bands);
+
+} // namespace regions
+} // namespace BroadcastRadio
+} // namespace server
+} // namespace android
+
+#endif // _ANDROID_SERVER_BROADCASTRADIO_REGIONS_H