Forum Archive

Objcblock restype define question.

wolf71

Define a objc function.
typedef AVAudioBuffer * _Nullable (^AVAudioConverterInputBlock)(AVAudioPacketCount inNumberOfPackets, AVAudioConverterInputStatus *outStatus);

Just like below code,but when return inBuffer data (<AVAudioPCMBuffer@0x1702091f0: 0/8192 bytes>) it's crash. Return None it's ok.

typedef AVAudioBuffer * _Nullable -> restype = c_void_p ??

def conv_block(self,inNumberOfPackets,buffstat):
    # buffstat: 0-have data 1-no data 2-endOfStream   3-error
    buffstat.contents.value = 0
    return inBuffer  #ctypes.cast(inBuffer,ctypes.c_void_p) 
        # return None ok, but return inBuffer crash!! return ctypes.cast(inBuffer,ctypes.c_void_p) crash!!

convblock=ObjCBlock(conv_block,restype=c_void_p,argtypes=[c_void_p,c_int32,POINTER(c_long)])
# if using restype = POINTER(c_void_p) , return TypeError: invalid result type for callback function

status = converter.convertToBuffer_error_withInputFromBlock_(outBuffer,error,convblock)
print '>>Ret1:',status,outBuffer
if error:
    print '>>Err:',ObjCInstance(error)


JonB

@wolf71 said:

status = converter.convertToBuffer_error_withInputFromBlock_

As usual, an example getting to this point would be useful. Does the uncaught exception handler provide any clues, or just st seg fault?

You might try returning pointer(inBuffer), since the type seems to be asking for a pointer to an AVAudioBuffer.

wolf71

@JonB

  1. Just seg fault.
    Fatal Python error: Segmentation fault
    Thread 0x000000016e14f000 (most recent call first):

2.I try return pointer(inBuffer), error,
so using pointer(ctypes.cast(inBuffer,ctypes.c_void_p)), error: Exception in ignored

  1. the restype = c_void_p it's right? or need using other?

  2. inBuffer is AVAudioBuffer.

JonB

c_void_p(addressof(inBuffer))
or
cast(pointer(inBuffer),c_void_p)
or possibly just
addressof(inBuffer), but I am not sure about the last one...

alternatively, what type does python think inBuffer is? Is it a custom Structure, or a c_void_p, etc? If it is a structure, you could set restype=POINTER(your_custom_struct), and then return pointer(inBuffer).

wolf71

@JonB said:

  1. ctypes.addressof(inBuffer) TypeError: invalid type
    ctypes.cast(pointer(inBuffer),c_void_p) TypeError: type must have storage info

  2. maybe the restype = c_void_p is wrong, because c_void_p is int/long or None,but the * Nullable it's a buffer. not int/long.

JonB

You will need to post actual code that got you this far. Where did you get inBuffer.

print(type(inBuffer))

wolf71

@JonB

JonB

Can you post a gist of your code... it would help to be able to help, otherwise I am just throwing around guesses.

inBufferPtr=c_void_p(inBuffer.ptr)

...
restype=POINTER(c_void_p)
...

return pointer(inBufferPtr)
wolf71

@JonB Test Code it's here.

# -*- coding: utf-8 -*-

from objc_util import *
import ctypes,time,os,struct,array,console

# AVAudio Define
AVAudioEngine=ObjCClass('AVAudioEngine')
AVAudioSession=ObjCClass('AVAudioSession')
AVAudioUnit=ObjCClass('AVAudioUnit')
AVAudioPlayerNode=ObjCClass('AVAudioPlayerNode')
AVAudioFile=ObjCClass('AVAudioFile')
AVAudioPCMBuffer=ObjCClass('AVAudioPCMBuffer')
AVAudioUnitEffect=ObjCClass('AVAudioUnitEffect')
AVAudioFormat=ObjCClass('AVAudioFormat')
AVAudioCompressedBuffer=ObjCClass('AVAudioCompressedBuffer')
AVAudioConverter=ObjCClass('AVAudioConverter')


