Use external lib
This commit is contained in:
parent
70b3dfd693
commit
530bc1c91d
|
@ -12,6 +12,7 @@ dynatraceSymbols.zip
|
||||||
Cartfile.resolved
|
Cartfile.resolved
|
||||||
Gemfile.lock
|
Gemfile.lock
|
||||||
dynatrace/
|
dynatrace/
|
||||||
|
Carthage
|
||||||
|
|
||||||
## Various settings
|
## Various settings
|
||||||
*.pbxuser
|
*.pbxuser
|
||||||
|
|
3
Cartfile
3
Cartfile
|
@ -1,2 +1,3 @@
|
||||||
binary "https://code.videolan.org/videolan/VLCKit/raw/master/Packaging/MobileVLCKit.json" ~> 3.4.0
|
binary "https://code.videolan.org/videolan/VLCKit/raw/master/Packaging/MobileVLCKit.json" ~> 3.4.0
|
||||||
binary "https://code.videolan.org/videolan/VLCKit/raw/master/Packaging/TVVLCKit.json" ~> 3.3.0
|
binary "https://code.videolan.org/videolan/VLCKit/raw/master/Packaging/TVVLCKit.json" ~> 3.3.0
|
||||||
|
github "gunterhager/UDPBroadcastConnection"
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import UDPBroadcast
|
||||||
|
|
||||||
public class ServerDiscovery {
|
public class ServerDiscovery {
|
||||||
public struct ServerLookupResponse: Codable, Hashable, Identifiable {
|
public struct ServerLookupResponse: Codable, Hashable, Identifiable {
|
||||||
|
@ -46,16 +47,12 @@ public class ServerDiscovery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let broadcastConn: UDPBroadcastConnection
|
private var connection: UDPBroadcastConnection?
|
||||||
|
|
||||||
public init() {
|
init() {}
|
||||||
func receiveHandler(_ ipAddress: String, _ port: Int, _ response: Data) {}
|
|
||||||
|
|
||||||
func errorHandler(error: UDPBroadcastConnection.ConnectionError) {}
|
|
||||||
self.broadcastConn = try! UDPBroadcastConnection(port: 7359, handler: receiveHandler, errorHandler: errorHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func locateServer(completion: @escaping (ServerLookupResponse?) -> Void) {
|
public func locateServer(completion: @escaping (ServerLookupResponse?) -> Void) {
|
||||||
|
|
||||||
func receiveHandler(_ ipAddress: String, _ port: Int, _ data: Data) {
|
func receiveHandler(_ ipAddress: String, _ port: Int, _ data: Data) {
|
||||||
do {
|
do {
|
||||||
let response = try JSONDecoder().decode(ServerLookupResponse.self, from: data)
|
let response = try JSONDecoder().decode(ServerLookupResponse.self, from: data)
|
||||||
|
@ -65,12 +62,17 @@ public class ServerDiscovery {
|
||||||
completion(nil)
|
completion(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.broadcastConn.handler = receiveHandler
|
|
||||||
|
func errorHandler(error: UDPBroadcastConnection.ConnectionError) {
|
||||||
|
LogManager.log.error("Error handling response: \(error.localizedDescription)", tag: "ServerDiscovery")
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try broadcastConn.sendBroadcast("Who is JellyfinServer?")
|
self.connection = try! UDPBroadcastConnection(port: 7359, handler: receiveHandler, errorHandler: errorHandler)
|
||||||
|
try self.connection?.sendBroadcast("Who is JellyfinServer?")
|
||||||
LogManager.log.debug("Discovery broadcast sent", tag: "ServerDiscovery")
|
LogManager.log.debug("Discovery broadcast sent", tag: "ServerDiscovery")
|
||||||
} catch {
|
} catch {
|
||||||
print(error)
|
LogManager.log.error("Error sending discovery broadcast", tag: "ServerDiscovery")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,311 +0,0 @@
|
||||||
//
|
|
||||||
// Swiftfin is subject to the terms of the Mozilla Public
|
|
||||||
// License, v2.0. If a copy of the MPL was not distributed with this
|
|
||||||
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
|
||||||
//
|
|
||||||
|
|
||||||
import Darwin
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
// Addresses
|
|
||||||
|
|
||||||
let INADDR_ANY = in_addr(s_addr: 0)
|
|
||||||
let INADDR_BROADCAST = in_addr(s_addr: 0xFFFF_FFFF)
|
|
||||||
|
|
||||||
/// An object representing the UDP broadcast connection. Uses a dispatch source to handle the incoming traffic on the UDP socket.
|
|
||||||
open class UDPBroadcastConnection {
|
|
||||||
// MARK: Properties
|
|
||||||
|
|
||||||
/// The address of the UDP socket.
|
|
||||||
var address: sockaddr_in
|
|
||||||
|
|
||||||
/// Type of a closure that handles incoming UDP packets.
|
|
||||||
public typealias ReceiveHandler = (_ ipAddress: String, _ port: Int, _ response: Data) -> Void
|
|
||||||
/// Closure that handles incoming UDP packets.
|
|
||||||
var handler: ReceiveHandler?
|
|
||||||
|
|
||||||
/// Type of a closure that handles errors that were encountered during receiving UDP packets.
|
|
||||||
public typealias ErrorHandler = (_ error: ConnectionError) -> Void
|
|
||||||
/// Closure that handles errors that were encountered during receiving UDP packets.
|
|
||||||
var errorHandler: ErrorHandler?
|
|
||||||
|
|
||||||
/// A dispatch source for reading data from the UDP socket.
|
|
||||||
var responseSource: DispatchSourceRead?
|
|
||||||
|
|
||||||
/// The dispatch queue to run responseSource & reconnection on
|
|
||||||
var dispatchQueue = DispatchQueue.main
|
|
||||||
|
|
||||||
/// Bind to port to start listening without first sending a message
|
|
||||||
var shouldBeBound: Bool = false
|
|
||||||
|
|
||||||
// MARK: Initializers
|
|
||||||
|
|
||||||
/// Initializes the UDP connection with the correct port address.
|
|
||||||
|
|
||||||
/// - Note: This doesn't open a socket! The socket is opened transparently as needed when sending broadcast messages. If you want to open a socket immediately, use the `bindIt` parameter. This will also try to reopen the socket if it gets closed.
|
|
||||||
///
|
|
||||||
/// - Parameters:
|
|
||||||
/// - port: Number of the UDP port to use.
|
|
||||||
/// - bindIt: Opens a port immediately if true, on demand if false. Default is false.
|
|
||||||
/// - handler: Handler that gets called when data is received.
|
|
||||||
/// - errorHandler: Handler that gets called when an error occurs.
|
|
||||||
/// - Throws: Throws a `ConnectionError` if an error occurs.
|
|
||||||
public init(port: UInt16, bindIt: Bool = false, handler: ReceiveHandler?, errorHandler: ErrorHandler?) throws {
|
|
||||||
self.address = sockaddr_in(sin_len: __uint8_t(MemoryLayout<sockaddr_in>.size),
|
|
||||||
sin_family: sa_family_t(AF_INET),
|
|
||||||
sin_port: UDPBroadcastConnection.htonsPort(port: port),
|
|
||||||
sin_addr: INADDR_BROADCAST,
|
|
||||||
sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
|
|
||||||
|
|
||||||
self.handler = handler
|
|
||||||
self.errorHandler = errorHandler
|
|
||||||
self.shouldBeBound = bindIt
|
|
||||||
if bindIt {
|
|
||||||
try createSocket()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deinit {
|
|
||||||
if responseSource != nil {
|
|
||||||
responseSource!.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Interface
|
|
||||||
|
|
||||||
/// Create a UDP socket for broadcasting and set up cancel and event handlers
|
|
||||||
///
|
|
||||||
/// - Throws: Throws a `ConnectionError` if an error occurs.
|
|
||||||
fileprivate func createSocket() throws {
|
|
||||||
// Create new socket
|
|
||||||
let newSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
|
|
||||||
guard newSocket > 0 else { throw ConnectionError.createSocketFailed }
|
|
||||||
|
|
||||||
// Enable broadcast on socket
|
|
||||||
var broadcastEnable = Int32(1)
|
|
||||||
let ret = setsockopt(newSocket, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, socklen_t(MemoryLayout<UInt32>.size))
|
|
||||||
if ret == -1 {
|
|
||||||
debugPrint("Couldn't enable broadcast on socket")
|
|
||||||
close(newSocket)
|
|
||||||
throw ConnectionError.enableBroadcastFailed
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind socket if needed
|
|
||||||
if shouldBeBound {
|
|
||||||
var saddr = sockaddr(sa_len: 0, sa_family: 0,
|
|
||||||
sa_data: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
|
|
||||||
address.sin_addr = INADDR_ANY
|
|
||||||
memcpy(&saddr, &address, MemoryLayout<sockaddr_in>.size)
|
|
||||||
address.sin_addr = INADDR_BROADCAST
|
|
||||||
let isBound = bind(newSocket, &saddr, socklen_t(MemoryLayout<sockaddr_in>.size))
|
|
||||||
if isBound == -1 {
|
|
||||||
debugPrint("Couldn't bind socket")
|
|
||||||
close(newSocket)
|
|
||||||
throw ConnectionError.bindSocketFailed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable global SIGPIPE handler so that the app doesn't crash
|
|
||||||
setNoSigPipe(socket: newSocket)
|
|
||||||
|
|
||||||
// Set up a dispatch source
|
|
||||||
let newResponseSource = DispatchSource.makeReadSource(fileDescriptor: newSocket, queue: dispatchQueue)
|
|
||||||
|
|
||||||
// Set up cancel handler
|
|
||||||
newResponseSource.setCancelHandler {
|
|
||||||
// debugPrint("Closing UDP socket")
|
|
||||||
let UDPSocket = Int32(newResponseSource.handle)
|
|
||||||
shutdown(UDPSocket, SHUT_RDWR)
|
|
||||||
close(UDPSocket)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up event handler (gets called when data arrives at the UDP socket)
|
|
||||||
newResponseSource.setEventHandler { [unowned self] in
|
|
||||||
guard let source = self.responseSource else { return }
|
|
||||||
|
|
||||||
var socketAddress = sockaddr_storage()
|
|
||||||
var socketAddressLength = socklen_t(MemoryLayout<sockaddr_storage>.size)
|
|
||||||
let response = [UInt8](repeating: 0, count: 4096)
|
|
||||||
let UDPSocket = Int32(source.handle)
|
|
||||||
|
|
||||||
// Do not fix pointer warning. It must work this way.
|
|
||||||
let bytesRead = withUnsafeMutablePointer(to: &socketAddress) {
|
|
||||||
recvfrom(UDPSocket, UnsafeMutableRawPointer(mutating: response), response.count, 0,
|
|
||||||
UnsafeMutableRawPointer($0).bindMemory(to: sockaddr.self, capacity: 1), &socketAddressLength)
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
guard bytesRead > 0 else {
|
|
||||||
self.closeConnection()
|
|
||||||
if bytesRead == 0 {
|
|
||||||
debugPrint("recvfrom returned EOF")
|
|
||||||
throw ConnectionError.receivedEndOfFile
|
|
||||||
} else {
|
|
||||||
if let errorString = String(validatingUTF8: strerror(errno)) {
|
|
||||||
debugPrint("recvfrom failed: \(errorString)")
|
|
||||||
}
|
|
||||||
throw ConnectionError.receiveFailed(code: errno)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let endpoint = withUnsafePointer(to: &socketAddress, {
|
|
||||||
self
|
|
||||||
.getEndpointFromSocketAddress(socketAddressPointer: UnsafeRawPointer($0)
|
|
||||||
.bindMemory(to: sockaddr.self, capacity: 1)) })
|
|
||||||
else {
|
|
||||||
// debugPrint("Failed to get the address and port from the socket address received from recvfrom")
|
|
||||||
self.closeConnection()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// debugPrint("UDP connection received \(bytesRead) bytes from \(endpoint.host):\(endpoint.port)")
|
|
||||||
|
|
||||||
let responseBytes = Data(response[0 ..< bytesRead])
|
|
||||||
|
|
||||||
// Handle response
|
|
||||||
self.handler?(endpoint.host, endpoint.port, responseBytes)
|
|
||||||
} catch {
|
|
||||||
if let error = error as? ConnectionError {
|
|
||||||
self.errorHandler?(error)
|
|
||||||
} else {
|
|
||||||
self.errorHandler?(ConnectionError.underlying(error: error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newResponseSource.resume()
|
|
||||||
responseSource = newResponseSource
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send broadcast message.
|
|
||||||
///
|
|
||||||
/// - Parameter message: Message to send via broadcast.
|
|
||||||
/// - Throws: Throws a `ConnectionError` if an error occurs.
|
|
||||||
open func sendBroadcast(_ message: String) throws {
|
|
||||||
guard let data = message.data(using: .utf8) else { throw ConnectionError.messageEncodingFailed }
|
|
||||||
try sendBroadcast(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send broadcast data.
|
|
||||||
///
|
|
||||||
/// - Parameter data: Data to send via broadcast.
|
|
||||||
/// - Throws: Throws a `ConnectionError` if an error occurs.
|
|
||||||
open func sendBroadcast(_ data: Data) throws {
|
|
||||||
if responseSource == nil {
|
|
||||||
try createSocket()
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let source = responseSource else { return }
|
|
||||||
let UDPSocket = Int32(source.handle)
|
|
||||||
let socketLength = socklen_t(address.sin_len)
|
|
||||||
try data.withUnsafeBytes { broadcastMessage in
|
|
||||||
let broadcastMessageLength = data.count
|
|
||||||
let sent = withUnsafeMutablePointer(to: &address) { pointer -> Int in
|
|
||||||
let memory = UnsafeRawPointer(pointer).bindMemory(to: sockaddr.self, capacity: 1)
|
|
||||||
return sendto(UDPSocket, broadcastMessage.baseAddress, broadcastMessageLength, 0, memory, socketLength)
|
|
||||||
}
|
|
||||||
|
|
||||||
guard sent > 0 else {
|
|
||||||
closeConnection()
|
|
||||||
throw ConnectionError.sendingMessageFailed(code: errno)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Close the connection.
|
|
||||||
///
|
|
||||||
/// - Parameter reopen: Automatically reopens the connection if true. Defaults to true.
|
|
||||||
open func closeConnection(reopen: Bool = true) {
|
|
||||||
if let source = responseSource {
|
|
||||||
source.cancel()
|
|
||||||
responseSource = nil
|
|
||||||
}
|
|
||||||
if shouldBeBound, reopen {
|
|
||||||
dispatchQueue.async {
|
|
||||||
do {
|
|
||||||
try self.createSocket()
|
|
||||||
} catch {
|
|
||||||
self.errorHandler?(ConnectionError.reopeningSocketFailed(error: error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Helper
|
|
||||||
|
|
||||||
/// Convert a sockaddr structure into an IP address string and port.
|
|
||||||
///
|
|
||||||
/// - Parameter socketAddressPointer: socketAddressPointer: Pointer to a socket address.
|
|
||||||
/// - Returns: Returns a tuple of the host IP address and the port in the socket address given.
|
|
||||||
func getEndpointFromSocketAddress(socketAddressPointer: UnsafePointer<sockaddr>) -> (host: String, port: Int)? {
|
|
||||||
let socketAddress = UnsafePointer<sockaddr>(socketAddressPointer).pointee
|
|
||||||
|
|
||||||
switch Int32(socketAddress.sa_family) {
|
|
||||||
case AF_INET:
|
|
||||||
var socketAddressInet = UnsafeRawPointer(socketAddressPointer).load(as: sockaddr_in.self)
|
|
||||||
let length = Int(INET_ADDRSTRLEN) + 2
|
|
||||||
var buffer = [CChar](repeating: 0, count: length)
|
|
||||||
let hostCString = inet_ntop(AF_INET, &socketAddressInet.sin_addr, &buffer, socklen_t(length))
|
|
||||||
let port = Int(UInt16(socketAddressInet.sin_port).byteSwapped)
|
|
||||||
return (String(cString: hostCString!), port)
|
|
||||||
|
|
||||||
case AF_INET6:
|
|
||||||
var socketAddressInet6 = UnsafeRawPointer(socketAddressPointer).load(as: sockaddr_in6.self)
|
|
||||||
let length = Int(INET6_ADDRSTRLEN) + 2
|
|
||||||
var buffer = [CChar](repeating: 0, count: length)
|
|
||||||
let hostCString = inet_ntop(AF_INET6, &socketAddressInet6.sin6_addr, &buffer, socklen_t(length))
|
|
||||||
let port = Int(UInt16(socketAddressInet6.sin6_port).byteSwapped)
|
|
||||||
return (String(cString: hostCString!), port)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Private
|
|
||||||
|
|
||||||
/// Prevents crashes when blocking calls are pending and the app is paused (via Home button).
|
|
||||||
///
|
|
||||||
/// - Parameter socket: The socket for which the signal should be disabled.
|
|
||||||
fileprivate func setNoSigPipe(socket: CInt) {
|
|
||||||
var no_sig_pipe: Int32 = 1
|
|
||||||
setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(MemoryLayout<Int32>.size))
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate class func htonsPort(port: in_port_t) -> in_port_t {
|
|
||||||
let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian
|
|
||||||
return isLittleEndian ? _OSSwapInt16(port) : port
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate class func ntohs(value: CUnsignedShort) -> CUnsignedShort {
|
|
||||||
(value << 8) + (value >> 8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Created by Gunter Hager on 25.03.19.
|
|
||||||
// Copyright © 2019 Gunter Hager. All rights reserved.
|
|
||||||
//
|
|
||||||
public extension UDPBroadcastConnection {
|
|
||||||
enum ConnectionError: Error {
|
|
||||||
// Creating socket
|
|
||||||
case createSocketFailed
|
|
||||||
case enableBroadcastFailed
|
|
||||||
case bindSocketFailed
|
|
||||||
|
|
||||||
// Sending message
|
|
||||||
case messageEncodingFailed
|
|
||||||
case sendingMessageFailed(code: Int32)
|
|
||||||
|
|
||||||
// Receiving data
|
|
||||||
case receivedEndOfFile
|
|
||||||
case receiveFailed(code: Int32)
|
|
||||||
|
|
||||||
// Closing socket
|
|
||||||
case reopeningSocketFailed(error: Error)
|
|
||||||
|
|
||||||
// Underlying
|
|
||||||
case underlying(error: Error)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,9 +8,7 @@
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091B5A872683142E00D78B61 /* ServerDiscovery.swift */; };
|
091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091B5A872683142E00D78B61 /* ServerDiscovery.swift */; };
|
||||||
091B5A8B2683142E00D78B61 /* UDPBroadCastConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091B5A882683142E00D78B61 /* UDPBroadCastConnection.swift */; };
|
|
||||||
091B5A8D268315D400D78B61 /* ServerDiscovery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091B5A872683142E00D78B61 /* ServerDiscovery.swift */; };
|
091B5A8D268315D400D78B61 /* ServerDiscovery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091B5A872683142E00D78B61 /* ServerDiscovery.swift */; };
|
||||||
091B5A8E268315D400D78B61 /* UDPBroadCastConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091B5A882683142E00D78B61 /* UDPBroadCastConnection.swift */; };
|
|
||||||
09389CC526814E4500AE350E /* DeviceProfileBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53192D5C265AA78A008A4215 /* DeviceProfileBuilder.swift */; };
|
09389CC526814E4500AE350E /* DeviceProfileBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53192D5C265AA78A008A4215 /* DeviceProfileBuilder.swift */; };
|
||||||
09389CC726819B4600AE350E /* VideoPlayerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09389CC626819B4500AE350E /* VideoPlayerModel.swift */; };
|
09389CC726819B4600AE350E /* VideoPlayerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09389CC626819B4500AE350E /* VideoPlayerModel.swift */; };
|
||||||
09389CC826819B4600AE350E /* VideoPlayerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09389CC626819B4500AE350E /* VideoPlayerModel.swift */; };
|
09389CC826819B4600AE350E /* VideoPlayerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09389CC626819B4500AE350E /* VideoPlayerModel.swift */; };
|
||||||
|
@ -249,6 +247,8 @@
|
||||||
62EC353226766849000E9F2D /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EC352E267666A5000E9F2D /* SessionManager.swift */; };
|
62EC353226766849000E9F2D /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EC352E267666A5000E9F2D /* SessionManager.swift */; };
|
||||||
62EC353426766B03000E9F2D /* DeviceRotationViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */; };
|
62EC353426766B03000E9F2D /* DeviceRotationViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */; };
|
||||||
62ECA01826FA685A00E8EBB7 /* DeepLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62ECA01726FA685A00E8EBB7 /* DeepLink.swift */; };
|
62ECA01826FA685A00E8EBB7 /* DeepLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62ECA01726FA685A00E8EBB7 /* DeepLink.swift */; };
|
||||||
|
637FCAF4287B5B2600C0A353 /* UDPBroadcast.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */; };
|
||||||
|
637FCAF5287B5B2600C0A353 /* UDPBroadcast.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */; };
|
||||||
AE8C3159265D6F90008AA076 /* bitrates.json in Resources */ = {isa = PBXBuildFile; fileRef = AE8C3158265D6F90008AA076 /* bitrates.json */; };
|
AE8C3159265D6F90008AA076 /* bitrates.json in Resources */ = {isa = PBXBuildFile; fileRef = AE8C3158265D6F90008AA076 /* bitrates.json */; };
|
||||||
C400DB6A27FE894F007B65FE /* LiveTVChannelsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C400DB6927FE894F007B65FE /* LiveTVChannelsView.swift */; };
|
C400DB6A27FE894F007B65FE /* LiveTVChannelsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C400DB6927FE894F007B65FE /* LiveTVChannelsView.swift */; };
|
||||||
C400DB6B27FE8C97007B65FE /* LiveTVChannelItemElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E52304272CE68800654268 /* LiveTVChannelItemElement.swift */; };
|
C400DB6B27FE8C97007B65FE /* LiveTVChannelItemElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E52304272CE68800654268 /* LiveTVChannelItemElement.swift */; };
|
||||||
|
@ -543,7 +543,7 @@
|
||||||
};
|
};
|
||||||
62666DF927E5012C00EC0ECD /* Embed Frameworks */ = {
|
62666DF927E5012C00EC0ECD /* Embed Frameworks */ = {
|
||||||
isa = PBXCopyFilesBuildPhase;
|
isa = PBXCopyFilesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 12;
|
||||||
dstPath = "";
|
dstPath = "";
|
||||||
dstSubfolderSpec = 10;
|
dstSubfolderSpec = 10;
|
||||||
files = (
|
files = (
|
||||||
|
@ -579,7 +579,6 @@
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
091B5A872683142E00D78B61 /* ServerDiscovery.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServerDiscovery.swift; sourceTree = "<group>"; };
|
091B5A872683142E00D78B61 /* ServerDiscovery.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServerDiscovery.swift; sourceTree = "<group>"; };
|
||||||
091B5A882683142E00D78B61 /* UDPBroadCastConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UDPBroadCastConnection.swift; sourceTree = "<group>"; };
|
|
||||||
09389CC626819B4500AE350E /* VideoPlayerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerModel.swift; sourceTree = "<group>"; };
|
09389CC626819B4500AE350E /* VideoPlayerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerModel.swift; sourceTree = "<group>"; };
|
||||||
53116A16268B919A003024C9 /* SeriesItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeriesItemView.swift; sourceTree = "<group>"; };
|
53116A16268B919A003024C9 /* SeriesItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeriesItemView.swift; sourceTree = "<group>"; };
|
||||||
53116A18268B947A003024C9 /* PlainLinkButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlainLinkButton.swift; sourceTree = "<group>"; };
|
53116A18268B947A003024C9 /* PlainLinkButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlainLinkButton.swift; sourceTree = "<group>"; };
|
||||||
|
@ -743,6 +742,7 @@
|
||||||
62EC352E267666A5000E9F2D /* SessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = "<group>"; };
|
62EC352E267666A5000E9F2D /* SessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = "<group>"; };
|
||||||
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
|
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
|
||||||
62ECA01726FA685A00E8EBB7 /* DeepLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLink.swift; sourceTree = "<group>"; };
|
62ECA01726FA685A00E8EBB7 /* DeepLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLink.swift; sourceTree = "<group>"; };
|
||||||
|
637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = UDPBroadcast.xcframework; path = Carthage/Build/UDPBroadcast.xcframework; sourceTree = "<group>"; };
|
||||||
AE8C3158265D6F90008AA076 /* bitrates.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = bitrates.json; sourceTree = "<group>"; };
|
AE8C3158265D6F90008AA076 /* bitrates.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = bitrates.json; sourceTree = "<group>"; };
|
||||||
C400DB6927FE894F007B65FE /* LiveTVChannelsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVChannelsView.swift; sourceTree = "<group>"; };
|
C400DB6927FE894F007B65FE /* LiveTVChannelsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVChannelsView.swift; sourceTree = "<group>"; };
|
||||||
C400DB6C27FE8E65007B65FE /* LiveTVChannelItemWideElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVChannelItemWideElement.swift; sourceTree = "<group>"; };
|
C400DB6C27FE8E65007B65FE /* LiveTVChannelItemWideElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTVChannelItemWideElement.swift; sourceTree = "<group>"; };
|
||||||
|
@ -925,6 +925,7 @@
|
||||||
62666E2327E501EB00EC0ECD /* Foundation.framework in Frameworks */,
|
62666E2327E501EB00EC0ECD /* Foundation.framework in Frameworks */,
|
||||||
62666E2127E501E400EC0ECD /* CoreVideo.framework in Frameworks */,
|
62666E2127E501E400EC0ECD /* CoreVideo.framework in Frameworks */,
|
||||||
6220D0C926D63F3700B8E046 /* Stinsen in Frameworks */,
|
6220D0C926D63F3700B8E046 /* Stinsen in Frameworks */,
|
||||||
|
637FCAF5287B5B2600C0A353 /* UDPBroadcast.xcframework in Frameworks */,
|
||||||
535870912669D7A800D05A09 /* Introspect in Frameworks */,
|
535870912669D7A800D05A09 /* Introspect in Frameworks */,
|
||||||
62666E1B27E501D400EC0ECD /* CoreGraphics.framework in Frameworks */,
|
62666E1B27E501D400EC0ECD /* CoreGraphics.framework in Frameworks */,
|
||||||
536D3D84267BEA550004248C /* ParallaxView in Frameworks */,
|
536D3D84267BEA550004248C /* ParallaxView in Frameworks */,
|
||||||
|
@ -967,6 +968,7 @@
|
||||||
62666E0C27E501A500EC0ECD /* OpenGLES.framework in Frameworks */,
|
62666E0C27E501A500EC0ECD /* OpenGLES.framework in Frameworks */,
|
||||||
C409CE9E285044C800CABC12 /* SwiftUICollection in Frameworks */,
|
C409CE9E285044C800CABC12 /* SwiftUICollection in Frameworks */,
|
||||||
62666E0127E5016900EC0ECD /* CoreFoundation.framework in Frameworks */,
|
62666E0127E5016900EC0ECD /* CoreFoundation.framework in Frameworks */,
|
||||||
|
637FCAF4287B5B2600C0A353 /* UDPBroadcast.xcframework in Frameworks */,
|
||||||
E1B6DCEA271A23880015B715 /* SwiftyJSON in Frameworks */,
|
E1B6DCEA271A23880015B715 /* SwiftyJSON in Frameworks */,
|
||||||
62666E2427E501F300EC0ECD /* Foundation.framework in Frameworks */,
|
62666E2427E501F300EC0ECD /* Foundation.framework in Frameworks */,
|
||||||
53352571265EA0A0006CCA86 /* Introspect in Frameworks */,
|
53352571265EA0A0006CCA86 /* Introspect in Frameworks */,
|
||||||
|
@ -1008,7 +1010,6 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
091B5A872683142E00D78B61 /* ServerDiscovery.swift */,
|
091B5A872683142E00D78B61 /* ServerDiscovery.swift */,
|
||||||
091B5A882683142E00D78B61 /* UDPBroadCastConnection.swift */,
|
|
||||||
);
|
);
|
||||||
path = ServerDiscovery;
|
path = ServerDiscovery;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1353,6 +1354,7 @@
|
||||||
53D5E3DB264B47EE00BADDC8 /* Frameworks */ = {
|
53D5E3DB264B47EE00BADDC8 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
637FCAF3287B5B2600C0A353 /* UDPBroadcast.xcframework */,
|
||||||
62666E3A27E503E400EC0ECD /* GoogleCastSDK.xcframework */,
|
62666E3A27E503E400EC0ECD /* GoogleCastSDK.xcframework */,
|
||||||
62666E3127E5021E00EC0ECD /* UIKit.framework */,
|
62666E3127E5021E00EC0ECD /* UIKit.framework */,
|
||||||
62666E2F27E5021800EC0ECD /* VideoToolbox.framework */,
|
62666E2F27E5021800EC0ECD /* VideoToolbox.framework */,
|
||||||
|
@ -2248,7 +2250,6 @@
|
||||||
536D3D7F267BDF100004248C /* LatestMediaView.swift in Sources */,
|
536D3D7F267BDF100004248C /* LatestMediaView.swift in Sources */,
|
||||||
E1384944278036C70024FB48 /* VLCPlayerViewController.swift in Sources */,
|
E1384944278036C70024FB48 /* VLCPlayerViewController.swift in Sources */,
|
||||||
E1002B652793CEE800E47059 /* ChapterInfoExtensions.swift in Sources */,
|
E1002B652793CEE800E47059 /* ChapterInfoExtensions.swift in Sources */,
|
||||||
091B5A8E268315D400D78B61 /* UDPBroadCastConnection.swift in Sources */,
|
|
||||||
E103A6A5278A82E500820EC7 /* HomeCinematicView.swift in Sources */,
|
E103A6A5278A82E500820EC7 /* HomeCinematicView.swift in Sources */,
|
||||||
E10EAA50277BBCC4000269ED /* CGSizeExtensions.swift in Sources */,
|
E10EAA50277BBCC4000269ED /* CGSizeExtensions.swift in Sources */,
|
||||||
E126F742278A656C00A522BF /* ServerStreamType.swift in Sources */,
|
E126F742278A656C00A522BF /* ServerStreamType.swift in Sources */,
|
||||||
|
@ -2472,7 +2473,6 @@
|
||||||
E1C812C3277A8E5D00918266 /* VLCPlayerOverlayView.swift in Sources */,
|
E1C812C3277A8E5D00918266 /* VLCPlayerOverlayView.swift in Sources */,
|
||||||
E1002B642793CEE800E47059 /* ChapterInfoExtensions.swift in Sources */,
|
E1002B642793CEE800E47059 /* ChapterInfoExtensions.swift in Sources */,
|
||||||
E188460026DECB9E00B0C5B7 /* ItemLandscapeTopBarView.swift in Sources */,
|
E188460026DECB9E00B0C5B7 /* ItemLandscapeTopBarView.swift in Sources */,
|
||||||
091B5A8B2683142E00D78B61 /* UDPBroadCastConnection.swift in Sources */,
|
|
||||||
6267B3D626710B8900A7371D /* CollectionExtensions.swift in Sources */,
|
6267B3D626710B8900A7371D /* CollectionExtensions.swift in Sources */,
|
||||||
E13DD3F5271793BB009D4DAF /* UserSignInView.swift in Sources */,
|
E13DD3F5271793BB009D4DAF /* UserSignInView.swift in Sources */,
|
||||||
5D1603FC278A3D5800D22B99 /* SubtitleSize.swift in Sources */,
|
5D1603FC278A3D5800D22B99 /* SubtitleSize.swift in Sources */,
|
||||||
|
|
Loading…
Reference in New Issue