Forum Archive

How to call objc function

wolf71

How to call objc function (not class).

etc: CACurrentMediaTime()

lukaskollmer

You have to "load" the function from the c library and manually set the return- and argument-types.

If the function returns an object, your fine, but if it returns a c struct, you'll have to recreate this struct in a Python class. example script that does this

Have a look at how @omz accessed the Reachability functions in his answer on this thread

wolf71

@wolf71 said:

CACurrentMediaTime

Thanks.

just using:
from ctypes import *
c = cdl.LoadLibrary(None)
c.CACurrentMediaTime()

JonB

@wolf71 you need to set the return tupe, and argtypes, though in this case argtypes=[].

c = cdll.LoadLibrary(None)
c.CACurrentMediaTime
c.CACurrentMediaTime.restype=c_double
print(c.CACurrentMediaTime())

wolf71

@JonB Thank you.

wolf71

@JonB How to get the ios default values?
etc: get NSDefaultRunLoopMode values

lukaskollmer

@wolf71 since most of these are defined as constants or macros, it's difficult to get their value at runtime. The easiest solution would be to pass the "raw" value of the constant in your code, instead of the constant itself. You can create a new playground in Xcode and just log the constant.
If it's an enum, you usually can just look at the documentation and count which case you need (they're represented by integers starting at 0)

wolf71

@lukaskollmer Thanks.
@JonB How can defind a struct for objc?
etc: AudioStreamBasicDescription (it's objc structure).
and using this to init. init(mSampleRate:mFormatID:mFormatFlags:mBytesPerPacket:mFramesPerPacket:mBytesPerFrame:mChannelsPerFrame:mBitsPerChannel:mReserved:)

JonB

@wolf71 said:

etc: get NSDefaultRunLoopMode values

Many constants can be found using in_dll for the appropriate ctypes type. For instance, NSDefaultRunLoopMode is declared as a NSString, therefore the appropriate ctypes type is a c_void_p. Calling ObjCInstance then gives you the object.

 NSDefaultRunLoopMode=ObjCInstance(c_void_p.in_dll(c,'NSDefaultRunLoopMode').value)

It really seems like you are doing things the hard way... not sure what you are trying to actually do, but if you just want to create a thread, using threading...

JonB

Since this is declared as a STRUCT and not an object, you need to use a ctypes struct.

import ctypes
class AudioStreamBasicDescription(ctypes.Structure):
    _fields_=[('mSampleRate',ctypes.c_double),
                    ('mFormatID',ctypes.c_uint32),
                    ('mFormatFlags',ctypes.c_uint32),
                    ('mBytesPerPacket',ctypes.c_uint32),
                    ('mBytesPerFrame',ctypes.c_uint32),
                    ('mBitsPerChannel',ctypes.c_uint32),
                    ('mReserved',ctypes.c_uint32)]

You initialize by passing positional or keyword arguments, or just init and set attributes.

bd=AudioStreamBasicDescription() #all zeros
bd.mSampleRate=11025

or 
bd=AudioStreamBasicDescription(11025, ........)
or
bd=AudioStreamBasicDescription(mSampleRate=11025, ........)

are all basically the same.
Obviously, you need to figure out the right flags, etc to use. You may need to us a variation of

import struct
struct.unpack('L', b'lpcm')

for the formatId, see the apple docs for the right 4 char code.

wolf71

@JonB Thanks.

This code crash.
** initWithStreamDescription:(const AudioStreamBasicDescription *)asbd
** The AVAudioFormat need this type:
but the AudioStreamBasicDescription is <main.AudioStreamBasicDescription object at 0x110512048>

class AudioStreamBasicDescription(ctypes.Structure):
    _fields_=[('mSampleRate',ctypes.c_double),('mFormatID',ctypes.c_uint32),('mFormatFlags',ctypes.c_uint32),('mBytesPerPacket',ctypes.c_uint32),('mFramesPerPacket',ctypes.c_uint32),('mBytesPerFrame',ctypes.c_uint32),('mChannelsPerFrame',ctypes.c_uint32),('mBitsPerChannel',ctypes.c_uint32),('mReserved',ctypes.c_uint32)]

outformat = AVAudioFormat.alloc().initWithStreamDescription_(AudioStreamBasicDescription(44100,1,0,0,0,0,2,0,0))

JonB

This is a case where you need to override argtypes to point to your structure definition, since the auto definition will not match yours.

Also, I am pretty sure your formatID is invalid. I think you need the four byte code described in the apple docs.

Actually... for what its worth, consider using one of the initWithCommonFormat or initWithStandardFormat methods, which eliminate the need to create your own stream description.

wolf71

@JonB ok,Thanks.

other question: how to define a NSUinteger * var?

# getBuffer:(uint8_t * _Nullable *)buffer
           length:(NSUInteger *)len             
aabuf = c_char_p()
aalen = c_ulong()
inStream.getBuffer_length_(aabuf,aalen)

Error: type 'exceptions.TypeError'>: expected LP_c_ulong instance instead of c_long

wolf71

Using:
inStream.getBuffer_length_(aabuf,pointer(aalen)) ???
or inStream.getBuffer_length_(aabuf,byref(aalen))

dgelessus

@wolf71 In this case you need to pass both arguments using byref. The first argument (buffer) is a pointer-to-pointer-to-char, and aabuf is a pointer-to-char, so you need to use byref to make it a pointer-to-pointer. Same with the next one - len needs to be a pointer-to-long, and aalen is a long, so you need to put it through byref to make it a pointer.