Issue #26 resolved

SDL_AudioSpec.callback should be type SDL_AudioCallBack not c_void_p

Michael McCandless
created an issue

I'm using py-sdl2 to play a sound file (see attachment), but when I try to pass my python function as a callback I hit this:

Traceback (most recent call last):
  File "", line 46, in <module>
  File "/Library/Python/2.7/site-packages/sdl2/", line 102, in __init__
    self.callback = callback
TypeError: incompatible types, CFunctionType instance instead of c_void_p instance

With this small fix I'm able to play the sound successfully:

*** /Library/Python/2.7/site-packages/sdl2/ Tue Nov 12 12:28:39 2013
--- /Library/Python/2.7/site-packages/sdl2/    Tue Nov 12 12:29:09 2013
*** 89,95 ****
                  ("samples", Uint16),
                  ("padding", Uint16),
                  ("size", Uint32),
!                 ("callback", c_void_p),
                  ("userdata", c_void_p)
      def __init__(self, freq, aformat, channels, samples,
--- 89,95 ----
                  ("samples", Uint16),
                  ("padding", Uint16),
                  ("size", Uint32),
!                 ("callback", SDL_AudioCallback),
                  ("userdata", c_void_p)
      def __init__(self, freq, aformat, channels, samples,

However, I don't have much experience with SDL, py-sdl2 nor ctypes so it could be I'm doing something wrong. Here's the script I'm using to play sounds (it loads an aiff file and plays it):

import sdl2
import sys
import aifc
import threading

class ReadAIFF:
  def __init__(self, fileName):
    self.a =
    self.frameUpto = 0
    self.bytesPerFrame = self.a.getnchannels() * self.a.getsampwidth()
    self.numFrames = self.a.getnframes()
    self.done = threading.Event()

  def playNextChunk(self, unused, buf, bufSize):
    framesInBuffer = bufSize/self.bytesPerFrame
    framesToRead = min(framesInBuffer, self.numFrames-self.frameUpto)

    if self.frameUpto == self.numFrames:

    # TODO: is there a faster way to copy the string into the ctypes
    # pointer/array?
    for i, b in enumerate(self.a.readframes(framesToRead)):
      buf[i] = ord(b)

    # Play silence after:
    # TODO: is there a faster way to zero out the array?
    for i in range(self.bytesPerFrame*framesToRead, self.bytesPerFrame*framesInBuffer):
      buf[i] = 0

    self.frameUpto += framesToRead

if sdl2.SDL_Init(sdl2.SDL_INIT_AUDIO) != 0:
  raise RuntimeError('failed to init audio')

p = ReadAIFF(sys.argv[1])
spec = sdl2.SDL_AudioSpec(p.a.getframerate(),

# TOOD: instead of passing None for the 4th arg, I really should pass
# anoter AudioSpec and then confirm it matched what I asked for:
devID = sdl2.SDL_OpenAudioDevice(None, 0, spec, None, 0)

# Tell audio device to start playing:
sdl2.SDL_PauseAudioDevice(devID, 0)


Comments (4)

  1. Marcus von Appen repo owner

    Initially the SDL_AudioCallback was avoided due to certain limitations in IronPython. One could cast the callback to a c_void_p, but using ctypes directly is hard enough. I'll recheck the IronPython status and try to come up with a solution.

  2. Log in to comment