blob: 6c75759f07be0f4d6d3008db3994756c4aca2892 [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 }
138 return isValidV2(sel.primaryId);
139}
140
Weilin Xu67e83a32024-01-10 13:40:28 -0800141bool isValidMetadataV2(const Metadata& metadata) {
142 if (!isValidMetadata(metadata)) {
143 return false;
144 }
Weilin Xu25409e52023-09-06 10:36:24 -0700145
Weilin Xu67e83a32024-01-10 13:40:28 -0800146 if (metadata.getTag() == Metadata::hdStationNameShort) {
147 if (metadata.get<Metadata::hdStationNameShort>().size() > 12) {
148 LOG(ERROR) << "metadata not valid, expected HD short name length <= 12";
149 return false;
150 }
151 } else if (metadata.getTag() == Metadata::hdSubChannelsAvailable) {
152 if (metadata.get<Metadata::hdSubChannelsAvailable>() < 0) {
153 LOG(ERROR) << "metadata not valid, expected HD subchannels available >= 0";
154 return false;
155 } else if (metadata.get<Metadata::hdSubChannelsAvailable>() >
156 std::numeric_limits<uint8_t>::max()) {
157 LOG(ERROR) << "metadata not valid, expected 8bit HD subchannels available";
158 return false;
159 }
160 }
161 return true;
162}
163
164std::optional<std::string> getMetadataStringV2(const ProgramInfo& info, const Metadata::Tag& tag) {
165 auto hasMetadataType = [tag](const Metadata& item) { return item.getTag() == tag; };
166
167 auto it = std::find_if(info.metadata.begin(), info.metadata.end(), hasMetadataType);
Weilin Xu25409e52023-09-06 10:36:24 -0700168 if (it == info.metadata.end()) {
169 return std::nullopt;
170 }
171
172 std::string metadataString;
173 switch (it->getTag()) {
174 case Metadata::rdsPs:
175 metadataString = it->get<Metadata::rdsPs>();
176 break;
177 case Metadata::rdsPty:
178 metadataString = std::to_string(it->get<Metadata::rdsPty>());
179 break;
180 case Metadata::rbdsPty:
181 metadataString = std::to_string(it->get<Metadata::rbdsPty>());
182 break;
183 case Metadata::rdsRt:
184 metadataString = it->get<Metadata::rdsRt>();
185 break;
186 case Metadata::songTitle:
187 metadataString = it->get<Metadata::songTitle>();
188 break;
189 case Metadata::songArtist:
190 metadataString = it->get<Metadata::songArtist>();
191 break;
192 case Metadata::songAlbum:
193 metadataString = it->get<Metadata::songAlbum>();
194 break;
195 case Metadata::stationIcon:
196 metadataString = std::to_string(it->get<Metadata::stationIcon>());
197 break;
198 case Metadata::albumArt:
199 metadataString = std::to_string(it->get<Metadata::albumArt>());
200 break;
201 case Metadata::programName:
202 metadataString = it->get<Metadata::programName>();
203 break;
204 case Metadata::dabEnsembleName:
205 metadataString = it->get<Metadata::dabEnsembleName>();
206 break;
207 case Metadata::dabEnsembleNameShort:
208 metadataString = it->get<Metadata::dabEnsembleNameShort>();
209 break;
210 case Metadata::dabServiceName:
211 metadataString = it->get<Metadata::dabServiceName>();
212 break;
213 case Metadata::dabServiceNameShort:
214 metadataString = it->get<Metadata::dabServiceNameShort>();
215 break;
216 case Metadata::dabComponentName:
217 metadataString = it->get<Metadata::dabComponentName>();
218 break;
219 case Metadata::dabComponentNameShort:
220 metadataString = it->get<Metadata::dabComponentNameShort>();
221 break;
222 case Metadata::genre:
223 metadataString = it->get<Metadata::genre>();
224 break;
225 case Metadata::commentShortDescription:
226 metadataString = it->get<Metadata::commentShortDescription>();
227 break;
228 case Metadata::commentActualText:
229 metadataString = it->get<Metadata::commentActualText>();
230 break;
231 case Metadata::commercial:
232 metadataString = it->get<Metadata::commercial>();
233 break;
234 case Metadata::ufids: {
235 auto& ufids = it->get<Metadata::ufids>();
236 metadataString = "[";
237 for (const auto& ufid : ufids) {
238 metadataString += std::string(ufid) + ",";
239 }
240 if (ufids.empty()) {
241 metadataString += "]";
242 } else {
243 metadataString[metadataString.size() - 1] = ']';
244 }
245 } break;
246 case Metadata::hdStationNameShort:
247 metadataString = it->get<Metadata::hdStationNameShort>();
248 break;
249 case Metadata::hdStationNameLong:
250 metadataString = it->get<Metadata::hdStationNameLong>();
251 break;
252 case Metadata::hdSubChannelsAvailable:
253 metadataString = std::to_string(it->get<Metadata::hdSubChannelsAvailable>());
254 break;
255 default:
256 LOG(ERROR) << "Metadata " << it->toString() << " is not converted.";
257 return std::nullopt;
258 }
259 return metadataString;
260}
261
262} // namespace utils
263
264} // namespace aidl::android::hardware::broadcastradio