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