Last active
August 29, 2015 14:05
-
-
Save andreif/018045f4a937213761f0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding=utf-8 | |
import ctypes | |
import ctypes.util | |
import sys | |
from coreaudio import ( | |
AudioObjectPropertyAddress, | |
kAudioHardwarePropertyDefaultInputDevice, | |
kAudioObjectPropertyScopeGlobal, | |
kAudioObjectPropertyScopeInput, | |
kAudioObjectPropertyElementMaster, | |
kAudioObjectSystemObject, | |
kAudioDevicePropertyStreamFormat, | |
AudioDeviceID, | |
AudioDeviceIOProc, | |
AudioDeviceIOProcID, | |
AudioDeviceCreateIOProcID, | |
AudioDeviceStart, | |
AudioDeviceStop, | |
AudioObjectGetPropertyData, | |
AudioObjectSetPropertyData, | |
AudioDeviceDestroyIOProcID, | |
AudioStreamBasicDescription, | |
) | |
@AudioDeviceIOProc | |
def proc_audio_input(inDevice, inNow, inInputData, inInputTime, outOutputData, inOutputTime, inClientData): | |
buf = inInputData[0].mBuffers[0] | |
s = ctypes.cast(buf.mData, ctypes.POINTER(ctypes.c_char)) | |
sys.stdout.write(s[:buf.mDataByteSize]) | |
return 0 | |
thePropertyAddress = AudioObjectPropertyAddress( | |
kAudioHardwarePropertyDefaultInputDevice, | |
kAudioObjectPropertyScopeGlobal, | |
kAudioObjectPropertyElementMaster, | |
) | |
inDevice = AudioDeviceID() | |
thePropSize = ctypes.c_uint32(ctypes.sizeof(AudioDeviceID)) | |
assert not AudioObjectGetPropertyData( | |
kAudioObjectSystemObject, | |
ctypes.byref(thePropertyAddress), | |
0, | |
None, | |
ctypes.byref(thePropSize), | |
ctypes.byref(inDevice) | |
) | |
inFormat = AudioStreamBasicDescription() | |
thePropSize = ctypes.c_uint32(ctypes.sizeof(AudioStreamBasicDescription)) | |
thePropertyAddress = AudioObjectPropertyAddress( | |
kAudioDevicePropertyStreamFormat, | |
kAudioObjectPropertyScopeInput, | |
kAudioObjectPropertyElementMaster, | |
) | |
assert not AudioObjectGetPropertyData( | |
inDevice, | |
ctypes.byref(thePropertyAddress), | |
0, | |
None, | |
ctypes.byref(thePropSize), | |
ctypes.byref(inFormat) | |
) | |
if inFormat.mSampleRate != 44100.0: | |
inFormat.mSampleRate = 44100.0 | |
assert not AudioObjectSetPropertyData( | |
inDevice, | |
ctypes.byref(thePropertyAddress), | |
0, | |
None, | |
ctypes.byref(thePropSize), | |
ctypes.byref(inFormat) | |
) | |
theIOProcID = AudioDeviceIOProcID() | |
assert not AudioDeviceCreateIOProcID(inDevice, proc_audio_input, None, ctypes.byref(theIOProcID)) | |
assert not AudioDeviceStart(inDevice, theIOProcID) | |
try: | |
while 1: | |
pass | |
except (KeyboardInterrupt, SystemExit): | |
pass | |
finally: | |
assert not AudioDeviceStop(inDevice, theIOProcID) | |
assert not AudioDeviceDestroyIOProcID(inDevice, theIOProcID) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding=utf-8 | |
import ctypes | |
import ctypes.util | |
CoreAudio = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreAudio')) | |
bytes2int = lambda s: int(s.encode('hex'), 16) | |
OSStatus = ctypes.c_int32 | |
kAudioObjectSystemObject = 1 | |
kAudioHardwarePropertyDefaultInputDevice = bytes2int('dIn ') | |
kAudioHardwarePropertyDefaultOutputDevice = bytes2int('dOut') | |
kAudioDevicePropertyStreamFormat = bytes2int('sfmt') | |
kAudioObjectPropertyScopeGlobal = bytes2int('glob') | |
kAudioObjectPropertyScopeInput = bytes2int('inpt') | |
kAudioObjectPropertyScopeOutput = bytes2int('outp') | |
kAudioObjectPropertyScopePlayThrough = bytes2int('ptru') | |
kAudioObjectPropertyElementMaster = 0 | |
AudioObjectPropertySelector = ctypes.c_uint32 | |
AudioObjectPropertyScope = ctypes.c_uint32 | |
AudioObjectPropertyElement = ctypes.c_uint32 | |
AudioObjectID = ctypes.c_uint32 | |
AudioDeviceID = AudioObjectID | |
class AudioObjectPropertyAddress(ctypes.Structure): | |
_fields_ = [ | |
('mSelector', AudioObjectPropertySelector), | |
('mScope', AudioObjectPropertyScope), | |
('mElement', AudioObjectPropertyElement), | |
] | |
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), | |
] | |
class AudioBuffer(ctypes.Structure): | |
_fields_ = [ | |
('mNumberChannels', ctypes.c_uint32), | |
('mDataByteSize', ctypes.c_uint32), | |
('mData', ctypes.c_void_p), | |
] | |
class AudioBufferList(ctypes.Structure): | |
_fields_ = [ | |
('mNumberBuffers', ctypes.c_uint32), | |
('mBuffers', AudioBuffer * 1), | |
] | |
# typedef OSStatus | |
# (*AudioDeviceIOProc)( AudioObjectID inDevice, | |
# const AudioTimeStamp* inNow, | |
# const AudioBufferList* inInputData, | |
# const AudioTimeStamp* inInputTime, | |
# AudioBufferList* outOutputData, | |
# const AudioTimeStamp* inOutputTime, | |
# void* inClientData); | |
AudioDeviceIOProc = ctypes.CFUNCTYPE( | |
OSStatus, # result type | |
AudioObjectID, # AudioObjectID inDevice, | |
ctypes.c_void_p, # const AudioTimeStamp* inNow, | |
ctypes.POINTER(AudioBufferList), # const AudioBufferList* inInputData, | |
ctypes.c_void_p, # const AudioTimeStamp* inInputTime, | |
ctypes.c_void_p, # AudioBufferList* outOutputData, | |
ctypes.c_void_p, # const AudioTimeStamp* inOutputTime, | |
ctypes.c_void_p, # void* inClientData | |
) | |
AudioDeviceIOProcID = AudioDeviceIOProc | |
def define(name, restype, argtypes): | |
f = getattr(CoreAudio, name) | |
f.restype = restype | |
f.argtypes = argtypes | |
return f | |
# extern OSStatus | |
# AudioObjectGetPropertyData( AudioObjectID inObjectID, | |
# const AudioObjectPropertyAddress* inAddress, | |
# UInt32 inQualifierDataSize, | |
# const void* inQualifierData, | |
# UInt32* ioDataSize, | |
# void* outData) | |
AudioObjectGetPropertyData = define('AudioObjectGetPropertyData', restype=OSStatus, argtypes=( | |
AudioObjectID, # inObjectID | |
ctypes.POINTER(AudioObjectPropertyAddress), # inAddress | |
ctypes.c_uint32, # inQualifierDataSize | |
ctypes.c_void_p, # inQualifierData | |
ctypes.POINTER(ctypes.c_uint32), # inDataSize | |
ctypes.c_void_p, # outData | |
)) | |
# extern OSStatus | |
# AudioObjectSetPropertyData( AudioObjectID inObjectID, | |
# const AudioObjectPropertyAddress* inAddress, | |
# UInt32 inQualifierDataSize, | |
# const void* inQualifierData, | |
# UInt32 inDataSize, | |
# const void* inData) | |
AudioObjectSetPropertyData = define('AudioObjectSetPropertyData', restype=OSStatus, argtypes=( | |
AudioObjectID, # inObjectID | |
ctypes.POINTER(AudioObjectPropertyAddress), # inAddress | |
ctypes.c_uint32, # inQualifierDataSize | |
ctypes.c_void_p, # inQualifierData | |
ctypes.c_uint32, # inDataSize | |
ctypes.c_void_p, # outData | |
)) | |
# extern OSStatus | |
# AudioDeviceCreateIOProcID( AudioObjectID inDevice, | |
# AudioDeviceIOProc inProc, | |
# void* inClientData, | |
# AudioDeviceIOProcID* outIOProcID) | |
AudioDeviceCreateIOProcID = define('AudioDeviceCreateIOProcID', restype=OSStatus, argtypes=( | |
AudioObjectID, | |
AudioDeviceIOProc, | |
ctypes.c_void_p, | |
ctypes.POINTER(AudioDeviceIOProcID), | |
)) | |
# extern OSStatus | |
# AudioDeviceStart( AudioObjectID inDevice, | |
# AudioDeviceIOProcID inProcID) | |
AudioDeviceStart = define('AudioDeviceStart', | |
restype=OSStatus, argtypes=(AudioObjectID, AudioDeviceIOProcID)) | |
AudioDeviceStop = define('AudioDeviceStop', | |
restype=OSStatus, argtypes=(AudioObjectID, AudioDeviceIOProcID)) | |
AudioDeviceDestroyIOProcID = define('AudioDeviceDestroyIOProcID', | |
restype=OSStatus, argtypes=(AudioObjectID, AudioDeviceIOProcID)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <CoreAudio/CoreAudio.h> | |
static OSStatus recordAudioProc( | |
AudioDeviceID inDevice, | |
const AudioTimeStamp* inNow, | |
const AudioBufferList* inInputData, | |
const AudioTimeStamp* inInputTime, | |
AudioBufferList* outOutputData, | |
const AudioTimeStamp* inOutputTime, | |
void* inClientData) | |
{ | |
unsigned byteCount = inInputData->mBuffers[0].mDataByteSize; | |
float *samples = (float*)inInputData->mBuffers[0].mData; | |
write(1, samples, byteCount); | |
return 0; | |
} | |
AudioDeviceID GetDefaultInputDevice() | |
{ | |
AudioDeviceID inDevice = 0; | |
UInt32 theSize = sizeof(AudioDeviceID); | |
AudioObjectPropertyAddress theAddress = { | |
kAudioHardwarePropertyDefaultInputDevice, | |
kAudioObjectPropertyScopeGlobal, | |
kAudioObjectPropertyElementMaster}; | |
AudioObjectGetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, &theSize, &inDevice); | |
return inDevice; | |
} | |
AudioStreamBasicDescription GetDefaultInputDeviceFormat(AudioDeviceID inDevice) | |
{ | |
AudioStreamBasicDescription inDeviceFormat; | |
UInt32 theSize = sizeof(AudioStreamBasicDescription); | |
AudioObjectPropertyAddress theAddress = { | |
kAudioDevicePropertyStreamFormat, | |
kAudioObjectPropertyScopeInput, | |
kAudioObjectPropertyElementMaster | |
}; | |
AudioObjectGetPropertyData(inDevice, &theAddress, 0, NULL, &theSize, &inDeviceFormat); | |
return inDeviceFormat; | |
} | |
OSStatus SetDefaultInputDeviceFormat(AudioDeviceID inDevice, AudioStreamBasicDescription inDeviceFormat) { | |
UInt32 theSize = sizeof(AudioStreamBasicDescription); | |
AudioObjectPropertyAddress theAddress = { | |
kAudioDevicePropertyStreamFormat, | |
kAudioObjectPropertyScopeInput, | |
kAudioObjectPropertyElementMaster | |
}; | |
return AudioObjectSetPropertyData(inDevice, &theAddress, 0, NULL, theSize, &inDeviceFormat); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
AudioDeviceID inDevice = GetDefaultInputDevice(); | |
AudioStreamBasicDescription inFormat = GetDefaultInputDeviceFormat(inDevice); | |
if (isatty(fileno(stdout))) { | |
printf("inDevice = %d \n", inDevice); | |
printf("inFormat->mSampleRate = %f \n", inFormat.mSampleRate); | |
printf("inFormat->mFormatID = %d \n", inFormat.mFormatID); | |
if (inFormat.mFormatID == kAudioFormatLinearPCM) | |
printf("inFormat->mFormatID == kAudioFormatLinearPCM \n"); | |
printf("inFormat->mBytesPerPacket = %d \n", inFormat.mBytesPerPacket); | |
printf("inFormat->mFramesPerPacket = %d \n", inFormat.mFramesPerPacket); | |
printf("inFormat->mBytesPerFrame = %d \n", inFormat.mBytesPerFrame); | |
printf("inFormat->mChannelsPerFrame = %d \n", inFormat.mChannelsPerFrame); | |
printf("inFormat->mBitsPerChannel = %d \n", inFormat.mBitsPerChannel); | |
printf("inFormat->mFormatFlags = %d \n", inFormat.mFormatFlags); | |
return 0; | |
} else { | |
const float standard_rate = 44100.0; | |
if (inFormat.mSampleRate != standard_rate) { | |
inFormat.mSampleRate = standard_rate; | |
SetDefaultInputDeviceFormat(inDevice, inFormat); | |
} | |
} | |
// register the IOProc | |
AudioDeviceIOProcID theIOProcID = NULL; | |
AudioDeviceCreateIOProcID(inDevice, recordAudioProc, NULL, &theIOProcID); | |
// start IO | |
AudioDeviceStart(inDevice, theIOProcID); | |
if (argc > 1) { | |
sleep(strtoumax(argv[1], NULL, 10)); | |
} else { | |
while (1) sleep(5); | |
} | |
// stop IO | |
AudioDeviceStop(inDevice, theIOProcID); | |
// unregister the IOProc | |
AudioDeviceDestroyIOProcID(inDevice, theIOProcID); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment