xref: /aosp_15_r20/hardware/interfaces/broadcastradio/common/utilsaidl/src/Utils.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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