blob: 4ab04d2a520b366fa75b176c5b41eb620abfb9ec [file] [log] [blame]
Weilin Xub2a6ca62022-05-08 23:47:04 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#define LOG_TAG "BcRadioAidlDef.utils"
18
19#include "broadcastradio-utils-aidl/Utils.h"
20
21#include <android-base/logging.h>
Weilin Xu97203b02022-06-23 00:19:03 +000022#include <android-base/parseint.h>
23#include <android-base/strings.h>
Weilin Xub2a6ca62022-05-08 23:47:04 +000024
25#include <math/HashCombine.h>
26
27namespace aidl::android::hardware::broadcastradio {
28
29namespace utils {
30
31namespace {
32
Weilin Xu97203b02022-06-23 00:19:03 +000033using ::android::base::EqualsIgnoreCase;
Weilin Xub2a6ca62022-05-08 23:47:04 +000034using ::std::vector;
35
36const int64_t kValueForNotFoundIdentifier = 0;
37
38bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
39 return hasId(a, type) && hasId(b, type);
40}
41
42bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
43 if (!bothHaveId(a, b, type)) {
44 return false;
45 }
46 /* We should check all Ids of a given type (ie. other AF),
47 * but it doesn't matter for default implementation.
48 */
49 return getId(a, type) == getId(b, type);
50}
51
Weilin Xub2a6ca62022-05-08 23:47:04 +000052bool maybeGetId(const ProgramSelector& sel, const IdentifierType& type, int64_t* val) {
53 // iterate through primaryId and secondaryIds
54 for (auto it = begin(sel); it != end(sel); it++) {
55 if (it->type == type) {
56 if (val != nullptr) {
57 *val = it->value;
58 }
59 return true;
60 }
61 }
62
63 return false;
64}
65
66} // namespace
67
68IdentifierIterator::IdentifierIterator(const ProgramSelector& sel) : IdentifierIterator(sel, 0) {}
69
70IdentifierIterator::IdentifierIterator(const ProgramSelector& sel, size_t pos)
71 : mSel(sel), mPos(pos) {}
72
73const IdentifierIterator IdentifierIterator::operator++(int) {
74 IdentifierIterator i = *this;
75 mPos++;
76 return i;
77}
78
79IdentifierIterator& IdentifierIterator::operator++() {
80 ++mPos;
81 return *this;
82}
83
84IdentifierIterator::refType IdentifierIterator::operator*() const {
85 if (mPos == 0) {
86 return getSelector().primaryId;
87 }
88
89 // mPos is 1-based for secondary identifiers
90 DCHECK(mPos <= getSelector().secondaryIds.size());
91 return getSelector().secondaryIds[mPos - 1];
92}
93
94bool IdentifierIterator::operator==(const IdentifierIterator& rhs) const {
95 // Check, if both iterators points at the same selector.
96 if (reinterpret_cast<intptr_t>(&getSelector()) !=
97 reinterpret_cast<intptr_t>(&rhs.getSelector())) {
98 return false;
99 }
100
101 return mPos == rhs.mPos;
102}
103
104int32_t resultToInt(Result result) {
105 return static_cast<int32_t>(result);
106}
107
108FrequencyBand getBand(int64_t freq) {
109 // keep in sync with
110 // frameworks/base/services/core/java/com/android/server/broadcastradio/aidl/Utils.java
111 if (freq < 30) return FrequencyBand::UNKNOWN;
112 if (freq < 500) return FrequencyBand::AM_LW;
113 if (freq < 1705) return FrequencyBand::AM_MW;
114 if (freq < 30000) return FrequencyBand::AM_SW;
115 if (freq < 60000) return FrequencyBand::UNKNOWN;
116 if (freq < 110000) return FrequencyBand::FM;
117 return FrequencyBand::UNKNOWN;
118}
119
120bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
121 IdentifierType type = b.primaryId.type;
122
123 switch (type) {
124 case IdentifierType::HD_STATION_ID_EXT:
125 case IdentifierType::RDS_PI:
126 case IdentifierType::AMFM_FREQUENCY_KHZ:
127 if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
128 if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
Weilin Xu39dd0f82023-09-07 17:00:57 -0700129 if (getHdSubchannel(b) != 0) { // supplemental program services
130 return false;
131 }
132 return haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY_KHZ) ||
133 (b.primaryId.type == IdentifierType::HD_STATION_ID_EXT &&
134 static_cast<uint32_t>(getId(a, IdentifierType::AMFM_FREQUENCY_KHZ)) ==
135 getAmFmFrequency(b));
Weilin Xub2a6ca62022-05-08 23:47:04 +0000136 case IdentifierType::DAB_SID_EXT:
Weilin Xu64cb9632023-03-15 23:46:43 +0000137 if (!haveEqualIds(a, b, IdentifierType::DAB_SID_EXT)) {
138 return false;
139 }
140 if (hasId(a, IdentifierType::DAB_ENSEMBLE) &&
141 !haveEqualIds(a, b, IdentifierType::DAB_ENSEMBLE)) {
142 return false;
143 }
144 if (hasId(a, IdentifierType::DAB_FREQUENCY_KHZ) &&
145 !haveEqualIds(a, b, IdentifierType::DAB_FREQUENCY_KHZ)) {
146 return false;
147 }
148 return true;
Weilin Xub2a6ca62022-05-08 23:47:04 +0000149 case IdentifierType::DRMO_SERVICE_ID:
150 return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
151 case IdentifierType::SXM_SERVICE_ID:
152 return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
153 default: // includes all vendor types
154 LOG(WARNING) << "unsupported program type: " << toString(type);
155 return false;
156 }
157}
158
159bool hasId(const ProgramSelector& sel, const IdentifierType& type) {
160 return maybeGetId(sel, type, /* val */ nullptr);
161}
162
163int64_t getId(const ProgramSelector& sel, const IdentifierType& type) {
164 int64_t val;
165
166 if (maybeGetId(sel, type, &val)) {
167 return val;
168 }
169
170 LOG(WARNING) << "identifier not found: " << toString(type);
171 return kValueForNotFoundIdentifier;
172}
173
174int64_t getId(const ProgramSelector& sel, const IdentifierType& type, int64_t defaultValue) {
175 if (!hasId(sel, type)) {
176 return defaultValue;
177 }
178 return getId(sel, type);
179}
180
181vector<int> getAllIds(const ProgramSelector& sel, const IdentifierType& type) {
182 vector<int> ret;
183
184 // iterate through primaryId and secondaryIds
185 for (auto it = begin(sel); it != end(sel); it++) {
186 if (it->type == type) {
187 ret.push_back(it->value);
188 }
189 }
190
191 return ret;
192}
193
194bool isSupported(const Properties& prop, const ProgramSelector& sel) {
195 for (auto it = prop.supportedIdentifierTypes.begin(); it != prop.supportedIdentifierTypes.end();
196 it++) {
197 if (hasId(sel, *it)) {
198 return true;
199 }
200 }
201 return false;
202}
203
204bool isValid(const ProgramIdentifier& id) {
Weilin Xu664048f2023-09-07 11:26:38 -0700205 uint64_t val = static_cast<uint64_t>(id.value);
Weilin Xub2a6ca62022-05-08 23:47:04 +0000206 bool valid = true;
207
Weilin Xu25409e52023-09-06 10:36:24 -0700208 auto expect = [&valid](bool condition, const std::string& message) {
Weilin Xub2a6ca62022-05-08 23:47:04 +0000209 if (!condition) {
210 valid = false;
211 LOG(ERROR) << "identifier not valid, expected " << message;
212 }
213 };
214
215 switch (id.type) {
216 case IdentifierType::INVALID:
217 expect(false, "IdentifierType::INVALID");
218 break;
219 case IdentifierType::DAB_FREQUENCY_KHZ:
220 expect(val > 100000u, "f > 100MHz");
221 [[fallthrough]];
222 case IdentifierType::AMFM_FREQUENCY_KHZ:
223 case IdentifierType::DRMO_FREQUENCY_KHZ:
224 expect(val > 100u, "f > 100kHz");
225 expect(val < 10000000u, "f < 10GHz");
226 break;
227 case IdentifierType::RDS_PI:
228 expect(val != 0u, "RDS PI != 0");
229 expect(val <= 0xFFFFu, "16bit id");
230 break;
231 case IdentifierType::HD_STATION_ID_EXT: {
Weilin Xu664048f2023-09-07 11:26:38 -0700232 uint64_t stationId = val & 0xFFFFFFFF; // 32bit
Weilin Xub2a6ca62022-05-08 23:47:04 +0000233 val >>= 32;
Weilin Xu664048f2023-09-07 11:26:38 -0700234 uint64_t subchannel = val & 0xF; // 4bit
Weilin Xub2a6ca62022-05-08 23:47:04 +0000235 val >>= 4;
Weilin Xu664048f2023-09-07 11:26:38 -0700236 uint64_t freq = val & 0x3FFFF; // 18bit
Weilin Xub2a6ca62022-05-08 23:47:04 +0000237 expect(stationId != 0u, "HD station id != 0");
238 expect(subchannel < 8u, "HD subch < 8");
239 expect(freq > 100u, "f > 100kHz");
240 expect(freq < 10000000u, "f < 10GHz");
241 break;
242 }
243 case IdentifierType::HD_STATION_NAME: {
244 while (val > 0) {
245 char ch = static_cast<char>(val & 0xFF);
246 val >>= 8;
247 expect((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'),
248 "HD_STATION_NAME does not match [A-Z0-9]+");
249 }
250 break;
251 }
252 case IdentifierType::DAB_SID_EXT: {
Weilin Xu664048f2023-09-07 11:26:38 -0700253 uint64_t sid = val & 0xFFFFFFFF; // 32bit
Weilin Xu0d4207d2022-12-09 00:37:44 +0000254 val >>= 32;
Weilin Xu664048f2023-09-07 11:26:38 -0700255 uint64_t ecc = val & 0xFF; // 8bit
Weilin Xub2a6ca62022-05-08 23:47:04 +0000256 expect(sid != 0u, "DAB SId != 0");
257 expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
258 break;
259 }
260 case IdentifierType::DAB_ENSEMBLE:
261 expect(val != 0u, "DAB ensemble != 0");
262 expect(val <= 0xFFFFu, "16bit id");
263 break;
264 case IdentifierType::DAB_SCID:
265 expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
266 expect(val <= 0xFFFu, "12bit id");
267 break;
268 case IdentifierType::DRMO_SERVICE_ID:
269 expect(val != 0u, "DRM SId != 0");
270 expect(val <= 0xFFFFFFu, "24bit id");
271 break;
272 case IdentifierType::SXM_SERVICE_ID:
273 expect(val != 0u, "SXM SId != 0");
274 expect(val <= 0xFFFFFFFFu, "32bit id");
275 break;
276 case IdentifierType::SXM_CHANNEL:
277 expect(val < 1000u, "SXM channel < 1000");
278 break;
Weilin Xu25409e52023-09-06 10:36:24 -0700279 default:
280 expect(id.type >= IdentifierType::VENDOR_START && id.type <= IdentifierType::VENDOR_END,
281 "Undefined identifier type");
Weilin Xub2a6ca62022-05-08 23:47:04 +0000282 break;
283 }
284
285 return valid;
286}
287
288bool isValid(const ProgramSelector& sel) {
Weilin Xu0d4207d2022-12-09 00:37:44 +0000289 if (sel.primaryId.type != IdentifierType::AMFM_FREQUENCY_KHZ &&
290 sel.primaryId.type != IdentifierType::RDS_PI &&
291 sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT &&
292 sel.primaryId.type != IdentifierType::DAB_SID_EXT &&
293 sel.primaryId.type != IdentifierType::DRMO_SERVICE_ID &&
294 sel.primaryId.type != IdentifierType::SXM_SERVICE_ID &&
295 (sel.primaryId.type < IdentifierType::VENDOR_START ||
296 sel.primaryId.type > IdentifierType::VENDOR_END)) {
297 return false;
298 }
Weilin Xu1b6c03d2024-03-05 16:48:08 -0800299 for (auto it = begin(sel); it != end(sel); it++) {
300 if (!isValid(*it)) {
301 return false;
302 }
303 }
304 return true;
Weilin Xub2a6ca62022-05-08 23:47:04 +0000305}
306
307ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
308 return {type, value};
309}
310
Weilin Xu664048f2023-09-07 11:26:38 -0700311ProgramSelector makeSelectorAmfm(uint32_t frequency) {
Weilin Xub2a6ca62022-05-08 23:47:04 +0000312 ProgramSelector sel = {};
313 sel.primaryId = makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, frequency);
314 return sel;
315}
316
Weilin Xu664048f2023-09-07 11:26:38 -0700317ProgramSelector makeSelectorDab(uint64_t sidExt) {
Weilin Xu64cb9632023-03-15 23:46:43 +0000318 ProgramSelector sel = {};
319 sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
320 return sel;
321}
322
Weilin Xu39dd0f82023-09-07 17:00:57 -0700323ProgramSelector makeSelectorHd(uint64_t stationId, uint64_t subChannel, uint64_t frequency) {
324 ProgramSelector sel = {};
325 uint64_t sidExt = stationId | (subChannel << 32) | (frequency << 36);
326 sel.primaryId = makeIdentifier(IdentifierType::HD_STATION_ID_EXT, sidExt);
327 return sel;
328}
329
Weilin Xu664048f2023-09-07 11:26:38 -0700330ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq) {
Weilin Xub2a6ca62022-05-08 23:47:04 +0000331 ProgramSelector sel = {};
Weilin Xub2a6ca62022-05-08 23:47:04 +0000332 sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
333 vector<ProgramIdentifier> secondaryIds = {
334 makeIdentifier(IdentifierType::DAB_ENSEMBLE, ensemble),
Weilin Xu0d4207d2022-12-09 00:37:44 +0000335 makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq)};
Weilin Xub2a6ca62022-05-08 23:47:04 +0000336 sel.secondaryIds = std::move(secondaryIds);
337 return sel;
338}
339
340bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel) {
341 if (filter.identifierTypes.size() > 0) {
342 auto typeEquals = [](const ProgramIdentifier& id, IdentifierType type) {
343 return id.type == type;
344 };
345 auto it = std::find_first_of(begin(sel), end(sel), filter.identifierTypes.begin(),
346 filter.identifierTypes.end(), typeEquals);
347 if (it == end(sel)) {
348 return false;
349 }
350 }
351
352 if (filter.identifiers.size() > 0) {
353 auto it = std::find_first_of(begin(sel), end(sel), filter.identifiers.begin(),
354 filter.identifiers.end());
355 if (it == end(sel)) {
356 return false;
357 }
358 }
359
Weilin Xub2a6ca62022-05-08 23:47:04 +0000360 return true;
361}
362
Weilin Xua7cc8a92023-12-07 17:04:21 -0800363bool ProgramSelectorComparator::operator()(const ProgramSelector& lhs,
364 const ProgramSelector& rhs) const {
365 if ((utils::hasId(lhs, IdentifierType::AMFM_FREQUENCY_KHZ) ||
366 lhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT) &&
367 (utils::hasId(rhs, IdentifierType::AMFM_FREQUENCY_KHZ) ||
368 rhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT)) {
369 uint32_t freq1 = utils::getAmFmFrequency(lhs);
370 int subChannel1 = lhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT
371 ? utils::getHdSubchannel(lhs)
372 : 0;
373 uint32_t freq2 = utils::getAmFmFrequency(rhs);
374 int subChannel2 = rhs.primaryId.type == IdentifierType::HD_STATION_ID_EXT
375 ? utils::getHdSubchannel(rhs)
376 : 0;
377 return freq1 < freq2 || (freq1 == freq2 && (lhs.primaryId.type < rhs.primaryId.type ||
378 subChannel1 < subChannel2));
379 }
380 if (lhs.primaryId.type == IdentifierType::DAB_SID_EXT &&
381 rhs.primaryId.type == IdentifierType::DAB_SID_EXT) {
382 uint64_t dabFreq1 = utils::getId(lhs, IdentifierType::DAB_FREQUENCY_KHZ);
383 uint64_t dabFreq2 = utils::getId(rhs, IdentifierType::DAB_FREQUENCY_KHZ);
384 if (dabFreq1 != dabFreq2) {
385 return dabFreq1 < dabFreq2;
386 }
387 uint32_t ecc1 = utils::getDabEccCode(lhs);
388 uint32_t ecc2 = utils::getDabEccCode(rhs);
389 if (ecc1 != ecc2) {
390 return ecc1 < ecc2;
391 }
392 uint64_t dabEnsemble1 = utils::getId(lhs, IdentifierType::DAB_ENSEMBLE);
393 uint64_t dabEnsemble2 = utils::getId(rhs, IdentifierType::DAB_ENSEMBLE);
394 if (dabEnsemble1 != dabEnsemble2) {
395 return dabEnsemble1 < dabEnsemble2;
396 }
397 uint32_t sId1 = utils::getDabSId(lhs);
398 uint32_t sId2 = utils::getDabSId(rhs);
399 return sId1 < sId2 || (sId1 == sId2 && utils::getDabSCIdS(lhs) < utils::getDabSCIdS(rhs));
400 }
401
402 if (lhs.primaryId.type != rhs.primaryId.type) {
403 return lhs.primaryId.type < rhs.primaryId.type;
404 }
405 return lhs.primaryId.value < rhs.primaryId.value;
406}
407
408bool ProgramInfoComparator::operator()(const ProgramInfo& lhs, const ProgramInfo& rhs) const {
409 return ProgramSelectorComparator()(lhs.selector, rhs.selector);
410}
411
Weilin Xub2a6ca62022-05-08 23:47:04 +0000412size_t ProgramInfoHasher::operator()(const ProgramInfo& info) const {
413 const ProgramIdentifier& id = info.selector.primaryId;
414
415 // This is not the best hash implementation, but good enough for default HAL
416 // implementation and tests.
417 size_t h = 0;
418 ::android::hashCombineSingle(h, id.type);
419 ::android::hashCombineSingle(h, id.value);
420 return h;
421}
422
423bool ProgramInfoKeyEqual::operator()(const ProgramInfo& info1, const ProgramInfo& info2) const {
424 const ProgramIdentifier& id1 = info1.selector.primaryId;
425 const ProgramIdentifier& id2 = info2.selector.primaryId;
426 return id1.type == id2.type && id1.value == id2.value;
427}
428
429void updateProgramList(const ProgramListChunk& chunk, ProgramInfoSet* list) {
430 if (chunk.purge) {
431 list->clear();
432 }
433
434 list->insert(chunk.modified.begin(), chunk.modified.end());
435
436 if (!chunk.removed.has_value()) {
437 return;
438 }
439
440 for (auto& id : chunk.removed.value()) {
441 if (id.has_value()) {
442 ProgramInfo info = {};
443 info.selector.primaryId = id.value();
444 list->erase(info);
445 }
446 }
447}
448
449std::optional<std::string> getMetadataString(const ProgramInfo& info, const Metadata::Tag& tag) {
Weilin Xu67e83a32024-01-10 13:40:28 -0800450 auto hasMetadataType = [tag](const Metadata& item) { return item.getTag() == tag; };
Weilin Xub2a6ca62022-05-08 23:47:04 +0000451
Weilin Xu67e83a32024-01-10 13:40:28 -0800452 auto it = std::find_if(info.metadata.begin(), info.metadata.end(), hasMetadataType);
Weilin Xub2a6ca62022-05-08 23:47:04 +0000453 if (it == info.metadata.end()) {
454 return std::nullopt;
455 }
456
457 std::string metadataString;
458 switch (it->getTag()) {
459 case Metadata::rdsPs:
460 metadataString = it->get<Metadata::rdsPs>();
461 break;
462 case Metadata::rdsPty:
463 metadataString = std::to_string(it->get<Metadata::rdsPty>());
464 break;
465 case Metadata::rbdsPty:
466 metadataString = std::to_string(it->get<Metadata::rbdsPty>());
467 break;
468 case Metadata::rdsRt:
469 metadataString = it->get<Metadata::rdsRt>();
470 break;
471 case Metadata::songTitle:
472 metadataString = it->get<Metadata::songTitle>();
473 break;
474 case Metadata::songArtist:
475 metadataString = it->get<Metadata::songArtist>();
476 break;
477 case Metadata::songAlbum:
478 metadataString = it->get<Metadata::songAlbum>();
479 break;
480 case Metadata::stationIcon:
481 metadataString = std::to_string(it->get<Metadata::stationIcon>());
482 break;
483 case Metadata::albumArt:
484 metadataString = std::to_string(it->get<Metadata::albumArt>());
485 break;
486 case Metadata::programName:
487 metadataString = it->get<Metadata::programName>();
488 break;
489 case Metadata::dabEnsembleName:
490 metadataString = it->get<Metadata::dabEnsembleName>();
491 break;
492 case Metadata::dabEnsembleNameShort:
493 metadataString = it->get<Metadata::dabEnsembleNameShort>();
494 break;
495 case Metadata::dabServiceName:
496 metadataString = it->get<Metadata::dabServiceName>();
497 break;
498 case Metadata::dabServiceNameShort:
499 metadataString = it->get<Metadata::dabServiceNameShort>();
500 break;
501 case Metadata::dabComponentName:
502 metadataString = it->get<Metadata::dabComponentName>();
503 break;
504 case Metadata::dabComponentNameShort:
505 metadataString = it->get<Metadata::dabComponentNameShort>();
506 break;
507 default:
508 LOG(ERROR) << "Metadata " << it->toString() << " is not converted.";
509 return std::nullopt;
510 }
511 return metadataString;
512}
513
Weilin Xu25409e52023-09-06 10:36:24 -0700514ProgramIdentifier makeHdRadioStationName(const std::string& name) {
Weilin Xub2a6ca62022-05-08 23:47:04 +0000515 constexpr size_t maxlen = 8;
516
Weilin Xu25409e52023-09-06 10:36:24 -0700517 std::string shortName;
Weilin Xub2a6ca62022-05-08 23:47:04 +0000518 shortName.reserve(maxlen);
519
520 const auto& loc = std::locale::classic();
521 for (const char& ch : name) {
522 if (!std::isalnum(ch, loc)) {
523 continue;
524 }
525 shortName.push_back(std::toupper(ch, loc));
526 if (shortName.length() >= maxlen) {
527 break;
528 }
529 }
530
531 // Short name is converted to HD_STATION_NAME by encoding each char into its ASCII value in
532 // in little-endian order. For example, "Abc" is converted to 0x434241.
533 int64_t val = 0;
534 for (auto rit = shortName.rbegin(); rit != shortName.rend(); ++rit) {
535 val <<= 8;
536 val |= static_cast<char>(*rit);
537 }
538
539 return makeIdentifier(IdentifierType::HD_STATION_NAME, val);
540}
541
Weilin Xu97203b02022-06-23 00:19:03 +0000542IdentifierType getType(int typeAsInt) {
543 return static_cast<IdentifierType>(typeAsInt);
544}
545
Weilin Xu90e39f52023-11-07 20:07:23 -0800546uint32_t getDabSId(const ProgramSelector& sel) {
547 int64_t dabSidExt = getId(sel, IdentifierType::DAB_SID_EXT, /* defaultValue */ 0);
548 return static_cast<uint32_t>(dabSidExt & 0xFFFFFFFF);
549}
550
551int getDabEccCode(const ProgramSelector& sel) {
552 int64_t dabSidExt = getId(sel, IdentifierType::DAB_SID_EXT, /* defaultValue */ 0);
553 return static_cast<uint32_t>((dabSidExt >> 32) & 0xFF);
554}
555
556int getDabSCIdS(const ProgramSelector& sel) {
557 int64_t dabSidExt = getId(sel, IdentifierType::DAB_SID_EXT, /* defaultValue */ 0);
558 return static_cast<uint32_t>((dabSidExt >> 40) & 0xF);
559}
560
Weilin Xu39dd0f82023-09-07 17:00:57 -0700561int getHdSubchannel(const ProgramSelector& sel) {
562 int64_t hdSidExt = getId(sel, IdentifierType::HD_STATION_ID_EXT, kValueForNotFoundIdentifier);
563 hdSidExt >>= 32; // Station ID number
564 return hdSidExt & 0xF; // HD Radio subchannel
565}
566
567uint32_t getHdFrequency(const ProgramSelector& sel) {
568 int64_t hdSidExt = getId(sel, IdentifierType::HD_STATION_ID_EXT, kValueForNotFoundIdentifier);
569 if (hdSidExt == kValueForNotFoundIdentifier) {
570 return kValueForNotFoundIdentifier;
571 }
572 return static_cast<uint32_t>((hdSidExt >> 36) & 0x3FFFF); // HD Radio subchannel
573}
574
575bool hasAmFmFrequency(const ProgramSelector& sel) {
576 return hasId(sel, IdentifierType::AMFM_FREQUENCY_KHZ) ||
577 sel.primaryId.type == IdentifierType::HD_STATION_ID_EXT;
578}
579
580uint32_t getAmFmFrequency(const ProgramSelector& sel) {
581 if (hasId(sel, IdentifierType::AMFM_FREQUENCY_KHZ)) {
582 return static_cast<uint32_t>(getId(sel, IdentifierType::AMFM_FREQUENCY_KHZ));
583 }
584 return getHdFrequency(sel);
585}
586
Weilin Xu67e83a32024-01-10 13:40:28 -0800587bool isValidMetadata(const Metadata& metadata) {
588 bool valid = true;
589
590 auto expect = [&valid](bool condition, const std::string& message) {
591 if (!condition) {
592 valid = false;
593 LOG(ERROR) << "metadata not valid, expected " << message;
594 }
595 };
596
597 switch (metadata.getTag()) {
598 case Metadata::rdsPty:
599 expect(metadata.get<Metadata::rdsPty>() >= 0, "RDS PTY >= 0");
600 expect(metadata.get<Metadata::rdsPty>() <= std::numeric_limits<uint8_t>::max(),
601 "8bit RDS PTY");
602 break;
603 case Metadata::rbdsPty:
604 expect(metadata.get<Metadata::rbdsPty>() >= 0, "RBDS PTY >= 0");
605 expect(metadata.get<Metadata::rbdsPty>() <= std::numeric_limits<uint8_t>::max(),
606 "8bit RBDS PTY");
607 break;
608 case Metadata::dabEnsembleNameShort:
609 expect(metadata.get<Metadata::dabEnsembleNameShort>().size() <= 8,
610 "Dab ensemble name abbreviated length <= 8");
611 break;
612 case Metadata::dabServiceNameShort:
613 expect(metadata.get<Metadata::dabServiceNameShort>().size() <= 8,
614 "Dab component name abbreviated length <= 8");
615 break;
616 case Metadata::dabComponentNameShort:
617 expect(metadata.get<Metadata::dabComponentNameShort>().size() <= 8,
618 "Dab component name abbreviated length <= 8");
619 break;
620 default:
621 break;
622 }
623 return valid;
624}
625
Weilin Xu25409e52023-09-06 10:36:24 -0700626bool parseArgInt(const std::string& s, int* out) {
Weilin Xu97203b02022-06-23 00:19:03 +0000627 return ::android::base::ParseInt(s, out);
628}
629
630bool parseArgLong(const std::string& s, long* out) {
631 return ::android::base::ParseInt(s, out);
632}
633
Weilin Xu25409e52023-09-06 10:36:24 -0700634bool parseArgBool(const std::string& s, bool* out) {
Weilin Xu97203b02022-06-23 00:19:03 +0000635 if (EqualsIgnoreCase(s, "true")) {
636 *out = true;
637 } else if (EqualsIgnoreCase(s, "false")) {
638 *out = false;
639 } else {
640 return false;
641 }
642 return true;
643}
644
Weilin Xu25409e52023-09-06 10:36:24 -0700645bool parseArgDirection(const std::string& s, bool* out) {
Weilin Xu97203b02022-06-23 00:19:03 +0000646 if (EqualsIgnoreCase(s, "up")) {
647 *out = true;
648 } else if (EqualsIgnoreCase(s, "down")) {
649 *out = false;
650 } else {
651 return false;
652 }
653 return true;
654}
655
Weilin Xu25409e52023-09-06 10:36:24 -0700656bool parseArgIdentifierTypeArray(const std::string& s, vector<IdentifierType>* out) {
657 for (const std::string& val : ::android::base::Split(s, ",")) {
Weilin Xu97203b02022-06-23 00:19:03 +0000658 int outInt;
659 if (!parseArgInt(val, &outInt)) {
660 return false;
661 }
662 out->push_back(getType(outInt));
663 }
664 return true;
665}
666
667bool parseProgramIdentifierList(const std::string& s, vector<ProgramIdentifier>* out) {
Weilin Xu25409e52023-09-06 10:36:24 -0700668 for (const std::string& idStr : ::android::base::Split(s, ",")) {
669 const vector<std::string> idStrPair = ::android::base::Split(idStr, ":");
Weilin Xu97203b02022-06-23 00:19:03 +0000670 if (idStrPair.size() != 2) {
671 return false;
672 }
673 int idType;
674 if (!parseArgInt(idStrPair[0], &idType)) {
675 return false;
676 }
677 long idVal;
678 if (!parseArgLong(idStrPair[1], &idVal)) {
679 return false;
680 }
681 ProgramIdentifier id = {getType(idType), idVal};
682 out->push_back(id);
683 }
684 return true;
685}
686
Weilin Xub2a6ca62022-05-08 23:47:04 +0000687} // namespace utils
688
689utils::IdentifierIterator begin(const ProgramSelector& sel) {
690 return utils::IdentifierIterator(sel);
691}
692
693utils::IdentifierIterator end(const ProgramSelector& sel) {
694 return utils::IdentifierIterator(sel) + 1 /* primary id */ + sel.secondaryIds.size();
695}
696
697} // namespace aidl::android::hardware::broadcastradio