source: trunk/StreamVision/AudioDevicemodule.c@ 670

Last change on this file since 670 was 662, checked in by Nicholas Riley, 12 years ago

AudioDevicemodule.c: Support compiling on 10.6 again.

File size: 4.2 KB
Line 
1#include "Python.h"
2#include <AudioToolbox/AudioServices.h>
3
4#define FourCC2Str(code) (char[5]){(code >> 24) & 0xFF, (code >> 16) & 0xFF, (code >> 8) & 0xFF, code & 0xFF, 0}
5
6static PyObject *
7OSError_from_HALError(const char *failed_operation, OSStatus err) {
8 // these error codes are actually mnemonic, so display them
9 return PyErr_Format(PyExc_OSError,
10 "%s failed (%ld - %s)",
11 failed_operation, (long)err, FourCC2Str(err));
12}
13
14#ifndef kAudioDeviceTransportTypeAirPlay
15enum { kAudioDeviceTransportTypeAirPlay = 'airp' }; /* 10.8+ */
16#endif
17
18static PyObject *
19AudioDevice_default_output_device_is_airplay(PyObject *self, PyObject *args) {
20 AudioObjectPropertyAddress propertyAddress;
21 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
22 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
23 propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
24
25 AudioDeviceID deviceID = kAudioDeviceUnknown;
26 UInt32 size = sizeof(deviceID);
27 OSStatus err;
28
29 err = AudioHardwareServiceGetPropertyData(kAudioObjectSystemObject,
30 &propertyAddress, 0, NULL,
31 &size, &deviceID);
32 if (err != noErr)
33 return OSError_from_HALError("AudioHardwareServiceGetPropertyData", err);
34
35 if (deviceID == kAudioDeviceUnknown)
36 Py_RETURN_NONE;
37
38 UInt32 transportType;
39 propertyAddress.mSelector = kAudioDevicePropertyTransportType,
40 err = AudioObjectGetPropertyData(deviceID,
41 &propertyAddress, 0, NULL,
42 &size, &transportType);
43 if (err == kAudioHardwareBadObjectError)
44 Py_RETURN_NONE;
45 if (err != noErr)
46 return OSError_from_HALError("AudioObjectGetPropertyData", err);
47
48 if (transportType == kAudioDeviceTransportTypeAirPlay)
49 Py_RETURN_TRUE;
50 else
51 Py_RETURN_FALSE;
52}
53
54static PyObject *default_output_device_changed_callback = NULL;
55
56OSStatus
57output_device_changed_listener(AudioObjectID inObjectID,
58 UInt32 inNumberAddresses,
59 const AudioObjectPropertyAddress inAddresses[],
60 void *inClientData) {
61 PyGILState_STATE gstate = PyGILState_Ensure();
62 PyObject_CallObject(default_output_device_changed_callback, NULL);
63 PyGILState_Release(gstate);
64
65 return noErr;
66}
67
68static PyObject *
69AudioDevice_set_default_output_device_changed_callback(PyObject *self,
70 PyObject *args) {
71 PyObject *new_callback;
72 if (!PyArg_ParseTuple(args, "O", &new_callback))
73 return NULL;
74
75 if (!PyCallable_Check(new_callback)) {
76 PyErr_SetString(PyExc_TypeError, "parameter must be callable");
77 return NULL;
78 }
79 Py_INCREF(new_callback);
80 if (default_output_device_changed_callback == NULL) {
81 AudioObjectPropertyAddress propertyAddress;
82 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
83 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
84 propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
85
86 OSStatus err;
87 err = AudioObjectAddPropertyListener(kAudioObjectSystemObject,
88 &propertyAddress,
89 &output_device_changed_listener,
90 NULL);
91 if (err != noErr)
92 return OSError_from_HALError("AudioObjectAddPropertyListener", err);
93 } else {
94 Py_DECREF(default_output_device_changed_callback);
95 }
96 default_output_device_changed_callback = new_callback;
97
98 Py_RETURN_NONE;
99}
100
101static PyMethodDef AudioDevicemodule_methods[] = {
102 {"default_output_device_is_airplay",
103 AudioDevice_default_output_device_is_airplay, METH_NOARGS,
104 "default_output_device() -> bool or None\n\n"
105 "Return whether the default CoreAudio output device is an AirPlay device."},
106 {"set_default_output_device_changed_callback",
107 AudioDevice_set_default_output_device_changed_callback, METH_VARARGS,
108 "set_default_output_device_changed_callback(callable)\n\n"
109 "Set a callback invoked when the default CoreAudio output device changes."},
110 {NULL, NULL, 0, NULL}
111};
112
113PyMODINIT_FUNC
114initAudioDevice(void) {
115 (void)Py_InitModule("AudioDevice", AudioDevicemodule_methods);
116}
Note: See TracBrowser for help on using the repository browser.