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