1 /*
2  * Copyright (C) 2023 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.utilsV2"
18 
19 #include "broadcastradio-utils-aidl/UtilsV2.h"
20 #include "broadcastradio-utils-aidl/Utils.h"
21 
22 #include <android-base/logging.h>
23 #include <android-base/strings.h>
24 
25 namespace aidl::android::hardware::broadcastradio {
26 
27 namespace utils {
28 
isValidV2(const ProgramIdentifier & id)29 bool isValidV2(const ProgramIdentifier& id) {
30     uint64_t val = static_cast<uint64_t>(id.value);
31     bool valid = true;
32 
33     auto expect = [&valid](bool condition, const std::string& message) {
34         if (!condition) {
35             valid = false;
36             LOG(ERROR) << "identifier not valid, expected " << message;
37         }
38     };
39 
40     switch (id.type) {
41         case IdentifierType::INVALID:
42             expect(false, "IdentifierType::INVALID");
43             break;
44         case IdentifierType::DAB_FREQUENCY_KHZ:
45             expect(val > 100000u, "f > 100MHz");
46             [[fallthrough]];
47         case IdentifierType::AMFM_FREQUENCY_KHZ:
48         case IdentifierType::DRMO_FREQUENCY_KHZ:
49             expect(val > 100u, "f > 100kHz");
50             expect(val < 10000000u, "f < 10GHz");
51             break;
52         case IdentifierType::RDS_PI:
53             expect(val != 0u, "RDS PI != 0");
54             expect(val <= 0xFFFFu, "16bit id");
55             break;
56         case IdentifierType::HD_STATION_ID_EXT: {
57             uint64_t stationId = val & 0xFFFFFFFF;  // 32bit
58             val >>= 32;
59             uint64_t subchannel = val & 0xF;  // 4bit
60             val >>= 4;
61             uint64_t freq = val & 0x3FFFF;  // 18bit
62             expect(stationId != 0u, "HD station id != 0");
63             expect(subchannel < 8u, "HD subch < 8");
64             expect(freq > 100u, "f > 100kHz");
65             expect(freq < 10000000u, "f < 10GHz");
66             break;
67         }
68         case IdentifierType::HD_STATION_NAME: {
69             while (val > 0) {
70                 char ch = static_cast<char>(val & 0xFF);
71                 val >>= 8;
72                 expect((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'),
73                        "HD_STATION_NAME does not match [A-Z0-9]+");
74             }
75             break;
76         }
77         case IdentifierType::DAB_SID_EXT: {
78             uint64_t sid = val & 0xFFFFFFFF;  // 32bit
79             val >>= 32;
80             uint64_t ecc = val & 0xFF;  // 8bit
81             expect(sid != 0u, "DAB SId != 0");
82             expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
83             break;
84         }
85         case IdentifierType::DAB_ENSEMBLE:
86             expect(val != 0u, "DAB ensemble != 0");
87             expect(val <= 0xFFFFu, "16bit id");
88             break;
89         case IdentifierType::DAB_SCID:
90             expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
91             expect(val <= 0xFFFu, "12bit id");
92             break;
93         case IdentifierType::DRMO_SERVICE_ID:
94             expect(val != 0u, "DRM SId != 0");
95             expect(val <= 0xFFFFFFu, "24bit id");
96             break;
97         case IdentifierType::SXM_SERVICE_ID:
98             expect(val != 0u, "SXM SId != 0");
99             expect(val <= 0xFFFFFFFFu, "32bit id");
100             break;
101         case IdentifierType::SXM_CHANNEL:
102             expect(val < 1000u, "SXM channel < 1000");
103             break;
104         case IdentifierType::HD_STATION_LOCATION: {
105             val >>= 26;
106             uint64_t latitudeBit = val & 0x1;
107             expect(latitudeBit == 0u, "Longitude comes first");
108             val >>= 1;
109             uint64_t latitudePad = val & 0x1Fu;
110             expect(latitudePad == 0u, "Longitude padding");
111             val >>= 31;
112             uint64_t longitudeBit = val & 0x1;
113             expect(longitudeBit == 1u, "Latitude comes next");
114             val >>= 1;
115             uint64_t longitudePad = val & 0x1Fu;
116             expect(longitudePad == 0u, "Latitude padding");
117             break;
118         }
119         default:
120             expect(id.type >= IdentifierType::VENDOR_START && id.type <= IdentifierType::VENDOR_END,
121                    "Undefined identifier type");
122             break;
123     }
124 
125     return valid;
126 }
127 
isValidV2(const ProgramSelector & sel)128 bool isValidV2(const ProgramSelector& sel) {
129     if (sel.primaryId.type != IdentifierType::AMFM_FREQUENCY_KHZ &&
130         sel.primaryId.type != IdentifierType::RDS_PI &&
131         sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT &&
132         sel.primaryId.type != IdentifierType::DAB_SID_EXT &&
133         sel.primaryId.type != IdentifierType::DRMO_SERVICE_ID &&
134         sel.primaryId.type != IdentifierType::SXM_SERVICE_ID &&
135         (sel.primaryId.type < IdentifierType::VENDOR_START ||
136          sel.primaryId.type > IdentifierType::VENDOR_END)) {
137         return false;
138     }
139     for (auto it = begin(sel); it != end(sel); it++) {
140         if (!isValidV2(*it)) {
141             return false;
142         }
143     }
144     return true;
145 }
146 
isValidMetadataV2(const Metadata & metadata)147 bool isValidMetadataV2(const Metadata& metadata) {
148     if (!isValidMetadata(metadata)) {
149         return false;
150     }
151 
152     if (metadata.getTag() == Metadata::hdStationNameShort) {
153         if (metadata.get<Metadata::hdStationNameShort>().size() > 12) {
154             LOG(ERROR) << "metadata not valid, expected HD short name length <= 12";
155             return false;
156         }
157     } else if (metadata.getTag() == Metadata::hdSubChannelsAvailable) {
158         if (metadata.get<Metadata::hdSubChannelsAvailable>() < 0) {
159             LOG(ERROR) << "metadata not valid, expected HD subchannels available >= 0";
160             return false;
161         } else if (metadata.get<Metadata::hdSubChannelsAvailable>() >
162                    std::numeric_limits<uint8_t>::max()) {
163             LOG(ERROR) << "metadata not valid, expected 8bit HD subchannels available";
164             return false;
165         }
166     }
167     return true;
168 }
169 
getMetadataStringV2(const ProgramInfo & info,const Metadata::Tag & tag)170 std::optional<std::string> getMetadataStringV2(const ProgramInfo& info, const Metadata::Tag& tag) {
171     auto hasMetadataType = [tag](const Metadata& item) { return item.getTag() == tag; };
172 
173     auto it = std::find_if(info.metadata.begin(), info.metadata.end(), hasMetadataType);
174     if (it == info.metadata.end()) {
175         return std::nullopt;
176     }
177 
178     std::string metadataString;
179     switch (it->getTag()) {
180         case Metadata::rdsPs:
181             metadataString = it->get<Metadata::rdsPs>();
182             break;
183         case Metadata::rdsPty:
184             metadataString = std::to_string(it->get<Metadata::rdsPty>());
185             break;
186         case Metadata::rbdsPty:
187             metadataString = std::to_string(it->get<Metadata::rbdsPty>());
188             break;
189         case Metadata::rdsRt:
190             metadataString = it->get<Metadata::rdsRt>();
191             break;
192         case Metadata::songTitle:
193             metadataString = it->get<Metadata::songTitle>();
194             break;
195         case Metadata::songArtist:
196             metadataString = it->get<Metadata::songArtist>();
197             break;
198         case Metadata::songAlbum:
199             metadataString = it->get<Metadata::songAlbum>();
200             break;
201         case Metadata::stationIcon:
202             metadataString = std::to_string(it->get<Metadata::stationIcon>());
203             break;
204         case Metadata::albumArt:
205             metadataString = std::to_string(it->get<Metadata::albumArt>());
206             break;
207         case Metadata::programName:
208             metadataString = it->get<Metadata::programName>();
209             break;
210         case Metadata::dabEnsembleName:
211             metadataString = it->get<Metadata::dabEnsembleName>();
212             break;
213         case Metadata::dabEnsembleNameShort:
214             metadataString = it->get<Metadata::dabEnsembleNameShort>();
215             break;
216         case Metadata::dabServiceName:
217             metadataString = it->get<Metadata::dabServiceName>();
218             break;
219         case Metadata::dabServiceNameShort:
220             metadataString = it->get<Metadata::dabServiceNameShort>();
221             break;
222         case Metadata::dabComponentName:
223             metadataString = it->get<Metadata::dabComponentName>();
224             break;
225         case Metadata::dabComponentNameShort:
226             metadataString = it->get<Metadata::dabComponentNameShort>();
227             break;
228         case Metadata::genre:
229             metadataString = it->get<Metadata::genre>();
230             break;
231         case Metadata::commentShortDescription:
232             metadataString = it->get<Metadata::commentShortDescription>();
233             break;
234         case Metadata::commentActualText:
235             metadataString = it->get<Metadata::commentActualText>();
236             break;
237         case Metadata::commercial:
238             metadataString = it->get<Metadata::commercial>();
239             break;
240         case Metadata::ufids: {
241             auto& ufids = it->get<Metadata::ufids>();
242             metadataString = "[";
243             for (const auto& ufid : ufids) {
244                 metadataString += std::string(ufid) + ",";
245             }
246             if (ufids.empty()) {
247                 metadataString += "]";
248             } else {
249                 metadataString[metadataString.size() - 1] = ']';
250             }
251         } break;
252         case Metadata::hdStationNameShort:
253             metadataString = it->get<Metadata::hdStationNameShort>();
254             break;
255         case Metadata::hdStationNameLong:
256             metadataString = it->get<Metadata::hdStationNameLong>();
257             break;
258         case Metadata::hdSubChannelsAvailable:
259             metadataString = std::to_string(it->get<Metadata::hdSubChannelsAvailable>());
260             break;
261         default:
262             LOG(ERROR) << "Metadata " << it->toString() << " is not converted.";
263             return std::nullopt;
264     }
265     return metadataString;
266 }
267 
268 }  // namespace utils
269 
270 }  // namespace aidl::android::hardware::broadcastradio
271