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