#include "convert.h"
+#include "regions.h"
+
#include <broadcastradio-utils/Utils.h>
#include <core_jni_helpers.h>
#include <nativehelper/JNIHelp.h>
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;
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 {
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 =
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;
}
}
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;
}
}
}
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);
}
--- /dev/null
+/**
+ * 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
--- /dev/null
+/**
+ * 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