2 * Copyright (C) 2017 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 #define LOG_TAG "BroadcastRadioDefault.utils"
17 //#define LOG_NDEBUG 0
25 namespace broadcastradio {
31 static bool isCompatibleProgramType(const uint32_t ia, const uint32_t ib) {
32 auto a = static_cast<ProgramType>(ia);
33 auto b = static_cast<ProgramType>(ib);
35 if (a == b) return true;
36 if (a == ProgramType::AM && b == ProgramType::AM_HD) return true;
37 if (a == ProgramType::AM_HD && b == ProgramType::AM) return true;
38 if (a == ProgramType::FM && b == ProgramType::FM_HD) return true;
39 if (a == ProgramType::FM_HD && b == ProgramType::FM) return true;
43 static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b,
44 const IdentifierType type) {
45 return hasId(a, type) && hasId(b, type);
48 static bool anyHaveId(const ProgramSelector& a, const ProgramSelector& b,
49 const IdentifierType type) {
50 return hasId(a, type) || hasId(b, type);
53 static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b,
54 const IdentifierType type) {
55 if (!bothHaveId(a, b, type)) return false;
56 // TODO(b/36864090): we should check all Ids of a given type (ie. other AF), not just one
57 auto aId = getId(a, type);
58 auto bId = getId(b, type);
62 bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
63 if (!isCompatibleProgramType(a.programType, b.programType)) return false;
65 auto type = getType(a);
69 case ProgramType::AM_HD:
71 case ProgramType::FM_HD:
72 if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
74 // if HD Radio subchannel is specified, it must match
75 if (anyHaveId(a, b, IdentifierType::HD_SUBCHANNEL)) {
76 // missing subchannel (analog) is an equivalent of first subchannel (MPS)
77 auto aCh = getId(a, IdentifierType::HD_SUBCHANNEL, 0);
78 auto bCh = getId(b, IdentifierType::HD_SUBCHANNEL, 0);
79 if (aCh != bCh) return false;
82 if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
84 return haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
85 case ProgramType::DAB:
86 return haveEqualIds(a, b, IdentifierType::DAB_SIDECC);
87 case ProgramType::DRMO:
88 return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
89 case ProgramType::SXM:
90 if (anyHaveId(a, b, IdentifierType::SXM_SERVICE_ID)) {
91 return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
93 return haveEqualIds(a, b, IdentifierType::SXM_CHANNEL);
94 case ProgramType::VENDOR1:
95 case ProgramType::VENDOR2:
96 case ProgramType::VENDOR3:
97 case ProgramType::VENDOR4:
99 ALOGW("Unsupported program type: %s", toString(type).c_str());
104 ProgramType getType(const ProgramSelector& sel) {
105 return static_cast<ProgramType>(sel.programType);
108 bool isAmFm(const ProgramType type) {
110 case ProgramType::AM:
111 case ProgramType::FM:
112 case ProgramType::AM_HD:
113 case ProgramType::FM_HD:
120 bool hasId(const ProgramSelector& sel, const IdentifierType type) {
121 auto itype = static_cast<uint32_t>(type);
122 if (sel.primaryId.type == itype) return true;
123 // not optimal, but we don't care in default impl
124 for (auto&& id : sel.secondaryIds) {
125 if (id.type == itype) return true;
130 uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
131 auto itype = static_cast<uint32_t>(type);
132 if (sel.primaryId.type == itype) return sel.primaryId.value;
133 // not optimal, but we don't care in default impl
134 for (auto&& id : sel.secondaryIds) {
135 if (id.type == itype) return id.value;
137 ALOGW("Identifier %s not found", toString(type).c_str());
141 uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) {
142 if (!hasId(sel, type)) return defval;
143 return getId(sel, type);
146 ProgramSelector make_selector(Band band, uint32_t channel, uint32_t subChannel) {
147 ProgramSelector sel = {};
149 ALOGW_IF((subChannel > 0) && (band == Band::AM || band == Band::FM),
150 "got subChannel for non-HD AM/FM");
152 // we can't use ProgramType::AM_HD or FM_HD, because we don't know HD station ID
157 type = ProgramType::AM;
161 type = ProgramType::FM;
164 LOG_ALWAYS_FATAL("Unsupported band: %s", toString(band).c_str());
167 sel.programType = static_cast<uint32_t>(type);
168 sel.primaryId.type = static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY);
169 sel.primaryId.value = channel;
170 if (subChannel > 0) {
171 /* stating sub channel for AM/FM channel does not give any guarantees,
172 * but we can't do much more without HD station ID
174 * The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based.
176 sel.secondaryIds = hidl_vec<ProgramIdentifier>{
177 {static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL), subChannel - 1},
184 bool getLegacyChannel(const ProgramSelector& sel, uint32_t* channelOut, uint32_t* subChannelOut) {
185 if (channelOut) *channelOut = 0;
186 if (subChannelOut) *subChannelOut = 0;
187 if (isAmFm(getType(sel))) {
188 if (channelOut) *channelOut = getId(sel, IdentifierType::AMFM_FREQUENCY);
189 if (subChannelOut && hasId(sel, IdentifierType::HD_SUBCHANNEL)) {
190 // The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based.
191 *subChannelOut = getId(sel, IdentifierType::HD_SUBCHANNEL) + 1;
198 bool isDigital(const ProgramSelector& sel) {
199 switch (getType(sel)) {
200 case ProgramType::AM:
201 case ProgramType::FM:
204 // VENDOR might not be digital, but it doesn't matter for default impl.
211 } // namespace broadcastradio
212 } // namespace hardware
213 } // namespace android