Fix up according to Coding Style
[pulseaudio-mirror.git] / src / modules / module-solaris.c
blobee06b3be4e24de284e97feaa9bd65b91bc8036f0
1 /***
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
21 USA.
22 ***/
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <limits.h>
35 #include <sys/ioctl.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
39 #include <signal.h>
40 #include <stropts.h>
41 #include <sys/conf.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);
70 PA_MODULE_USAGE(
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> "
80 "rate=<sample rate> "
81 "buffer_length=<milliseconds> "
82 "channel_map=<channel map>");
83 PA_MODULE_LOAD_ONCE(FALSE);
85 struct userdata {
86 pa_core *core;
87 pa_sink *sink;
88 pa_source *source;
90 pa_thread *thread;
91 pa_thread_mq thread_mq;
92 pa_rtpoll *rtpoll;
94 pa_signal_event *sig;
96 pa_memchunk memchunk;
98 uint32_t frame_size;
99 int32_t buffer_size;
100 uint64_t written_bytes, read_bytes;
102 char *device_name;
103 int mode;
104 int fd;
105 pa_rtpoll_item *rtpoll_item;
106 pa_module *module;
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[] = {
119 "sink_name",
120 "sink_properties",
121 "source_name",
122 "source_properties",
123 "device",
124 "record",
125 "playback",
126 "buffer_length",
127 "format",
128 "rate",
129 "channels",
130 "channel_map",
131 NULL
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) {
143 audio_info_t info;
144 uint64_t played_bytes;
145 int err;
147 pa_assert(u->sink);
149 err = ioctl(u->fd, AUDIO_GETINFO, &info);
150 pa_assert(err >= 0);
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;
162 } else {
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) {
175 pa_usec_t r = 0;
177 pa_assert(u);
178 pa_assert(ss);
180 if (u->fd >= 0) {
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);
185 return r;
188 static uint64_t get_recorded_bytes(struct userdata *u) {
189 audio_info_t info;
190 uint64_t result;
191 int err;
193 pa_assert(u->source);
195 err = ioctl(u->fd, AUDIO_GETINFO, &info);
196 pa_assert(err >= 0);
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;
203 return result;
206 static pa_usec_t source_get_latency(struct userdata *u, pa_sample_spec *ss) {
207 pa_usec_t r = 0;
208 audio_info_t info;
210 pa_assert(u);
211 pa_assert(ss);
213 if (u->fd) {
214 int err = ioctl(u->fd, AUDIO_GETINFO, &info);
215 pa_assert(err >= 0);
217 r = pa_bytes_to_usec(get_recorded_bytes(u), ss) - pa_bytes_to_usec(u->read_bytes, ss);
219 return r;
222 static void build_pollfd(struct userdata *u) {
223 struct pollfd *pollfd;
225 pa_assert(u);
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);
230 pollfd->fd = u->fd;
231 pollfd->events = 0;
232 pollfd->revents = 0;
235 static int set_buffer(int fd, int buffer_size) {
236 audio_info_t info;
238 pa_assert(fd >= 0);
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) {
245 if (errno == EINVAL)
246 pa_log("AUDIO_SETINFO: Unsupported buffer size.");
247 else
248 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
249 return -1;
252 return 0;
255 static int auto_format(int fd, int mode, pa_sample_spec *ss) {
256 audio_info_t info;
258 pa_assert(fd >= 0);
259 pa_assert(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) {
267 case PA_SAMPLE_U8:
268 info.play.precision = 8;
269 info.play.encoding = AUDIO_ENCODING_LINEAR;
270 break;
271 case PA_SAMPLE_ALAW:
272 info.play.precision = 8;
273 info.play.encoding = AUDIO_ENCODING_ALAW;
274 break;
275 case PA_SAMPLE_ULAW:
276 info.play.precision = 8;
277 info.play.encoding = AUDIO_ENCODING_ULAW;
278 break;
279 case PA_SAMPLE_S16NE:
280 info.play.precision = 16;
281 info.play.encoding = AUDIO_ENCODING_LINEAR;
282 break;
283 default:
284 pa_log("AUDIO_SETINFO: Unsupported sample format.");
285 return -1;
289 if (mode != O_WRONLY) {
290 info.record.sample_rate = ss->rate;
291 info.record.channels = ss->channels;
292 switch (ss->format) {
293 case PA_SAMPLE_U8:
294 info.record.precision = 8;
295 info.record.encoding = AUDIO_ENCODING_LINEAR;
296 break;
297 case PA_SAMPLE_ALAW:
298 info.record.precision = 8;
299 info.record.encoding = AUDIO_ENCODING_ALAW;
300 break;
301 case PA_SAMPLE_ULAW:
302 info.record.precision = 8;
303 info.record.encoding = AUDIO_ENCODING_ULAW;
304 break;
305 case PA_SAMPLE_S16NE:
306 info.record.precision = 16;
307 info.record.encoding = AUDIO_ENCODING_LINEAR;
308 break;
309 default:
310 pa_log("AUDIO_SETINFO: Unsupported sample format.");
311 return -1;
315 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
316 if (errno == EINVAL)
317 pa_log("AUDIO_SETINFO: Failed to set sample format.");
318 else
319 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
320 return -1;
323 return 0;
326 static int open_audio_device(struct userdata *u, pa_sample_spec *ss) {
327 pa_assert(u);
328 pa_assert(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));
332 return -1;
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)
338 return -1;
340 if (set_buffer(u->fd, u->buffer_size) < 0)
341 return -1;
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;
347 return u->fd;
350 static int suspend(struct userdata *u) {
351 pa_assert(u);
352 pa_assert(u->fd >= 0);
354 pa_log_info("Suspending...");
356 ioctl(u->fd, AUDIO_DRAIN, NULL);
357 pa_close(u->fd);
358 u->fd = -1;
360 if (u->rtpoll_item) {
361 pa_rtpoll_item_free(u->rtpoll_item);
362 u->rtpoll_item = NULL;
365 pa_log_info("Device suspended.");
367 return 0;
370 static int unsuspend(struct userdata *u) {
371 pa_assert(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)
377 return -1;
379 build_pollfd(u);
381 pa_log_info("Device resumed.");
383 return 0;
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;
389 switch (code) {
391 case PA_SINK_MESSAGE_GET_LATENCY:
392 *((pa_usec_t*) data) = sink_get_latency(u, &PA_SINK(o)->sample_spec);
393 return 0;
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) {
406 if (suspend(u) < 0)
407 return -1;
409 u->sink_suspended = TRUE;
410 break;
412 case PA_SINK_IDLE:
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)
420 return -1;
421 u->sink->get_volume(u->sink);
422 u->sink->get_mute(u->sink);
424 u->sink_suspended = FALSE;
426 break;
428 case PA_SINK_INVALID_STATE:
429 case PA_SINK_UNLINKED:
430 case PA_SINK_INIT:
434 break;
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;
443 switch (code) {
445 case PA_SOURCE_MESSAGE_GET_LATENCY:
446 *((pa_usec_t*) data) = source_get_latency(u, &PA_SOURCE(o)->sample_spec);
447 return 0;
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) {
458 if (suspend(u) < 0)
459 return -1;
461 u->source_suspended = TRUE;
462 break;
464 case PA_SOURCE_IDLE:
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)
470 return -1;
471 u->source->get_volume(u->source);
473 u->source_suspended = FALSE;
475 break;
477 case PA_SOURCE_UNLINKED:
478 case PA_SOURCE_INIT:
479 case PA_SOURCE_INVALID_STATE:
483 break;
487 return pa_source_process_msg(o, code, data, offset, chunk);
490 static void sink_set_volume(pa_sink *s) {
491 struct userdata *u;
492 audio_info_t info;
494 pa_assert_se(u = s->userdata);
496 if (u->fd >= 0) {
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) {
503 if (errno == EINVAL)
504 pa_log("AUDIO_SETINFO: Unsupported volume.");
505 else
506 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
511 static void sink_get_volume(pa_sink *s) {
512 struct userdata *u;
513 audio_info_t info;
515 pa_assert_se(u = s->userdata);
517 if (u->fd >= 0) {
518 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
519 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
520 else
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) {
526 struct userdata *u;
527 audio_info_t info;
529 pa_assert_se(u = s->userdata);
531 if (u->fd >= 0) {
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) {
538 if (errno == EINVAL)
539 pa_log("AUDIO_SETINFO: Unsupported volume.");
540 else
541 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
546 static void source_get_volume(pa_source *s) {
547 struct userdata *u;
548 audio_info_t info;
550 pa_assert_se(u = s->userdata);
552 if (u->fd >= 0) {
553 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
554 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
555 else
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;
562 audio_info_t info;
564 pa_assert(u);
566 if (u->fd >= 0) {
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;
578 audio_info_t info;
580 pa_assert(u);
582 if (u->fd >= 0) {
583 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
584 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
585 else
586 s->muted = !!info.output_muted;
590 static void process_rewind(struct userdata *u) {
591 size_t rewind_nbytes;
593 pa_assert(u);
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;
616 int ret, err;
617 audio_info_t info;
619 pa_assert(u);
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());
630 for (;;) {
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)
638 process_rewind(u);
640 err = ioctl(u->fd, AUDIO_GETINFO, &info);
641 if (err < 0) {
642 pa_log("AUDIO_GETINFO ioctl failed: %s", pa_cstrerror(errno));
643 goto fail;
646 if (info.play.error) {
647 pa_log_debug("buffer under-run!");
649 AUDIO_INITINFO(&info);
650 info.play.error = 0;
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);
657 for (;;) {
658 void *p;
659 ssize_t w;
660 size_t len;
661 int write_type = 1;
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)
670 break;
672 len = u->buffer_size - buffered_bytes;
673 len -= len % u->frame_size;
675 if (len < (size_t) u->minimum_request)
676 break;
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);
687 if (w <= 0) {
688 if (errno == EINTR) {
689 continue;
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);
693 break;
694 } else {
695 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
696 goto fail;
698 } else {
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));
714 } else
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;
721 void *p;
722 ssize_t r;
723 size_t len;
725 err = ioctl(u->fd, AUDIO_GETINFO, &info);
726 pa_assert(err >= 0);
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);
738 pa_assert(err >= 0);
740 if (len > 0) {
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);
748 if (r < 0) {
749 pa_memblock_unref(memchunk.memblock);
750 if (errno == EAGAIN)
751 break;
752 else {
753 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
754 goto fail;
756 } else {
757 u->read_bytes += r;
759 memchunk.index = 0;
760 memchunk.length = r;
762 pa_source_post(u->source, &memchunk);
763 pa_memblock_unref(memchunk.memblock);
765 revents &= ~POLLIN;
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)
781 goto fail;
783 if (ret == 0)
784 goto finish;
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.");
793 goto fail;
796 revents = pollfd->revents;
797 } else
798 revents = 0;
801 fail:
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);
807 finish:
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;
814 assert(u);
816 pa_log_debug("caught signal");
818 if (u->sink) {
819 pa_sink_get_volume(u->sink, TRUE);
820 pa_sink_get_mute(u->sink, TRUE);
823 if (u->source)
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;
830 pa_sample_spec ss;
831 pa_channel_map map;
832 pa_modargs *ma = NULL;
833 uint32_t buffer_length_msec;
834 int fd = -1;
835 pa_sink_new_data sink_new_data;
836 pa_source_new_data source_new_data;
837 char const *name;
838 char *name_buf;
839 pa_bool_t namereg_fail;
841 pa_assert(m);
843 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
844 pa_log("failed to parse module arguments.");
845 goto fail;
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.");
850 goto fail;
853 if (!playback && !record) {
854 pa_log("neither playback nor record enabled for device.");
855 goto fail;
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)))
861 goto fail;
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");
873 goto fail;
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");
882 goto fail;
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));
888 goto fail;
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));
893 goto fail;
896 u->device_name = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
898 if ((fd = open_audio_device(u, &ss)) < 0)
899 goto fail;
901 u->core = m->core;
902 u->module = m;
903 m->userdata = u;
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;
911 build_pollfd(u);
913 if (u->mode != O_WRONLY) {
914 name_buf = NULL;
915 namereg_fail = TRUE;
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);
938 goto fail;
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);
943 pa_xfree(name_buf);
945 if (!u->source) {
946 pa_log("Failed to create source object");
947 goto fail;
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;
960 } else
961 u->source = NULL;
963 if (u->mode != O_RDONLY) {
964 name_buf = NULL;
965 namereg_fail = TRUE;
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);
986 goto fail;
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);
992 pa_assert(u->sink);
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;
1007 } else
1008 u->sink = NULL;
1010 pa_assert(u->source || u->sink);
1012 u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
1013 if (u->sig)
1014 ioctl(u->fd, I_SETSIG, S_MSG);
1015 else
1016 pa_log_warn("Could not register SIGPOLL handler");
1018 if (!(u->thread = pa_thread_new("solaris", thread_func, u))) {
1019 pa_log("Failed to create thread.");
1020 goto fail;
1023 /* Read mixer settings */
1024 if (u->sink) {
1025 if (sink_new_data.volume_is_set)
1026 u->sink->set_volume(u->sink);
1027 else
1028 u->sink->get_volume(u->sink);
1030 if (sink_new_data.muted_is_set)
1031 u->sink->set_mute(u->sink);
1032 else
1033 u->sink->get_mute(u->sink);
1035 pa_sink_put(u->sink);
1038 if (u->source) {
1039 if (source_new_data.volume_is_set)
1040 u->source->set_volume(u->source);
1041 else
1042 u->source->get_volume(u->source);
1044 pa_source_put(u->source);
1047 pa_modargs_free(ma);
1049 return 0;
1051 fail:
1052 if (u)
1053 pa__done(m);
1054 else if (fd >= 0)
1055 close(fd);
1057 if (ma)
1058 pa_modargs_free(ma);
1060 return -1;
1063 void pa__done(pa_module *m) {
1064 struct userdata *u;
1066 pa_assert(m);
1068 if (!(u = m->userdata))
1069 return;
1071 if (u->sig) {
1072 ioctl(u->fd, I_SETSIG, 0);
1073 pa_signal_free(u->sig);
1076 if (u->sink)
1077 pa_sink_unlink(u->sink);
1079 if (u->source)
1080 pa_source_unlink(u->source);
1082 if (u->thread) {
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);
1089 if (u->sink)
1090 pa_sink_unref(u->sink);
1092 if (u->source)
1093 pa_source_unref(u->source);
1095 if (u->memchunk.memblock)
1096 pa_memblock_unref(u->memchunk.memblock);
1098 if (u->rtpoll_item)
1099 pa_rtpoll_item_free(u->rtpoll_item);
1101 if (u->rtpoll)
1102 pa_rtpoll_free(u->rtpoll);
1104 if (u->fd >= 0)
1105 close(u->fd);
1107 if (u->smoother)
1108 pa_smoother_free(u->smoother);
1110 pa_xfree(u->device_name);
1112 pa_xfree(u);