PTPIP camera access

Hi!


Hope this is the right forum but I don't see anything more appropriate for ImageCaptureCore related questions.


Has anybody got PTPIP camera access working on Mojave? Finally Bonjour advertized cameras are visible again in the Image Capture application, but I don't receive an connection on the listener.


The implementation I have

- works fine in macOS < 10.10,

- on 10.11 the connection stalls after reading the camera date property

- on 10.12 and 10.13 an advertized bonjour service is not displayed

- on 10.14 it is displayed again but I don't see any connect to my listener


Minimal aample to reproduce in a macOS playground -

when you

- open ImageCapture.app,

- select "shared devies",

- expand

- select the "Sample Server",


you should see two messages with "New state:..." in the console (== Socket connection establishment).


import Foundation
import Network
import PlaygroundSupport

class PTPIPProtocolHandler {
    private var commandPacketsToSend = [Data]()
    private var commandConnection : NWConnection! = nil

    private var eventPacketsToSend = [Data]()
    private var eventConnection : NWConnection! = nil

    func readHeader(connection: NWConnection) {
        // Read exactly the length of the header
        let headerLength: Int = 12
        connection.receive(minimumIncompleteLength: headerLength, maximumLength: headerLength)
        { (content, contentContext, isComplete, error) in

            Swift.print( "Received: \(content) error:\(error)" )

            if let error = error {
               // 
            } else {
                // Parse out body length
                var length = 0
                var type = 0
                var dataPhaseInfo = 0

                content!.withUnsafeBytes() {
                    (p: UnsafePointer<UInt32>) in
                    length =        Int( UInt32( littleEndian:p[0] ) )
                    type =          Int( UInt32( littleEndian:p[1] ) )
                    dataPhaseInfo = Int( UInt32( littleEndian:p[2] ) )
                }
                self.readPacket(connection, type:type, length: length)
            }
        }
    }

    func readPacket( _ connection: NWConnection, type: Int, length: Int ) {
        connection.receive(minimumIncompleteLength: length, maximumLength: length)
        { (content, contentContext, isComplete, error) in

            Swift.print( "Received data: \(content) error:\(error)" )

            if let error = error {
                 // 
            } else {
                self.handle( connection, data: content!, type: type )
            }
        }
    }

    func handle( _ connection: NWConnection, data: Data, type: Int  ) {

    }
}

class PTPIPDevice : PTPIPProtocolHandler {
    let deviceName : String
    let bonjour : NWListener!
    let listenerQueue = DispatchQueue( label: "PTPIP Discovery" )
    let newConnectionQueue = DispatchQueue( label: "PTPIP connectiom queue" )

    private override init() {
        preconditionFailure( "Need an device name" )
    }

    init?( name: String  ) {
        deviceName = name

        var tcpOptions = NWProtocolTCP.Options()
        let tcpParameters = NWParameters(tls:nil, tcp:tcpOptions  )
        tcpParameters.prohibitExpensivePaths = true
        // tcpParameters.prohibitedInterfaceTypes = [.cellular, .loopback, .wifi]
        tcpParameters.requiredInterfaceType = .wiredEthernet

        if let port = NWEndpoint.Port( rawValue: 15740 ) {
            bonjour = try? NWListener(using: tcpParameters, on: port )
        } else {
            bonjour = try? NWListener(using: .tcp )
        }

        guard let listener = bonjour else {
            return nil
        }
        super.init()

        // Advertise a Bonjour service
        listener.service = NWListener.Service(name:name, type: "_ptp._tcp.")
        listener.newConnectionHandler = {
            (newConnection) in
             Swift.print( "New connection! \(newConnection.endpoint)" )
            // Handle inbound connections
            newConnection.stateUpdateHandler = {
                [weak self] state in
                // .. handle state transitions
                print( "New State: \(state)")
            }
            newConnection.start( queue: self.newConnectionQueue )
            self.readHeader(connection: newConnection )

        }

        listener.stateUpdateHandler = {
            state in
            Swift.print( "New listener state \(state)" )
        }

        listener.start( queue: listenerQueue )
    }
}

let device = PTPIPDevice( name:"Sample Server" )

PlaygroundPage.current.needsIndefiniteExecution = true