2 This file is part of PulseAudio.
4 Copyright 2006 Lennart Poettering
5 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 Copyright 2009 Finn Thain
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2.1 of the License,
11 or (at your option) any later version.
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
35 #include <sys/ioctl.h>
37 #include <sys/types.h>
42 #include <sys/audio.h>
44 #include <pulse/error.h>
45 #include <pulse/mainloop-signal.h>
46 #include <pulse/xmalloc.h>
47 #include <pulse/timeval.h>
48 #include <pulse/util.h>
49 #include <pulse/rtclock.h>
51 #include <pulsecore/iochannel.h>
52 #include <pulsecore/sink.h>
53 #include <pulsecore/source.h>
54 #include <pulsecore/module.h>
55 #include <pulsecore/sample-util.h>
56 #include <pulsecore/core-util.h>
57 #include <pulsecore/modargs.h>
58 #include <pulsecore/log.h>
59 #include <pulsecore/core-error.h>
60 #include <pulsecore/thread-mq.h>
61 #include <pulsecore/rtpoll.h>
62 #include <pulsecore/thread.h>
63 #include <pulsecore/time-smoother.h>
65 #include "module-solaris-symdef.h"
67 PA_MODULE_AUTHOR("Pierre Ossman");
68 PA_MODULE_DESCRIPTION("Solaris Sink/Source");
69 PA_MODULE_VERSION(PACKAGE_VERSION);
71 "sink_name=<name for the sink> "
72 "sink_properties=<properties for the sink> "
73 "source_name=<name for the source> "
74 "source_properties=<properties for the source> "
75 "device=<audio device file name> "
76 "record=<enable source?> "
77 "playback=<enable sink?> "
78 "format=<sample format> "
79 "channels=<number of channels> "
81 "buffer_length=<milliseconds> "
82 "channel_map=<channel map>");
83 PA_MODULE_LOAD_ONCE(FALSE);
91 pa_thread_mq thread_mq;
100 uint64_t written_bytes, read_bytes;
105 pa_rtpoll_item *rtpoll_item;
108 pa_bool_t sink_suspended, source_suspended;
110 uint32_t play_samples_msw, record_samples_msw;
111 uint32_t prev_playback_samples, prev_record_samples;
113 int32_t minimum_request;
115 pa_smoother *smoother;
118 static const char* const valid_modargs[] = {
134 #define DEFAULT_DEVICE "/dev/audio"
136 #define MAX_RENDER_HZ (300)
137 /* This render rate limit imposes a minimum latency, but without it we waste too much CPU time. */
139 #define MAX_BUFFER_SIZE (128 * 1024)
140 /* An attempt to buffer more than 128 KB causes write() to fail with errno == EAGAIN. */
142 static uint64_t get_playback_buffered_bytes(struct userdata *u) {
144 uint64_t played_bytes;
149 err = ioctl(u->fd, AUDIO_GETINFO, &info);
152 /* Handle wrap-around of the device's sample counter, which is a uint_32. */
153 if (u->prev_playback_samples > info.play.samples) {
155 * Unfortunately info.play.samples can sometimes go backwards, even before it wraps!
156 * The bug seems to be absent on Solaris x86 nv117 with audio810 driver, at least on this (UP) machine.
157 * The bug is present on a different (SMP) machine running Solaris x86 nv103 with audioens driver.
158 * An earlier revision of this file mentions the same bug independently (unknown configuration).
160 if (u->prev_playback_samples + info.play.samples < 240000) {
161 ++u->play_samples_msw;
163 pa_log_debug("play.samples went backwards %d bytes", u->prev_playback_samples - info.play.samples);
166 u->prev_playback_samples = info.play.samples;
167 played_bytes = (((uint64_t)u->play_samples_msw << 32) + info.play.samples) * u->frame_size;
169 pa_smoother_put(u->smoother, pa_rtclock_now(), pa_bytes_to_usec(played_bytes, &u->sink->sample_spec));
171 return u->written_bytes - played_bytes;
174 static pa_usec_t sink_get_latency(struct userdata *u, pa_sample_spec *ss) {
181 r = pa_bytes_to_usec(get_playback_buffered_bytes(u), ss);
182 if (u->memchunk.memblock)
183 r += pa_bytes_to_usec(u->memchunk.length, ss);
188 static uint64_t get_recorded_bytes(struct userdata *u) {
193 pa_assert(u->source);
195 err = ioctl(u->fd, AUDIO_GETINFO, &info);
198 if (u->prev_record_samples > info.record.samples)
199 ++u->record_samples_msw;
200 u->prev_record_samples = info.record.samples;
201 result = (((uint64_t)u->record_samples_msw << 32) + info.record.samples) * u->frame_size;
206 static pa_usec_t source_get_latency(struct userdata *u, pa_sample_spec *ss) {
214 int err = ioctl(u->fd, AUDIO_GETINFO, &info);
217 r = pa_bytes_to_usec(get_recorded_bytes(u), ss) - pa_bytes_to_usec(u->read_bytes, ss);
222 static void build_pollfd(struct userdata *u) {
223 struct pollfd *pollfd;
226 pa_assert(!u->rtpoll_item);
227 u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
229 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
235 static int set_buffer(int fd, int buffer_size) {
240 AUDIO_INITINFO(&info);
241 info.play.buffer_size = buffer_size;
242 info.record.buffer_size = buffer_size;
244 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
246 pa_log("AUDIO_SETINFO: Unsupported buffer size.");
248 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
255 static int auto_format(int fd, int mode, pa_sample_spec *ss) {
261 AUDIO_INITINFO(&info);
263 if (mode != O_RDONLY) {
264 info.play.sample_rate = ss->rate;
265 info.play.channels = ss->channels;
266 switch (ss->format) {
268 info.play.precision = 8;
269 info.play.encoding = AUDIO_ENCODING_LINEAR;
272 info.play.precision = 8;
273 info.play.encoding = AUDIO_ENCODING_ALAW;
276 info.play.precision = 8;
277 info.play.encoding = AUDIO_ENCODING_ULAW;
279 case PA_SAMPLE_S16NE:
280 info.play.precision = 16;
281 info.play.encoding = AUDIO_ENCODING_LINEAR;
284 pa_log("AUDIO_SETINFO: Unsupported sample format.");
289 if (mode != O_WRONLY) {
290 info.record.sample_rate = ss->rate;
291 info.record.channels = ss->channels;
292 switch (ss->format) {
294 info.record.precision = 8;
295 info.record.encoding = AUDIO_ENCODING_LINEAR;
298 info.record.precision = 8;
299 info.record.encoding = AUDIO_ENCODING_ALAW;
302 info.record.precision = 8;
303 info.record.encoding = AUDIO_ENCODING_ULAW;
305 case PA_SAMPLE_S16NE:
306 info.record.precision = 16;
307 info.record.encoding = AUDIO_ENCODING_LINEAR;
310 pa_log("AUDIO_SETINFO: Unsupported sample format.");
315 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
317 pa_log("AUDIO_SETINFO: Failed to set sample format.");
319 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
326 static int open_audio_device(struct userdata *u, pa_sample_spec *ss) {
330 if ((u->fd = pa_open_cloexec(u->device_name, u->mode | O_NONBLOCK, 0)) < 0) {
331 pa_log_warn("open %s failed (%s)", u->device_name, pa_cstrerror(errno));
335 pa_log_info("device opened in %s mode.", u->mode == O_WRONLY ? "O_WRONLY" : (u->mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
337 if (auto_format(u->fd, u->mode, ss) < 0)
340 if (set_buffer(u->fd, u->buffer_size) < 0)
343 u->written_bytes = u->read_bytes = 0;
344 u->play_samples_msw = u->record_samples_msw = 0;
345 u->prev_playback_samples = u->prev_record_samples = 0;
350 static int suspend(struct userdata *u) {
352 pa_assert(u->fd >= 0);
354 pa_log_info("Suspending...");
356 ioctl(u->fd, AUDIO_DRAIN, NULL);
360 if (u->rtpoll_item) {
361 pa_rtpoll_item_free(u->rtpoll_item);
362 u->rtpoll_item = NULL;
365 pa_log_info("Device suspended.");
370 static int unsuspend(struct userdata *u) {
372 pa_assert(u->fd < 0);
374 pa_log_info("Resuming...");
376 if (open_audio_device(u, u->sink ? &u->sink->sample_spec : &u->source->sample_spec) < 0)
381 pa_log_info("Device resumed.");
386 static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
387 struct userdata *u = PA_SINK(o)->userdata;
391 case PA_SINK_MESSAGE_GET_LATENCY:
392 *((pa_usec_t*) data) = sink_get_latency(u, &PA_SINK(o)->sample_spec);
395 case PA_SINK_MESSAGE_SET_STATE:
397 switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
399 case PA_SINK_SUSPENDED:
401 pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
403 pa_smoother_pause(u->smoother, pa_rtclock_now());
405 if (!u->source || u->source_suspended) {
409 u->sink_suspended = TRUE;
413 case PA_SINK_RUNNING:
415 if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
416 pa_smoother_resume(u->smoother, pa_rtclock_now(), TRUE);
418 if (!u->source || u->source_suspended) {
419 if (unsuspend(u) < 0)
421 u->sink->get_volume(u->sink);
422 u->sink->get_mute(u->sink);
424 u->sink_suspended = FALSE;
428 case PA_SINK_INVALID_STATE:
429 case PA_SINK_UNLINKED:
437 return pa_sink_process_msg(o, code, data, offset, chunk);
440 static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
441 struct userdata *u = PA_SOURCE(o)->userdata;
445 case PA_SOURCE_MESSAGE_GET_LATENCY:
446 *((pa_usec_t*) data) = source_get_latency(u, &PA_SOURCE(o)->sample_spec);
449 case PA_SOURCE_MESSAGE_SET_STATE:
451 switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
453 case PA_SOURCE_SUSPENDED:
455 pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
457 if (!u->sink || u->sink_suspended) {
461 u->source_suspended = TRUE;
465 case PA_SOURCE_RUNNING:
467 if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
468 if (!u->sink || u->sink_suspended) {
469 if (unsuspend(u) < 0)
471 u->source->get_volume(u->source);
473 u->source_suspended = FALSE;
477 case PA_SOURCE_UNLINKED:
479 case PA_SOURCE_INVALID_STATE:
487 return pa_source_process_msg(o, code, data, offset, chunk);
490 static void sink_set_volume(pa_sink *s) {
494 pa_assert_se(u = s->userdata);
497 AUDIO_INITINFO(&info);
499 info.play.gain = pa_cvolume_max(&s->real_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
500 assert(info.play.gain <= AUDIO_MAX_GAIN);
502 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
504 pa_log("AUDIO_SETINFO: Unsupported volume.");
506 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
511 static void sink_get_volume(pa_sink *s) {
515 pa_assert_se(u = s->userdata);
518 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
519 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
521 pa_cvolume_set(&s->real_volume, s->sample_spec.channels, info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
525 static void source_set_volume(pa_source *s) {
529 pa_assert_se(u = s->userdata);
532 AUDIO_INITINFO(&info);
534 info.play.gain = pa_cvolume_max(&s->volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
535 assert(info.play.gain <= AUDIO_MAX_GAIN);
537 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
539 pa_log("AUDIO_SETINFO: Unsupported volume.");
541 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
546 static void source_get_volume(pa_source *s) {
550 pa_assert_se(u = s->userdata);
553 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
554 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
556 pa_cvolume_set(&s->volume, s->sample_spec.channels, info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
560 static void sink_set_mute(pa_sink *s) {
561 struct userdata *u = s->userdata;
567 AUDIO_INITINFO(&info);
569 info.output_muted = !!s->muted;
571 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
572 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
576 static void sink_get_mute(pa_sink *s) {
577 struct userdata *u = s->userdata;
583 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
584 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
586 s->muted = !!info.output_muted;
590 static void process_rewind(struct userdata *u) {
591 size_t rewind_nbytes;
595 /* Figure out how much we shall rewind and reset the counter */
596 rewind_nbytes = u->sink->thread_info.rewind_nbytes;
597 u->sink->thread_info.rewind_nbytes = 0;
599 if (rewind_nbytes > 0) {
600 pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes);
601 rewind_nbytes = PA_MIN(u->memchunk.length, rewind_nbytes);
602 u->memchunk.length -= rewind_nbytes;
603 if (u->memchunk.length <= 0 && u->memchunk.memblock) {
604 pa_memblock_unref(u->memchunk.memblock);
605 pa_memchunk_reset(&u->memchunk);
607 pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes);
610 pa_sink_process_rewind(u->sink, rewind_nbytes);
613 static void thread_func(void *userdata) {
614 struct userdata *u = userdata;
615 unsigned short revents = 0;
621 pa_log_debug("Thread starting up");
623 if (u->core->realtime_scheduling)
624 pa_make_realtime(u->core->realtime_priority);
626 pa_thread_mq_install(&u->thread_mq);
628 pa_smoother_set_time_offset(u->smoother, pa_rtclock_now());
631 /* Render some data and write it to the dsp */
633 if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
634 pa_usec_t xtime0, ysleep_interval, xsleep_interval;
635 uint64_t buffered_bytes;
637 if (u->sink->thread_info.rewind_requested)
640 err = ioctl(u->fd, AUDIO_GETINFO, &info);
642 pa_log("AUDIO_GETINFO ioctl failed: %s", pa_cstrerror(errno));
646 if (info.play.error) {
647 pa_log_debug("buffer under-run!");
649 AUDIO_INITINFO(&info);
651 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
652 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
654 pa_smoother_reset(u->smoother, pa_rtclock_now(), TRUE);
664 * Since we cannot modify the size of the output buffer we fake it
665 * by not filling it more than u->buffer_size.
667 xtime0 = pa_rtclock_now();
668 buffered_bytes = get_playback_buffered_bytes(u);
669 if (buffered_bytes >= (uint64_t)u->buffer_size)
672 len = u->buffer_size - buffered_bytes;
673 len -= len % u->frame_size;
675 if (len < (size_t) u->minimum_request)
678 if (!u->memchunk.length)
679 pa_sink_render(u->sink, u->sink->thread_info.max_request, &u->memchunk);
681 len = PA_MIN(u->memchunk.length, len);
683 p = pa_memblock_acquire(u->memchunk.memblock);
684 w = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, len, &write_type);
685 pa_memblock_release(u->memchunk.memblock);
688 if (errno == EINTR) {
690 } else if (errno == EAGAIN) {
691 /* We may have realtime priority so yield the CPU to ensure that fd can become writable again. */
692 pa_log_debug("EAGAIN with %llu bytes buffered.", buffered_bytes);
695 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
699 pa_assert(w % u->frame_size == 0);
701 u->written_bytes += w;
702 u->memchunk.index += w;
703 u->memchunk.length -= w;
704 if (u->memchunk.length <= 0) {
705 pa_memblock_unref(u->memchunk.memblock);
706 pa_memchunk_reset(&u->memchunk);
711 ysleep_interval = pa_bytes_to_usec(buffered_bytes / 2, &u->sink->sample_spec);
712 xsleep_interval = pa_smoother_translate(u->smoother, xtime0, ysleep_interval);
713 pa_rtpoll_set_timer_absolute(u->rtpoll, xtime0 + PA_MIN(xsleep_interval, ysleep_interval));
715 pa_rtpoll_set_timer_disabled(u->rtpoll);
717 /* Try to read some data and pass it on to the source driver */
719 if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state) && (revents & POLLIN)) {
720 pa_memchunk memchunk;
725 err = ioctl(u->fd, AUDIO_GETINFO, &info);
728 if (info.record.error) {
729 pa_log_debug("buffer overflow!");
731 AUDIO_INITINFO(&info);
732 info.record.error = 0;
733 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
734 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
737 err = ioctl(u->fd, I_NREAD, &len);
741 memchunk.memblock = pa_memblock_new(u->core->mempool, len);
742 pa_assert(memchunk.memblock);
744 p = pa_memblock_acquire(memchunk.memblock);
745 r = pa_read(u->fd, p, len, NULL);
746 pa_memblock_release(memchunk.memblock);
749 pa_memblock_unref(memchunk.memblock);
753 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
762 pa_source_post(u->source, &memchunk);
763 pa_memblock_unref(memchunk.memblock);
770 if (u->rtpoll_item) {
771 struct pollfd *pollfd;
773 pa_assert(u->fd >= 0);
775 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
776 pollfd->events = (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) ? POLLIN : 0;
779 /* Hmm, nothing to do. Let's sleep */
780 if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
786 if (u->rtpoll_item) {
787 struct pollfd *pollfd;
789 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
791 if (pollfd->revents & ~(POLLOUT|POLLIN)) {
792 pa_log("DSP shutdown.");
796 revents = pollfd->revents;
802 /* We have to continue processing messages until we receive the
803 * SHUTDOWN message */
804 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
805 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
808 pa_log_debug("Thread shutting down");
811 static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) {
812 struct userdata *u = userdata;
816 pa_log_debug("caught signal");
819 pa_sink_get_volume(u->sink, TRUE);
820 pa_sink_get_mute(u->sink, TRUE);
824 pa_source_get_volume(u->source, TRUE);
827 int pa__init(pa_module *m) {
828 struct userdata *u = NULL;
829 pa_bool_t record = TRUE, playback = TRUE;
832 pa_modargs *ma = NULL;
833 uint32_t buffer_length_msec;
835 pa_sink_new_data sink_new_data;
836 pa_source_new_data source_new_data;
839 pa_bool_t namereg_fail;
843 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
844 pa_log("failed to parse module arguments.");
848 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
849 pa_log("record= and playback= expect a boolean argument.");
853 if (!playback && !record) {
854 pa_log("neither playback nor record enabled for device.");
858 u = pa_xnew0(struct userdata, 1);
860 if (!(u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC * 2, TRUE, TRUE, 10, pa_rtclock_now(), TRUE)))
864 * For a process (or several processes) to use the same audio device for both
865 * record and playback at the same time, the device's mixer must be enabled.
866 * See mixerctl(1). It may be turned off for playback only or record only.
868 u->mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
870 ss = m->core->default_sample_spec;
871 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
872 pa_log("failed to parse sample specification");
875 u->frame_size = pa_frame_size(&ss);
877 u->minimum_request = pa_usec_to_bytes(PA_USEC_PER_SEC / MAX_RENDER_HZ, &ss);
879 buffer_length_msec = 100;
880 if (pa_modargs_get_value_u32(ma, "buffer_length", &buffer_length_msec) < 0) {
881 pa_log("failed to parse buffer_length argument");
884 u->buffer_size = pa_usec_to_bytes(1000 * buffer_length_msec, &ss);
885 if (u->buffer_size < 2 * u->minimum_request) {
886 pa_log("buffer_length argument cannot be smaller than %u",
887 (unsigned)(pa_bytes_to_usec(2 * u->minimum_request, &ss) / 1000));
890 if (u->buffer_size > MAX_BUFFER_SIZE) {
891 pa_log("buffer_length argument cannot be greater than %u",
892 (unsigned)(pa_bytes_to_usec(MAX_BUFFER_SIZE, &ss) / 1000));
896 u->device_name = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
898 if ((fd = open_audio_device(u, &ss)) < 0)
905 pa_memchunk_reset(&u->memchunk);
907 u->rtpoll = pa_rtpoll_new();
908 pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
910 u->rtpoll_item = NULL;
913 if (u->mode != O_WRONLY) {
917 if (!(name = pa_modargs_get_value(ma, "source_name", NULL))) {
918 name = name_buf = pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u->device_name));
919 namereg_fail = FALSE;
922 pa_source_new_data_init(&source_new_data);
923 source_new_data.driver = __FILE__;
924 source_new_data.module = m;
925 pa_source_new_data_set_name(&source_new_data, name);
926 source_new_data.namereg_fail = namereg_fail;
927 pa_source_new_data_set_sample_spec(&source_new_data, &ss);
928 pa_source_new_data_set_channel_map(&source_new_data, &map);
929 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
930 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
931 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM source");
932 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");
933 pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) u->buffer_size);
935 if (pa_modargs_get_proplist(ma, "source_properties", source_new_data.proplist, PA_UPDATE_REPLACE) < 0) {
936 pa_log("Invalid properties");
937 pa_source_new_data_done(&source_new_data);
941 u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL);
942 pa_source_new_data_done(&source_new_data);
946 pa_log("Failed to create source object");
950 u->source->userdata = u;
951 u->source->parent.process_msg = source_process_msg;
953 pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
954 pa_source_set_rtpoll(u->source, u->rtpoll);
955 pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->buffer_size, &u->source->sample_spec));
957 u->source->get_volume = source_get_volume;
958 u->source->set_volume = source_set_volume;
959 u->source->refresh_volume = TRUE;
963 if (u->mode != O_RDONLY) {
966 if (!(name = pa_modargs_get_value(ma, "sink_name", NULL))) {
967 name = name_buf = pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u->device_name));
968 namereg_fail = FALSE;
971 pa_sink_new_data_init(&sink_new_data);
972 sink_new_data.driver = __FILE__;
973 sink_new_data.module = m;
974 pa_sink_new_data_set_name(&sink_new_data, name);
975 sink_new_data.namereg_fail = namereg_fail;
976 pa_sink_new_data_set_sample_spec(&sink_new_data, &ss);
977 pa_sink_new_data_set_channel_map(&sink_new_data, &map);
978 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
979 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
980 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM sink");
981 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");
983 if (pa_modargs_get_proplist(ma, "sink_properties", sink_new_data.proplist, PA_UPDATE_REPLACE) < 0) {
984 pa_log("Invalid properties");
985 pa_sink_new_data_done(&sink_new_data);
989 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);
990 pa_sink_new_data_done(&sink_new_data);
993 u->sink->userdata = u;
994 u->sink->parent.process_msg = sink_process_msg;
996 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
997 pa_sink_set_rtpoll(u->sink, u->rtpoll);
998 pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->buffer_size, &u->sink->sample_spec));
999 pa_sink_set_max_request(u->sink, u->buffer_size);
1000 pa_sink_set_max_rewind(u->sink, u->buffer_size);
1002 u->sink->get_volume = sink_get_volume;
1003 u->sink->set_volume = sink_set_volume;
1004 u->sink->get_mute = sink_get_mute;
1005 u->sink->set_mute = sink_set_mute;
1006 u->sink->refresh_volume = u->sink->refresh_muted = TRUE;
1010 pa_assert(u->source || u->sink);
1012 u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
1014 ioctl(u->fd, I_SETSIG, S_MSG);
1016 pa_log_warn("Could not register SIGPOLL handler");
1018 if (!(u->thread = pa_thread_new(thread_func, u))) {
1019 pa_log("Failed to create thread.");
1023 /* Read mixer settings */
1025 if (sink_new_data.volume_is_set)
1026 u->sink->set_volume(u->sink);
1028 u->sink->get_volume(u->sink);
1030 if (sink_new_data.muted_is_set)
1031 u->sink->set_mute(u->sink);
1033 u->sink->get_mute(u->sink);
1035 pa_sink_put(u->sink);
1039 if (source_new_data.volume_is_set)
1040 u->source->set_volume(u->source);
1042 u->source->get_volume(u->source);
1044 pa_source_put(u->source);
1047 pa_modargs_free(ma);
1058 pa_modargs_free(ma);
1063 void pa__done(pa_module *m) {
1068 if (!(u = m->userdata))
1072 ioctl(u->fd, I_SETSIG, 0);
1073 pa_signal_free(u->sig);
1077 pa_sink_unlink(u->sink);
1080 pa_source_unlink(u->source);
1083 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
1084 pa_thread_free(u->thread);
1087 pa_thread_mq_done(&u->thread_mq);
1090 pa_sink_unref(u->sink);
1093 pa_source_unref(u->source);
1095 if (u->memchunk.memblock)
1096 pa_memblock_unref(u->memchunk.memblock);
1099 pa_rtpoll_item_free(u->rtpoll_item);
1102 pa_rtpoll_free(u->rtpoll);
1108 pa_smoother_free(u->smoother);
1110 pa_xfree(u->device_name);