serve-sim-sjchmiela 0.1.55 → 0.1.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Package.swift CHANGED
@@ -14,8 +14,12 @@
14
14
  // arch only, and cross-compiling per-arch with `--triple` breaks the
15
15
  // `#NodeModule` macro.
16
16
 
17
+ import Foundation
17
18
  import PackageDescription
18
19
 
20
+ let packageRoot = URL(fileURLWithPath: #filePath).deletingLastPathComponent().path
21
+ let liveKitWebRTCFrameworkSearchPath = "\(packageRoot)/bin"
22
+
19
23
  let package = Package(
20
24
  name: "serve-sim-native",
21
25
  platforms: [.macOS(.v14)],
@@ -23,7 +27,7 @@ let package = Package(
23
27
  .library(
24
28
  name: "serve-sim-native",
25
29
  type: .dynamic,
26
- targets: ["SimNativeModule"]
30
+ targets: ["SimNative"]
27
31
  ),
28
32
  ],
29
33
  dependencies: [
@@ -31,42 +35,25 @@ let package = Package(
31
35
  ],
32
36
  targets: [
33
37
  .target(
34
- name: "SimNativeModule",
38
+ name: "SimNative",
35
39
  dependencies: [
36
40
  .product(name: "NodeAPI", package: "node-swift"),
37
41
  .product(name: "NodeModuleSupport", package: "node-swift"),
38
42
  ],
39
- path: "Sources",
40
- // Sibling targets built by their own build.sh (Obj-C/ObjC++), not
41
- // part of this SwiftPM package.
42
43
  exclude: [
43
- "SimCameraInjector",
44
- "SimCameraHelper",
45
- "SimAXSettings",
46
- "SimNative/build.sh",
47
- ],
48
- sources: [
49
- "SimNative/sim-module.swift",
50
- "SimNative/sim-capture.swift",
51
- "SimStreamHelper/WebRTCPublisher.swift",
52
- "SimStreamHelper/HIDInjector.swift",
53
- "SimStreamHelper/FrameCapture.swift",
54
- "SimStreamHelper/VideoEncoder.swift",
55
- "SimStreamHelper/H264Encoder.swift",
56
- "SimStreamHelper/StreamFormat.swift",
57
- "SimStreamHelper/AccessibilityBridge.swift",
58
- "SimStreamHelper/SimFrameworks.swift",
59
- "SimStreamHelper/Xcode.swift",
44
+ "build.sh",
60
45
  ],
61
46
  swiftSettings: [
62
- .unsafeFlags(["-F", "bin"]),
47
+ .unsafeFlags(["-F", liveKitWebRTCFrameworkSearchPath]),
63
48
  ],
64
49
  linkerSettings: [
65
50
  .unsafeFlags([
66
- "-F", "bin",
51
+ "-F", liveKitWebRTCFrameworkSearchPath,
67
52
  "-framework", "LiveKitWebRTC",
68
53
  "-Xlinker", "-rpath",
69
54
  "-Xlinker", "@loader_path/../bin",
55
+ "-Xlinker", "-undefined",
56
+ "-Xlinker", "dynamic_lookup",
70
57
  ]),
71
58
  .linkedFramework("CoreVideo"),
72
59
  .linkedFramework("CoreMedia"),
@@ -1,7 +1,9 @@
1
1
  import Foundation
2
+ import Darwin
2
3
  import CoreVideo
3
4
  import CoreMedia
4
5
  import Accelerate
6
+ import VideoToolbox
5
7
  import LiveKitWebRTC
6
8
 
7
9
  struct WebRTCIceServerPayload: Codable {
@@ -47,8 +49,10 @@ final class WebRTCPublisher {
47
49
  private var lastForwardedPixelFormat: OSType?
48
50
  private var lastFrameMode = "none"
49
51
  private var useNativePixelBufferFrames: Bool?
52
+ private var requestedCodecName = "H264"
50
53
  private var selectedCodecName = "H264"
51
54
  private let h264PixelBufferConverter = H264WebRTCPixelBufferConverter()
55
+ private let h264WebRTCSupport: WebRTCH264Support
52
56
  private var maxFps = 30
53
57
  private var targetBitrate = 6_000_000
54
58
  private var convertedFrameCount: Int64 = 0
@@ -61,6 +65,7 @@ final class WebRTCPublisher {
61
65
  }
62
66
 
63
67
  init() {
68
+ h264WebRTCSupport = Self.detectH264WebRTCSupport()
64
69
  let encoderFactory = LKRTCDefaultVideoEncoderFactory()
65
70
  let decoderFactory = LKRTCDefaultVideoDecoderFactory()
66
71
  factory = LKRTCPeerConnectionFactory(
@@ -71,9 +76,12 @@ final class WebRTCPublisher {
71
76
  videoTrack = factory.videoTrack(with: videoSource, trackId: "simulator-video")
72
77
  videoTrack.isEnabled = true
73
78
  capturer = LKRTCVideoCapturer(delegate: videoSource)
79
+ let h264Status = h264WebRTCSupport.allowed
80
+ ? "enabled(\(h264WebRTCSupport.probeSummary))"
81
+ : "disabled(\(h264WebRTCSupport.reason ?? "unsupported runtime"))"
74
82
  print(
75
83
  "[webrtc] Publisher ready (default codec factory + screen-cast video source) " +
76
- "senderCodecs=\(senderCodecSummary())"
84
+ "h264=\(h264Status) senderCodecs=\(senderCodecSummary())"
77
85
  )
78
86
  }
79
87
 
@@ -135,7 +143,10 @@ final class WebRTCPublisher {
135
143
  "active": session != nil,
136
144
  "targetFps": maxFps,
137
145
  "targetBitrate": targetBitrate,
146
+ "requestedCodec": requestedCodecName,
138
147
  "selectedCodec": selectedCodecName,
148
+ "h264WebRTCEnabled": h264WebRTCSupport.allowed,
149
+ "h264WebRTCProbe": h264WebRTCSupport.probeSummary,
139
150
  "frameMode": lastFrameMode,
140
151
  "outputWidth": lastOutputWidth,
141
152
  "outputHeight": lastOutputHeight,
@@ -159,6 +170,15 @@ final class WebRTCPublisher {
159
170
  if let lastForwardedPixelFormat {
160
171
  stats["forwardedPixelFormat"] = pixelFormatDescription(lastForwardedPixelFormat)
161
172
  }
173
+ if let reason = h264WebRTCSupport.reason {
174
+ stats["h264WebRTCDisabledReason"] = reason
175
+ }
176
+ if let encoderID = h264WebRTCSupport.encoderID {
177
+ stats["h264VideoToolboxEncoderID"] = encoderID
178
+ }
179
+ if let usesHardware = h264WebRTCSupport.usesHardware {
180
+ stats["h264VideoToolboxUsesHardware"] = usesHardware
181
+ }
162
182
  if let session {
163
183
  stats["outboundRtp"] = session.delegate.outboundStatsSnapshot()
164
184
  }
@@ -567,10 +587,22 @@ final class WebRTCPublisher {
567
587
  }
568
588
 
569
589
  private func applyVideoCodecPreference(_ codec: String?, to transceiver: LKRTCRtpTransceiver) {
570
- let preferredName = Self.preferredVideoCodecName(codec)
590
+ let requestedName = Self.preferredVideoCodecName(codec)
591
+ requestedCodecName = requestedName
592
+ var preferredName = requestedName
593
+ if requestedName == "H264", !h264WebRTCSupport.allowed {
594
+ preferredName = "VP8"
595
+ print(
596
+ "[webrtc] H.264 requested but disabled (\(h264WebRTCSupport.reason ?? "unsupported runtime")); " +
597
+ "preferring VP8"
598
+ )
599
+ }
571
600
  selectedCodecName = preferredName
572
601
  let capabilities = factory.rtpSenderCapabilities(forKind: "video")
573
- let preferredCodecs = capabilities.codecs.filter {
602
+ let usableCodecs = capabilities.codecs.filter { capability in
603
+ h264WebRTCSupport.allowed || !Self.codecCapability(capability, matches: "H264")
604
+ }
605
+ let preferredCodecs = usableCodecs.filter {
574
606
  $0.name.caseInsensitiveCompare(preferredName) == .orderedSame ||
575
607
  $0.mimeType.caseInsensitiveCompare("video/\(preferredName)") == .orderedSame
576
608
  }
@@ -578,7 +610,7 @@ final class WebRTCPublisher {
578
610
  print("[webrtc] No sender codec capability found for \(preferredName); using default order")
579
611
  return
580
612
  }
581
- let remainingCodecs = capabilities.codecs.filter { capability in
613
+ let remainingCodecs = usableCodecs.filter { capability in
582
614
  !preferredCodecs.contains { $0 === capability }
583
615
  }
584
616
  let orderedCodecs = preferredCodecs + remainingCodecs
@@ -650,10 +682,258 @@ final class WebRTCPublisher {
650
682
  }
651
683
  }
652
684
 
685
+ private static func codecCapability(_ capability: LKRTCRtpCodecCapability, matches name: String) -> Bool {
686
+ capability.name.caseInsensitiveCompare(name) == .orderedSame ||
687
+ capability.mimeType.caseInsensitiveCompare("video/\(name)") == .orderedSame
688
+ }
689
+
653
690
  private static func isBiPlanar420(_ pixelFormat: OSType) -> Bool {
654
691
  pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ||
655
692
  pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
656
693
  }
694
+
695
+ private static func detectH264WebRTCSupport() -> WebRTCH264Support {
696
+ let environment = ProcessInfo.processInfo.environment
697
+ if envFlagEnabled(environment["SERVE_SIM_DISABLE_WEBRTC_H264"]) {
698
+ return WebRTCH264Support(
699
+ allowed: false,
700
+ reason: "disabled by SERVE_SIM_DISABLE_WEBRTC_H264",
701
+ encoderID: nil,
702
+ usesHardware: nil,
703
+ probeSummary: "disabled by environment"
704
+ )
705
+ }
706
+ if envFlagEnabled(environment["SERVE_SIM_ALLOW_VM_H264_WEBRTC"]) ||
707
+ envFlagEnabled(environment["SERVE_SIM_FORCE_WEBRTC_H264"]) {
708
+ return WebRTCH264Support(
709
+ allowed: true,
710
+ reason: nil,
711
+ encoderID: nil,
712
+ usesHardware: nil,
713
+ probeSummary: "forced by environment"
714
+ )
715
+ }
716
+ let probe = probeVideoToolboxH264Encoder()
717
+ if probe.encodedFrame {
718
+ return WebRTCH264Support(
719
+ allowed: true,
720
+ reason: nil,
721
+ encoderID: probe.encoderID,
722
+ usesHardware: probe.usesHardware,
723
+ probeSummary: probe.summary
724
+ )
725
+ }
726
+ let modelPrefix = sysctlString("hw.model").map { " on \($0)" } ?? ""
727
+ return WebRTCH264Support(
728
+ allowed: false,
729
+ reason: "VideoToolbox H.264 probe failed\(modelPrefix): \(probe.summary)",
730
+ encoderID: probe.encoderID,
731
+ usesHardware: probe.usesHardware,
732
+ probeSummary: probe.summary
733
+ )
734
+ }
735
+
736
+ private static func probeVideoToolboxH264Encoder() -> H264VideoToolboxProbe {
737
+ let width: Int32 = 64
738
+ let height: Int32 = 64
739
+ let attrs: [String: Any] = [
740
+ kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
741
+ kCVPixelBufferWidthKey as String: Int(width),
742
+ kCVPixelBufferHeightKey as String: Int(height),
743
+ kCVPixelBufferIOSurfacePropertiesKey as String: [:],
744
+ ]
745
+ var session: VTCompressionSession?
746
+ let createStatus = VTCompressionSessionCreate(
747
+ allocator: kCFAllocatorDefault,
748
+ width: width,
749
+ height: height,
750
+ codecType: kCMVideoCodecType_H264,
751
+ encoderSpecification: nil,
752
+ imageBufferAttributes: attrs as CFDictionary,
753
+ compressedDataAllocator: nil,
754
+ outputCallback: nil,
755
+ refcon: nil,
756
+ compressionSessionOut: &session
757
+ )
758
+ guard createStatus == noErr, let session else {
759
+ return H264VideoToolboxProbe(
760
+ encodedFrame: false,
761
+ encoderID: nil,
762
+ usesHardware: nil,
763
+ summary: "createStatus=\(createStatus)"
764
+ )
765
+ }
766
+ defer { VTCompressionSessionInvalidate(session) }
767
+
768
+ _ = VTSessionSetProperty(session, key: kVTCompressionPropertyKey_RealTime, value: kCFBooleanTrue)
769
+ _ = VTSessionSetProperty(session, key: kVTCompressionPropertyKey_ProfileLevel, value: kVTProfileLevel_H264_Baseline_AutoLevel)
770
+ _ = VTSessionSetProperty(session, key: kVTCompressionPropertyKey_AllowFrameReordering, value: kCFBooleanFalse)
771
+ _ = VTSessionSetProperty(session, key: kVTCompressionPropertyKey_ExpectedFrameRate, value: NSNumber(value: 30))
772
+
773
+ let prepareStatus = VTCompressionSessionPrepareToEncodeFrames(session)
774
+ let encoderID = vtSessionStringProperty(session, key: kVTCompressionPropertyKey_EncoderID)
775
+ let usesHardware = inferredHardwareAcceleration(
776
+ encoderID: encoderID,
777
+ reported: vtSessionBoolProperty(session, key: kVTCompressionPropertyKey_UsingHardwareAcceleratedVideoEncoder)
778
+ )
779
+ guard prepareStatus == noErr else {
780
+ return H264VideoToolboxProbe(
781
+ encodedFrame: false,
782
+ encoderID: encoderID,
783
+ usesHardware: usesHardware,
784
+ summary: "encoderID=\(encoderID ?? "unknown") prepareStatus=\(prepareStatus)"
785
+ )
786
+ }
787
+
788
+ guard let pixelBuffer = makeH264ProbePixelBuffer(width: Int(width), height: Int(height)) else {
789
+ return H264VideoToolboxProbe(
790
+ encodedFrame: false,
791
+ encoderID: encoderID,
792
+ usesHardware: usesHardware,
793
+ summary: "encoderID=\(encoderID ?? "unknown") pixelBufferAllocationFailed"
794
+ )
795
+ }
796
+ let semaphore = DispatchSemaphore(value: 0)
797
+ var callbackStatus: OSStatus?
798
+ var producedSample = false
799
+ let encodeStatus = VTCompressionSessionEncodeFrame(
800
+ session,
801
+ imageBuffer: pixelBuffer,
802
+ presentationTimeStamp: CMTime(value: 0, timescale: 30),
803
+ duration: CMTime(value: 1, timescale: 30),
804
+ frameProperties: nil,
805
+ infoFlagsOut: nil
806
+ ) { status, _, sampleBuffer in
807
+ callbackStatus = status
808
+ producedSample = status == noErr && sampleBuffer.map(CMSampleBufferDataIsReady) == true
809
+ semaphore.signal()
810
+ }
811
+ let completeStatus = VTCompressionSessionCompleteFrames(session, untilPresentationTimeStamp: .invalid)
812
+ let completed = semaphore.wait(timeout: .now() + .milliseconds(750)) == .success
813
+ let encodedFrame = encodeStatus == noErr &&
814
+ completeStatus == noErr &&
815
+ completed &&
816
+ callbackStatus == noErr &&
817
+ producedSample
818
+ let hardwareSummary = usesHardware.map { "hardware=\($0)" } ?? "hardware=unknown"
819
+ return H264VideoToolboxProbe(
820
+ encodedFrame: encodedFrame,
821
+ encoderID: encoderID,
822
+ usesHardware: usesHardware,
823
+ summary: "encoderID=\(encoderID ?? "unknown") \(hardwareSummary) " +
824
+ "encodeStatus=\(encodeStatus) completeStatus=\(completeStatus) " +
825
+ "callbackStatus=\(callbackStatus.map(String.init) ?? "missing") " +
826
+ "sample=\(producedSample)"
827
+ )
828
+ }
829
+
830
+ private static func makeH264ProbePixelBuffer(width: Int, height: Int) -> CVPixelBuffer? {
831
+ let attrs: [String: Any] = [
832
+ kCVPixelBufferIOSurfacePropertiesKey as String: [:],
833
+ ]
834
+ var pixelBuffer: CVPixelBuffer?
835
+ let status = CVPixelBufferCreate(
836
+ kCFAllocatorDefault,
837
+ width,
838
+ height,
839
+ kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
840
+ attrs as CFDictionary,
841
+ &pixelBuffer
842
+ )
843
+ guard status == kCVReturnSuccess, let pixelBuffer else { return nil }
844
+ CVPixelBufferLockBaseAddress(pixelBuffer, [])
845
+ defer { CVPixelBufferUnlockBaseAddress(pixelBuffer, []) }
846
+ guard
847
+ let yAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0),
848
+ let cbCrAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1)
849
+ else {
850
+ return nil
851
+ }
852
+ let yStride = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0)
853
+ let cbCrStride = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1)
854
+ let yPointer = yAddress.assumingMemoryBound(to: UInt8.self)
855
+ let cbCrPointer = cbCrAddress.assumingMemoryBound(to: UInt8.self)
856
+ for row in 0..<height {
857
+ let rowPointer = yPointer.advanced(by: row * yStride)
858
+ for column in 0..<width {
859
+ rowPointer[column] = UInt8((row + column) & 0xff)
860
+ }
861
+ }
862
+ for row in 0..<(height / 2) {
863
+ let rowPointer = cbCrPointer.advanced(by: row * cbCrStride)
864
+ for column in stride(from: 0, to: width, by: 2) {
865
+ rowPointer[column] = 128
866
+ rowPointer[column + 1] = 128
867
+ }
868
+ }
869
+ return pixelBuffer
870
+ }
871
+
872
+ private static func vtSessionStringProperty(_ session: VTCompressionSession, key: CFString) -> String? {
873
+ var value: CFTypeRef?
874
+ let status = withUnsafeMutablePointer(to: &value) { pointer in
875
+ VTSessionCopyProperty(session, key: key, allocator: kCFAllocatorDefault, valueOut: pointer)
876
+ }
877
+ guard status == noErr, let value else { return nil }
878
+ return String(describing: value)
879
+ }
880
+
881
+ private static func vtSessionBoolProperty(_ session: VTCompressionSession, key: CFString) -> Bool? {
882
+ var value: CFTypeRef?
883
+ let status = withUnsafeMutablePointer(to: &value) { pointer in
884
+ VTSessionCopyProperty(session, key: key, allocator: kCFAllocatorDefault, valueOut: pointer)
885
+ }
886
+ guard status == noErr, let value else { return nil }
887
+ if CFGetTypeID(value) == CFBooleanGetTypeID() {
888
+ return CFBooleanGetValue((value as! CFBoolean))
889
+ }
890
+ return (value as? NSNumber)?.boolValue
891
+ }
892
+
893
+ private static func inferredHardwareAcceleration(encoderID: String?, reported: Bool?) -> Bool? {
894
+ if let reported { return reported }
895
+ guard let encoderID else { return nil }
896
+ let normalized = encoderID.lowercased()
897
+ if normalized.contains("paravirtualized") || normalized.contains(".ave.") {
898
+ return true
899
+ }
900
+ if normalized.contains("com.apple.videotoolbox.videoencoder.h264") {
901
+ return false
902
+ }
903
+ return nil
904
+ }
905
+
906
+ private static func envFlagEnabled(_ value: String?) -> Bool {
907
+ switch value?.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() {
908
+ case "1", "true", "yes", "on":
909
+ return true
910
+ default:
911
+ return false
912
+ }
913
+ }
914
+
915
+ private static func sysctlString(_ name: String) -> String? {
916
+ var size = 0
917
+ guard sysctlbyname(name, nil, &size, nil, 0) == 0, size > 1 else { return nil }
918
+ var buffer = [CChar](repeating: 0, count: size)
919
+ guard sysctlbyname(name, &buffer, &size, nil, 0) == 0 else { return nil }
920
+ return String(cString: buffer)
921
+ }
922
+ }
923
+
924
+ private struct WebRTCH264Support {
925
+ let allowed: Bool
926
+ let reason: String?
927
+ let encoderID: String?
928
+ let usesHardware: Bool?
929
+ let probeSummary: String
930
+ }
931
+
932
+ private struct H264VideoToolboxProbe {
933
+ let encodedFrame: Bool
934
+ let encoderID: String?
935
+ let usesHardware: Bool?
936
+ let summary: String
657
937
  }
658
938
 
659
939
  private final class H264WebRTCPixelBufferConverter {
@@ -3,15 +3,11 @@
3
3
  # spawned serve-sim-bin helper. The JS bindings are written in Swift with
4
4
  # node-swift (see ../../Package.swift and sim-module.swift).
5
5
  #
6
- # Host-arch only (arm64 on Apple Silicon / CI). We use a plain `swift build`,
7
- # i.e. the NATIVE SwiftPM build system, because that is the only mode that
8
- # resolves node-swift's #NodeModule macro plugin: both `--arch X --arch Y`
9
- # (universal) and `--triple <other-arch>` force Xcode's XCBuild, which fails to
10
- # resolve the NodeAPIMacros plugin on stock toolchains ("missing target
11
- # NodeAPIMacros" / "unable to resolve module SwiftSyntax"). Cross-compiling the
12
- # x86_64 slice would therefore require an x86_64-native toolchain (Rosetta),
13
- # which isn't available everywhere; serve-sim targets Apple Silicon. napi_* stay
14
- # undefined and resolve against the host (Node/Bun) at dlopen via
6
+ # We opt into the new `swiftbuild` build system, because it supports building universal
7
+ # binaries with macros, which neither the legacy `native` build system nor the
8
+ # perennially-janky legacy `xcode` build system had support for.
9
+ #
10
+ # napi_* stay undefined and resolve against the host (Node/Bun) at dlopen via
15
11
  # `-undefined dynamic_lookup`.
16
12
  set -euo pipefail
17
13
  HERE="$(cd "$(dirname "$0")" && pwd)"
@@ -26,25 +22,23 @@ if [ ! -d "$PKG/node_modules/node-swift" ]; then
26
22
  exit 1
27
23
  fi
28
24
 
29
- swift build \
30
- -c release \
31
- --product "$PRODUCT" \
32
- --package-path "$PKG" \
33
- --build-path "$BUILD_DIR" \
34
- -Xlinker -undefined -Xlinker dynamic_lookup
35
-
36
- # `-print -quit` (not `| head`): under `pipefail`, head closing the pipe early
37
- # would SIGPIPE find and fail the script. Match by name rather than a fixed
38
- # subpath: the product dir varies by toolchain (native SwiftPM emits
39
- # .build/release/, the Xcode build system emits .build/out/Products/Release/).
40
- DYLIB="$(find "$BUILD_DIR" -name "lib${PRODUCT}.dylib" -type f -not -path '*.dSYM*' -print -quit)"
41
- if [ -z "$DYLIB" ]; then
42
- echo "Build succeeded but lib${PRODUCT}.dylib was not found under $BUILD_DIR" >&2
25
+ build_flags=(
26
+ -c release
27
+ --product "$PRODUCT"
28
+ --package-path "$PKG"
29
+ --build-path "$BUILD_DIR"
30
+ --build-system swiftbuild
31
+ )
32
+ swift build "${build_flags[@]}" >&2
33
+ DYLIB="$(swift build --show-bin-path "${build_flags[@]}")/lib${PRODUCT}.dylib"
34
+ if [ ! -f "$DYLIB" ]; then
35
+ echo "Expected build product not found at $DYLIB" >&2
43
36
  exit 1
44
37
  fi
45
38
 
46
39
  OUT="$OUT_DIR/${PRODUCT}.node"
47
- cp "$DYLIB" "$OUT"
40
+ cp -a "$DYLIB" "$OUT"
41
+ strip -x "$OUT"
48
42
  install_name_tool \
49
43
  -change "@rpath/LiveKitWebRTC.framework/LiveKitWebRTC" \
50
44
  "@loader_path/../../bin/LiveKitWebRTC.framework/Versions/A/LiveKitWebRTC" \
@@ -20,7 +20,7 @@
20
20
  NS_ASSUME_NONNULL_BEGIN
21
21
 
22
22
  RTC_OBJC_EXPORT
23
- @interface RTC_OBJC_TYPE (RTCAudioProcessingConfig) : NSObject
23
+ @interface RTC_OBJC_TYPE (RTCAudioProcessingConfig) : NSObject
24
24
 
25
25
  @property(nonatomic, assign) BOOL isEchoCancellationEnabled;
26
26
  @property(nonatomic, assign) BOOL isEchoCancellationMobileMode;
@@ -60,7 +60,7 @@ RTC_OBJC_EXPORT
60
60
  uncryptedMagicBytes:(nullable NSData *)uncryptedMagicBytes
61
61
  failureTolerance:(int)failureTolerance
62
62
  keyRingSize:(int)keyRingSize
63
- discardFrameWhenCryptorNotReady:(BOOL)discardFrameWhenCryptorNotReady;
63
+ discardFrameWhenCryptorNotReady:(BOOL)discardFrameWhenCryptorNotReady;
64
64
 
65
65
  - (instancetype)initWithRatchetSalt:(NSData *)salt
66
66
  ratchetWindowSize:(int)windowSize