• 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::string;
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 
getHdSubchannel(const ProgramSelector & sel)53 int getHdSubchannel(const ProgramSelector& sel) {
54     int64_t hdSidExt = getId(sel, IdentifierType::HD_STATION_ID_EXT, /* defaultValue */ 0);
55     hdSidExt >>= 32;        // Station ID number
56     return hdSidExt & 0xF;  // HD Radio subchannel
57 }
58 
maybeGetId(const ProgramSelector & sel,const IdentifierType & type,int64_t * val)59 bool maybeGetId(const ProgramSelector& sel, const IdentifierType& type, int64_t* val) {
60     // iterate through primaryId and secondaryIds
61     for (auto it = begin(sel); it != end(sel); it++) {
62         if (it->type == type) {
63             if (val != nullptr) {
64                 *val = it->value;
65             }
66             return true;
67         }
68     }
69 
70     return false;
71 }
72 
73 }  // namespace
74 
IdentifierIterator(const ProgramSelector & sel)75 IdentifierIterator::IdentifierIterator(const ProgramSelector& sel) : IdentifierIterator(sel, 0) {}
76 
IdentifierIterator(const ProgramSelector & sel,size_t pos)77 IdentifierIterator::IdentifierIterator(const ProgramSelector& sel, size_t pos)
78     : mSel(sel), mPos(pos) {}
79 
operator ++(int)80 const IdentifierIterator IdentifierIterator::operator++(int) {
81     IdentifierIterator i = *this;
82     mPos++;
83     return i;
84 }
85 
operator ++()86 IdentifierIterator& IdentifierIterator::operator++() {
87     ++mPos;
88     return *this;
89 }
90 
operator *() const91 IdentifierIterator::refType IdentifierIterator::operator*() const {
92     if (mPos == 0) {
93         return getSelector().primaryId;
94     }
95 
96     // mPos is 1-based for secondary identifiers
97     DCHECK(mPos <= getSelector().secondaryIds.size());
98     return getSelector().secondaryIds[mPos - 1];
99 }
100 
operator ==(const IdentifierIterator & rhs) const101 bool IdentifierIterator::operator==(const IdentifierIterator& rhs) const {
102     // Check, if both iterators points at the same selector.
103     if (reinterpret_cast<intptr_t>(&getSelector()) !=
104         reinterpret_cast<intptr_t>(&rhs.getSelector())) {
105         return false;
106     }
107 
108     return mPos == rhs.mPos;
109 }
110 
resultToInt(Result result)111 int32_t resultToInt(Result result) {
112     return static_cast<int32_t>(result);
113 }
114 
getBand(int64_t freq)115 FrequencyBand getBand(int64_t freq) {
116     // keep in sync with
117     // frameworks/base/services/core/java/com/android/server/broadcastradio/aidl/Utils.java
118     if (freq < 30) return FrequencyBand::UNKNOWN;
119     if (freq < 500) return FrequencyBand::AM_LW;
120     if (freq < 1705) return FrequencyBand::AM_MW;
121     if (freq < 30000) return FrequencyBand::AM_SW;
122     if (freq < 60000) return FrequencyBand::UNKNOWN;
123     if (freq < 110000) return FrequencyBand::FM;
124     return FrequencyBand::UNKNOWN;
125 }
126 
tunesTo(const ProgramSelector & a,const ProgramSelector & b)127 bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
128     IdentifierType type = b.primaryId.type;
129 
130     switch (type) {
131         case IdentifierType::HD_STATION_ID_EXT:
132         case IdentifierType::RDS_PI:
133         case IdentifierType::AMFM_FREQUENCY_KHZ:
134             if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
135             if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
136             return getHdSubchannel(b) == 0 &&
137                    haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY_KHZ);
138         case IdentifierType::DAB_SID_EXT:
139             if (!haveEqualIds(a, b, IdentifierType::DAB_SID_EXT)) {
140                 return false;
141             }
142             if (hasId(a, IdentifierType::DAB_ENSEMBLE) &&
143                 !haveEqualIds(a, b, IdentifierType::DAB_ENSEMBLE)) {
144                 return false;
145             }
146             if (hasId(a, IdentifierType::DAB_FREQUENCY_KHZ) &&
147                 !haveEqualIds(a, b, IdentifierType::DAB_FREQUENCY_KHZ)) {
148                 return false;
149             }
150             return true;
151         case IdentifierType::DRMO_SERVICE_ID:
152             return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
153         case IdentifierType::SXM_SERVICE_ID:
154             return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
155         default:  // includes all vendor types
156             LOG(WARNING) << "unsupported program type: " << toString(type);
157             return false;
158     }
159 }
160 
hasId(const ProgramSelector & sel,const IdentifierType & type)161 bool hasId(const ProgramSelector& sel, const IdentifierType& type) {
162     return maybeGetId(sel, type, /* val */ nullptr);
163 }
164 
getId(const ProgramSelector & sel,const IdentifierType & type)165 int64_t getId(const ProgramSelector& sel, const IdentifierType& type) {
166     int64_t val;
167 
168     if (maybeGetId(sel, type, &val)) {
169         return val;
170     }
171 
172     LOG(WARNING) << "identifier not found: " << toString(type);
173     return kValueForNotFoundIdentifier;
174 }
175 
getId(const ProgramSelector & sel,const IdentifierType & type,int64_t defaultValue)176 int64_t getId(const ProgramSelector& sel, const IdentifierType& type, int64_t defaultValue) {
177     if (!hasId(sel, type)) {
178         return defaultValue;
179     }
180     return getId(sel, type);
181 }
182 
getAllIds(const ProgramSelector & sel,const IdentifierType & type)183 vector<int> getAllIds(const ProgramSelector& sel, const IdentifierType& type) {
184     vector<int> ret;
185 
186     // iterate through primaryId and secondaryIds
187     for (auto it = begin(sel); it != end(sel); it++) {
188         if (it->type == type) {
189             ret.push_back(it->value);
190         }
191     }
192 
193     return ret;
194 }
195 
isSupported(const Properties & prop,const ProgramSelector & sel)196 bool isSupported(const Properties& prop, const ProgramSelector& sel) {
197     for (auto it = prop.supportedIdentifierTypes.begin(); it != prop.supportedIdentifierTypes.end();
198          it++) {
199         if (hasId(sel, *it)) {
200             return true;
201         }
202     }
203     return false;
204 }
205 
isValid(const ProgramIdentifier & id)206 bool isValid(const ProgramIdentifier& id) {
207     uint64_t val = static_cast<uint64_t>(id.value);
208     bool valid = true;
209 
210     auto expect = [&valid](bool condition, const string& message) {
211         if (!condition) {
212             valid = false;
213             LOG(ERROR) << "identifier not valid, expected " << message;
214         }
215     };
216 
217     switch (id.type) {
218         case IdentifierType::INVALID:
219             expect(false, "IdentifierType::INVALID");
220             break;
221         case IdentifierType::DAB_FREQUENCY_KHZ:
222             expect(val > 100000u, "f > 100MHz");
223             [[fallthrough]];
224         case IdentifierType::AMFM_FREQUENCY_KHZ:
225         case IdentifierType::DRMO_FREQUENCY_KHZ:
226             expect(val > 100u, "f > 100kHz");
227             expect(val < 10000000u, "f < 10GHz");
228             break;
229         case IdentifierType::RDS_PI:
230             expect(val != 0u, "RDS PI != 0");
231             expect(val <= 0xFFFFu, "16bit id");
232             break;
233         case IdentifierType::HD_STATION_ID_EXT: {
234             uint64_t stationId = val & 0xFFFFFFFF;  // 32bit
235             val >>= 32;
236             uint64_t subchannel = val & 0xF;  // 4bit
237             val >>= 4;
238             uint64_t freq = val & 0x3FFFF;  // 18bit
239             expect(stationId != 0u, "HD station id != 0");
240             expect(subchannel < 8u, "HD subch < 8");
241             expect(freq > 100u, "f > 100kHz");
242             expect(freq < 10000000u, "f < 10GHz");
243             break;
244         }
245         case IdentifierType::HD_STATION_NAME: {
246             while (val > 0) {
247                 char ch = static_cast<char>(val & 0xFF);
248                 val >>= 8;
249                 expect((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'),
250                        "HD_STATION_NAME does not match [A-Z0-9]+");
251             }
252             break;
253         }
254         case IdentifierType::DAB_SID_EXT: {
255             uint64_t sid = val & 0xFFFFFFFF;  // 32bit
256             val >>= 32;
257             uint64_t ecc = val & 0xFF;  // 8bit
258             expect(sid != 0u, "DAB SId != 0");
259             expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
260             break;
261         }
262         case IdentifierType::DAB_ENSEMBLE:
263             expect(val != 0u, "DAB ensemble != 0");
264             expect(val <= 0xFFFFu, "16bit id");
265             break;
266         case IdentifierType::DAB_SCID:
267             expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
268             expect(val <= 0xFFFu, "12bit id");
269             break;
270         case IdentifierType::DRMO_SERVICE_ID:
271             expect(val != 0u, "DRM SId != 0");
272             expect(val <= 0xFFFFFFu, "24bit id");
273             break;
274         case IdentifierType::SXM_SERVICE_ID:
275             expect(val != 0u, "SXM SId != 0");
276             expect(val <= 0xFFFFFFFFu, "32bit id");
277             break;
278         case IdentifierType::SXM_CHANNEL:
279             expect(val < 1000u, "SXM channel < 1000");
280             break;
281         case IdentifierType::VENDOR_START:
282         case IdentifierType::VENDOR_END:
283             // skip
284             break;
285     }
286 
287     return valid;
288 }
289 
isValid(const ProgramSelector & sel)290 bool isValid(const ProgramSelector& sel) {
291     if (sel.primaryId.type != IdentifierType::AMFM_FREQUENCY_KHZ &&
292         sel.primaryId.type != IdentifierType::RDS_PI &&
293         sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT &&
294         sel.primaryId.type != IdentifierType::DAB_SID_EXT &&
295         sel.primaryId.type != IdentifierType::DRMO_SERVICE_ID &&
296         sel.primaryId.type != IdentifierType::SXM_SERVICE_ID &&
297         (sel.primaryId.type < IdentifierType::VENDOR_START ||
298          sel.primaryId.type > IdentifierType::VENDOR_END)) {
299         return false;
300     }
301     return isValid(sel.primaryId);
302 }
303 
makeIdentifier(IdentifierType type,int64_t value)304 ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
305     return {type, value};
306 }
307 
makeSelectorAmfm(uint32_t frequency)308 ProgramSelector makeSelectorAmfm(uint32_t frequency) {
309     ProgramSelector sel = {};
310     sel.primaryId = makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, frequency);
311     return sel;
312 }
313 
makeSelectorDab(uint64_t sidExt)314 ProgramSelector makeSelectorDab(uint64_t sidExt) {
315     ProgramSelector sel = {};
316     sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
317     return sel;
318 }
319 
makeSelectorDab(uint64_t sidExt,uint32_t ensemble,uint64_t freq)320 ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq) {
321     ProgramSelector sel = {};
322     sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
323     vector<ProgramIdentifier> secondaryIds = {
324             makeIdentifier(IdentifierType::DAB_ENSEMBLE, ensemble),
325             makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq)};
326     sel.secondaryIds = std::move(secondaryIds);
327     return sel;
328 }
329 
satisfies(const ProgramFilter & filter,const ProgramSelector & sel)330 bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel) {
331     if (filter.identifierTypes.size() > 0) {
332         auto typeEquals = [](const ProgramIdentifier& id, IdentifierType type) {
333             return id.type == type;
334         };
335         auto it = std::find_first_of(begin(sel), end(sel), filter.identifierTypes.begin(),
336                                      filter.identifierTypes.end(), typeEquals);
337         if (it == end(sel)) {
338             return false;
339         }
340     }
341 
342     if (filter.identifiers.size() > 0) {
343         auto it = std::find_first_of(begin(sel), end(sel), filter.identifiers.begin(),
344                                      filter.identifiers.end());
345         if (it == end(sel)) {
346             return false;
347         }
348     }
349 
350     return true;
351 }
352 
operator ()(const ProgramInfo & info) const353 size_t ProgramInfoHasher::operator()(const ProgramInfo& info) const {
354     const ProgramIdentifier& id = info.selector.primaryId;
355 
356     // This is not the best hash implementation, but good enough for default HAL
357     // implementation and tests.
358     size_t h = 0;
359     ::android::hashCombineSingle(h, id.type);
360     ::android::hashCombineSingle(h, id.value);
361     return h;
362 }
363 
operator ()(const ProgramInfo & info1,const ProgramInfo & info2) const364 bool ProgramInfoKeyEqual::operator()(const ProgramInfo& info1, const ProgramInfo& info2) const {
365     const ProgramIdentifier& id1 = info1.selector.primaryId;
366     const ProgramIdentifier& id2 = info2.selector.primaryId;
367     return id1.type == id2.type && id1.value == id2.value;
368 }
369 
updateProgramList(const ProgramListChunk & chunk,ProgramInfoSet * list)370 void updateProgramList(const ProgramListChunk& chunk, ProgramInfoSet* list) {
371     if (chunk.purge) {
372         list->clear();
373     }
374 
375     list->insert(chunk.modified.begin(), chunk.modified.end());
376 
377     if (!chunk.removed.has_value()) {
378         return;
379     }
380 
381     for (auto& id : chunk.removed.value()) {
382         if (id.has_value()) {
383             ProgramInfo info = {};
384             info.selector.primaryId = id.value();
385             list->erase(info);
386         }
387     }
388 }
389 
getMetadataString(const ProgramInfo & info,const Metadata::Tag & tag)390 std::optional<std::string> getMetadataString(const ProgramInfo& info, const Metadata::Tag& tag) {
391     auto isRdsPs = [tag](const Metadata& item) { return item.getTag() == tag; };
392 
393     auto it = std::find_if(info.metadata.begin(), info.metadata.end(), isRdsPs);
394     if (it == info.metadata.end()) {
395         return std::nullopt;
396     }
397 
398     std::string metadataString;
399     switch (it->getTag()) {
400         case Metadata::rdsPs:
401             metadataString = it->get<Metadata::rdsPs>();
402             break;
403         case Metadata::rdsPty:
404             metadataString = std::to_string(it->get<Metadata::rdsPty>());
405             break;
406         case Metadata::rbdsPty:
407             metadataString = std::to_string(it->get<Metadata::rbdsPty>());
408             break;
409         case Metadata::rdsRt:
410             metadataString = it->get<Metadata::rdsRt>();
411             break;
412         case Metadata::songTitle:
413             metadataString = it->get<Metadata::songTitle>();
414             break;
415         case Metadata::songArtist:
416             metadataString = it->get<Metadata::songArtist>();
417             break;
418         case Metadata::songAlbum:
419             metadataString = it->get<Metadata::songAlbum>();
420             break;
421         case Metadata::stationIcon:
422             metadataString = std::to_string(it->get<Metadata::stationIcon>());
423             break;
424         case Metadata::albumArt:
425             metadataString = std::to_string(it->get<Metadata::albumArt>());
426             break;
427         case Metadata::programName:
428             metadataString = it->get<Metadata::programName>();
429             break;
430         case Metadata::dabEnsembleName:
431             metadataString = it->get<Metadata::dabEnsembleName>();
432             break;
433         case Metadata::dabEnsembleNameShort:
434             metadataString = it->get<Metadata::dabEnsembleNameShort>();
435             break;
436         case Metadata::dabServiceName:
437             metadataString = it->get<Metadata::dabServiceName>();
438             break;
439         case Metadata::dabServiceNameShort:
440             metadataString = it->get<Metadata::dabServiceNameShort>();
441             break;
442         case Metadata::dabComponentName:
443             metadataString = it->get<Metadata::dabComponentName>();
444             break;
445         case Metadata::dabComponentNameShort:
446             metadataString = it->get<Metadata::dabComponentNameShort>();
447             break;
448         default:
449             LOG(ERROR) << "Metadata " << it->toString() << " is not converted.";
450             return std::nullopt;
451     }
452     return metadataString;
453 }
454 
makeHdRadioStationName(const string & name)455 ProgramIdentifier makeHdRadioStationName(const string& name) {
456     constexpr size_t maxlen = 8;
457 
458     string shortName;
459     shortName.reserve(maxlen);
460 
461     const auto& loc = std::locale::classic();
462     for (const char& ch : name) {
463         if (!std::isalnum(ch, loc)) {
464             continue;
465         }
466         shortName.push_back(std::toupper(ch, loc));
467         if (shortName.length() >= maxlen) {
468             break;
469         }
470     }
471 
472     // Short name is converted to HD_STATION_NAME by encoding each char into its ASCII value in
473     // in little-endian order. For example, "Abc" is converted to 0x434241.
474     int64_t val = 0;
475     for (auto rit = shortName.rbegin(); rit != shortName.rend(); ++rit) {
476         val <<= 8;
477         val |= static_cast<char>(*rit);
478     }
479 
480     return makeIdentifier(IdentifierType::HD_STATION_NAME, val);
481 }
482 
getType(int typeAsInt)483 IdentifierType getType(int typeAsInt) {
484     return static_cast<IdentifierType>(typeAsInt);
485 }
486 
parseArgInt(const string & s,int * out)487 bool parseArgInt(const string& s, int* out) {
488     return ::android::base::ParseInt(s, out);
489 }
490 
parseArgLong(const std::string & s,long * out)491 bool parseArgLong(const std::string& s, long* out) {
492     return ::android::base::ParseInt(s, out);
493 }
494 
parseArgBool(const string & s,bool * out)495 bool parseArgBool(const string& s, bool* out) {
496     if (EqualsIgnoreCase(s, "true")) {
497         *out = true;
498     } else if (EqualsIgnoreCase(s, "false")) {
499         *out = false;
500     } else {
501         return false;
502     }
503     return true;
504 }
505 
parseArgDirection(const string & s,bool * out)506 bool parseArgDirection(const string& s, bool* out) {
507     if (EqualsIgnoreCase(s, "up")) {
508         *out = true;
509     } else if (EqualsIgnoreCase(s, "down")) {
510         *out = false;
511     } else {
512         return false;
513     }
514     return true;
515 }
516 
parseArgIdentifierTypeArray(const string & s,vector<IdentifierType> * out)517 bool parseArgIdentifierTypeArray(const string& s, vector<IdentifierType>* out) {
518     for (const string& val : ::android::base::Split(s, ",")) {
519         int outInt;
520         if (!parseArgInt(val, &outInt)) {
521             return false;
522         }
523         out->push_back(getType(outInt));
524     }
525     return true;
526 }
527 
parseProgramIdentifierList(const std::string & s,vector<ProgramIdentifier> * out)528 bool parseProgramIdentifierList(const std::string& s, vector<ProgramIdentifier>* out) {
529     for (const string& idStr : ::android::base::Split(s, ",")) {
530         const vector<string> idStrPair = ::android::base::Split(idStr, ":");
531         if (idStrPair.size() != 2) {
532             return false;
533         }
534         int idType;
535         if (!parseArgInt(idStrPair[0], &idType)) {
536             return false;
537         }
538         long idVal;
539         if (!parseArgLong(idStrPair[1], &idVal)) {
540             return false;
541         }
542         ProgramIdentifier id = {getType(idType), idVal};
543         out->push_back(id);
544     }
545     return true;
546 }
547 
548 }  // namespace utils
549 
begin(const ProgramSelector & sel)550 utils::IdentifierIterator begin(const ProgramSelector& sel) {
551     return utils::IdentifierIterator(sel);
552 }
553 
end(const ProgramSelector & sel)554 utils::IdentifierIterator end(const ProgramSelector& sel) {
555     return utils::IdentifierIterator(sel) + 1 /* primary id */ + sel.secondaryIds.size();
556 }
557 
558 }  // namespace aidl::android::hardware::broadcastradio
559