blob: 7077be92f3d1ab26500f4dab054f87ba762a1bfe [file] [log] [blame]
Weilin Xu25409e52023-09-06 10:36:24 -07001/*
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"
Weilin Xu67e83a32024-01-10 13:40:28 -080020#include "broadcastradio-utils-aidl/Utils.h"
Weilin Xu25409e52023-09-06 10:36:24 -070021
22#include <android-base/logging.h>
23#include <android-base/strings.h>
24
25namespace aidl::android::hardware::broadcastradio {
26
27namespace utils {
28
29bool 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 uint64_t latitudeBit = val & 0x1;
106 expect(latitudeBit == 1u, "Latitude comes first");
107 val >>= 27;
108 uint64_t latitudePad = val & 0x1Fu;
109 expect(latitudePad == 0u, "Latitude padding");
110 val >>= 5;
111 uint64_t longitudeBit = val & 0x1;
112 expect(longitudeBit == 1u, "Longitude comes next");
113 val >>= 27;
114 uint64_t longitudePad = val & 0x1Fu;
115 expect(longitudePad == 0u, "Latitude padding");
116 break;
117 }
118 default:
119 expect(id.type >= IdentifierType::VENDOR_START && id.type <= IdentifierType::VENDOR_END,
120 "Undefined identifier type");
121 break;
122 }
123
124 return valid;
125}
126
127bool isValidV2(const ProgramSelector& sel) {
128 if (sel.primaryId.type != IdentifierType::AMFM_FREQUENCY_KHZ &&
129 sel.primaryId.type != IdentifierType::RDS_PI &&
130 sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT &&
131 sel.primaryId.type != IdentifierType::DAB_SID_EXT &&
132 sel.primaryId.type != IdentifierType::DRMO_SERVICE_ID &&
133 sel.primaryId.type != IdentifierType::SXM_SERVICE_ID &&
134 (sel.primaryId.type < IdentifierType::VENDOR_START ||
135 sel.primaryId.type > IdentifierType::VENDOR_END)) {
136 return false;
137 }
Weilin Xu1b6c03d2024-03-05 16:48:08 -0800138 for (auto it = begin(sel); it != end(sel); it++) {
139 if (!isValidV2(*it)) {
140 return false;
141 }
142 }
143 return true;
Weilin Xu25409e52023-09-06 10:36:24 -0700144}
145
Weilin Xu67e83a32024-01-10 13:40:28 -0800146bool isValidMetadataV2(const Metadata& metadata) {
147 if (!isValidMetadata(metadata)) {
148 return false;
149 }
Weilin Xu25409e52023-09-06 10:36:24 -0700150
Weilin Xu67e83a32024-01-10 13:40:28 -0800151 if (metadata.getTag() == Metadata::hdStationNameShort) {
152 if (metadata.get<Metadata::hdStationNameShort>().size() > 12) {
153 LOG(ERROR) << "metadata not valid, expected HD short name length <= 12";
154 return false;
155 }
156 } else if (metadata.getTag() == Metadata::hdSubChannelsAvailable) {
157 if (metadata.get<Metadata::hdSubChannelsAvailable>() < 0) {
158 LOG(ERROR) << "metadata not valid, expected HD subchannels available >= 0";
159 return false;
160 } else if (metadata.get<Metadata::hdSubChannelsAvailable>() >
161 std::numeric_limits<uint8_t>::max()) {
162 LOG(ERROR) << "metadata not valid, expected 8bit HD subchannels available";
163 return false;
164 }
165 }
166 return true;
167}
168
169std::optional<std::string> getMetadataStringV2(const ProgramInfo& info, const Metadata::Tag& tag) {
170 auto hasMetadataType = [tag](const Metadata& item) { return item.getTag() == tag; };
171
172 auto it = std::find_if(info.metadata.begin(), info.metadata.end(), hasMetadataType);
Weilin Xu25409e52023-09-06 10:36:24 -0700173 if (it == info.metadata.end()) {
174 return std::nullopt;
175 }
176
177 std::string metadataString;
178 switch (it->getTag()) {
179 case Metadata::rdsPs:
180 metadataString = it->get<Metadata::rdsPs>();
181 break;
182 case Metadata::rdsPty:
183 metadataString = std::to_string(it->get<Metadata::rdsPty>());
184 break;
185 case Metadata::rbdsPty:
186 metadataString = std::to_string(it->get<Metadata::rbdsPty>());
187 break;
188 case Metadata::rdsRt:
189 metadataString = it->get<Metadata::rdsRt>();
190 break;
191 case Metadata::songTitle:
192 metadataString = it->get<Metadata::songTitle>();
193 break;
194 case Metadata::songArtist:
195 metadataString = it->get<Metadata::songArtist>();
196 break;
197 case Metadata::songAlbum:
198 metadataString = it->get<Metadata::songAlbum>();
199 break;
200 case Metadata::stationIcon:
201 metadataString = std::to_string(it->get<Metadata::stationIcon>());
202 break;
203 case Metadata::albumArt:
204 metadataString = std::to_string(it->get<Metadata::albumArt>());
205 break;
206 case Metadata::programName:
207 metadataString = it->get<Metadata::programName>();
208 break;
209 case Metadata::dabEnsembleName:
210 metadataString = it->get<Metadata::dabEnsembleName>();
211 break;
212 case Metadata::dabEnsembleNameShort:
213 metadataString = it->get<Metadata::dabEnsembleNameShort>();
214 break;
215 case Metadata::dabServiceName:
216 metadataString = it->get<Metadata::dabServiceName>();
217 break;
218 case Metadata::dabServiceNameShort:
219 metadataString = it->get<Metadata::dabServiceNameShort>();
220 break;
221 case Metadata::dabComponentName:
222 metadataString = it->get<Metadata::dabComponentName>();
223 break;
224 case Metadata::dabComponentNameShort:
225 metadataString = it->get<Metadata::dabComponentNameShort>();
226 break;
227 case Metadata::genre:
228 metadataString = it->get<Metadata::genre>();
229 break;
230 case Metadata::commentShortDescription:
231 metadataString = it->get<Metadata::commentShortDescription>();
232 break;
233 case Metadata::commentActualText:
234 metadataString = it->get<Metadata::commentActualText>();
235 break;
236 case Metadata::commercial:
237 metadataString = it->get<Metadata::commercial>();
238 break;
239 case Metadata::ufids: {
240 auto& ufids = it->get<Metadata::ufids>();
241 metadataString = "[";
242 for (const auto& ufid : ufids) {
243 metadataString += std::string(ufid) + ",";
244 }
245 if (ufids.empty()) {
246 metadataString += "]";
247 } else {
248 metadataString[metadataString.size() - 1] = ']';
249 }
250 } break;
251 case Metadata::hdStationNameShort:
252 metadataString = it->get<Metadata::hdStationNameShort>();
253 break;
254 case Metadata::hdStationNameLong:
255 metadataString = it->get<Metadata::hdStationNameLong>();
256 break;
257 case Metadata::hdSubChannelsAvailable:
258 metadataString = std::to_string(it->get<Metadata::hdSubChannelsAvailable>());
259 break;
260 default:
261 LOG(ERROR) << "Metadata " << it->toString() << " is not converted.";
262 return std::nullopt;
263 }
264 return metadataString;
265}
266
267} // namespace utils
268
269} // namespace aidl::android::hardware::broadcastradio