default: esd is obsolete, hence don't load it anymore by default
[pulseaudio-mirror.git] / src / modules / module-solaris.c
blob0e4e4017a8558caadda9e214ab9240a69b740855
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 <fcntl.h>
32 #include <unistd.h>
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
36 #include <signal.h>
37 #include <stropts.h>
38 #include <sys/conf.h>
39 #include <sys/audio.h>
41 #include <pulse/mainloop-signal.h>
42 #include <pulse/xmalloc.h>
43 #include <pulse/timeval.h>
44 #include <pulse/util.h>
45 #include <pulse/rtclock.h>
47 #include <pulsecore/sink.h>
48 #include <pulsecore/source.h>
49 #include <pulsecore/module.h>
50 #include <pulsecore/sample-util.h>
51 #include <pulsecore/core-util.h>
52 #include <pulsecore/modargs.h>
53 #include <pulsecore/log.h>
54 #include <pulsecore/core-error.h>
55 #include <pulsecore/thread-mq.h>
56 #include <pulsecore/rtpoll.h>
57 #include <pulsecore/thread.h>
58 #include <pulsecore/time-smoother.h>
60 #include "module-solaris-symdef.h"
62 PA_MODULE_AUTHOR("Pierre Ossman");
63 PA_MODULE_DESCRIPTION("Solaris Sink/Source");
64 PA_MODULE_VERSION(PACKAGE_VERSION);
65 PA_MODULE_USAGE(
66 "sink_name=<name for the sink> "
67 "sink_properties=<properties for the sink> "
68 "source_name=<name for the source> "
69 "source_properties=<properties for the source> "
70 "device=<audio device file name> "
71 "record=<enable source?> "
72 "playback=<enable sink?> "
73 "format=<sample format> "
74 "channels=<number of channels> "
75 "rate=<sample rate> "
76 "buffer_length=<milliseconds> "
77 "channel_map=<channel map>");
78 PA_MODULE_LOAD_ONCE(FALSE);
80 struct userdata {
81 pa_core *core;
82 pa_sink *sink;
83 pa_source *source;
85 pa_thread *thread;
86 pa_thread_mq thread_mq;
87 pa_rtpoll *rtpoll;
89 pa_signal_event *sig;
91 pa_memchunk memchunk;
93 uint32_t frame_size;
94 int32_t buffer_size;
95 uint64_t written_bytes, read_bytes;
97 char *device_name;
98 int mode;
99 int fd;
100 pa_rtpoll_item *rtpoll_item;
101 pa_module *module;
103 pa_bool_t sink_suspended, source_suspended;
105 uint32_t play_samples_msw, record_samples_msw;
106 uint32_t prev_playback_samples, prev_record_samples;
108 int32_t minimum_request;
110 pa_smoother *smoother;
113 static const char* const valid_modargs[] = {
114 "sink_name",
115 "sink_properties",
116 "source_name",
117 "source_properties",
118 "device",
119 "record",
120 "playback",
121 "buffer_length",
122 "format",
123 "rate",
124 "channels",
125 "channel_map",
126 NULL
129 #define DEFAULT_DEVICE "/dev/audio"
131 #define MAX_RENDER_HZ (300)
132 /* This render rate limit imposes a minimum latency, but without it we waste too much CPU time. */
134 #define MAX_BUFFER_SIZE (128 * 1024)
135 /* An attempt to buffer more than 128 KB causes write() to fail with errno == EAGAIN. */
137 static uint64_t get_playback_buffered_bytes(struct userdata *u) {
138 audio_info_t info;
139 uint64_t played_bytes;
140 int err;
142 pa_assert(u->sink);
144 err = ioctl(u->fd, AUDIO_GETINFO, &info);
145 pa_assert(err >= 0);
147 /* Handle wrap-around of the device's sample counter, which is a uint_32. */
148 if (u->prev_playback_samples > info.play.samples) {
150 * Unfortunately info.play.samples can sometimes go backwards, even before it wraps!
151 * The bug seems to be absent on Solaris x86 nv117 with audio810 driver, at least on this (UP) machine.
152 * The bug is present on a different (SMP) machine running Solaris x86 nv103 with audioens driver.
153 * An earlier revision of this file mentions the same bug independently (unknown configuration).
155 if (u->prev_playback_samples + info.play.samples < 240000) {
156 ++u->play_samples_msw;
157 } else {
158 pa_log_debug("play.samples went backwards %d bytes", u->prev_playback_samples - info.play.samples);
161 u->prev_playback_samples = info.play.samples;
162 played_bytes = (((uint64_t)u->play_samples_msw << 32) + info.play.samples) * u->frame_size;
164 pa_smoother_put(u->smoother, pa_rtclock_now(), pa_bytes_to_usec(played_bytes, &u->sink->sample_spec));
166 return u->written_bytes - played_bytes;
169 static pa_usec_t sink_get_latency(struct userdata *u, pa_sample_spec *ss) {
170 pa_usec_t r = 0;
172 pa_assert(u);
173 pa_assert(ss);
175 if (u->fd >= 0) {
176 r = pa_bytes_to_usec(get_playback_buffered_bytes(u), ss);
177 if (u->memchunk.memblock)
178 r += pa_bytes_to_usec(u->memchunk.length, ss);
180 return r;
183 static uint64_t get_recorded_bytes(struct userdata *u) {
184 audio_info_t info;
185 uint64_t result;
186 int err;
188 pa_assert(u->source);
190 err = ioctl(u->fd, AUDIO_GETINFO, &info);
191 pa_assert(err >= 0);
193 if (u->prev_record_samples > info.record.samples)
194 ++u->record_samples_msw;
195 u->prev_record_samples = info.record.samples;
196 result = (((uint64_t)u->record_samples_msw << 32) + info.record.samples) * u->frame_size;
198 return result;
201 static pa_usec_t source_get_latency(struct userdata *u, pa_sample_spec *ss) {
202 pa_usec_t r = 0;
203 audio_info_t info;
205 pa_assert(u);
206 pa_assert(ss);
208 if (u->fd) {
209 int err = ioctl(u->fd, AUDIO_GETINFO, &info);
210 pa_assert(err >= 0);
212 r = pa_bytes_to_usec(get_recorded_bytes(u), ss) - pa_bytes_to_usec(u->read_bytes, ss);
214 return r;
217 static void build_pollfd(struct userdata *u) {
218 struct pollfd *pollfd;
220 pa_assert(u);
221 pa_assert(!u->rtpoll_item);
222 u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
224 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
225 pollfd->fd = u->fd;
226 pollfd->events = 0;
227 pollfd->revents = 0;
230 static int set_buffer(int fd, int buffer_size) {
231 audio_info_t info;
233 pa_assert(fd >= 0);
235 AUDIO_INITINFO(&info);
236 info.play.buffer_size = buffer_size;
237 info.record.buffer_size = buffer_size;
239 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
240 if (errno == EINVAL)
241 pa_log("AUDIO_SETINFO: Unsupported buffer size.");
242 else
243 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
244 return -1;
247 return 0;
250 static int auto_format(int fd, int mode, pa_sample_spec *ss) {
251 audio_info_t info;
253 pa_assert(fd >= 0);
254 pa_assert(ss);
256 AUDIO_INITINFO(&info);
258 if (mode != O_RDONLY) {
259 info.play.sample_rate = ss->rate;
260 info.play.channels = ss->channels;
261 switch (ss->format) {
262 case PA_SAMPLE_U8:
263 info.play.precision = 8;
264 info.play.encoding = AUDIO_ENCODING_LINEAR;
265 break;
266 case PA_SAMPLE_ALAW:
267 info.play.precision = 8;
268 info.play.encoding = AUDIO_ENCODING_ALAW;
269 break;
270 case PA_SAMPLE_ULAW:
271 info.play.precision = 8;
272 info.play.encoding = AUDIO_ENCODING_ULAW;
273 break;
274 case PA_SAMPLE_S16NE:
275 info.play.precision = 16;
276 info.play.encoding = AUDIO_ENCODING_LINEAR;
277 break;
278 default:
279 pa_log("AUDIO_SETINFO: Unsupported sample format.");
280 return -1;
284 if (mode != O_WRONLY) {
285 info.record.sample_rate = ss->rate;
286 info.record.channels = ss->channels;
287 switch (ss->format) {
288 case PA_SAMPLE_U8:
289 info.record.precision = 8;
290 info.record.encoding = AUDIO_ENCODING_LINEAR;
291 break;
292 case PA_SAMPLE_ALAW:
293 info.record.precision = 8;
294 info.record.encoding = AUDIO_ENCODING_ALAW;
295 break;
296 case PA_SAMPLE_ULAW:
297 info.record.precision = 8;
298 info.record.encoding = AUDIO_ENCODING_ULAW;
299 break;
300 case PA_SAMPLE_S16NE:
301 info.record.precision = 16;
302 info.record.encoding = AUDIO_ENCODING_LINEAR;
303 break;
304 default:
305 pa_log("AUDIO_SETINFO: Unsupported sample format.");
306 return -1;
310 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
311 if (errno == EINVAL)
312 pa_log("AUDIO_SETINFO: Failed to set sample format.");
313 else
314 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
315 return -1;
318 return 0;
321 static int open_audio_device(struct userdata *u, pa_sample_spec *ss) {
322 pa_assert(u);
323 pa_assert(ss);
325 if ((u->fd = pa_open_cloexec(u->device_name, u->mode | O_NONBLOCK, 0)) < 0) {
326 pa_log_warn("open %s failed (%s)", u->device_name, pa_cstrerror(errno));
327 return -1;
330 pa_log_info("device opened in %s mode.", u->mode == O_WRONLY ? "O_WRONLY" : (u->mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
332 if (auto_format(u->fd, u->mode, ss) < 0)
333 return -1;
335 if (set_buffer(u->fd, u->buffer_size) < 0)
336 return -1;
338 u->written_bytes = u->read_bytes = 0;
339 u->play_samples_msw = u->record_samples_msw = 0;
340 u->prev_playback_samples = u->prev_record_samples = 0;
342 return u->fd;
345 static int suspend(struct userdata *u) {
346 pa_assert(u);
347 pa_assert(u->fd >= 0);
349 pa_log_info("Suspending...");
351 ioctl(u->fd, AUDIO_DRAIN, NULL);
352 pa_close(u->fd);
353 u->fd = -1;
355 if (u->rtpoll_item) {
356 pa_rtpoll_item_free(u->rtpoll_item);
357 u->rtpoll_item = NULL;
360 pa_log_info("Device suspended.");
362 return 0;
365 static int unsuspend(struct userdata *u) {
366 pa_assert(u);
367 pa_assert(u->fd < 0);
369 pa_log_info("Resuming...");
371 if (open_audio_device(u, u->sink ? &u->sink->sample_spec : &u->source->sample_spec) < 0)
372 return -1;
374 build_pollfd(u);
376 pa_log_info("Device resumed.");
378 return 0;
381 static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
382 struct userdata *u = PA_SINK(o)->userdata;
384 switch (code) {
386 case PA_SINK_MESSAGE_GET_LATENCY:
387 *((pa_usec_t*) data) = sink_get_latency(u, &PA_SINK(o)->sample_spec);
388 return 0;
390 case PA_SINK_MESSAGE_SET_STATE:
392 switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
394 case PA_SINK_SUSPENDED:
396 pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
398 pa_smoother_pause(u->smoother, pa_rtclock_now());
400 if (!u->source || u->source_suspended) {
401 if (suspend(u) < 0)
402 return -1;
404 u->sink_suspended = TRUE;
405 break;
407 case PA_SINK_IDLE:
408 case PA_SINK_RUNNING:
410 if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
411 pa_smoother_resume(u->smoother, pa_rtclock_now(), TRUE);
413 if (!u->source || u->source_suspended) {
414 if (unsuspend(u) < 0)
415 return -1;
416 u->sink->get_volume(u->sink);
417 u->sink->get_mute(u->sink);
419 u->sink_suspended = FALSE;
421 break;
423 case PA_SINK_INVALID_STATE:
424 case PA_SINK_UNLINKED:
425 case PA_SINK_INIT:
429 break;
432 return pa_sink_process_msg(o, code, data, offset, chunk);
435 static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
436 struct userdata *u = PA_SOURCE(o)->userdata;
438 switch (code) {
440 case PA_SOURCE_MESSAGE_GET_LATENCY:
441 *((pa_usec_t*) data) = source_get_latency(u, &PA_SOURCE(o)->sample_spec);
442 return 0;
444 case PA_SOURCE_MESSAGE_SET_STATE:
446 switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
448 case PA_SOURCE_SUSPENDED:
450 pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
452 if (!u->sink || u->sink_suspended) {
453 if (suspend(u) < 0)
454 return -1;
456 u->source_suspended = TRUE;
457 break;
459 case PA_SOURCE_IDLE:
460 case PA_SOURCE_RUNNING:
462 if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
463 if (!u->sink || u->sink_suspended) {
464 if (unsuspend(u) < 0)
465 return -1;
466 u->source->get_volume(u->source);
468 u->source_suspended = FALSE;
470 break;
472 case PA_SOURCE_UNLINKED:
473 case PA_SOURCE_INIT:
474 case PA_SOURCE_INVALID_STATE:
478 break;
482 return pa_source_process_msg(o, code, data, offset, chunk);
485 static void sink_set_volume(pa_sink *s) {
486 struct userdata *u;
487 audio_info_t info;
489 pa_assert_se(u = s->userdata);
491 if (u->fd >= 0) {
492 AUDIO_INITINFO(&info);
494 info.play.gain = pa_cvolume_max(&s->real_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
495 assert(info.play.gain <= AUDIO_MAX_GAIN);
497 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
498 if (errno == EINVAL)
499 pa_log("AUDIO_SETINFO: Unsupported volume.");
500 else
501 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
506 static void sink_get_volume(pa_sink *s) {
507 struct userdata *u;
508 audio_info_t info;
510 pa_assert_se(u = s->userdata);
512 if (u->fd >= 0) {
513 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
514 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
515 else
516 pa_cvolume_set(&s->real_volume, s->sample_spec.channels, info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
520 static void source_set_volume(pa_source *s) {
521 struct userdata *u;
522 audio_info_t info;
524 pa_assert_se(u = s->userdata);
526 if (u->fd >= 0) {
527 AUDIO_INITINFO(&info);
529 info.play.gain = pa_cvolume_max(&s->volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
530 assert(info.play.gain <= AUDIO_MAX_GAIN);
532 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
533 if (errno == EINVAL)
534 pa_log("AUDIO_SETINFO: Unsupported volume.");
535 else
536 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
541 static void source_get_volume(pa_source *s) {
542 struct userdata *u;
543 audio_info_t info;
545 pa_assert_se(u = s->userdata);
547 if (u->fd >= 0) {
548 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
549 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
550 else
551 pa_cvolume_set(&s->volume, s->sample_spec.channels, info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
555 static void sink_set_mute(pa_sink *s) {
556 struct userdata *u = s->userdata;
557 audio_info_t info;
559 pa_assert(u);
561 if (u->fd >= 0) {
562 AUDIO_INITINFO(&info);
564 info.output_muted = !!s->muted;
566 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
567 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
571 static void sink_get_mute(pa_sink *s) {
572 struct userdata *u = s->userdata;
573 audio_info_t info;
575 pa_assert(u);
577 if (u->fd >= 0) {
578 if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
579 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
580 else
581 s->muted = !!info.output_muted;
585 static void process_rewind(struct userdata *u) {
586 size_t rewind_nbytes;
588 pa_assert(u);
590 /* Figure out how much we shall rewind and reset the counter */
591 rewind_nbytes = u->sink->thread_info.rewind_nbytes;
592 u->sink->thread_info.rewind_nbytes = 0;
594 if (rewind_nbytes > 0) {
595 pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes);
596 rewind_nbytes = PA_MIN(u->memchunk.length, rewind_nbytes);
597 u->memchunk.length -= rewind_nbytes;
598 if (u->memchunk.length <= 0 && u->memchunk.memblock) {
599 pa_memblock_unref(u->memchunk.memblock);
600 pa_memchunk_reset(&u->memchunk);
602 pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes);
605 pa_sink_process_rewind(u->sink, rewind_nbytes);
608 static void thread_func(void *userdata) {
609 struct userdata *u = userdata;
610 unsigned short revents = 0;
611 int ret, err;
612 audio_info_t info;
614 pa_assert(u);
616 pa_log_debug("Thread starting up");
618 if (u->core->realtime_scheduling)
619 pa_make_realtime(u->core->realtime_priority);
621 pa_thread_mq_install(&u->thread_mq);
623 pa_smoother_set_time_offset(u->smoother, pa_rtclock_now());
625 for (;;) {
626 /* Render some data and write it to the dsp */
628 if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
629 pa_usec_t xtime0, ysleep_interval, xsleep_interval;
630 uint64_t buffered_bytes;
632 if (u->sink->thread_info.rewind_requested)
633 process_rewind(u);
635 err = ioctl(u->fd, AUDIO_GETINFO, &info);
636 if (err < 0) {
637 pa_log("AUDIO_GETINFO ioctl failed: %s", pa_cstrerror(errno));
638 goto fail;
641 if (info.play.error) {
642 pa_log_debug("buffer under-run!");
644 AUDIO_INITINFO(&info);
645 info.play.error = 0;
646 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
647 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
649 pa_smoother_reset(u->smoother, pa_rtclock_now(), TRUE);
652 for (;;) {
653 void *p;
654 ssize_t w;
655 size_t len;
656 int write_type = 1;
659 * Since we cannot modify the size of the output buffer we fake it
660 * by not filling it more than u->buffer_size.
662 xtime0 = pa_rtclock_now();
663 buffered_bytes = get_playback_buffered_bytes(u);
664 if (buffered_bytes >= (uint64_t)u->buffer_size)
665 break;
667 len = u->buffer_size - buffered_bytes;
668 len -= len % u->frame_size;
670 if (len < (size_t) u->minimum_request)
671 break;
673 if (!u->memchunk.length)
674 pa_sink_render(u->sink, u->sink->thread_info.max_request, &u->memchunk);
676 len = PA_MIN(u->memchunk.length, len);
678 p = pa_memblock_acquire(u->memchunk.memblock);
679 w = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, len, &write_type);
680 pa_memblock_release(u->memchunk.memblock);
682 if (w <= 0) {
683 if (errno == EINTR) {
684 continue;
685 } else if (errno == EAGAIN) {
686 /* We may have realtime priority so yield the CPU to ensure that fd can become writable again. */
687 pa_log_debug("EAGAIN with %llu bytes buffered.", buffered_bytes);
688 break;
689 } else {
690 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
691 goto fail;
693 } else {
694 pa_assert(w % u->frame_size == 0);
696 u->written_bytes += w;
697 u->memchunk.index += w;
698 u->memchunk.length -= w;
699 if (u->memchunk.length <= 0) {
700 pa_memblock_unref(u->memchunk.memblock);
701 pa_memchunk_reset(&u->memchunk);
706 ysleep_interval = pa_bytes_to_usec(buffered_bytes / 2, &u->sink->sample_spec);
707 xsleep_interval = pa_smoother_translate(u->smoother, xtime0, ysleep_interval);
708 pa_rtpoll_set_timer_absolute(u->rtpoll, xtime0 + PA_MIN(xsleep_interval, ysleep_interval));
709 } else
710 pa_rtpoll_set_timer_disabled(u->rtpoll);
712 /* Try to read some data and pass it on to the source driver */
714 if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state) && (revents & POLLIN)) {
715 pa_memchunk memchunk;
716 void *p;
717 ssize_t r;
718 size_t len;
720 err = ioctl(u->fd, AUDIO_GETINFO, &info);
721 pa_assert(err >= 0);
723 if (info.record.error) {
724 pa_log_debug("buffer overflow!");
726 AUDIO_INITINFO(&info);
727 info.record.error = 0;
728 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
729 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
732 err = ioctl(u->fd, I_NREAD, &len);
733 pa_assert(err >= 0);
735 if (len > 0) {
736 memchunk.memblock = pa_memblock_new(u->core->mempool, len);
737 pa_assert(memchunk.memblock);
739 p = pa_memblock_acquire(memchunk.memblock);
740 r = pa_read(u->fd, p, len, NULL);
741 pa_memblock_release(memchunk.memblock);
743 if (r < 0) {
744 pa_memblock_unref(memchunk.memblock);
745 if (errno == EAGAIN)
746 break;
747 else {
748 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
749 goto fail;
751 } else {
752 u->read_bytes += r;
754 memchunk.index = 0;
755 memchunk.length = r;
757 pa_source_post(u->source, &memchunk);
758 pa_memblock_unref(memchunk.memblock);
760 revents &= ~POLLIN;
765 if (u->rtpoll_item) {
766 struct pollfd *pollfd;
768 pa_assert(u->fd >= 0);
770 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
771 pollfd->events = (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) ? POLLIN : 0;
774 /* Hmm, nothing to do. Let's sleep */
775 if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
776 goto fail;
778 if (ret == 0)
779 goto finish;
781 if (u->rtpoll_item) {
782 struct pollfd *pollfd;
784 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
786 if (pollfd->revents & ~(POLLOUT|POLLIN)) {
787 pa_log("DSP shutdown.");
788 goto fail;
791 revents = pollfd->revents;
792 } else
793 revents = 0;
796 fail:
797 /* We have to continue processing messages until we receive the
798 * SHUTDOWN message */
799 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
800 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
802 finish:
803 pa_log_debug("Thread shutting down");
806 static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) {
807 struct userdata *u = userdata;
809 assert(u);
811 pa_log_debug("caught signal");
813 if (u->sink) {
814 pa_sink_get_volume(u->sink, TRUE);
815 pa_sink_get_mute(u->sink, TRUE);
818 if (u->source)
819 pa_source_get_volume(u->source, TRUE);
822 int pa__init(pa_module *m) {
823 struct userdata *u = NULL;
824 pa_bool_t record = TRUE, playback = TRUE;
825 pa_sample_spec ss;
826 pa_channel_map map;
827 pa_modargs *ma = NULL;
828 uint32_t buffer_length_msec;
829 int fd = -1;
830 pa_sink_new_data sink_new_data;
831 pa_source_new_data source_new_data;
832 char const *name;
833 char *name_buf;
834 pa_bool_t namereg_fail;
836 pa_assert(m);
838 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
839 pa_log("failed to parse module arguments.");
840 goto fail;
843 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
844 pa_log("record= and playback= expect a boolean argument.");
845 goto fail;
848 if (!playback && !record) {
849 pa_log("neither playback nor record enabled for device.");
850 goto fail;
853 u = pa_xnew0(struct userdata, 1);
855 if (!(u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC * 2, TRUE, TRUE, 10, pa_rtclock_now(), TRUE)))
856 goto fail;
859 * For a process (or several processes) to use the same audio device for both
860 * record and playback at the same time, the device's mixer must be enabled.
861 * See mixerctl(1). It may be turned off for playback only or record only.
863 u->mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
865 ss = m->core->default_sample_spec;
866 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
867 pa_log("failed to parse sample specification");
868 goto fail;
870 u->frame_size = pa_frame_size(&ss);
872 u->minimum_request = pa_usec_to_bytes(PA_USEC_PER_SEC / MAX_RENDER_HZ, &ss);
874 buffer_length_msec = 100;
875 if (pa_modargs_get_value_u32(ma, "buffer_length", &buffer_length_msec) < 0) {
876 pa_log("failed to parse buffer_length argument");
877 goto fail;
879 u->buffer_size = pa_usec_to_bytes(1000 * buffer_length_msec, &ss);
880 if (u->buffer_size < 2 * u->minimum_request) {
881 pa_log("buffer_length argument cannot be smaller than %u",
882 (unsigned)(pa_bytes_to_usec(2 * u->minimum_request, &ss) / 1000));
883 goto fail;
885 if (u->buffer_size > MAX_BUFFER_SIZE) {
886 pa_log("buffer_length argument cannot be greater than %u",
887 (unsigned)(pa_bytes_to_usec(MAX_BUFFER_SIZE, &ss) / 1000));
888 goto fail;
891 u->device_name = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
893 if ((fd = open_audio_device(u, &ss)) < 0)
894 goto fail;
896 u->core = m->core;
897 u->module = m;
898 m->userdata = u;
900 pa_memchunk_reset(&u->memchunk);
902 u->rtpoll = pa_rtpoll_new();
903 pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
905 u->rtpoll_item = NULL;
906 build_pollfd(u);
908 if (u->mode != O_WRONLY) {
909 name_buf = NULL;
910 namereg_fail = TRUE;
912 if (!(name = pa_modargs_get_value(ma, "source_name", NULL))) {
913 name = name_buf = pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u->device_name));
914 namereg_fail = FALSE;
917 pa_source_new_data_init(&source_new_data);
918 source_new_data.driver = __FILE__;
919 source_new_data.module = m;
920 pa_source_new_data_set_name(&source_new_data, name);
921 source_new_data.namereg_fail = namereg_fail;
922 pa_source_new_data_set_sample_spec(&source_new_data, &ss);
923 pa_source_new_data_set_channel_map(&source_new_data, &map);
924 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
925 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
926 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM source");
927 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");
928 pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) u->buffer_size);
930 if (pa_modargs_get_proplist(ma, "source_properties", source_new_data.proplist, PA_UPDATE_REPLACE) < 0) {
931 pa_log("Invalid properties");
932 pa_source_new_data_done(&source_new_data);
933 goto fail;
936 u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL);
937 pa_source_new_data_done(&source_new_data);
938 pa_xfree(name_buf);
940 if (!u->source) {
941 pa_log("Failed to create source object");
942 goto fail;
945 u->source->userdata = u;
946 u->source->parent.process_msg = source_process_msg;
948 pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
949 pa_source_set_rtpoll(u->source, u->rtpoll);
950 pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->buffer_size, &u->source->sample_spec));
952 u->source->get_volume = source_get_volume;
953 u->source->set_volume = source_set_volume;
954 u->source->refresh_volume = TRUE;
955 } else
956 u->source = NULL;
958 if (u->mode != O_RDONLY) {
959 name_buf = NULL;
960 namereg_fail = TRUE;
961 if (!(name = pa_modargs_get_value(ma, "sink_name", NULL))) {
962 name = name_buf = pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u->device_name));
963 namereg_fail = FALSE;
966 pa_sink_new_data_init(&sink_new_data);
967 sink_new_data.driver = __FILE__;
968 sink_new_data.module = m;
969 pa_sink_new_data_set_name(&sink_new_data, name);
970 sink_new_data.namereg_fail = namereg_fail;
971 pa_sink_new_data_set_sample_spec(&sink_new_data, &ss);
972 pa_sink_new_data_set_channel_map(&sink_new_data, &map);
973 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
974 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
975 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM sink");
976 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");
978 if (pa_modargs_get_proplist(ma, "sink_properties", sink_new_data.proplist, PA_UPDATE_REPLACE) < 0) {
979 pa_log("Invalid properties");
980 pa_sink_new_data_done(&sink_new_data);
981 goto fail;
984 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);
985 pa_sink_new_data_done(&sink_new_data);
987 pa_assert(u->sink);
988 u->sink->userdata = u;
989 u->sink->parent.process_msg = sink_process_msg;
991 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
992 pa_sink_set_rtpoll(u->sink, u->rtpoll);
993 pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->buffer_size, &u->sink->sample_spec));
994 pa_sink_set_max_request(u->sink, u->buffer_size);
995 pa_sink_set_max_rewind(u->sink, u->buffer_size);
997 u->sink->get_volume = sink_get_volume;
998 u->sink->set_volume = sink_set_volume;
999 u->sink->get_mute = sink_get_mute;
1000 u->sink->set_mute = sink_set_mute;
1001 u->sink->refresh_volume = u->sink->refresh_muted = TRUE;
1002 } else
1003 u->sink = NULL;
1005 pa_assert(u->source || u->sink);
1007 u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
1008 if (u->sig)
1009 ioctl(u->fd, I_SETSIG, S_MSG);
1010 else
1011 pa_log_warn("Could not register SIGPOLL handler");
1013 if (!(u->thread = pa_thread_new("solaris", thread_func, u))) {
1014 pa_log("Failed to create thread.");
1015 goto fail;
1018 /* Read mixer settings */
1019 if (u->sink) {
1020 if (sink_new_data.volume_is_set)
1021 u->sink->set_volume(u->sink);
1022 else
1023 u->sink->get_volume(u->sink);
1025 if (sink_new_data.muted_is_set)
1026 u->sink->set_mute(u->sink);
1027 else
1028 u->sink->get_mute(u->sink);
1030 pa_sink_put(u->sink);
1033 if (u->source) {
1034 if (source_new_data.volume_is_set)
1035 u->source->set_volume(u->source);
1036 else
1037 u->source->get_volume(u->source);
1039 pa_source_put(u->source);
1042 pa_modargs_free(ma);
1044 return 0;
1046 fail:
1047 if (u)
1048 pa__done(m);
1049 else if (fd >= 0)
1050 close(fd);
1052 if (ma)
1053 pa_modargs_free(ma);
1055 return -1;
1058 void pa__done(pa_module *m) {
1059 struct userdata *u;
1061 pa_assert(m);
1063 if (!(u = m->userdata))
1064 return;
1066 if (u->sig) {
1067 ioctl(u->fd, I_SETSIG, 0);
1068 pa_signal_free(u->sig);
1071 if (u->sink)
1072 pa_sink_unlink(u->sink);
1074 if (u->source)
1075 pa_source_unlink(u->source);
1077 if (u->thread) {
1078 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
1079 pa_thread_free(u->thread);
1082 pa_thread_mq_done(&u->thread_mq);
1084 if (u->sink)
1085 pa_sink_unref(u->sink);
1087 if (u->source)
1088 pa_source_unref(u->source);
1090 if (u->memchunk.memblock)
1091 pa_memblock_unref(u->memchunk.memblock);
1093 if (u->rtpoll_item)
1094 pa_rtpoll_item_free(u->rtpoll_item);
1096 if (u->rtpoll)
1097 pa_rtpoll_free(u->rtpoll);
1099 if (u->fd >= 0)
1100 close(u->fd);
1102 if (u->smoother)
1103 pa_smoother_free(u->smoother);
1105 pa_xfree(u->device_name);
1107 pa_xfree(u);