Skip to content

Commit 24ee325

Browse files
committed
Merge branch 'release/2.2.2_xcode16' of https://github.com/kimbely0320/mamba into release/2.2.2_xcode16
2 parents 18535c2 + 2f3f81e commit 24ee325

18 files changed

+1889
-201
lines changed

.github/workflows/build-and-test.yml

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: Build and test
2+
3+
on:
4+
pull_request:
5+
branches: [ "develop", "develop_1.x", "main", "main_1.x" ]
6+
7+
jobs:
8+
define-ios-device:
9+
name: Get iOS simulator device to run iOS tests on
10+
runs-on: macos-latest
11+
outputs:
12+
device: ${{ steps.ios.outputs.device }}
13+
steps:
14+
- id: ios
15+
run: echo "device=`xcrun xctrace list devices 2>&1 | grep -oE 'iPhone.*?[^\(]+' | head -1 | awk '{$1=$1;print}' | sed -e "s/ Simulator$//"`" >> "$GITHUB_OUTPUT"
16+
17+
build:
18+
name: Build and Test mamba and mambaTVOS
19+
runs-on: macos-latest
20+
needs: define-ios-device
21+
strategy:
22+
matrix:
23+
target:
24+
- scheme: mamba
25+
platform: iOS Simulator
26+
device: ${{ needs.define-ios-device.outputs.device }}
27+
- scheme: mambaTVOS
28+
platform: tvOS Simulator
29+
device: Apple TV
30+
steps:
31+
- name: Checkout
32+
uses: actions/checkout@v4
33+
- name: Build
34+
env:
35+
scheme: ${{ matrix.target.scheme }}
36+
platform: ${{ matrix.target.platform }}
37+
device: ${{ matrix.target.device }}
38+
run: |
39+
echo "scheme = $scheme"
40+
echo "platform = $platform"
41+
echo "device = $device"
42+
xcodebuild build-for-testing -scheme "$scheme" -"workspace" "mamba.xcworkspace" -destination "platform=$platform,name=$device"
43+
- name: Test
44+
env:
45+
scheme: ${{ matrix.target.scheme }}
46+
platform: ${{ matrix.target.platform }}
47+
device: ${{ matrix.target.device }}
48+
run: |
49+
echo "scheme = $scheme"
50+
echo "platform = $platform"
51+
echo "device = $device"
52+
xcodebuild test-without-building -scheme "$scheme" -"workspace" "mamba.xcworkspace" -destination "platform=$platform,name=$device"

mamba.xcodeproj/project.pbxproj

+41-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@
88

99
/* Begin PBXBuildFile section */
1010
01CD2E7A1DE4D46F002510E7 /* EXT_X_MAPTagParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01CD2E791DE4D46F002510E7 /* EXT_X_MAPTagParserTests.swift */; };
11+
1447582D2C83C20800D12CCD /* EXT_X_SESSION_KEYValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1447582C2C83C20800D12CCD /* EXT_X_SESSION_KEYValidator.swift */; };
12+
1447582E2C83C20800D12CCD /* EXT_X_SESSION_KEYValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1447582C2C83C20800D12CCD /* EXT_X_SESSION_KEYValidator.swift */; };
13+
1447582F2C83C20800D12CCD /* EXT_X_SESSION_KEYValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1447582C2C83C20800D12CCD /* EXT_X_SESSION_KEYValidator.swift */; };
14+
144758312C83C72B00D12CCD /* EXT_X_SESSION_DATATagValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144758302C83C72B00D12CCD /* EXT_X_SESSION_DATATagValidator.swift */; };
15+
144758322C83C72B00D12CCD /* EXT_X_SESSION_DATATagValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144758302C83C72B00D12CCD /* EXT_X_SESSION_DATATagValidator.swift */; };
16+
144758332C83C72B00D12CCD /* EXT_X_SESSION_DATATagValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144758302C83C72B00D12CCD /* EXT_X_SESSION_DATATagValidator.swift */; };
17+
144758352C83D23100D12CCD /* EXT_X_SESSION_DATAPlaylistValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144758342C83D23100D12CCD /* EXT_X_SESSION_DATAPlaylistValidator.swift */; };
18+
144758362C83D23100D12CCD /* EXT_X_SESSION_DATAPlaylistValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144758342C83D23100D12CCD /* EXT_X_SESSION_DATAPlaylistValidator.swift */; };
19+
144758372C83D23100D12CCD /* EXT_X_SESSION_DATAPlaylistValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144758342C83D23100D12CCD /* EXT_X_SESSION_DATAPlaylistValidator.swift */; };
20+
144758392C8620C000D12CCD /* ChannelsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144758382C8620C000D12CCD /* ChannelsTests.swift */; };
21+
1447583A2C8620C000D12CCD /* ChannelsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144758382C8620C000D12CCD /* ChannelsTests.swift */; };
22+
1447583B2C8620C000D12CCD /* ChannelsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 144758382C8620C000D12CCD /* ChannelsTests.swift */; };
23+
1447583D2C8693E000D12CCD /* VideoLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1447583C2C8693E000D12CCD /* VideoLayoutTests.swift */; };
24+
1447583E2C8693E000D12CCD /* VideoLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1447583C2C8693E000D12CCD /* VideoLayoutTests.swift */; };
25+
1447583F2C8693E000D12CCD /* VideoLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1447583C2C8693E000D12CCD /* VideoLayoutTests.swift */; };
1126
1D28F3451EAA9E500010320B /* hls_ad_master_playlist.m3u8 in Resources */ = {isa = PBXBuildFile; fileRef = 1D28F3401EAA9E500010320B /* hls_ad_master_playlist.m3u8 */; };
1227
1D28F3461EAA9E500010320B /* hls_ad_variant_playlist.m3u8 in Resources */ = {isa = PBXBuildFile; fileRef = 1D28F3411EAA9E500010320B /* hls_ad_variant_playlist.m3u8 */; };
1328
1D28F3471EAA9E500010320B /* hls_master_playlist_sap.m3u8 in Resources */ = {isa = PBXBuildFile; fileRef = 1D28F3421EAA9E500010320B /* hls_master_playlist_sap.m3u8 */; };
@@ -635,6 +650,11 @@
635650