# AVAudioFormat: 0-other,1-PCM float32,2 PCM float64,3-PCM int16,4-PCM int32
informat = AVAudioFormat.alloc().initWithCommonFormat_sampleRate_channels_interleaved_(3,44100,2,False) 
outformat = AVAudioFormat.alloc().initWithSettings_(ns({'AVSampleRateKey':44100,'AVNumberOfChannelsKey':2,'AVFormatIDKey':struct.unpack('I', b' caa')[0]})) # ,'mFramesPerPacket':1024}))

inBuffer = AVAudioPCMBuffer.alloc().initWithPCMFormat_frameCapacity_(informat,4096)
converter = AVAudioConverter.alloc().initFromFormat_toFormat_(informat,outformat)
outBuffer = AVAudioCompressedBuffer.alloc().initWithFormat_packetCapacity_maximumPacketSize_(outformat, 8,converter.maximumOutputPacketSize())

gcnt = 0

# typedef AVAudioBuffer * _Nullable (^AVAudioConverterInputBlock)(AVAudioPacketCount inNumberOfPackets, AVAudioConverterInputStatus *outStatus);
def conv_block(self,inNumberOfPackets,buffstat):
    global gcnt

    # buffstat: 0-have data 1-no data 2-endOfStream   3-error
    print '@1',inNumberOfPackets,buffstat.contents.value
    gcnt += 1
    if gcnt == 1:
        buffstat.contents.value = 0
        print '@2',inNumberOfPackets,buffstat.contents.value
        print '!!! InBuff:',inBuffer,type(inBuffer),ctypes.cast(inBuffer,ctypes.c_void_p) #,ctypes.addressof(inBuffer)
        return None #pointer(c_void_p(inBuffer.ptr))
    else:
        buffstat.contents.value = 2
        return None

#convblock=ObjCBlock(conv_block,restype=POINTER(c_void_p),argtypes=[c_void_p,c_int32,POINTER(c_long)])
convblock=ObjCBlock(conv_block,restype=c_void_p,argtypes=[c_void_p,c_int32,POINTER(c_long)])

error=ctypes.c_void_p(0)

status = converter.convertToBuffer_error_withInputFromBlock_(outBuffer,error,convblock)
print '>>Ret1:',status
print '>>out1:',outBuffer
if error:
    print '>>Err:',ObjCInstance(error)

status = converter.convertToBuffer_error_withInputFromBlock_(outBuffer,None,convblock)
print '>>Ret2:',status
print '>>out2:',outBuffer


wolf71

if using restype=POINTER(c_void_p)

Error:
PythonistaKit.framework/pylib/site-packages/objc_util.py", line 955, in init
block.invoke = InvokeFuncType(func)
TypeError: invalid result type for callback function

wolf71

@JonB I Try Using this, it's ok.

return inBuffer.ptr

convblock=ObjCBlock(conv_block,restype=c_void_p,argtypes=[c_void_p,c_int32,POINTER(c_long)])

wolf71

@JonB other question.

the outBuffer.data() is a UnsafeMutableRawPointer,

print outBuffer.data() 
# >>> c_void_p(4635022848) 

# I need get data,so using 
oData = ObjCInstance(outBuffer.data())

# but Pythonista crash.

How Can get the data?

JonB

here is an example i found
http://stackoverflow.com/questions/13723384/audioconverter-number-of-packets-is-wrong

data looks undocumented, you need to go through the audioBufferList, imthink.

For dealing with pointers to buffers, there are a few ways, depening on how you want to fill the data. For the buffer you have to create, probably c_buffer(lengthInBytes) creates the buffer, then use addressof or pointer to get a pointer to the buffer.

For the one you need to read, cast to a (c_charlengthBytes), or use (c_charlengthBytes).from_address, then use regular slicing to access the contents as bytes.

wolf71

@JonB Thanks.


tbuf = (ctypes.c_int16*1024).from_address(outBuffer.data().value)
# Not error,and using tbuf[1] can get data.

# It's right ??