From a46ddfebb592852ff791bc90b3953880c49073dd Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sun, 1 Nov 2009 20:06:08 +0100 Subject: core-rtclock.c: tweak OS_IS_DARWIN constraints Move the code for OS_IS_DARWIN to the top as on Darwin, HAVE_CLOCK_GETTIME is also defined. --- src/pulsecore/core-rtclock.c | 69 ++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/pulsecore/core-rtclock.c b/src/pulsecore/core-rtclock.c index 4fe0a47b..110158ba 100644 --- a/src/pulsecore/core-rtclock.c +++ b/src/pulsecore/core-rtclock.c @@ -37,6 +37,7 @@ #include #include #include +#include #endif #include @@ -54,7 +55,19 @@ pa_usec_t pa_rtclock_age(const struct timeval *tv) { struct timeval *pa_rtclock_get(struct timeval *tv) { -#if defined(HAVE_CLOCK_GETTIME) +#if defined(OS_IS_DARWIN) + uint64_t val, abs_time = mach_absolute_time(); + Nanoseconds nanos; + + nanos = AbsoluteToNanoseconds(*(AbsoluteTime *) &abs_time); + val = *(uint64_t *) &nanos; + + tv->tv_sec = val / PA_NSEC_PER_SEC; + tv->tv_usec = (val % PA_NSEC_PER_SEC) / PA_NSEC_PER_USEC; + + return tv; + +#elif defined(HAVE_CLOCK_GETTIME) struct timespec ts; #ifdef CLOCK_MONOTONIC @@ -75,65 +88,39 @@ struct timeval *pa_rtclock_get(struct timeval *tv) { tv->tv_usec = ts.tv_nsec / PA_NSEC_PER_USEC; return tv; - -#elif defined(OS_IS_DARWIN) - static mach_timebase_info_data_t tbi; - uint64_t nticks; - uint64_t time_nsec; - - /* Refer Apple ADC QA1398 - Also: http://devworld.apple.com/documentation/Darwin/Conceptual/KernelProgramming/services/services.html - - Note: argument is timespec NOT timeval (timespec uses nsec, timeval uses usec) - */ - - /* try and be a mite efficient - maybe I should keep the N/D as a float !? */ - if (tbi.denom == 0) - mach_timebase_info(&tbi); - - nticks = mach_absolute_time(); - time_nsec = nticks * tbi.numer / tbi.denom; // see above - - tv->tv_sec = time_nsec / PA_NSEC_PER_SEC; - tv->tv_usec = time_nsec / PA_NSEC_PER_USEC; - - return tv; - -#else /* OS_IS_DARWIN */ +#endif /* HAVE_CLOCK_GETTIME */ return pa_gettimeofday(tv); - -#endif } pa_bool_t pa_rtclock_hrtimer(void) { -#if defined(HAVE_CLOCK_GETTIME) +#if defined (OS_IS_DARWIN) + mach_timebase_info_data_t tbi; + uint64_t time_nsec; + + mach_timebase_info(&tbi); + + /* nsec = nticks * (N/D) - we want 1 tick == resolution !? */ + time_nsec = tbi.numer / tbi.denom; + return time_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC); + +#elif defined(HAVE_CLOCK_GETTIME) struct timespec ts; #ifdef CLOCK_MONOTONIC if (clock_getres(CLOCK_MONOTONIC, &ts) >= 0) return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC); + #endif /* CLOCK_MONOTONIC */ pa_assert_se(clock_getres(CLOCK_REALTIME, &ts) == 0); return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC); -#elif defined (OS_IS_DARWIN) - mach_timebase_info_data_t tbi; - uint64_t time_nsec; - - mach_timebase_info(&tbi); +#endif /* HAVE_CLOCK_GETTIME */ - /* nsec = nticks * (N/D) - we want 1 tick == resolution !? */ - time_nsec = tbi.numer / tbi.denom; - return time_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC); - -#else /* OS_IS_DARWIN */ return FALSE; - -#endif } #define TIMER_SLACK_NS (int) ((500 * PA_NSEC_PER_USEC)) -- cgit From 962164a3b7f17f8a981862d7913a420636241a41 Mon Sep 17 00:00:00 2001 From: Kim Lester Date: Wed, 16 Sep 2009 09:24:27 +0800 Subject: src/Makefile.am: add specific OS_IS_DARWIN files Signed-off-by: Kim Lester Signed-off-by: Daniel Mack --- src/Makefile.am | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 11826a42..90160d1d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -640,12 +640,21 @@ libpulsecommon_@PA_MAJORMINORMICRO@_la_SOURCES += \ pulsecore/mutex-win32.c pulsecore/mutex.h \ pulsecore/thread-win32.c pulsecore/thread.h \ pulsecore/semaphore-win32.c pulsecore/semaphore.h -else +else !OS_IS_WIN32 +if OS_IS_DARWIN +libpulsecommon_@PA_MAJORMINORMICRO@_la_SOURCES += \ + pulsecore/mutex-posix.c pulsecore/mutex.h \ + pulsecore/thread-posix.c pulsecore/thread.h \ + pulsecore/semaphore-osx.c pulsecore/semaphore.h +libpulsecommon_@PA_MAJORMINORMICRO@_la_CFLAGS += "-I/Developer/Headers/FlatCarbon/" +#libpulsecommon_@PA_MAJORMINORMICRO@_la_LDFLAGS += "-framework CoreServices" +else !OS_IS_DARWIN libpulsecommon_@PA_MAJORMINORMICRO@_la_SOURCES += \ pulsecore/mutex-posix.c pulsecore/mutex.h \ pulsecore/thread-posix.c pulsecore/thread.h \ pulsecore/semaphore-posix.c pulsecore/semaphore.h -endif +endif !OS_IS_DARWIN +endif !OS_IS_WIN32 if HAVE_X11 libpulsecommon_@PA_MAJORMINORMICRO@_la_SOURCES += pulsecore/x11prop.c pulsecore/x11prop.h -- cgit From 17d34462eace417075efa2314999a77e41a3849b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 23 Nov 2009 00:12:18 +0100 Subject: poll() is totally broken on Mac OS X Even on 10.5.8, poll() does not do the right thing. Haven't checked on newer versions. Hence, wrap all occurences of poll() to pa_poll and emulate that call with select() on OSX. This is totally embarassing. --- src/modules/module-sine-source.c | 2 +- src/modules/raop/module-raop-sink.c | 2 +- src/modules/raop/raop_client.c | 5 ----- src/modules/rtp/rtsp_client.c | 5 ----- src/pulse/mainloop.c | 9 ++------- src/pulsecore/lock-autospawn.c | 3 ++- src/pulsecore/poll.c | 11 ++++++++--- src/pulsecore/poll.h | 18 +++++++++++++----- src/pulsecore/rtpoll.c | 9 ++------- src/tests/lock-autospawn-test.c | 4 ++-- src/tests/rtpoll-test.c | 2 +- src/utils/pacmd.c | 4 ++-- 12 files changed, 34 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/modules/module-sine-source.c b/src/modules/module-sine-source.c index 9826e5f4..53f53353 100644 --- a/src/modules/module-sine-source.c +++ b/src/modules/module-sine-source.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -48,6 +47,7 @@ #include #include #include +#include #include "module-sine-source-symdef.h" diff --git a/src/modules/raop/module-raop-sink.c b/src/modules/raop/module-raop-sink.c index ac48ab10..ce534ce3 100644 --- a/src/modules/raop/module-raop-sink.c +++ b/src/modules/raop/module-raop-sink.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -60,6 +59,7 @@ #include #include #include +#include #include "module-raop-sink-symdef.h" #include "rtp.h" diff --git a/src/modules/raop/raop_client.c b/src/modules/raop/raop_client.c index c4b02371..e3152dd3 100644 --- a/src/modules/raop/raop_client.c +++ b/src/modules/raop/raop_client.c @@ -51,12 +51,7 @@ #include #include #include - -#ifdef HAVE_POLL_H -#include -#else #include -#endif #include "raop_client.h" #include "rtsp_client.h" diff --git a/src/modules/rtp/rtsp_client.c b/src/modules/rtp/rtsp_client.c index 59618064..6094eb82 100644 --- a/src/modules/rtp/rtsp_client.c +++ b/src/modules/rtp/rtsp_client.c @@ -45,12 +45,7 @@ #include #include #include - -#ifdef HAVE_POLL_H -#include -#else #include -#endif #include "rtsp_client.h" diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index 6cd089ef..8f743ec7 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -32,12 +32,6 @@ #include #include -#ifdef HAVE_POLL_H -#include -#else -#include -#endif - #ifndef HAVE_PIPE #include #endif @@ -47,6 +41,7 @@ #include #include +#include #include #include #include @@ -887,7 +882,7 @@ int pa_mainloop_poll(pa_mainloop *m) { m->prepared_timeout == PA_USEC_INVALID ? NULL : pa_timespec_store(&ts, m->prepared_timeout), NULL); #else - m->poll_func_ret = poll( + m->poll_func_ret = pa_poll( m->pollfds, m->n_pollfds, usec_to_timeout(m->prepared_timeout)); #endif diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c index 65e35634..95ca04a8 100644 --- a/src/pulsecore/lock-autospawn.c +++ b/src/pulsecore/lock-autospawn.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -182,7 +183,7 @@ static void wait_for_ping(void) { pfd.fd = pipe_fd[0]; pfd.events = POLLIN; - if ((k = poll(&pfd, 1, -1)) != 1) { + if ((k = pa_poll(&pfd, 1, -1)) != 1) { pa_assert(k < 0); pa_assert(errno == EINTR); } else if ((s = read(pipe_fd[0], &x, 1)) != 1) { diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c index 46a69c5f..1dcace8b 100644 --- a/src/pulsecore/poll.c +++ b/src/pulsecore/poll.c @@ -43,13 +43,18 @@ #include "winsock.h" -#ifndef HAVE_POLL_H - #include +#include #include "poll.h" -int poll (struct pollfd *fds, unsigned long int nfds, int timeout) { +/* Mac OSX fails to implement poll() in a working way since 10.4. IOW, for + * several years. We need to enable a dirty workaround and emulate that call + * with select(), just like for Windows. sic! */ + +#if !defined(HAVE_POLL_H) || defined(OS_IS_DARWIN) + +int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) { struct timeval tv; fd_set rset, wset, xset; struct pollfd *f; diff --git a/src/pulsecore/poll.h b/src/pulsecore/poll.h index fe0c6af6..a137d974 100644 --- a/src/pulsecore/poll.h +++ b/src/pulsecore/poll.h @@ -24,6 +24,10 @@ Copyright (C) 1994,96,97,98,99,2000,2001,2004 Free Software Foundation, Inc. ***/ +#if defined(HAVE_POLL_H) +#include +#else + /* Event types that can be polled for. These bits may be set in `events' to indicate the interesting event types; they will appear in `revents' to indicate the status of the file descriptor. */ @@ -38,10 +42,6 @@ #define POLLHUP 0x010 /* Hung up. */ #define POLLNVAL 0x020 /* Invalid polling request. */ - -/* Type used for the number of file descriptors. */ -typedef unsigned long int nfds_t; - /* Data structure describing a polling request. */ struct pollfd { @@ -50,9 +50,17 @@ struct pollfd short int revents; /* Types of events that actually occurred. */ }; + /* Poll the file descriptors described by the NFDS structures starting at FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for an event to occur; if TIMEOUT is -1, block until an event occurs. Returns the number of file descriptors with events, zero if timed out, or -1 for errors. */ -extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout); + +#endif /* HAVE_POLL_H */ + +#if defined(HAVE_POLL_H) && !defined(OS_IS_DARWIN) +#define pa_poll(fds,nfds,timeout) poll((fds),(nfds),(timeout)) +#else +int pa_poll (struct pollfd *fds, unsigned long nfds, int timeout); +#endif diff --git a/src/pulsecore/rtpoll.c b/src/pulsecore/rtpoll.c index 666cbc98..83993f02 100644 --- a/src/pulsecore/rtpoll.c +++ b/src/pulsecore/rtpoll.c @@ -30,15 +30,10 @@ #include #include -#ifdef HAVE_POLL_H -#include -#else -#include -#endif - #include #include +#include #include #include #include @@ -304,7 +299,7 @@ int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait_op) { r = ppoll(p->pollfd, p->n_pollfd_used, (!wait_op || p->quit || p->timer_enabled) ? &ts : NULL, NULL); } #else - r = poll(p->pollfd, p->n_pollfd_used, (!wait_op || p->quit || p->timer_enabled) ? (int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)) : -1); + r = pa_poll(p->pollfd, p->n_pollfd_used, (!wait_op || p->quit || p->timer_enabled) ? (int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)) : -1); #endif p->timer_elapsed = r == 0; diff --git a/src/tests/lock-autospawn-test.c b/src/tests/lock-autospawn-test.c index c754e230..6f7156d7 100644 --- a/src/tests/lock-autospawn-test.c +++ b/src/tests/lock-autospawn-test.c @@ -23,9 +23,9 @@ #include #endif -#include #include +#include #include #include #include @@ -69,7 +69,7 @@ static void thread_func2(void *k) { pollfd.fd = fd; pollfd.events = POLLIN; - pa_assert_se(poll(&pollfd, 1, -1) == 1); + pa_assert_se(pa_poll(&pollfd, 1, -1) == 1); pa_log("%i, woke up", PA_PTR_TO_INT(k)); } diff --git a/src/tests/rtpoll-test.c b/src/tests/rtpoll-test.c index 1706cdfa..6a6b73a8 100644 --- a/src/tests/rtpoll-test.c +++ b/src/tests/rtpoll-test.c @@ -22,8 +22,8 @@ #endif #include -#include +#include #include #include diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index ef58e9ce..6ffe94fe 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -38,6 +37,7 @@ #include #include +#include #include #include #include @@ -153,7 +153,7 @@ int main(int argc, char*argv[]) { else if (!ibuf_eof) pollfd[WATCH_STDIN].events |= POLLIN; - if (poll(pollfd, N_WATCH, -1) < 0) { + if (pa_poll(pollfd, N_WATCH, -1) < 0) { if (errno == EINTR) continue; -- cgit From 28a73ad1203efc6f6dc33629ce653f45081210fa Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 7 Dec 2009 00:40:03 +0100 Subject: hack around another OS X bug: recv() with MSG_PEEK does not work At least for pipes, recv() with MSG_PEEK does actually eat up data from file descriptors. Hence, this can't be used for PULLHUP emulation. Use another ioctl hack for that. --- src/pulsecore/poll.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src') diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c index 1dcace8b..b98fb169 100644 --- a/src/pulsecore/poll.c +++ b/src/pulsecore/poll.c @@ -35,6 +35,10 @@ #include #endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + #include #ifdef HAVE_SYS_SELECT_H @@ -60,7 +64,9 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) { struct pollfd *f; int ready; int maxfd = 0; +#ifdef OS_IS_WIN32 char data[64]; +#endif FD_ZERO (&rset); FD_ZERO (&wset); @@ -103,6 +109,7 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) { ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset, SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset, SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv)); + if ((ready == -1) && (errno == EBADF)) { ready = 0; @@ -165,6 +172,8 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) { #endif if (ready > 0) { + int r; + ready = 0; for (f = fds; f < &fds[nfds]; ++f) { f->revents = 0; @@ -172,6 +181,18 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) { if (FD_ISSET (f->fd, &rset)) { /* support for POLLHUP. An hung up descriptor does not increase the return value! */ +#ifdef OS_IS_DARWIN + /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK + * for some kinds of descriptors. Detect if this descriptor is a + * connected socket, a server socket, or something else using a + * 0-byte recv, and use ioctl(2) to detect POLLHUP. */ + r = recv(f->fd, NULL, 0, MSG_PEEK); + if (r == 0 || (r < 0 && errno == ENOTSOCK)) + ioctl(f->fd, FIONREAD, &r); + + if (r == 0) + f->revents |= POLLHUP; +#else /* !OS_IS_DARWIN */ if (recv (f->fd, data, 64, MSG_PEEK) == -1) { if (errno == ESHUTDOWN || errno == ECONNRESET || errno == ECONNABORTED || errno == ENETRESET) { @@ -179,6 +200,7 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) { f->revents |= POLLHUP; } } +#endif if (f->revents == 0) f->revents |= POLLIN; -- cgit From a23f5cf33d21461bdb6e7bb19dd3426041ca5bc1 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 22 Sep 2009 11:10:26 +0800 Subject: CoreAudio: add device detection module This adds a new module for CoreAudio device detection. It registers a callback to detect hotplugged devices and creates/destroys modules named 'module-coreaudio-device'. Devices are identified via a system-wide unique AudioDeviceID. --- src/Makefile.am | 14 ++ src/modules/coreaudio/module-coreaudio-detect.c | 229 ++++++++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 src/modules/coreaudio/module-coreaudio-detect.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 90160d1d..70ab5b07 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1066,6 +1066,11 @@ modlibexec_LTLIBRARIES += \ module-oss.la endif +if HAVE_COREAUDIO +modlibexec_LTLIBRARIES += \ + module-coreaudio-detect.la +endif + pulselibexec_PROGRAMS = if HAVE_ALSA @@ -1238,6 +1243,7 @@ SYMDEF_FILES = \ modules/alsa/module-alsa-sink-symdef.h \ modules/alsa/module-alsa-source-symdef.h \ modules/alsa/module-alsa-card-symdef.h \ + modules/coreaudio/module-coreaudio-detect-symdef.h \ modules/module-solaris-symdef.h \ modules/module-waveout-symdef.h \ modules/module-detect-symdef.h \ @@ -1469,6 +1475,14 @@ module_oss_la_SOURCES = modules/oss/module-oss.c module_oss_la_LDFLAGS = $(MODULE_LDFLAGS) module_oss_la_LIBADD = $(AM_LIBADD) liboss-util.la libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la +# COREAUDIO + +module_coreaudio_detect_la_SOURCES = modules/coreaudio/module-coreaudio-detect.c +module_coreaudio_detect_la_LDFLAGS = $(MODULE_LDFLAGS) \ + -Wl,-framework -Wl,Cocoa -framework CoreAudio \ + -Wl,-framework -Wl,AudioUnit -framework AudioUnit +module_coreaudio_detect_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la + # ALSA libalsa_util_la_SOURCES = modules/alsa/alsa-util.c modules/alsa/alsa-util.h modules/alsa/alsa-mixer.c modules/alsa/alsa-mixer.h modules/alsa/alsa-sink.c modules/alsa/alsa-sink.h modules/alsa/alsa-source.c modules/alsa/alsa-source.h modules/reserve-wrap.c modules/reserve-wrap.h diff --git a/src/modules/coreaudio/module-coreaudio-detect.c b/src/modules/coreaudio/module-coreaudio-detect.c new file mode 100644 index 00000000..872678e7 --- /dev/null +++ b/src/modules/coreaudio/module-coreaudio-detect.c @@ -0,0 +1,229 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Daniel Mack + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include + +#include "module-coreaudio-detect-symdef.h" + +#define DEVICE_MODULE_NAME "module-coreaudio-device" + +PA_MODULE_AUTHOR("Daniel Mack"); +PA_MODULE_DESCRIPTION("CoreAudio device detection"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_USAGE(""); + +typedef struct ca_device ca_device; + +struct ca_device { + AudioDeviceID id; + unsigned int module_index; + PA_LLIST_FIELDS(ca_device); +}; + +struct userdata { + int detect_fds[2]; + pa_io_event *detect_io; + + PA_LLIST_HEAD(ca_device, devices); +}; + +static int ca_device_added(struct pa_module *m, AudioDeviceID id) { + pa_module *mod; + struct userdata *u = m->userdata; + struct ca_device *dev; + char *args; + + pa_assert(u); + + args = pa_sprintf_malloc("device_id=%d", (int) id); + pa_log_debug("Loading %s with arguments '%s'", DEVICE_MODULE_NAME, args); + mod = pa_module_load(m->core, DEVICE_MODULE_NAME, args); + pa_xfree(args); + + if (!mod) { + pa_log_info("Failed to load module %s with arguments '%s'", DEVICE_MODULE_NAME, args); + return -1; + } + + dev = pa_xnew0(ca_device, 1); + dev->module_index = mod->index; + dev->id = id; + + PA_LLIST_INIT(ca_device, dev); + PA_LLIST_PREPEND(ca_device, u->devices, dev); + + return 0; +} + +static int ca_update_device_list(struct pa_module *m) { + OSStatus err; + UInt32 i, size, num_devices; + Boolean writable; + AudioDeviceID *device_id; + struct ca_device *dev; + struct userdata *u = m->userdata; + + pa_assert(u); + + /* get the number of currently available audio devices */ + err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &writable); + if (err) { + pa_log("Unable to get info for kAudioHardwarePropertyDevices."); + return -1; + } + + num_devices = size / sizeof(AudioDeviceID); + device_id = pa_xnew(AudioDeviceID, num_devices); + + err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, device_id); + if (err) { + pa_log("Unable to get kAudioHardwarePropertyDevices."); + pa_xfree(device_id); + return -1; + } + + /* scan for devices which are reported but not in our cached list */ + for (i = 0; i < num_devices; i++) { + bool found = FALSE; + + PA_LLIST_FOREACH(dev, u->devices) + if (dev->id == device_id[i]) { + found = TRUE; + break; + } + + if (!found) + ca_device_added(m, device_id[i]); + } + + /* scan for devices which are in our cached list but are not reported */ +scan_removed: + + PA_LLIST_FOREACH(dev, u->devices) { + bool found = FALSE; + + for (i = 0; i < num_devices; i++) + if (dev->id == device_id[i]) { + found = TRUE; + break; + } + + if (!found) { + pa_log_debug("device id %d has been removed (module index %d) %p", (unsigned int) dev->id, dev->module_index, dev); + pa_module_unload_request_by_index(m->core, dev->module_index, TRUE); + PA_LLIST_REMOVE(ca_device, u->devices, dev); + pa_xfree(dev); + /* the current list item pointer is not valid anymore, so start over. */ + goto scan_removed; + } + } + + pa_xfree(device_id); + return 0; +} + +static OSStatus property_listener_proc(AudioHardwarePropertyID property, void *data) { + struct userdata *u = data; + char dummy = 1; + + pa_assert(u); + + /* dispatch module load/unload operations in main thread */ + if (property == kAudioHardwarePropertyDevices) + write(u->detect_fds[1], &dummy, 1); + + return 0; +} + +static void detect_handle(pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) { + pa_module *m = userdata; + char dummy; + + pa_assert(m); + + read(fd, &dummy, 1); + ca_update_device_list(m); +} + +int pa__init(pa_module *m) { + struct userdata *u = pa_xnew0(struct userdata, 1); + + m->userdata = u; + + if (AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, property_listener_proc, u)) { + pa_log("AudioHardwareAddPropertyListener() failed."); + goto fail; + } + + if (ca_update_device_list(m)) + goto fail; + + pa_assert_se(pipe(u->detect_fds) == 0); + pa_assert_se(u->detect_io = m->core->mainloop->io_new(m->core->mainloop, u->detect_fds[0], PA_IO_EVENT_INPUT, detect_handle, m)); + + return 0; + +fail: + pa_xfree(u); + return -1; +} + +void pa__done(pa_module *m) { + struct userdata *u = m->userdata; + struct ca_device *dev = u->devices; + + pa_assert(u); + + AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, property_listener_proc); + + while (dev) { + struct ca_device *next = dev->next; + + pa_module_unload_request_by_index(m->core, dev->module_index, TRUE); + pa_xfree(dev); + + dev = next; + } + + if (u->detect_fds[0] >= 0) + close(u->detect_fds[0]); + + if (u->detect_fds[1] >= 0) + close(u->detect_fds[1]); + + if (u->detect_io) + m->core->mainloop->io_free(u->detect_io); + + pa_xfree(u); +} -- cgit From 7732421a27870a832d7121bc8342503f2fbf3c2a Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 22 Sep 2009 11:27:57 +0800 Subject: CoreAudio: add audio device module This patch adds support for CoreAudio driven devices under Mac OS X. It is typically instanciated by the CoreAudio device detection module and handles all available streams on a specific device. Sinks are created according to the reported stream configuration. Float32 is used as default audio sample format at it is the only format CoreAudio speaks natively. Hardware volume control is not implemented yet. --- src/Makefile.am | 9 +- src/modules/coreaudio/module-coreaudio-device.c | 820 ++++++++++++++++++++++++ 2 files changed, 828 insertions(+), 1 deletion(-) create mode 100644 src/modules/coreaudio/module-coreaudio-device.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 70ab5b07..fa5d1702 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1068,7 +1068,8 @@ endif if HAVE_COREAUDIO modlibexec_LTLIBRARIES += \ - module-coreaudio-detect.la + module-coreaudio-detect.la \ + module-coreaudio-device.la endif pulselibexec_PROGRAMS = @@ -1244,6 +1245,7 @@ SYMDEF_FILES = \ modules/alsa/module-alsa-source-symdef.h \ modules/alsa/module-alsa-card-symdef.h \ modules/coreaudio/module-coreaudio-detect-symdef.h \ + modules/coreaudio/module-coreaudio-device-symdef.h \ modules/module-solaris-symdef.h \ modules/module-waveout-symdef.h \ modules/module-detect-symdef.h \ @@ -1483,6 +1485,11 @@ module_coreaudio_detect_la_LDFLAGS = $(MODULE_LDFLAGS) \ -Wl,-framework -Wl,AudioUnit -framework AudioUnit module_coreaudio_detect_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la +module_coreaudio_device_la_SOURCES = modules/coreaudio/module-coreaudio-device.c +module_coreaudio_device_la_LDFLAGS = $(MODULE_LDFLAGS) \ + -Wl,-framework -Wl,Cocoa -framework CoreAudio \ + -Wl,-framework -Wl,AudioUnit -framework AudioUnit +module_coreaudio_device_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la # ALSA libalsa_util_la_SOURCES = modules/alsa/alsa-util.c modules/alsa/alsa-util.h modules/alsa/alsa-mixer.c modules/alsa/alsa-mixer.h modules/alsa/alsa-sink.c modules/alsa/alsa-sink.h modules/alsa/alsa-source.c modules/alsa/alsa-source.h modules/reserve-wrap.c modules/reserve-wrap.h diff --git a/src/modules/coreaudio/module-coreaudio-device.c b/src/modules/coreaudio/module-coreaudio-device.c new file mode 100644 index 00000000..a3699e68 --- /dev/null +++ b/src/modules/coreaudio/module-coreaudio-device.c @@ -0,0 +1,820 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Daniel Mack + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* TODO: + - implement hardware volume controls + - handle audio device stream format changes (will require changes to the core) +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "module-coreaudio-device-symdef.h" + +#define DEFAULT_FRAMES_PER_IOPROC 512 + +PA_MODULE_AUTHOR("Daniel Mack"); +PA_MODULE_DESCRIPTION("CoreAudio device"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); +PA_MODULE_USAGE("device_id= " + "ioproc_frames=