2017-12-04 18:53:32 +01:00
|
|
|
/*
|
|
|
|
* 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 "BcRadioDef.utils"
|
|
|
|
//#define LOG_NDEBUG 0
|
|
|
|
|
|
|
|
#include <broadcastradio-utils-2x/Utils.h>
|
|
|
|
|
|
|
|
#include <log/log.h>
|
|
|
|
|
|
|
|
namespace android {
|
|
|
|
namespace hardware {
|
|
|
|
namespace broadcastradio {
|
|
|
|
namespace utils {
|
|
|
|
|
|
|
|
using V2_0::IdentifierType;
|
|
|
|
using V2_0::Metadata;
|
|
|
|
using V2_0::MetadataKey;
|
|
|
|
using V2_0::ProgramIdentifier;
|
|
|
|
using V2_0::ProgramSelector;
|
|
|
|
|
|
|
|
using std::string;
|
2017-12-05 18:36:11 +01:00
|
|
|
using std::vector;
|
2017-12-04 18:53:32 +01:00
|
|
|
|
|
|
|
IdentifierType getType(const ProgramIdentifier& id) {
|
|
|
|
return static_cast<IdentifierType>(id.type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b,
|
|
|
|
const IdentifierType type) {
|
|
|
|
return hasId(a, type) && hasId(b, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b,
|
|
|
|
const IdentifierType type) {
|
|
|
|
if (!bothHaveId(a, b, type)) return false;
|
|
|
|
/* We should check all Ids of a given type (ie. other AF),
|
|
|
|
* but it doesn't matter for default implementation.
|
|
|
|
*/
|
|
|
|
return getId(a, type) == getId(b, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int getHdSubchannel(const ProgramSelector& sel) {
|
|
|
|
auto hdsidext = getId(sel, IdentifierType::HD_STATION_ID_EXT, 0);
|
|
|
|
hdsidext >>= 32; // Station ID number
|
|
|
|
return hdsidext & 0xF; // HD Radio subchannel
|
|
|
|
}
|
|
|
|
|
|
|
|
bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
|
|
|
|
auto type = getType(b.primaryId);
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case IdentifierType::HD_STATION_ID_EXT:
|
|
|
|
case IdentifierType::RDS_PI:
|
|
|
|
case IdentifierType::AMFM_FREQUENCY:
|
|
|
|
if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
|
|
|
|
if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
|
|
|
|
return getHdSubchannel(b) == 0 && haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
|
|
|
|
case IdentifierType::DAB_SID_EXT:
|
|
|
|
return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT);
|
|
|
|
case IdentifierType::DRMO_SERVICE_ID:
|
|
|
|
return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
|
|
|
|
case IdentifierType::SXM_SERVICE_ID:
|
|
|
|
return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
|
|
|
|
default: // includes all vendor types
|
|
|
|
ALOGW("Unsupported program type: %s", toString(type).c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool maybeGetId(const ProgramSelector& sel, const IdentifierType type, uint64_t* val) {
|
|
|
|
auto itype = static_cast<uint32_t>(type);
|
|
|
|
|
|
|
|
if (sel.primaryId.type == itype) {
|
|
|
|
if (val) *val = sel.primaryId.value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// not optimal, but we don't care in default impl
|
|
|
|
for (auto&& id : sel.secondaryIds) {
|
|
|
|
if (id.type == itype) {
|
|
|
|
if (val) *val = id.value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool hasId(const ProgramSelector& sel, const IdentifierType type) {
|
|
|
|
return maybeGetId(sel, type, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
|
|
|
|
uint64_t val;
|
|
|
|
|
|
|
|
if (maybeGetId(sel, type, &val)) {
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
ALOGW("Identifier %s not found", toString(type).c_str());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) {
|
|
|
|
if (!hasId(sel, type)) return defval;
|
|
|
|
return getId(sel, type);
|
|
|
|
}
|
|
|
|
|
2017-12-05 18:36:11 +01:00
|
|
|
vector<uint64_t> getAllIds(const ProgramSelector& sel, const IdentifierType type) {
|
|
|
|
vector<uint64_t> ret;
|
|
|
|
auto itype = static_cast<uint32_t>(type);
|
|
|
|
|
|
|
|
if (sel.primaryId.type == itype) ret.push_back(sel.primaryId.value);
|
|
|
|
|
|
|
|
for (auto&& id : sel.secondaryIds) {
|
|
|
|
if (id.type == itype) ret.push_back(id.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-12-04 18:53:32 +01:00
|
|
|
bool isSupported(const V2_0::Properties& prop, const V2_0::ProgramSelector& sel) {
|
|
|
|
// Not optimal, but it doesn't matter for default impl nor VTS tests.
|
|
|
|
for (auto&& idTypeI : prop.supportedIdentifierTypes) {
|
|
|
|
auto idType = static_cast<IdentifierType>(idTypeI);
|
|
|
|
if (hasId(sel, idType)) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isValid(const ProgramIdentifier& id) {
|
|
|
|
auto val = id.value;
|
|
|
|
bool valid = true;
|
|
|
|
|
|
|
|
auto expect = [&valid](bool condition, std::string message) {
|
|
|
|
if (!condition) {
|
|
|
|
valid = false;
|
|
|
|
ALOGE("Identifier not valid, expected %s", message.c_str());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
switch (static_cast<IdentifierType>(id.type)) {
|
|
|
|
case IdentifierType::AMFM_FREQUENCY:
|
|
|
|
case IdentifierType::DAB_FREQUENCY:
|
|
|
|
case IdentifierType::DRMO_FREQUENCY:
|
|
|
|
expect(val > 100u, "f > 100kHz");
|
|
|
|
expect(val < 10000000u, "f < 10GHz");
|
|
|
|
break;
|
|
|
|
case IdentifierType::RDS_PI:
|
|
|
|
expect(val != 0u, "RDS PI != 0");
|
|
|
|
expect(val <= 0xFFFFu, "16bit id");
|
|
|
|
break;
|
|
|
|
case IdentifierType::HD_STATION_ID_EXT: {
|
|
|
|
auto stationId = val & 0xFFFFFFFF; // 32bit
|
|
|
|
val >>= 32;
|
|
|
|
auto subchannel = val & 0xF; // 4bit
|
|
|
|
val >>= 4;
|
|
|
|
auto freq = val & 0x3FFFF; // 18bit
|
|
|
|
expect(stationId != 0u, "HD station id != 0");
|
|
|
|
expect(subchannel < 8u, "HD subch < 8");
|
|
|
|
expect(freq > 100u, "f > 100kHz");
|
|
|
|
expect(freq < 10000000u, "f < 10GHz");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IdentifierType::DAB_SID_EXT: {
|
|
|
|
auto sid = val & 0xFFFF; // 16bit
|
|
|
|
val >>= 16;
|
|
|
|
auto ecc = val & 0xFF; // 8bit
|
|
|
|
expect(sid != 0u, "DAB SId != 0");
|
|
|
|
expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IdentifierType::DAB_ENSEMBLE:
|
|
|
|
expect(val != 0u, "DAB ensemble != 0");
|
|
|
|
expect(val <= 0xFFFFu, "16bit id");
|
|
|
|
break;
|
|
|
|
case IdentifierType::DAB_SCID:
|
|
|
|
expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
|
|
|
|
expect(val <= 0xFFFu, "12bit id");
|
|
|
|
break;
|
|
|
|
case IdentifierType::DRMO_SERVICE_ID:
|
|
|
|
expect(val != 0u, "DRM SId != 0");
|
|
|
|
expect(val <= 0xFFFFFFu, "24bit id");
|
|
|
|
break;
|
|
|
|
case IdentifierType::SXM_SERVICE_ID:
|
|
|
|
expect(val != 0u, "SXM SId != 0");
|
|
|
|
expect(val <= 0xFFFFFFFFu, "32bit id");
|
|
|
|
break;
|
|
|
|
case IdentifierType::SXM_CHANNEL:
|
|
|
|
expect(val < 1000u, "SXM channel < 1000");
|
|
|
|
break;
|
|
|
|
case IdentifierType::VENDOR_START:
|
|
|
|
case IdentifierType::VENDOR_END:
|
|
|
|
// skip
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isValid(const V2_0::ProgramSelector& sel) {
|
|
|
|
if (!isValid(sel.primaryId)) return false;
|
|
|
|
for (auto&& id : sel.secondaryIds) {
|
|
|
|
if (!isValid(id)) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ProgramIdentifier make_identifier(IdentifierType type, uint64_t value) {
|
|
|
|
return {static_cast<uint32_t>(type), value};
|
|
|
|
}
|
|
|
|
|
|
|
|
ProgramSelector make_selector_amfm(uint32_t frequency) {
|
|
|
|
ProgramSelector sel = {};
|
|
|
|
sel.primaryId = make_identifier(IdentifierType::AMFM_FREQUENCY, frequency);
|
|
|
|
return sel;
|
|
|
|
}
|
|
|
|
|
|
|
|
Metadata make_metadata(MetadataKey key, int64_t value) {
|
|
|
|
Metadata meta = {};
|
|
|
|
meta.key = static_cast<uint32_t>(key);
|
|
|
|
meta.intValue = value;
|
|
|
|
return meta;
|
|
|
|
}
|
|
|
|
|
|
|
|
Metadata make_metadata(MetadataKey key, string value) {
|
|
|
|
Metadata meta = {};
|
|
|
|
meta.key = static_cast<uint32_t>(key);
|
|
|
|
meta.stringValue = value;
|
|
|
|
return meta;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace utils
|
|
|
|
} // namespace broadcastradio
|
|
|
|
} // namespace hardware
|
|
|
|
} // namespace android
|