636651
/* Begin PBXFileReference section */
637652
01CD2E791DE4D46F002510E7 /* EXT_X_MAPTagParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EXT_X_MAPTagParserTests.swift; sourceTree = "<group>"; };
653+
1447582C2C83C20800D12CCD /* EXT_X_SESSION_KEYValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EXT_X_SESSION_KEYValidator.swift; sourceTree = "<group>"; };
654+
144758302C83C72B00D12CCD /* EXT_X_SESSION_DATATagValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EXT_X_SESSION_DATATagValidator.swift; sourceTree = "<group>"; };
655+
144758342C83D23100D12CCD /* EXT_X_SESSION_DATAPlaylistValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EXT_X_SESSION_DATAPlaylistValidator.swift; sourceTree = "<group>"; };
656+
144758382C8620C000D12CCD /* ChannelsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelsTests.swift; sourceTree = "<group>"; };
657+
1447583C2C8693E000D12CCD /* VideoLayoutTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoLayoutTests.swift; sourceTree = "<group>"; };
638658
1D28F3401EAA9E500010320B /* hls_ad_master_playlist.m3u8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = hls_ad_master_playlist.m3u8; sourceTree = "<group>"; };
639659
1D28F3411EAA9E500010320B /* hls_ad_variant_playlist.m3u8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = hls_ad_variant_playlist.m3u8; sourceTree = "<group>"; };
640660
1D28F3421EAA9E500010320B /* hls_master_playlist_sap.m3u8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = hls_master_playlist_sap.m3u8; sourceTree = "<group>"; };
@@ -930,6 +950,9 @@
930950
EC3B01A11DD4D47900B512E3 /* EXT_X_MEDIARenditionGroupNAMEValidator.swift */,
931951
EC3B01A21DD4D47900B512E3 /* EXT_X_MEDIARenditionGroupTYPEValidator.swift */,
932952
43DE4EFC1E564DBE00EEE800 /* EXT_X_MEDIARenditionINSTREAMIDValidator.swift */,
953+
144758342C83D23100D12CCD /* EXT_X_SESSION_DATAPlaylistValidator.swift */,
954+
144758302C83C72B00D12CCD /* EXT_X_SESSION_DATATagValidator.swift */,
955+
1447582C2C83C20800D12CCD /* EXT_X_SESSION_KEYValidator.swift */,
933956
43DE4EFA1E564DA300EEE800 /* EXT_X_STARTTimeOffsetValidator.swift */,
934957
EC3B01A31DD4D47900B512E3 /* EXT_X_STREAM_INFRenditionGroupValidator.swift */,
935958
EC3B01A41DD4D47900B512E3 /* EXT_X_TARGETDURATIONLengthValidator.swift */,
@@ -1318,10 +1341,12 @@
13181341
EC9BCAA21D749D8B0032BEBE /* Value Types */ = {
13191342
isa = PBXGroup;
13201343
children = (
1344+
144758382C8620C000D12CCD /* ChannelsTests.swift */,
13211345
EC7492AF1DD29F8900AF4E20 /* CodecArrayTests.swift */,
13221346
EC7492B01DD29F8900AF4E20 /* MediaTypeTests.swift */,
1323-
EC7492B21DD29F8900AF4E20 /* ResolutionTests.swift */,
13241347
EC7492B11DD29F8900AF4E20 /* PlaylistTypeTests.swift */,
1348+
EC7492B21DD29F8900AF4E20 /* ResolutionTests.swift */,
1349+
1447583C2C8693E000D12CCD /* VideoLayoutTests.swift */,
13251350
);
13261351
path = "Value Types";
13271352
sourceTree = "<group>";
@@ -1773,6 +1798,7 @@
17731798
EC7491811DD29C3500AF4E20 /* String+Trim.swift in Sources */,
17741799
EC7491C31DD29D5C00AF4E20 /* PlaylistValidationIssue.swift in Sources */,
17751800
ECDE184C22383230008566BB /* PlaylistParser.swift in Sources */,
1801+
144758352C83D23100D12CCD /* EXT_X_SESSION_DATAPlaylistValidator.swift in Sources */,
17761802
EC74916E1DD29B5D00AF4E20 /* CollectionType+FindExtensions.swift in Sources */,
17771803
EC7491DA1DD29D9600AF4E20 /* GenericNoDataTagParser.swift in Sources */,
17781804
EC7491C91DD29D5C00AF4E20 /* PlaylistWriter.swift in Sources */,
@@ -1847,6 +1873,8 @@
18471873
EC349ACE2236C3A60077432B /* PlaylistStructureInterface.swift in Sources */,
18481874
EC3B01A71DD4D47900B512E3 /* EXT_X_MEDIARenditionGroupAUTOSELECTValidator.swift in Sources */,
18491875
F700CD391E78A2BE001C9487 /* MambaStringRef_ConcreteNSString.m in Sources */,
1876+
144758312C83C72B00D12CCD /* EXT_X_SESSION_DATATagValidator.swift in Sources */,
1877+
1447582D2C83C20800D12CCD /* EXT_X_SESSION_KEYValidator.swift in Sources */,
18501878
43DE4EFB1E564DA300EEE800 /* EXT_X_STARTTimeOffsetValidator.swift in Sources */,
18511879
EC74918A1DD29CCB00AF4E20 /* StringDictionaryParser.swift in Sources */,
18521880
ECDE184022381146008566BB /* MasterPlaylist.swift in Sources */,
@@ -1930,8 +1958,10 @@
19301958
ECFBD9101E5CCC2200379FC2 /* ParseArrayTests.m in Sources */,
19311959
EC7492B31DD29F8900AF4E20 /* CodecArrayTests.swift in Sources */,
19321960
01CD2E7A1DE4D46F002510E7 /* EXT_X_MAPTagParserTests.swift in Sources */,
1961+
144758392C8620C000D12CCD /* ChannelsTests.swift in Sources */,
19331962
EC7492AB1DD29F7000AF4E20 /* OrderedDictionaryTests.swift in Sources */,
19341963
EC7492781DD29EC800AF4E20 /* EXT_X_MEDIATagParserTests.swift in Sources */,
1964+
1447583D2C8693E000D12CCD /* VideoLayoutTests.swift in Sources */,
19351965
);
19361966
runOnlyForDeploymentPostprocessing = 0;
19371967
};
@@ -1945,6 +1975,7 @@
19451975
EC3B01AA1DD4D47900B512E3 /* EXT_X_MEDIARenditionGroupDEFAULTValidator.swift in Sources */,
19461976
EC3B01C41DD4D49A00B512E3 /* PlaylistOneToManyValidator.swift in Sources */,
19471977
ECDE184D22383230008566BB /* PlaylistParser.swift in Sources */,
1978+
144758362C83D23100D12CCD /* EXT_X_SESSION_DATAPlaylistValidator.swift in Sources */,
19481979
EC7491821DD29C3500AF4E20 /* String+Trim.swift in Sources */,
19491980
EC7491C41DD29D5C00AF4E20 /* PlaylistValidationIssue.swift in Sources */,
19501981
EC74916F1DD29B5D00AF4E20 /* CollectionType+FindExtensions.swift in Sources */,
@@ -2019,6 +2050,8 @@
20192050
EC349ACF2236C3A60077432B /* PlaylistStructureInterface.swift in Sources */,
20202051
EC7491471DD299B400AF4E20 /* PlaylistTypes.swift in Sources */,
20212052
F700CD3A1E78A2BE001C9487 /* MambaStringRef_ConcreteNSString.m in Sources */,
2053+
144758322C83C72B00D12CCD /* EXT_X_SESSION_DATATagValidator.swift in Sources */,
2054+
1447582E2C83C20800D12CCD /* EXT_X_SESSION_KEYValidator.swift in Sources */,
20222055
EC3B01A81DD4D47900B512E3 /* EXT_X_MEDIARenditionGroupAUTOSELECTValidator.swift in Sources */,
20232056
EC74918B1DD29CCB00AF4E20 /* StringDictionaryParser.swift in Sources */,
20242057
ECDE184122381146008566BB /* MasterPlaylist.swift in Sources */,
@@ -2102,8 +2135,10 @@
21022135
ECFBD9111E5CCC2200379FC2 /* ParseArrayTests.m in Sources */,
21032136
EC7492B81DD29F8900AF4E20 /* PlaylistTypeTests.swift in Sources */,
21042137
EC7492B41DD29F8900AF4E20 /* CodecArrayTests.swift in Sources */,
2138+
1447583A2C8620C000D12CCD /* ChannelsTests.swift in Sources */,
21052139
EC7492AC1DD29F7000AF4E20 /* OrderedDictionaryTests.swift in Sources */,
21062140
EC7492791DD29EC800AF4E20 /* EXT_X_MEDIATagParserTests.swift in Sources */,
2141+
1447583E2C8693E000D12CCD /* VideoLayoutTests.swift in Sources */,
21072142
);
21082143
runOnlyForDeploymentPostprocessing = 0;
21092144
};
@@ -2118,6 +2153,7 @@
21182153
EC1CCD32209A2CF9006B59FF /* String+Trim.swift in Sources */,
21192154
EC1CCD46209A2CF9006B59FF /* GenericSingleTagValidator.swift in Sources */,
21202155
ECDE184E22383230008566BB /* PlaylistParser.swift in Sources */,
2156+
144758372C83D23100D12CCD /* EXT_X_SESSION_DATAPlaylistValidator.swift in Sources */,
21212157
EC1CCD30209A2CF9006B59FF /* String+DateParsing.swift in Sources */,
21222158
EC1CCD53209A2CF9006B59FF /* GenericDictionaryTagWriter.swift in Sources */,
21232159
EC1CCD55209A2CF9006B59FF /* GenericTagWriter.swift in Sources */,
@@ -2189,7 +2225,9 @@
21892225
EC1CCD4F209A2CF9006B59FF /* PlaylistTagCardinalityValidation.swift in Sources */,
21902226
EC1CCD2B209A2CF9006B59FF /* IndeterminateBool.swift in Sources */,
21912227
EC349AD02236C3A60077432B /* PlaylistStructureInterface.swift in Sources */,
2228+
144758332C83C72B00D12CCD /* EXT_X_SESSION_DATATagValidator.swift in Sources */,
21922229
EC1CCD43209A2CF9006B59FF /* EXT_X_STREAM_INFRenditionGroupValidator.swift in Sources */,
2230+
1447582F2C83C20800D12CCD /* EXT_X_SESSION_KEYValidator.swift in Sources */,
21932231
EC1CCD35209A2CF9006B59FF /* StringDictionaryParser.swift in Sources */,
21942232
EC1CCD02209A2CF9006B59FF /* MambaStringRef_ConcreteNSString.m in Sources */,
21952233
EC1CCD38209A2CF9006B59FF /* GenericNoDataTagParser.swift in Sources */,
@@ -2272,10 +2310,12 @@
22722310
ECE253FD209A50B500D388CE /* ThirdPartyTagListSupportTests.swift in Sources */,
22732311
ECE25408209A50B500D388CE /* ResolutionTests.swift in Sources */,
22742312
ECE253F6209A50B500D388CE /* GenericSingleValueTagParserTests.swift in Sources */,
2313+
1447583B2C8620C000D12CCD /* ChannelsTests.swift in Sources */,
22752314
ECE253FA209A50B500D388CE /* GenericSingleTagValidatorTests.swift in Sources */,
22762315
ECE253F1209A50B500D388CE /* EXT_X_KEYTagParserTests.swift in Sources */,
22772316
ECE25403209A50B500D388CE /* String+Helio.swift in Sources */,
22782317
ECE25400209A50B500D388CE /* IndeterminateBoolTests.swift in Sources */,
2318+
1447583F2C8693E000D12CCD /* VideoLayoutTests.swift in Sources */,
22792319
);
22802320
runOnlyForDeploymentPostprocessing = 0;
22812321
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//
2+
// EXT_X_SESSION_DATAPlaylistValidator.swift
3+
// mamba
4+
//
5+
// Created by Robert Galluccio on 8/31/24.
6+
// Copyright © 2024 Comcast Corporation.
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License. All rights reserved.
18+
//
19+
20+
import Foundation
21+
22+
final class EXT_X_SESSION_DATAPlaylistValidator: MasterPlaylistValidator {
23+
static func validate(masterPlaylist: any MasterPlaylistInterface) -> [PlaylistValidationIssue] {
24+
var issues = [PlaylistValidationIssue]()
25+
26+
if let issue = duplicateIssue(
27+
tags: masterPlaylist.tags.filter { $0.tagDescriptor == PantosTag.EXT_X_SESSION_DATA }
28+
) {
29+
issues.append(issue)
30+
}
31+
32+
return issues
33+
}
34+
35+
// A Playlist MAY contain multiple EXT-X-SESSION-DATA tags with the same DATA-ID attribute. A Playlist MUST NOT
36+
// contain more than one EXT-X-SESSION-DATA tag with the same DATA-ID attribute and the same LANGUAGE attribute.
37+
private static func duplicateIssue(tags: [PlaylistTag]) -> PlaylistValidationIssue? {
38+
var dataIdToLanguagesMap = [String: [String?]]()
39+
for tag in tags {
40+
guard let dataId = tag.value(forValueIdentifier: PantosValue.dataId) else { continue }
41+
var existingLanguages = dataIdToLanguagesMap[dataId] ?? []
42+
existingLanguages.append(tag.value(forValueIdentifier: PantosValue.language))
43+
dataIdToLanguagesMap[dataId] = existingLanguages
44+
}
45+
for languages in dataIdToLanguagesMap.values {
46+
if languages.count != Set(languages).count {
47+
return PlaylistValidationIssue(description: .EXT_X_SESSION_DATAPlaylistValidator, severity: .error)
48+
}
49+
}
50+
return nil
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//
2+
// EXT_X_SESSION_DATATagValidator.swift
3+
// mamba
4+
//
5+
// Created by Robert Galluccio on 8/31/24.
6+
// Copyright © 2024 Comcast Corporation.
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License. All rights reserved.
18+
//
19+
20+
import Foundation
21+
22+
struct EXT_X_SESSION_DATATagValidator: PlaylistTagValidator {
23+
private var genericValidator: GenericDictionaryTagValidator
24+
25+
init() {
26+
genericValidator = GenericDictionaryTagValidator(
27+
tag: PantosTag.EXT_X_SESSION_DATA,
28+
dictionaryValueIdentifiers: [
29+
DictionaryTagValueIdentifierImpl(
30+
valueId: PantosValue.dataId,
31+
optional: false,
32+
expectedType: String.self
33+
),
34+
DictionaryTagValueIdentifierImpl(
35+
valueId: PantosValue.value,
36+
optional: true,
37+
expectedType: String.self
38+
),
39+
DictionaryTagValueIdentifierImpl(
40+
valueId: PantosValue.uri,
41+
optional: true,
42+
expectedType: String.self
43+
),
44+
DictionaryTagValueIdentifierImpl(
45+
valueId: PantosValue.format,
46+
optional: true,
47+
expectedType: SessionDataFormat.self
48+
),
49+
DictionaryTagValueIdentifierImpl(
50+
valueId: PantosValue.language,
51+
optional: true,
52+
expectedType: String.self
53+
),
54+
]
55+
)
56+
}
57+
58+
func validate(tag: PlaylistTag) -> [PlaylistValidationIssue]? {
59+
var issueList = genericValidator.validate(tag: tag) ?? []
60+
61+
// Each EXT-X-SESSION-DATA tag MUST contain either a VALUE or URI attribute, but not both.
62+
switch (tag.value(forValueIdentifier: PantosValue.value), tag.value(forValueIdentifier: PantosValue.uri)) {
63+
case (.none, .some), (.some, .none):
64+
break
65+
case (.some, .some), (.none, .none):
66+
issueList.append(PlaylistValidationIssue(description: .EXT_X_SESSION_DATATagValidator, severity: .error))
67+
}
68+
69+
return issueList.isEmpty ? nil : issueList
70+
}
71+
}

0 commit comments

Comments
 (0)