Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
How to Support Multipeer Connectivity ?
-
@dgelessus Thank you very much.
edit the bug, but can you tell me how to process the browser:lostPeer: delegate?
======================================
Fatal Python error: AbortedThread 0x000000016e2d3000 (most recent call first):
Objective-C exception details:
NSInvalidArgumentException: -[BrowserDelegate_6 browser:lostPeer:]: unrecognized selector sent to instance 0x134eb9c40
Stack trace:
0 CoreFoundation 0x0000000181f02dc8 <redacted> + 148
1 libobjc.A.dylib 0x0000000181567f80 objc_exception_throw + 56
2 CoreFoundation 0x0000000181f09c4c <redacted> + 0
3 CoreFoundation 0x0000000181f06bec <redacted> + 872
4 CoreFoundation 0x0000000181e04c5c _CF_forwarding_prep_0 + 92
5 libdispatch.dylib 0x000000018194d4bc <redacted> + 24
6 libdispatch.dylib 0x000000018194d47c <redacted> + 16
7 libdispatch.dylib 0x0000000181952b84 _dispatch_main_queue_callback_4CF + 1844
8 CoreFoundation 0x0000000181eb8d50 <redacted> + 12
9 CoreFoundation 0x0000000181eb6bb8 <redacted> + 1628
10 CoreFoundation 0x0000000181de0c50 CFRunLoopRunSpecific + 384
11 GraphicsServices 0x00000001836c8088 GSEventRunModal + 180
12 UIKit 0x00000001870c6088 UIApplicationMain + 204
13 Pythonista3 0x00000001000b01c8 Pythonista3 + 180680
14 libdyld.dylib 0x000000018197e8b8 <redacted> + 4End of exception details.
-
That bug is saying that it tried to call broswe:lostPeer:, but your object did not implement it.
The protocol reference shows those as required.Simply create a method
def browser_lostPeer_(_self, _cmd, browser, peer): print ('lost peer')
and when you create the class pass both methods in the methods argument
... methods=[browser_lostPeer_, browser_foundPeer_withDiscoveryInfo_], ...
-
@JonB Thank you very much.
It's work !!! -
@JonB can you tell me how write this type delegate.
invitationHandler:(void (^)(BOOL accept,
MCSession *session))invitationHandlerdef advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_(_self,_cmd,_advertiser,_peerID,_context,_invitationHandler): print 'ppppppp'
OBJECTIVE-C
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser
didReceiveInvitationFromPeer:(MCPeerID *)peerID
withContext:(NSData *)context
invitationHandler:(void (^)(BOOL accept,
MCSession *session))invitationHandler
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser
-
What you have looks right. Add it to the methods argument of your delegate, and also add the right protocol to your delegate class. MCNearbyServiceAdvertiserDelegate
You are requires to call the handler block with a boolean accept argument, and a MCSession initalized from the peer. StackOverflow gives me:
accept=true session = ObjCClass('MCSession').alloc().initWithPeer(peerID) session.delegate = YOURSERVICEADVERTISERDELEGATE ObjCInstance(handler).invoke(accept, session)
Disclaimer... I don't have anything to test out, you need o find a good end to end example written in ObjC or swift to port over... some of these frameworks are tricky to work with just from the docs alone.
-
@JonB you can using this test code.
Server side:# -*- coding: utf-8 -*- from objc_util import * import ctypes,time,os NSBundle.bundle(Path="/System/Library/Frameworks/MultipeerConnectivity.framework").load() MCPeerID=ObjCClass('MCPeerID') MCSession=ObjCClass('MCSession') MCNearbyServiceAdvertiser=ObjCClass('MCNearbyServiceAdvertiser') MCNearbyServiceBrowser=ObjCClass('MCNearbyServiceBrowser') # Session Delegate def session_peer_didChangeState_(_self,_cmd,_session,_peerID,_state): print 'session change',_peerID,_session,_state def session_didReceiveData_fromPeer_(_self,_cmd,_session,_data,_peerID): print 'Received Data',_data def session_didReceiveStream_withName_fromPeer_(_self,_cmd,_session,_stream,_streamName,_peerID): print 'Received Stream....',_streamName SessionDelegate = create_objc_class('SessionDelegate',methods=[session_peer_didChangeState_, session_didReceiveData_fromPeer_, session_didReceiveStream_withName_fromPeer_],protocols=['MCSessionDelegate']) SDelegate = SessionDelegate.alloc().init() # Advertiser Delegate def advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_(_self,_cmd,advertiser,peerID,context,invitationHandler): print 'ppppppp' #ObjCInstance(invitationHandler).invoke(True,mySession) AdvertiserDelegate = create_objc_class('AdvertiserDelegate',methods=[advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_],protocols=['MCNearbyServiceAdvertiserDelegate']) ADelegate = AdvertiserDelegate.alloc().init() # init PeerID myID = MCPeerID.alloc().initWithDisplayName('wolf_srv') # init Session and delegate mySession = MCSession.alloc().initWithPeer_(myID) mySession.setDelegate_(SDelegate) ''' Server ''' # Create Server and set delegate aSrv = MCNearbyServiceAdvertiser.alloc().initWithPeer_discoveryInfo_serviceType_(myID,ns({'player.name':'apple'}),'audio-srv1') aSrv.setDelegate_(ADelegate) # Start Server aSrv.startAdvertisingPeer() print 'Server start, ID is : ',myID try: while 1: time.sleep(0.1) except KeyboardInterrupt: print 'Server Stop...' aSrv.stopAdvertisingPeer() except: raise
=================================
Browser side# -*- coding: utf-8 -*- from objc_util import * import ctypes,time,os cnt = 0 NSBundle.bundle(Path="/System/Library/Frameworks/MultipeerConnectivity.framework").load() MCPeerID=ObjCClass('MCPeerID') MCSession=ObjCClass('MCSession') MCNearbyServiceAdvertiser=ObjCClass('MCNearbyServiceAdvertiser') MCNearbyServiceBrowser=ObjCClass('MCNearbyServiceBrowser') def session_peer_didChangeState_(_self,_cmd,_session,_peerID,_state): print 'session change',ObjCInstance(_peerID),_state def session_didReceiveData_fromPeer_(_self,_cmd,_session,_data,_peerID): print 'Received Data',_data def session_didReceiveStream_withName_fromPeer_(_self,_cmd,_session,_stream,_streamName,_peerID): print 'Received Stream....',_streamName SessionDelegate = create_objc_class('SessionDelegate',methods=[session_peer_didChangeState_, session_didReceiveData_fromPeer_, session_didReceiveStream_withName_fromPeer_],protocols=['MCSessionDelegate']) SDelegate = SessionDelegate.alloc().init() def browser_didNotStartBrowsingForPeers_(_self,_cmd,_browser,_err): print ('ERROR!!!') def browser_foundPeer_withDiscoveryInfo_(_self, _cmd, _browser, _peerID, _info): global aBr,mySession peerID = ObjCInstance(_peerID) aBr.invitePeer_toSession_withContext_timeout_(peerID,mySession,None,0) #mySession.connectPeer_withNearbyConnectionData_(peerID,None) print '#',peerID,ObjCInstance(_info) def browser_lostPeer_(_self, _cmd, browser, peer): print ('lost peer') BrowserDelegate = create_objc_class('BrowserDelegate',methods=[browser_foundPeer_withDiscoveryInfo_, browser_lostPeer_, browser_didNotStartBrowsingForPeers_],protocols=['MCNearbyServiceBrowserDelegate']) Bdelegate = BrowserDelegate.alloc().init() myID = MCPeerID.alloc().initWithDisplayName('wolf_client') mySession = MCSession.alloc().initWithPeer_(myID) mySession.setDelegate_(SDelegate) print 'my ID',myID aBr = MCNearbyServiceBrowser.alloc().initWithPeer_serviceType_(myID,'audio-srv1') aBr.setDelegate_(Bdelegate) aBr.startBrowsingForPeers() try: while 1: time.sleep(0.1) except KeyboardInterrupt: print 'Close...' aBr.stopBrowsingForPeers() except: raise
-
when delegate trip, Show Error box
Type Error ================ cannot build parament globals == locals =================== def advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_(_self,_cmd,advertiser,peerID,context,invitationHandler):
-
Can you paste the actual traceback (if the debugger pops up, click the button in the corner to expand it, then tap Print Traceback). I seem to remember encountering a similar problem in the past. This comes from ctypes, but we need to know which argument is causing problepms.
-
@JonB not trackback info.
maybe the delegate define problem.
:(void(^)(BOOL accept, MCSession *session))invitationHandler
-
The error comes from ctypes callback.c. I suspect the issue is the ObjCBlock, the c code cannot convert the pointer it gets.
I know I encountered and solved this elsewhere, but can't find the solution, you might trydef advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_(_self,_cmd,advertiser,peerID,context,invitationHandler): print('invitation received') f= advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_ f.argtypes =[c_void_p]*4 f.restype = None f.encoding=b'v@:@@@@?' # also, try f.encoding=b'v@:@@@@' AdvertiserDelegate = create_objc_class('AdvertiserDelegate',methods=[advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_])
-
@JonB It's work. :-)
-
@JonB other problem.
ObjCInstance(invitationHandler).invoke(True,mySession)
No method found for selector "invoke"
print ObjCInstance(invitationHandler)
< NSStackBlock >
Traceback (most recent call last):
File "ctypes/callbacks.c", line 314, in 'calling callback function'
File "/private/var/mobile/Containers/Shared/AppGroup/A2331A94-5917-4220-83BB-A1CC1ED4E5A7/Pythonista3/Documents/Research/MCSrv.py", line 29, in advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler
ObjCInstance(invitationHandler).invoke(True,mySession)
File "/var/containers/Bundle/Application/C653EC7F-B29A-4BAD-8AA1-1B562C926512/Pythonista3.app/Frameworks/PythonistaKit.framework/pylib/site-packages/objc_util.py", line 636, in getattr
cached_method = ObjCInstanceMethod(self, attr)
File "/var/containers/Bundle/Application/C653EC7F-B29A-4BAD-8AA1-1B562C926512/Pythonista3.app/Frameworks/PythonistaKit.framework/pylib/site-packages/objc_util.py", line 860, in init
raise AttributeError('No method found for selector "%s"' % (self.sel_name))
AttributeError: No method found for selector "invoke:" -
It is possible you might need to do something like this
class _block_descriptor (Structure): _fields_ = [('reserved', c_ulong), ('size', c_ulong), ('copy_helper', c_void_p), ('dispose_helper', c_void_p), ('signature', c_char_p)] InvokeFuncType = ctypes.CFUNCTYPE(None, *[c_void_p,ctypes.cbool,c_void_p]) class block_literal(Structure): _fields_ = [('isa', c_void_p), ('flags', c_int), ('reserved', c_int), ('invoke', InvokeFuncType), ('descriptor', _block_descriptor)]
then,
blk=block_literal.from_address(invitationHandler) blk.invoke(ObjCInstance(invitationHandler),True, ObjCInstance(mySession))
It seems as though the ObjCInstance does not handle invoke properly, since invoke is sort of special. The code abive creates the ctypes struct corresponding to the signature, i think, along with the hidden block argument, then calls it.
-
@JonB Thank you very much. I will try it later.
The other question.
I need call this objc function:- (NSInteger)write:(const uint8_t *)buffer
maxLength:(NSUInteger)length
I write this code:
buf=bytearray('sldfjksadklkadflksadjlsadkjsldfksadlf;sajflksddfjkl')
blen=len(buf)
outstream.write_maxLength_(id(buf),blen)=============
Traceback (most recent call last):
File "ctypes/callbacks.c", line 314, in 'calling callback function'
File "/private/var/mobile/Containers/Shared/AppGroup/A2331A94-5917-4220-83BB-A1CC1ED4E5A7/Pythonista3/Documents/Research/MCTest.py", line 40, in session_peer_didChangeState
outstream.write_maxLength_(id(buf),blen)
File "/var/containers/Bundle/Application/C653EC7F-B29A-4BAD-8AA1-1B562C926512/Pythonista3.app/Frameworks/PythonistaKit.framework/pylib/site-packages/objc_util.py", line 897, in call
res = objc_msgSend(obj.ptr, sel(self.sel_name), *args)
ArgumentError: argument 3: <type 'exceptions.TypeError'>: wrong type - (NSInteger)write:(const uint8_t *)buffer
-
@wolf71
A way to check what objc_util thinks you need:restype,argtypes,encoding=objc_util.parse_types(outstream.write_maxLength_.encoding)
which gives
argtypes=[<class 'ctypes.c_void_p'>, <class 'ctypes.c_void_p'>, <class 'ctypes.c_char_p'>, <class 'ctypes.c_ulong'>]
the first two are the hidden self/selector, so the arguments need to be convertible to a char_p and a long.
write_maxlength(b'hello',5)
works (python3), or probably just the string without bytesarray in py2.
buf=ctypes.create_string_buffer(10) buf.value=b'hello'
is another way.
-
@JonB The
b"stuff"
syntax is valid in Python 2 as well, and returns a normalstr
(since Python 2str
is 8-bit anyway). -
@JonB Thank you very much.
It's work !!!
-
I know this is an old thread, but I am desperately wanting to do this in my app. I have copied the code from what was given and it got the two to print seeing each other. After the big section of server and browser side with the correction what needs to be done to get this working and communicating in an app?
-
I am trying to get this to work, but the following just crashes Pythonista (latest beta). All fine if you uncomment the last line. Any ideas?
#coding: utf-8 from objc_util import * NSBundle.bundle(Path="/System/Library/Frameworks/MultipeerConnectivity.framework").load() MCPeerID = ObjCClass('MCPeerID') MCNearbyServiceAdvertiser = ObjCClass('MCNearbyServiceAdvertiser') myID = MCPeerID.alloc().initWithDisplayName('peer') advertiser = MCNearbyServiceAdvertiser.alloc().initWithPeer_discoveryInfo_serviceType_(myID, None, 'dev_srv')
-
Ah, enabled the fault handler and noticed that it was just the service type with an underscore... Nothing to see here, please move along.