• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/parseint.h>
23 #include <android-base/strings.h>
24 
25 #include <math/HashCombine.h>
26 
27 namespace aidl::android::hardware::broadcastradio {
28 
29 namespace utils {
30 
31 namespace {
32 
33 using ::android::base::EqualsIgnoreCase;
34 using ::std::vector;
35 
36 const int64_t kValueForNotFoundIdentifier = 0;
37 
bothHaveId(const ProgramSelector & a,const ProgramSelector & b,const IdentifierType & type)38 bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b, const IdentifierType& type) {
39     return hasId(a, type) && hasId(b, type);
40 }
41 
haveEqualIds(const ProgramSelector & a,const ProgramSelector & b,const IdentifierType & type)42 bool 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 
maybeGetId(const ProgramSelector & sel,const IdentifierType & type,int64_t * val)52 bool 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 
IdentifierIterator(const ProgramSelector & sel)68 IdentifierIterator::IdentifierIterator(const ProgramSelector& sel) : IdentifierIterator(sel, 0) {}
69 
IdentifierIterator(const ProgramSelector & sel,size_t pos)70 IdentifierIterator::IdentifierIterator(const ProgramSelector& sel, size_t pos)
71     : mSel(sel), mPos(pos) {}
72 
operator ++(int)73 const IdentifierIterator IdentifierIterator::operator++(int) {
74     IdentifierIterator i = *this;
75     mPos++;
76     return i;
77 }
78 
operator ++()79 IdentifierIterator& IdentifierIterator::operator++() {
80     ++mPos;
81     return *this;
82 }
83 
operator *() const84 IdentifierIterator::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 
operator ==(const IdentifierIterator & rhs) const94 bool 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 
resultToInt(Result result)104 int32_t resultToInt(Result result) {
105     return static_cast<int32_t>(result);
106 }
107 
getBand(int64_t freq)108 FrequencyBand 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 
tunesTo(const ProgramSelector & a,const ProgramSelector & b)120 bool 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;
129             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));
136         case IdentifierType::DAB_SID_EXT:
137             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;
149         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 
hasId(const ProgramSelector & sel,const IdentifierType & type)159 bool hasId(const ProgramSelector& sel, const IdentifierType& type) {
160     return maybeGetId(sel, type, /* val */ nullptr);
161 }
162 
getId(const ProgramSelector & sel,const IdentifierType & type)163 int64_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 
getId(const ProgramSelector & sel,const IdentifierType & type,int64_t defaultValue)174 int64_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 
getAllIds(const ProgramSelector & sel,const IdentifierType & type)181 vector<int64_t> getAllIds(const ProgramSelector& sel, const IdentifierType& type) {
182     vector<int64_t> 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 
isSupported(const Properties & prop,const ProgramSelector & sel)194 bool 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 
isValid(const ProgramIdentifier & id)204 bool isValid(const ProgramIdentifier& id) {
205     uint64_t val = static_cast<uint64_t>(id.value);
206     bool valid = true;
207 
208     auto expect = [&valid](bool condition, const std::string& message) {
209         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: {
232             uint64_t stationId = val & 0xFFFFFFFF;  // 32bit
233             val >>= 32;
234             uint64_t subchannel = val & 0xF;  // 4bit
235             val >>= 4;
236             uint64_t freq = val & 0x3FFFF;  // 18bit
237             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: {
253             uint64_t sid = val & 0xFFFFFFFF;  // 32bit
254             val >>= 32;
255             uint64_t ecc = val & 0xFF;  // 8bit
256             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;
279         default:
280             expect(id.type >= IdentifierType::VENDOR_START && id.type <= IdentifierType::VENDOR_END,
281                    "Undefined identifier type");
282             break;
283     }
284 
285     return valid;
286 }
287 
isValid(const ProgramSelector & sel)288 bool isValid(const ProgramSelector& sel) {
289     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     }
299     for (auto it = begin(sel); it != end(sel); it++) {
300         if (!isValid(*it)) {
301             return false;
302         }
303     }
304     return true;
305 }
306 
makeIdentifier(IdentifierType type,int64_t value)307 ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
308     return {type, value};
309 }
310 
makeSelectorAmfm(uint32_t frequency)311 ProgramSelector makeSelectorAmfm(uint32_t frequency) {
312     ProgramSelector sel = {};
313     sel.primaryId = makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, frequency);
314     return sel;
315 }
316 
makeSelectorDab(uint64_t sidExt)317 ProgramSelector makeSelectorDab(uint64_t sidExt) {
318     ProgramSelector sel = {};
319     sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
320     return sel;
321 }
322 
makeSelectorHd(uint64_t stationId,uint64_t subChannel,uint64_t frequency)323 ProgramSelector 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 
makeSelectorDab(uint64_t sidExt,uint32_t ensemble,uint64_t freq)330 ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq) {
331     ProgramSelector sel = {};
332     sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
333     vector<ProgramIdentifier> secondaryIds = {
334             makeIdentifier(IdentifierType::DAB_ENSEMBLE, ensemble),
335             makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq)};
336     sel.secondaryIds = std::move(secondaryIds);
337     return sel;
338 }
339 
satisfies(const ProgramFilter & filter,const ProgramSelector & sel)340 bool 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 
360     return true;
361 }
362 
operator ()(const ProgramSelector & lhs,const ProgramSelector & rhs) const363 bool 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 
operator ()(const ProgramInfo & lhs,const ProgramInfo & rhs) const408 bool ProgramInfoComparator::operator()(const ProgramInfo& lhs, const ProgramInfo& rhs) const {
409     return ProgramSelectorComparator()(lhs.selector, rhs.selector);
410 }
411 
operator ()(const ProgramInfo & info) const412 size_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 
operator ()(const ProgramInfo & info1,const ProgramInfo & info2) const423 bool 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 
updateProgramList(const ProgramListChunk & chunk,ProgramInfoSet * list)429 void 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 
getMetadataString(const ProgramInfo & info,const Metadata::Tag & tag)449 std::optional<std::string> getMetadataString(const ProgramInfo& info, const Metadata::Tag& tag) {
450     auto hasMetadataType = [tag](const Metadata& item) { return item.getTag() == tag; };
451 
452     auto it = std::find_if(info.metadata.begin(), info.metadata.end(), hasMetadataType);
453     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 
makeHdRadioStationName(const std::string & name)514 ProgramIdentifier makeHdRadioStationName(const std::string& name) {
515     constexpr size_t maxlen = 8;
516 
517     std::string shortName;
518     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 
getType(int typeAsInt)542 IdentifierType getType(int typeAsInt) {
543     return static_cast<IdentifierType>(typeAsInt);
544 }
545 
getDabSId(const ProgramSelector & sel)546 uint32_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 
getDabEccCode(const ProgramSelector & sel)551 int 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 
getDabSCIdS(const ProgramSelector & sel)556 int 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 
getHdSubchannel(const ProgramSelector & sel)561 int 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 
getHdFrequency(const ProgramSelector & sel)567 uint32_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 
hasAmFmFrequency(const ProgramSelector & sel)575 bool hasAmFmFrequency(const ProgramSelector& sel) {
576     return hasId(sel, IdentifierType::AMFM_FREQUENCY_KHZ) ||
577            sel.primaryId.type == IdentifierType::HD_STATION_ID_EXT;
578 }
579 
getAmFmFrequency(const ProgramSelector & sel)580 uint32_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 
isValidMetadata(const Metadata & metadata)587 bool 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 
parseArgInt(const std::string & s,int * out)626 bool parseArgInt(const std::string& s, int* out) {
627     return ::android::base::ParseInt(s, out);
628 }
629 
parseArgLong(const std::string & s,long * out)630 bool parseArgLong(const std::string& s, long* out) {
631     return ::android::base::ParseInt(s, out);
632 }
633 
parseArgBool(const std::string & s,bool * out)634 bool parseArgBool(const std::string& s, bool* out) {
635     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 
parseArgDirection(const std::string & s,bool * out)645 bool parseArgDirection(const std::string& s, bool* out) {
646     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 
parseArgIdentifierTypeArray(const std::string & s,vector<IdentifierType> * out)656 bool parseArgIdentifierTypeArray(const std::string& s, vector<IdentifierType>* out) {
657     for (const std::string& val : ::android::base::Split(s, ",")) {
658         int outInt;
659         if (!parseArgInt(val, &outInt)) {
660             return false;
661         }
662         out->push_back(getType(outInt));
663     }
664     return true;
665 }
666 
parseProgramIdentifierList(const std::string & s,vector<ProgramIdentifier> * out)667 bool parseProgramIdentifierList(const std::string& s, vector<ProgramIdentifier>* out) {
668     for (const std::string& idStr : ::android::base::Split(s, ",")) {
669         const vector<std::string> idStrPair = ::android::base::Split(idStr, ":");
670         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 
687 }  // namespace utils
688 
begin(const ProgramSelector & sel)689 utils::IdentifierIterator begin(const ProgramSelector& sel) {
690     return utils::IdentifierIterator(sel);
691 }
692 
end(const ProgramSelector & sel)693 utils::IdentifierIterator end(const ProgramSelector& sel) {
694     return utils::IdentifierIterator(sel) + 1 /* primary id */ + sel.secondaryIds.size();
695 }
696 
697 }  // namespace aidl::android::hardware::broadcastradio
698