diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 20 | ||||
| -rw-r--r-- | src/daemon/daemon-conf.c | 10 | ||||
| -rw-r--r-- | src/daemon/daemon-conf.h | 6 | ||||
| -rw-r--r-- | src/daemon/main.c | 2 | ||||
| -rw-r--r-- | src/modules/module-solaris.c | 957 | ||||
| -rw-r--r-- | src/modules/raop/raop_client.c | 5 | ||||
| -rw-r--r-- | src/modules/rtp/rtsp_client.c | 7 | ||||
| -rw-r--r-- | src/pulsecore/core-util.c | 2 | ||||
| -rw-r--r-- | src/pulsecore/rtclock.c | 5 | 
9 files changed, 670 insertions, 344 deletions
| diff --git a/src/Makefile.am b/src/Makefile.am index 9f2fa02a..aa190a45 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -713,8 +713,11 @@ libpulse_la_SOURCES = \  		pulse/xmalloc.c pulse/xmalloc.h  libpulse_la_CFLAGS = $(AM_CFLAGS) -libpulse_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBPULSE_VERSION_INFO) -Wl,-version-script=$(srcdir)/map-file  libpulse_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) $(LTLIBICONV) libpulsecommon-@PA_MAJORMINORMICRO@.la +libpulse_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBPULSE_VERSION_INFO) +if HAVE_GNU_LD +libpulse_la_LDFLAGS += -Wl,-version-script=$(srcdir)/map-file +endif  if HAVE_X11  libpulse_la_SOURCES += pulse/client-conf-x11.c pulse/client-conf-x11.h @@ -725,17 +728,26 @@ endif  libpulse_simple_la_SOURCES = pulse/simple.c pulse/simple.h  libpulse_simple_la_CFLAGS = $(AM_CFLAGS)  libpulse_simple_la_LIBADD = $(AM_LIBADD) libpulse.la libpulsecommon-@PA_MAJORMINORMICRO@.la -libpulse_simple_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBPULSE_SIMPLE_VERSION_INFO) -Wl,-version-script=$(srcdir)/map-file +libpulse_simple_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBPULSE_SIMPLE_VERSION_INFO) +if HAVE_GNU_LD +libpulse_simple_la_LDFLAGS += -Wl,-version-script=$(srcdir)/map-file +endif  libpulse_browse_la_SOURCES = pulse/browser.c pulse/browser.h pulsecore/avahi-wrap.c pulsecore/avahi-wrap.h  libpulse_browse_la_CFLAGS = $(AM_CFLAGS) $(AVAHI_CFLAGS)  libpulse_browse_la_LIBADD = $(AM_LIBADD) libpulse.la libpulsecommon-@PA_MAJORMINORMICRO@.la $(AVAHI_LIBS) -libpulse_browse_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBPULSE_BROWSE_VERSION_INFO) -Wl,-version-script=$(srcdir)/map-file +libpulse_browse_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBPULSE_BROWSE_VERSION_INFO) +if HAVE_GNU_LD +libpulse_browse_la_LDFLAGS += -Wl,-version-script=$(srcdir)/map-file +endif  libpulse_mainloop_glib_la_SOURCES = pulse/glib-mainloop.h pulse/glib-mainloop.c  libpulse_mainloop_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS)  libpulse_mainloop_glib_la_LIBADD = $(AM_LIBADD) libpulse.la libpulsecommon-@PA_MAJORMINORMICRO@.la $(GLIB20_LIBS) -libpulse_mainloop_glib_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO) -Wl,-version-script=$(srcdir)/map-file +libpulse_mainloop_glib_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO) +if HAVE_GNU_LD +libpulse_mainloop_glib_la_LDFLAGS += -Wl,-version-script=$(srcdir)/map-file +endif  ###################################  #         OSS emulation           # diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index b02377ab..ac6cc8aa 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -94,8 +94,10 @@ static const pa_daemon_conf default_conf = {     ,.rlimit_fsize = { .value = 0, .is_set = FALSE },      .rlimit_data = { .value = 0, .is_set = FALSE },      .rlimit_stack = { .value = 0, .is_set = FALSE }, -    .rlimit_core = { .value = 0, .is_set = FALSE }, -    .rlimit_rss = { .value = 0, .is_set = FALSE } +    .rlimit_core = { .value = 0, .is_set = FALSE } +#ifdef RLIMIT_RSS +   ,.rlimit_rss = { .value = 0, .is_set = FALSE } +#endif  #ifdef RLIMIT_NPROC     ,.rlimit_nproc = { .value = 0, .is_set = FALSE }  #endif @@ -472,7 +474,9 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {          { "rlimit-data",                parse_rlimit,             &c->rlimit_data, NULL },          { "rlimit-stack",               parse_rlimit,             &c->rlimit_stack, NULL },          { "rlimit-core",                parse_rlimit,             &c->rlimit_core, NULL }, +#ifdef RLIMIT_RSS          { "rlimit-rss",                 parse_rlimit,             &c->rlimit_rss, NULL }, +#endif  #ifdef RLIMIT_NOFILE          { "rlimit-nofile",              parse_rlimit,             &c->rlimit_nofile, NULL },  #endif @@ -651,7 +655,9 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {      pa_strbuf_printf(s, "rlimit-data = %li\n", c->rlimit_data.is_set ? (long int) c->rlimit_data.value : -1);      pa_strbuf_printf(s, "rlimit-stack = %li\n", c->rlimit_stack.is_set ? (long int) c->rlimit_stack.value : -1);      pa_strbuf_printf(s, "rlimit-core = %li\n", c->rlimit_core.is_set ? (long int) c->rlimit_core.value : -1); +#ifdef RLIMIT_RSS      pa_strbuf_printf(s, "rlimit-rss = %li\n", c->rlimit_rss.is_set ? (long int) c->rlimit_rss.value : -1); +#endif  #ifdef RLIMIT_AS      pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1);  #endif diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index 787676c7..9cec189f 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -87,8 +87,10 @@ typedef struct pa_daemon_conf {      char *config_file;  #ifdef HAVE_SYS_RESOURCE_H -    pa_rlimit rlimit_fsize, rlimit_data, rlimit_stack, rlimit_core, rlimit_rss; - +    pa_rlimit rlimit_fsize, rlimit_data, rlimit_stack, rlimit_core; +#ifdef RLIMIT_RSS +    pa_rlimit rlimit_rss; +#endif  #ifdef RLIMIT_NOFILE      pa_rlimit rlimit_nofile;  #endif diff --git a/src/daemon/main.c b/src/daemon/main.c index 46a279d0..0048e7b7 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -294,7 +294,9 @@ static void set_all_rlimits(const pa_daemon_conf *conf) {      set_one_rlimit(&conf->rlimit_data, RLIMIT_DATA, "RLIMIT_DATA");      set_one_rlimit(&conf->rlimit_stack, RLIMIT_STACK, "RLIMIT_STACK");      set_one_rlimit(&conf->rlimit_core, RLIMIT_CORE, "RLIMIT_CORE"); +#ifdef RLIMIT_RSS      set_one_rlimit(&conf->rlimit_rss, RLIMIT_RSS, "RLIMIT_RSS"); +#endif  #ifdef RLIMIT_NPROC      set_one_rlimit(&conf->rlimit_nproc, RLIMIT_NPROC, "RLIMIT_NPROC");  #endif diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 738115c5..783c2440 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -3,6 +3,7 @@    Copyright 2006 Lennart Poettering    Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB +  Copyright 2009 Finn Thain    PulseAudio is free software; you can redistribute it and/or modify    it under the terms of the GNU Lesser General Public License as published @@ -44,6 +45,7 @@  #include <pulse/mainloop-signal.h>  #include <pulse/xmalloc.h>  #include <pulse/timeval.h> +#include <pulse/util.h>  #include <pulsecore/iochannel.h>  #include <pulsecore/sink.h> @@ -57,22 +59,25 @@  #include <pulsecore/thread-mq.h>  #include <pulsecore/rtpoll.h>  #include <pulsecore/thread.h> +#include <pulsecore/rtclock.h>  #include "module-solaris-symdef.h" -PA_MODULE_AUTHOR("Pierre Ossman") -PA_MODULE_DESCRIPTION("Solaris Sink/Source") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Pierre Ossman"); +PA_MODULE_DESCRIPTION("Solaris Sink/Source"); +PA_MODULE_VERSION(PACKAGE_VERSION);  PA_MODULE_USAGE(      "sink_name=<name for the sink> "      "source_name=<name for the source> " -    "device=<OSS device> record=<enable source?> " +    "device=<audio device file name> " +    "record=<enable source?> "      "playback=<enable sink?> "      "format=<sample format> "      "channels=<number of channels> "      "rate=<sample rate> "      "buffer_size=<record buffer size> " -    "channel_map=<channel map>") +    "channel_map=<channel map>"); +PA_MODULE_LOAD_ONCE(FALSE);  struct userdata {      pa_core *core; @@ -87,15 +92,24 @@ struct userdata {      pa_memchunk memchunk; -    unsigned int page_size; -      uint32_t frame_size; -    uint32_t buffer_size; -    unsigned int written_bytes, read_bytes; +    int32_t buffer_size; +    volatile uint64_t written_bytes, read_bytes; +    pa_mutex *written_bytes_lock; +    char *device_name; +    int mode;      int fd;      pa_rtpoll_item *rtpoll_item;      pa_module *module; + +    pa_bool_t sink_suspended, source_suspended; + +    uint32_t play_samples_msw, record_samples_msw; +    uint32_t prev_playback_samples, prev_record_samples; +    pa_mutex *sample_counter_lock; + +    size_t min_request;  };  static const char* const valid_modargs[] = { @@ -112,89 +126,303 @@ static const char* const valid_modargs[] = {      NULL  }; -#define DEFAULT_SINK_NAME "solaris_output" -#define DEFAULT_SOURCE_NAME "solaris_input"  #define DEFAULT_DEVICE "/dev/audio" +#define MIN_BUFFER_SIZE (640) +#define MAX_RENDER_HZ   (300) -static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { -    struct userdata *u = PA_SINK(o)->userdata; +/* This render rate limit implies a minimum latency,  but without it we waste too much CPU time in the + * IO thread. The maximum render rate and minimum latency (or minimum buffer size) are unachievable on + * common hardware anyway. Note that MIN_BUFFER_SIZE * MAX_RENDER_HZ >= 4 * 48000 Bps. + */ + +static uint64_t get_playback_buffered_bytes(struct userdata *u) { +    audio_info_t info; +    uint64_t played_bytes;      int err; + +    pa_assert(u->sink); + +    pa_mutex_lock(u->sample_counter_lock); + +    err = ioctl(u->fd, AUDIO_GETINFO, &info); +    pa_assert(err >= 0); + +    /* Handle wrap-around of the device's sample counter, which is a uint_32. */ +    if (u->prev_playback_samples > info.play.samples) { +        /* Unfortunately info.play.samples can sometimes go backwards, even before it wraps! */ +        if (u->prev_playback_samples + info.play.samples < 240000) { +            ++u->play_samples_msw; +        } else { +            pa_log_debug("play.samples went backwards %d bytes", u->prev_playback_samples - info.play.samples); +        } +    } +    u->prev_playback_samples = info.play.samples; +    played_bytes = (((uint64_t)u->play_samples_msw << 32) + info.play.samples) * u->frame_size; + +    pa_mutex_unlock(u->sample_counter_lock); + +    return u->written_bytes - played_bytes; +} + +static pa_usec_t sink_get_latency(struct userdata *u, pa_sample_spec *ss) { +    pa_usec_t r = 0; + +    pa_assert(u); +    pa_assert(ss); + +    if (u->fd >= 0) { +        pa_mutex_lock(u->written_bytes_lock); +        r = pa_bytes_to_usec(get_playback_buffered_bytes(u), ss); +        if (u->memchunk.memblock) +            r += pa_bytes_to_usec(u->memchunk.length, ss); +        pa_mutex_unlock(u->written_bytes_lock); +    } +    return r; +} + +static uint64_t get_recorded_bytes(struct userdata *u) {      audio_info_t info; +    uint64_t result; +    int err; -    switch (code) { -    case PA_SINK_MESSAGE_GET_LATENCY: { -        pa_usec_t r = 0; +    pa_assert(u->source); -        if (u->fd >= 0) { +    err = ioctl(u->fd, AUDIO_GETINFO, &info); +    pa_assert(err >= 0); -            err = ioctl(u->fd, AUDIO_GETINFO, &info); -            pa_assert(err >= 0); +    if (u->prev_record_samples > info.record.samples) +        ++u->record_samples_msw; +    u->prev_record_samples = info.record.samples; +    result = (((uint64_t)u->record_samples_msw << 32) + info.record.samples) * u->frame_size; -            r += pa_bytes_to_usec(u->written_bytes, &PA_SINK(o)->sample_spec); -            r -= pa_bytes_to_usec(info.play.samples * u->frame_size, &PA_SINK(o)->sample_spec); +    return result; +} -            if (u->memchunk.memblock) -                r += pa_bytes_to_usec(u->memchunk.length, &PA_SINK(o)->sample_spec); -        } +static pa_usec_t source_get_latency(struct userdata *u, pa_sample_spec *ss) { +    pa_usec_t r = 0; +    audio_info_t info; + +    pa_assert(u); +    pa_assert(ss); -        *((pa_usec_t*) data) = r; +    if (u->fd) { +        int err = ioctl(u->fd, AUDIO_GETINFO, &info); +        pa_assert(err >= 0); -        return 0; +        r = pa_bytes_to_usec(get_recorded_bytes(u), ss) - pa_bytes_to_usec(u->read_bytes, ss);      } +    return r; +} -    case PA_SINK_MESSAGE_SET_VOLUME: -        if (u->fd >= 0) { -            AUDIO_INITINFO(&info); +static void build_pollfd(struct userdata *u) { +    struct pollfd *pollfd; -            info.play.gain = pa_cvolume_avg((pa_cvolume*)data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; -            assert(info.play.gain <= AUDIO_MAX_GAIN); +    pa_assert(u); +    pa_assert(!u->rtpoll_item); +    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); -            if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { -                if (errno == EINVAL) -                    pa_log("AUDIO_SETINFO: Unsupported volume."); -                else -                    pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); -            } else { -                return 0; -            } -        } -        break; +    pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); +    pollfd->fd = u->fd; +    pollfd->events = 0; +    pollfd->revents = 0; +} -    case PA_SINK_MESSAGE_GET_VOLUME: -        if (u->fd >= 0) { -            err = ioctl(u->fd, AUDIO_GETINFO, &info); -            assert(err >= 0); +static int set_buffer(int fd, int buffer_size) { +    audio_info_t info; -            pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels, -                info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); +    pa_assert(fd >= 0); -            return 0; -        } -        break; +    AUDIO_INITINFO(&info); +    info.play.buffer_size = buffer_size; +    info.record.buffer_size = buffer_size; -    case PA_SINK_MESSAGE_SET_MUTE: -        if (u->fd >= 0) { -            AUDIO_INITINFO(&info); +    if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { +        if (errno == EINVAL) +            pa_log("AUDIO_SETINFO: Unsupported buffer size."); +        else +            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); +        return -1; +    } -            info.output_muted = !!PA_PTR_TO_UINT(data); +    return 0; +} -            if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) -                pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); -            else -                return 0; +static int auto_format(int fd, int mode, pa_sample_spec *ss) { +    audio_info_t info; + +    pa_assert(fd >= 0); +    pa_assert(ss); + +    AUDIO_INITINFO(&info); + +    if (mode != O_RDONLY) { +        info.play.sample_rate = ss->rate; +        info.play.channels = ss->channels; +        switch (ss->format) { +        case PA_SAMPLE_U8: +            info.play.precision = 8; +            info.play.encoding = AUDIO_ENCODING_LINEAR; +            break; +        case PA_SAMPLE_ALAW: +            info.play.precision = 8; +            info.play.encoding = AUDIO_ENCODING_ALAW; +            break; +        case PA_SAMPLE_ULAW: +            info.play.precision = 8; +            info.play.encoding = AUDIO_ENCODING_ULAW; +            break; +        case PA_SAMPLE_S16NE: +            info.play.precision = 16; +            info.play.encoding = AUDIO_ENCODING_LINEAR; +            break; +        default: +            pa_log("AUDIO_SETINFO: Unsupported sample format."); +            return -1;          } -        break; +    } -    case PA_SINK_MESSAGE_GET_MUTE: -        if (u->fd >= 0) { -            err = ioctl(u->fd, AUDIO_GETINFO, &info); -            pa_assert(err >= 0); +    if (mode != O_WRONLY) { +        info.record.sample_rate = ss->rate; +        info.record.channels = ss->channels; +        switch (ss->format) { +        case PA_SAMPLE_U8: +            info.record.precision = 8; +            info.record.encoding = AUDIO_ENCODING_LINEAR; +            break; +        case PA_SAMPLE_ALAW: +            info.record.precision = 8; +            info.record.encoding = AUDIO_ENCODING_ALAW; +            break; +        case PA_SAMPLE_ULAW: +            info.record.precision = 8; +            info.record.encoding = AUDIO_ENCODING_ULAW; +            break; +        case PA_SAMPLE_S16NE: +            info.record.precision = 16; +            info.record.encoding = AUDIO_ENCODING_LINEAR; +            break; +        default: +             pa_log("AUDIO_SETINFO: Unsupported sample format."); +             return -1; +        } +    } + +    if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { +        if (errno == EINVAL) +            pa_log("AUDIO_SETINFO: Failed to set sample format."); +        else +            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); +        return -1; +    } + +    return 0; +} + +static int open_audio_device(struct userdata *u, pa_sample_spec *ss) { +    pa_assert(u); +    pa_assert(ss); + +    if ((u->fd = open(u->device_name, u->mode | O_NONBLOCK)) < 0) { +        pa_log_warn("open %s failed (%s)", u->device_name, pa_cstrerror(errno)); +        return -1; +    } + +    pa_log_info("device opened in %s mode.", u->mode == O_WRONLY ? "O_WRONLY" : (u->mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + +    if (auto_format(u->fd, u->mode, ss) < 0) +        return -1; + +    if (set_buffer(u->fd, u->buffer_size) < 0) +        return -1; + +    u->written_bytes = u->read_bytes = 0; +    u->play_samples_msw = u->record_samples_msw = 0; +    u->prev_playback_samples = u->prev_record_samples = 0; + +    return u->fd; +} + +static int suspend(struct userdata *u) { +    pa_assert(u); +    pa_assert(u->fd >= 0); + +    pa_log_info("Suspending..."); + +    ioctl(u->fd, AUDIO_DRAIN, NULL); +    pa_close(u->fd); +    u->fd = -1; + +    if (u->rtpoll_item) { +        pa_rtpoll_item_free(u->rtpoll_item); +        u->rtpoll_item = NULL; +    } + +    pa_log_info("Device suspended."); + +    return 0; +} + +static int unsuspend(struct userdata *u) { +    pa_assert(u); +    pa_assert(u->fd < 0); -            *(int*)data = !!info.output_muted; +    pa_log_info("Resuming..."); +    if (open_audio_device(u, u->sink ? &u->sink->sample_spec : &u->source->sample_spec) < 0) +        return -1; + +    build_pollfd(u); + +    pa_log_info("Device resumed."); + +    return 0; +} + +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { +    struct userdata *u = PA_SINK(o)->userdata; + +    switch (code) { + +        case PA_SINK_MESSAGE_GET_LATENCY: +            *((pa_usec_t*) data) = sink_get_latency(u, &PA_SINK(o)->sample_spec);              return 0; -        } -        break; + +        case PA_SINK_MESSAGE_SET_STATE: + +            switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { + +                case PA_SINK_SUSPENDED: + +                    pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state)); + +                    if (!u->source || u->source_suspended) { +                        if (suspend(u) < 0) +                            return -1; +                    } +                    u->sink_suspended = TRUE; +                    break; + +                case PA_SINK_IDLE: +                case PA_SINK_RUNNING: + +                    if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { +                        if (!u->source || u->source_suspended) { +                            if (unsuspend(u) < 0) +                                return -1; +                            u->sink->get_volume(u->sink); +                            u->sink->get_mute(u->sink); +                        } +                        u->sink_suspended = FALSE; +                    } +                    break; + +                case PA_SINK_INVALID_STATE: +                case PA_SINK_UNLINKED: +                case PA_SINK_INIT: +                    ; +            } + +            break;      }      return pa_sink_process_msg(o, code, data, offset, chunk); @@ -202,95 +430,168 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse  static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {      struct userdata *u = PA_SOURCE(o)->userdata; -    int err; -    audio_info_t info;      switch (code) { -        case PA_SOURCE_MESSAGE_GET_LATENCY: { -            pa_usec_t r = 0; -            if (u->fd) { -                err = ioctl(u->fd, AUDIO_GETINFO, &info); -                pa_assert(err >= 0); +        case PA_SOURCE_MESSAGE_GET_LATENCY: +            *((pa_usec_t*) data) = source_get_latency(u, &PA_SOURCE(o)->sample_spec); +            return 0; -                r += pa_bytes_to_usec(info.record.samples * u->frame_size, &PA_SOURCE(o)->sample_spec); -                r -= pa_bytes_to_usec(u->read_bytes, &PA_SOURCE(o)->sample_spec); -            } +        case PA_SOURCE_MESSAGE_SET_STATE: -            *((pa_usec_t*) data) = r; +            switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) { -            return 0; -        } +                case PA_SOURCE_SUSPENDED: -        case PA_SOURCE_MESSAGE_SET_VOLUME: -            if (u->fd >= 0) { -                AUDIO_INITINFO(&info); +                    pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state)); -                info.record.gain = pa_cvolume_avg((pa_cvolume*) data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; -                assert(info.record.gain <= AUDIO_MAX_GAIN); +                    if (!u->sink || u->sink_suspended) { +                        if (suspend(u) < 0) +                            return -1; +                    } +                    u->source_suspended = TRUE; +                    break; + +                case PA_SOURCE_IDLE: +                case PA_SOURCE_RUNNING: + +                    if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) { +                        if (!u->sink || u->sink_suspended) { +                            if (unsuspend(u) < 0) +                                return -1; +                            u->source->get_volume(u->source); +                        } +                        u->source_suspended = FALSE; +                    } +                    break; + +                case PA_SOURCE_UNLINKED: +                case PA_SOURCE_INIT: +                case PA_SOURCE_INVALID_STATE: +                    ; -                if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { -                    if (errno == EINVAL) -                        pa_log("AUDIO_SETINFO: Unsupported volume."); -                    else -                        pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); -                } else { -                    return 0; -                }              }              break; -        case PA_SOURCE_MESSAGE_GET_VOLUME: -            if (u->fd >= 0) { -                err = ioctl(u->fd, AUDIO_GETINFO, &info); -                pa_assert(err >= 0); +    } -                pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels, -                    info.record.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); +    return pa_source_process_msg(o, code, data, offset, chunk); +} -                return 0; -            } -            break; +static void sink_set_volume(pa_sink *s) { +    struct userdata *u; +    audio_info_t info; + +    pa_assert_se(u = s->userdata); + +    if (u->fd >= 0) { +        AUDIO_INITINFO(&info); + +        info.play.gain = pa_cvolume_avg(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; +        assert(info.play.gain <= AUDIO_MAX_GAIN); + +        if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { +            if (errno == EINVAL) +                pa_log("AUDIO_SETINFO: Unsupported volume."); +            else +                pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); +        }      } +} -    return pa_source_process_msg(o, code, data, offset, chunk); +static void sink_get_volume(pa_sink *s) { +    struct userdata *u; +    audio_info_t info; + +    pa_assert_se(u = s->userdata); + +    if (u->fd >= 0) { +        if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0) +            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); +        else +            pa_cvolume_set(&s->virtual_volume, s->sample_spec.channels, +                info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); +    }  } -static void clear_underflow(struct userdata *u) -{ +static void source_set_volume(pa_source *s) { +    struct userdata *u;      audio_info_t info; -    AUDIO_INITINFO(&info); +    pa_assert_se(u = s->userdata); + +    if (u->fd >= 0) { +        AUDIO_INITINFO(&info); -    info.play.error = 0; +        info.play.gain = pa_cvolume_avg(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; +        assert(info.play.gain <= AUDIO_MAX_GAIN); -    if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) -        pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); +        if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { +            if (errno == EINVAL) +                pa_log("AUDIO_SETINFO: Unsupported volume."); +            else +                pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); +        } +    }  } -static void clear_overflow(struct userdata *u) -{ +static void source_get_volume(pa_source *s) { +    struct userdata *u;      audio_info_t info; -    AUDIO_INITINFO(&info); +    pa_assert_se(u = s->userdata); -    info.record.error = 0; +    if (u->fd >= 0) { +        if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0) +            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); +        else +            pa_cvolume_set(&s->virtual_volume, s->sample_spec.channels, +                info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); +    } +} -    if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) -        pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); +static void sink_set_mute(pa_sink *s) { +    struct userdata *u = s->userdata; +    audio_info_t info; + +    pa_assert(u); + +    if (u->fd >= 0) { +        AUDIO_INITINFO(&info); + +        info.output_muted = !!s->muted; + +        if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) +            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); +    } +} + +static void sink_get_mute(pa_sink *s) { +    struct userdata *u = s->userdata; +    audio_info_t info; + +    pa_assert(u); + +    if (u->fd >= 0) { +        if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0) +            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); +        else +            s->muted = !!info.output_muted; +    }  }  static void thread_func(void *userdata) {      struct userdata *u = userdata;      unsigned short revents = 0; -    int ret; +    int ret, err; +    audio_info_t info;      pa_assert(u);      pa_log_debug("Thread starting up"); -    if (u->core->high_priority) -        pa_make_realtime(); +    if (u->core->realtime_scheduling) +        pa_make_realtime(u->core->realtime_priority);      pa_thread_mq_install(&u->thread_mq);      pa_rtpoll_install(u->rtpoll); @@ -298,139 +599,158 @@ static void thread_func(void *userdata) {      for (;;) {          /* Render some data and write it to the dsp */ -        if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) { -            audio_info_t info; -            int err; -            size_t len; +        if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) { +            pa_usec_t xtime0; +            uint64_t buffered_bytes; + +            if (u->sink->thread_info.rewind_requested) +                pa_sink_process_rewind(u->sink, 0);              err = ioctl(u->fd, AUDIO_GETINFO, &info);              pa_assert(err >= 0); -            /* -             * Since we cannot modify the size of the output buffer we fake it -             * by not filling it more than u->buffer_size. -             */ -            len = u->buffer_size; -            len -= u->written_bytes - (info.play.samples * u->frame_size); - -            /* The sample counter can sometimes go backwards :( */ -            if (len > u->buffer_size) -                len = 0; -              if (info.play.error) { -                pa_log_debug("Solaris buffer underflow!"); -                clear_underflow(u); -            } +                pa_log_debug("buffer under-run!"); -            len -= len % u->frame_size; +                AUDIO_INITINFO(&info); +                info.play.error = 0; +                if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) +                    pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); +            } -            while (len) { +            for (;;) {                  void *p; -                ssize_t r; +                ssize_t w; +                size_t len; + +                /* +                 * Since we cannot modify the size of the output buffer we fake it +                 * by not filling it more than u->buffer_size. +                 */ +                xtime0 = pa_rtclock_usec(); +                buffered_bytes = get_playback_buffered_bytes(u); +                if (buffered_bytes >= (uint64_t)u->buffer_size) +                    break; + +                len = u->buffer_size - buffered_bytes; +                len -= len % u->frame_size; -                if (!u->memchunk.length) -                    pa_sink_render(u->sink, len, &u->memchunk); +                if (len < u->min_request) +                    break; -                pa_assert(u->memchunk.length); +                if (u->memchunk.length < len) +                    pa_sink_render(u->sink, u->sink->thread_info.max_request, &u->memchunk);                  p = pa_memblock_acquire(u->memchunk.memblock); -                r = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, NULL); +                w = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, NULL);                  pa_memblock_release(u->memchunk.memblock); -                if (r < 0) { -                    if (errno == EINTR) -                        continue; -                    else if (errno != EAGAIN) { -                        pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno)); -                        goto fail; +                if (w <= 0) { +                    switch (errno) { +                        case EINTR: +                            break; +                        case EAGAIN: +                            u->buffer_size = u->buffer_size * 18 / 25; +                            u->buffer_size -= u->buffer_size % u->frame_size; +                            u->buffer_size = PA_MAX(u->buffer_size, (int32_t)MIN_BUFFER_SIZE); +                            pa_sink_set_max_request(u->sink, u->buffer_size); +                            pa_log("EAGAIN. Buffer size is now %u bytes (%llu buffered)", u->buffer_size, buffered_bytes); +                            break; +                        default: +                            pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno)); +                            goto fail;                      }                  } else { -                    pa_assert(r % u->frame_size == 0); +                    pa_assert(w % u->frame_size == 0); -                    u->memchunk.index += r; -                    u->memchunk.length -= r; +                    pa_mutex_lock(u->written_bytes_lock); +                    u->written_bytes += w; +                    u->memchunk.length -= w; +                    pa_mutex_unlock(u->written_bytes_lock); +                    u->memchunk.index += w;                      if (u->memchunk.length <= 0) {                          pa_memblock_unref(u->memchunk.memblock);                          pa_memchunk_reset(&u->memchunk);                      } - -                    len -= r; -                    u->written_bytes += r;                  }              } + +            pa_rtpoll_set_timer_absolute(u->rtpoll, xtime0 + pa_bytes_to_usec(buffered_bytes / 2, &u->sink->sample_spec)); +        } else { +            pa_rtpoll_set_timer_disabled(u->rtpoll);          }          /* Try to read some data and pass it on to the source driver */ -        if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state) && ((revents & POLLIN))) { +        if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state) && (revents & POLLIN)) {              pa_memchunk memchunk; -            int err; -            size_t l;              void *p;              ssize_t r; -            audio_info_t info; +            size_t len;              err = ioctl(u->fd, AUDIO_GETINFO, &info);              pa_assert(err >= 0);              if (info.record.error) { -                pa_log_debug("Solaris buffer overflow!"); -                clear_overflow(u); +                pa_log_debug("buffer overflow!"); + +                AUDIO_INITINFO(&info); +                info.record.error = 0; +                if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) +                    pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));              } -            err = ioctl(u->fd, I_NREAD, &l); +            err = ioctl(u->fd, I_NREAD, &len);              pa_assert(err >= 0); -            if (l > 0) { -                /* This is to make sure it fits in the memory pool. Also, a page -                   should be the most efficient transfer size. */ -                if (l > u->page_size) -                    l = u->page_size; - -                memchunk.memblock = pa_memblock_new(u->core->mempool, l); +            if (len > 0) { +                memchunk.memblock = pa_memblock_new(u->core->mempool, len);                  pa_assert(memchunk.memblock);                  p = pa_memblock_acquire(memchunk.memblock); -                r = pa_read(u->fd, p, l, NULL); +                r = pa_read(u->fd, p, len, NULL);                  pa_memblock_release(memchunk.memblock);                  if (r < 0) {                      pa_memblock_unref(memchunk.memblock); -                    if (errno != EAGAIN) { +                    if (errno == EAGAIN) +                        break; +                    else {                          pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));                          goto fail;                      }                  } else { +                    u->read_bytes += r; +                      memchunk.index = 0;                      memchunk.length = r;                      pa_source_post(u->source, &memchunk);                      pa_memblock_unref(memchunk.memblock); -                    u->read_bytes += r; -                      revents &= ~POLLIN;                  }              }          } -        if (u->fd >= 0) { +        if (u->rtpoll_item) {              struct pollfd *pollfd; +            pa_assert(u->fd >= 0); +              pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); -            pollfd->events = -                ((u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) ? POLLIN : 0); +            pollfd->events = (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) ? POLLIN : 0;          }          /* Hmm, nothing to do. Let's sleep */ -        if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0) +        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)              goto fail;          if (ret == 0)              goto finish; -        if (u->fd >= 0) { +        if (u->rtpoll_item) {              struct pollfd *pollfd;              pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); @@ -460,112 +780,29 @@ static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void      assert(u); +    pa_log_debug("caught signal"); +      if (u->sink) { -        pa_sink_get_volume(u->sink); -        pa_sink_get_mute(u->sink); +        pa_sink_get_volume(u->sink, TRUE); +        pa_sink_get_mute(u->sink, TRUE);      }      if (u->source) -        pa_source_get_volume(u->source); -} - -static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) { -    audio_info_t info; - -    AUDIO_INITINFO(&info); - -    if (mode != O_RDONLY) { -        info.play.sample_rate = ss->rate; -        info.play.channels = ss->channels; -        switch (ss->format) { -        case PA_SAMPLE_U8: -            info.play.precision = 8; -            info.play.encoding = AUDIO_ENCODING_LINEAR; -            break; -        case PA_SAMPLE_ALAW: -            info.play.precision = 8; -            info.play.encoding = AUDIO_ENCODING_ALAW; -            break; -        case PA_SAMPLE_ULAW: -            info.play.precision = 8; -            info.play.encoding = AUDIO_ENCODING_ULAW; -            break; -        case PA_SAMPLE_S16NE: -            info.play.precision = 16; -            info.play.encoding = AUDIO_ENCODING_LINEAR; -            break; -        default: -            return -1; -        } -    } - -    if (mode != O_WRONLY) { -        info.record.sample_rate = ss->rate; -        info.record.channels = ss->channels; -        switch (ss->format) { -        case PA_SAMPLE_U8: -            info.record.precision = 8; -            info.record.encoding = AUDIO_ENCODING_LINEAR; -            break; -        case PA_SAMPLE_ALAW: -            info.record.precision = 8; -            info.record.encoding = AUDIO_ENCODING_ALAW; -            break; -        case PA_SAMPLE_ULAW: -            info.record.precision = 8; -            info.record.encoding = AUDIO_ENCODING_ULAW; -            break; -        case PA_SAMPLE_S16NE: -            info.record.precision = 16; -            info.record.encoding = AUDIO_ENCODING_LINEAR; -            break; -        default: -            return -1; -        } -    } - -    if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { -        if (errno == EINVAL) -            pa_log("AUDIO_SETINFO: Unsupported sample format."); -        else -            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); -        return -1; -    } - -    return 0; -} - -static int pa_solaris_set_buffer(int fd, int buffer_size) { -    audio_info_t info; - -    AUDIO_INITINFO(&info); - -    info.play.buffer_size = buffer_size; -    info.record.buffer_size = buffer_size; - -    if (ioctl(fd, AUDIO_SETINFO, &info) < 0) { -        if (errno == EINVAL) -            pa_log("AUDIO_SETINFO: Unsupported buffer size."); -        else -            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); -        return -1; -    } - -    return 0; +        pa_source_get_volume(u->source, TRUE);  }  int pa__init(pa_module *m) {      struct userdata *u = NULL; -    const char *p; -    int fd = -1; -    int buffer_size; -    int mode; -    int record = 1, playback = 1; +    pa_bool_t record = TRUE, playback = TRUE;      pa_sample_spec ss;      pa_channel_map map;      pa_modargs *ma = NULL; -    char *t; -    struct pollfd *pollfd; +    int fd; +    pa_sink_new_data sink_new_data; +    pa_source_new_data source_new_data; +    char const *name; +    char *name_buf; +    pa_bool_t namereg_fail;      pa_assert(m); @@ -575,7 +812,7 @@ int pa__init(pa_module *m) {      }      if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { -        pa_log("record= and playback= expect numeric argument."); +        pa_log("record= and playback= expect a boolean argument.");          goto fail;      } @@ -584,97 +821,135 @@ int pa__init(pa_module *m) {          goto fail;      } -    mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - -    buffer_size = 16384; -    if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) { -        pa_log("failed to parse buffer size argument"); +    if (!(u = pa_xnew0(struct userdata, 1)))          goto fail; -    } + +    u->sample_counter_lock = pa_mutex_new(FALSE, FALSE); +    u->written_bytes_lock = pa_mutex_new(FALSE, FALSE); + +    /* +     * For a process (or several processes) to use the same audio device for both +     * record and playback at the same time, the device's mixer must be enabled. +     * See mixerctl(1). It may be turned off for playback only or record only. +     */ +    u->mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));      ss = m->core->default_sample_spec;      if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {          pa_log("failed to parse sample specification");          goto fail;      } +    u->frame_size = pa_frame_size(&ss); -    if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0) +    u->buffer_size = 16384; +    if (pa_modargs_get_value_s32(ma, "buffer_size", &u->buffer_size) < 0) { +        pa_log("failed to parse buffer size argument");          goto fail; - -    pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - -    if (pa_solaris_auto_format(fd, mode, &ss) < 0) +    } +    u->buffer_size -= u->buffer_size % u->frame_size; +    if (u->buffer_size < (int32_t)MIN_BUFFER_SIZE) { +        pa_log("supplied buffer size argument is too small");          goto fail; +    } + +    u->device_name = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE)); -    if (pa_solaris_set_buffer(fd, buffer_size) < 0) +    if ((fd = open_audio_device(u, &ss)) < 0)          goto fail; -    u = pa_xmalloc(sizeof(struct userdata));      u->core = m->core; - -    u->fd = fd; - -    pa_memchunk_reset(&u->memchunk); - -    /* We use this to get a reasonable chunk size */ -    u->page_size = PA_PAGE_SIZE; - -    u->frame_size = pa_frame_size(&ss); -    u->buffer_size = buffer_size; - -    u->written_bytes = 0; -    u->read_bytes = 0; -      u->module = m;      m->userdata = u; -    pa_thread_mq_init(&u->thread_mq, m->core->mainloop); +    pa_memchunk_reset(&u->memchunk);      u->rtpoll = pa_rtpoll_new(); -    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); +    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); -    pa_rtpoll_set_timer_periodic(u->rtpoll, pa_bytes_to_usec(u->buffer_size / 10, &ss)); +    u->rtpoll_item = NULL; +    build_pollfd(u); -    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); -    pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); -    pollfd->fd = fd; -    pollfd->events = 0; -    pollfd->revents = 0; +    if (u->mode != O_WRONLY) { +        name_buf = NULL; +        namereg_fail = TRUE; -    if (mode != O_WRONLY) { -        u->source = pa_source_new(m->core, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map); -        pa_assert(u->source); +        if (!(name = pa_modargs_get_value(ma, "source_name", NULL))) { +            name = name_buf = pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u->device_name)); +            namereg_fail = FALSE; +        } + +        pa_source_new_data_init(&source_new_data); +        source_new_data.driver = __FILE__; +        source_new_data.module = m; +        pa_source_new_data_set_name(&source_new_data, name); +        source_new_data.namereg_fail = namereg_fail; +        pa_source_new_data_set_sample_spec(&source_new_data, &ss); +        pa_source_new_data_set_channel_map(&source_new_data, &map); +        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name); +        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "solaris"); +        pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM source"); +        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial"); +        pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) u->buffer_size); + +        u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL); +        pa_source_new_data_done(&source_new_data); +        pa_xfree(name_buf); + +        if (!u->source) { +            pa_log("Failed to create source object"); +            goto fail; +        }          u->source->userdata = u;          u->source->parent.process_msg = source_process_msg; -        pa_source_set_module(u->source, m); -        pa_source_set_description(u->source, t = pa_sprintf_malloc("Solaris PCM on '%s'", p)); -        pa_xfree(t);          pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);          pa_source_set_rtpoll(u->source, u->rtpoll); -        u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL; -        u->source->refresh_volume = 1; +        u->source->get_volume = source_get_volume; +        u->source->set_volume = source_set_volume; +        u->source->refresh_volume = TRUE;      } else          u->source = NULL; -    if (mode != O_RDONLY) { -        u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map); -        pa_assert(u->sink); +    if (u->mode != O_RDONLY) { +        name_buf = NULL; +        namereg_fail = TRUE; +        if (!(name = pa_modargs_get_value(ma, "sink_name", NULL))) { +            name = name_buf = pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u->device_name)); +            namereg_fail = FALSE; +        } + +        pa_sink_new_data_init(&sink_new_data); +        sink_new_data.driver = __FILE__; +        sink_new_data.module = m; +        pa_sink_new_data_set_name(&sink_new_data, name); +        sink_new_data.namereg_fail = namereg_fail; +        pa_sink_new_data_set_sample_spec(&sink_new_data, &ss); +        pa_sink_new_data_set_channel_map(&sink_new_data, &map); +        pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name); +        pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_API, "solaris"); +        pa_proplist_setf(sink_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM sink"); +        pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial"); + +        u->sink = pa_sink_new(m->core, &sink_new_data, PA_SINK_HARDWARE|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL|PA_SINK_HW_MUTE_CTRL); +        pa_sink_new_data_done(&sink_new_data); +        pa_assert(u->sink);          u->sink->userdata = u;          u->sink->parent.process_msg = sink_process_msg; -        pa_sink_set_module(u->sink, m); -        pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Solaris PCM on '%s'", p)); -        pa_xfree(t);          pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);          pa_sink_set_rtpoll(u->sink, u->rtpoll); -        u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL; -        u->sink->refresh_volume = 1; -        u->sink->refresh_mute = 1; +        u->sink->get_volume = sink_get_volume; +        u->sink->set_volume = sink_set_volume; +        u->sink->get_mute = sink_get_mute; +        u->sink->set_mute = sink_set_mute; +        u->sink->refresh_volume = u->sink->refresh_muted = TRUE; + +        u->sink->thread_info.max_request = u->buffer_size; +        u->min_request = pa_usec_to_bytes(PA_USEC_PER_SEC / MAX_RENDER_HZ, &ss);      } else          u->sink = NULL; @@ -690,17 +965,28 @@ int pa__init(pa_module *m) {      }      /* Read mixer settings */ -    if (u->source) -        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->source), PA_SOURCE_MESSAGE_GET_VOLUME, &u->source->volume, 0, NULL);      if (u->sink) { -        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_VOLUME, &u->sink->volume, 0, NULL); -        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_MUTE, &u->sink->muted, 0, NULL); -    } +        if (sink_new_data.volume_is_set) +            u->sink->set_volume(u->sink); +        else +            u->sink->get_volume(u->sink); + +        if (sink_new_data.muted_is_set) +            u->sink->set_mute(u->sink); +        else +            u->sink->get_mute(u->sink); -    if (u->sink)          pa_sink_put(u->sink); -    if (u->source) +    } + +    if (u->source) { +        if (source_new_data.volume_is_set) +            u->source->set_volume(u->source); +        else +            u->source->get_volume(u->source); +          pa_source_put(u->source); +    }      pa_modargs_free(ma); @@ -748,7 +1034,7 @@ void pa__done(pa_module *m) {      if (u->source)          pa_source_unref(u->source); -     if (u->memchunk.memblock) +    if (u->memchunk.memblock)          pa_memblock_unref(u->memchunk.memblock);      if (u->rtpoll_item) @@ -760,5 +1046,10 @@ void pa__done(pa_module *m) {      if (u->fd >= 0)          close(u->fd); +    pa_mutex_free(u->written_bytes_lock); +    pa_mutex_free(u->sample_counter_lock); + +    pa_xfree(u->device_name); +      pa_xfree(u);  } diff --git a/src/modules/raop/raop_client.c b/src/modules/raop/raop_client.c index 8e59a577..b3f243c3 100644 --- a/src/modules/raop/raop_client.c +++ b/src/modules/raop/raop_client.c @@ -51,7 +51,12 @@  #include <pulsecore/macro.h>  #include <pulsecore/strbuf.h>  #include <pulsecore/random.h> + +#ifdef HAVE_POLL_H +#include <poll.h> +#else  #include <pulsecore/poll.h> +#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 b0b8a1e0..98db05dd 100644 --- a/src/modules/rtp/rtsp_client.c +++ b/src/modules/rtp/rtsp_client.c @@ -43,9 +43,14 @@  #include <pulsecore/log.h>  #include <pulsecore/macro.h>  #include <pulsecore/strbuf.h> -#include <pulsecore/poll.h>  #include <pulsecore/ioline.h> +#ifdef HAVE_POLL_H +#include <poll.h> +#else +#include <pulsecore/poll.h> +#endif +  #include "rtsp_client.h"  struct pa_rtsp_client { diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index a184bebd..0d243ee6 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -2505,7 +2505,7 @@ char *pa_machine_id(void) {  char *pa_uname_string(void) {      struct utsname u; -    pa_assert_se(uname(&u) == 0); +    pa_assert_se(uname(&u) >= 0);      return pa_sprintf_malloc("%s %s %s %s", u.sysname, u.machine, u.release, u.version);  } diff --git a/src/pulsecore/rtclock.c b/src/pulsecore/rtclock.c index dcbd1184..56ab2ef0 100644 --- a/src/pulsecore/rtclock.c +++ b/src/pulsecore/rtclock.c @@ -27,9 +27,12 @@  #include <stddef.h>  #include <time.h>  #include <sys/time.h> -#include <sys/prctl.h>  #include <errno.h> +#ifdef HAVE_SYS_PRCTL_H +#include <sys/prctl.h> +#endif +  #include <pulse/timeval.h>  #include <pulsecore/macro.h>  #include <pulsecore/core-error.h> | 
