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>
50 #include <pulsecore/iochannel.h>
51 #include <pulsecore/sink.h>
52 #include <pulsecore/source.h>
53 #include <pulsecore/module.h>
54 #include <pulsecore/sample-util.h>
55 #include <pulsecore/core-util.h>
56 #include <pulsecore/modargs.h>
57 #include <pulsecore/log.h>
58 #include <pulsecore/core-error.h>
59 #include <pulsecore/thread-mq.h>
60 #include <pulsecore/rtpoll.h>
61 #include <pulsecore/thread.h>
62 #include <pulsecore/rtclock.h>
64 #include "module-solaris-symdef.h"
66 PA_MODULE_AUTHOR("Pierre Ossman");
67 PA_MODULE_DESCRIPTION("Solaris Sink/Source");
68 PA_MODULE_VERSION(PACKAGE_VERSION
);
70 "sink_name=<name for the sink> "
71 "source_name=<name for the source> "
72 "device=<audio device file name> "
73 "record=<enable source?> "
74 "playback=<enable sink?> "
75 "format=<sample format> "
76 "channels=<number of channels> "
78 "buffer_length=<milliseconds> "
79 "channel_map=<channel map>");
80 PA_MODULE_LOAD_ONCE(FALSE
);
88 pa_thread_mq thread_mq
;
97 uint64_t written_bytes
, read_bytes
;
102 pa_rtpoll_item
*rtpoll_item
;
105 pa_bool_t sink_suspended
, source_suspended
;
107 uint32_t play_samples_msw
, record_samples_msw
;
108 uint32_t prev_playback_samples
, prev_record_samples
;
110 int32_t minimum_request
;
113 static const char* const valid_modargs
[] = {
127 #define DEFAULT_DEVICE "/dev/audio"
129 #define MAX_RENDER_HZ (300)
130 /* This render rate limit imposes a minimum latency, but without it we waste too much CPU time. */
132 static uint64_t get_playback_buffered_bytes(struct userdata
*u
) {
134 uint64_t played_bytes
;
139 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
142 /* Handle wrap-around of the device's sample counter, which is a uint_32. */
143 if (u
->prev_playback_samples
> info
.play
.samples
) {
144 /* Unfortunately info.play.samples can sometimes go backwards, even before it wraps! */
145 if (u
->prev_playback_samples
+ info
.play
.samples
< 240000) {
146 ++u
->play_samples_msw
;
148 pa_log_debug("play.samples went backwards %d bytes", u
->prev_playback_samples
- info
.play
.samples
);
151 u
->prev_playback_samples
= info
.play
.samples
;
152 played_bytes
= (((uint64_t)u
->play_samples_msw
<< 32) + info
.play
.samples
) * u
->frame_size
;
154 return u
->written_bytes
- played_bytes
;
157 static pa_usec_t
sink_get_latency(struct userdata
*u
, pa_sample_spec
*ss
) {
164 r
= pa_bytes_to_usec(get_playback_buffered_bytes(u
), ss
);
165 if (u
->memchunk
.memblock
)
166 r
+= pa_bytes_to_usec(u
->memchunk
.length
, ss
);
171 static uint64_t get_recorded_bytes(struct userdata
*u
) {
176 pa_assert(u
->source
);
178 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
181 if (u
->prev_record_samples
> info
.record
.samples
)
182 ++u
->record_samples_msw
;
183 u
->prev_record_samples
= info
.record
.samples
;
184 result
= (((uint64_t)u
->record_samples_msw
<< 32) + info
.record
.samples
) * u
->frame_size
;
189 static pa_usec_t
source_get_latency(struct userdata
*u
, pa_sample_spec
*ss
) {
197 int err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
200 r
= pa_bytes_to_usec(get_recorded_bytes(u
), ss
) - pa_bytes_to_usec(u
->read_bytes
, ss
);
205 static void build_pollfd(struct userdata
*u
) {
206 struct pollfd
*pollfd
;
209 pa_assert(!u
->rtpoll_item
);
210 u
->rtpoll_item
= pa_rtpoll_item_new(u
->rtpoll
, PA_RTPOLL_NEVER
, 1);
212 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
218 static int set_buffer(int fd
, int buffer_size
) {
223 AUDIO_INITINFO(&info
);
224 info
.play
.buffer_size
= buffer_size
;
225 info
.record
.buffer_size
= buffer_size
;
227 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0) {
229 pa_log("AUDIO_SETINFO: Unsupported buffer size.");
231 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
238 static int auto_format(int fd
, int mode
, pa_sample_spec
*ss
) {
244 AUDIO_INITINFO(&info
);
246 if (mode
!= O_RDONLY
) {
247 info
.play
.sample_rate
= ss
->rate
;
248 info
.play
.channels
= ss
->channels
;
249 switch (ss
->format
) {
251 info
.play
.precision
= 8;
252 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
255 info
.play
.precision
= 8;
256 info
.play
.encoding
= AUDIO_ENCODING_ALAW
;
259 info
.play
.precision
= 8;
260 info
.play
.encoding
= AUDIO_ENCODING_ULAW
;
262 case PA_SAMPLE_S16NE
:
263 info
.play
.precision
= 16;
264 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
267 pa_log("AUDIO_SETINFO: Unsupported sample format.");
272 if (mode
!= O_WRONLY
) {
273 info
.record
.sample_rate
= ss
->rate
;
274 info
.record
.channels
= ss
->channels
;
275 switch (ss
->format
) {
277 info
.record
.precision
= 8;
278 info
.record
.encoding
= AUDIO_ENCODING_LINEAR
;
281 info
.record
.precision
= 8;
282 info
.record
.encoding
= AUDIO_ENCODING_ALAW
;
285 info
.record
.precision
= 8;
286 info
.record
.encoding
= AUDIO_ENCODING_ULAW
;
288 case PA_SAMPLE_S16NE
:
289 info
.record
.precision
= 16;
290 info
.record
.encoding
= AUDIO_ENCODING_LINEAR
;
293 pa_log("AUDIO_SETINFO: Unsupported sample format.");
298 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0) {
300 pa_log("AUDIO_SETINFO: Failed to set sample format.");
302 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
309 static int open_audio_device(struct userdata
*u
, pa_sample_spec
*ss
) {
313 if ((u
->fd
= open(u
->device_name
, u
->mode
| O_NONBLOCK
)) < 0) {
314 pa_log_warn("open %s failed (%s)", u
->device_name
, pa_cstrerror(errno
));
318 pa_log_info("device opened in %s mode.", u
->mode
== O_WRONLY
? "O_WRONLY" : (u
->mode
== O_RDONLY
? "O_RDONLY" : "O_RDWR"));
320 if (auto_format(u
->fd
, u
->mode
, ss
) < 0)
323 if (set_buffer(u
->fd
, u
->buffer_size
) < 0)
326 u
->written_bytes
= u
->read_bytes
= 0;
327 u
->play_samples_msw
= u
->record_samples_msw
= 0;
328 u
->prev_playback_samples
= u
->prev_record_samples
= 0;
333 static int suspend(struct userdata
*u
) {
335 pa_assert(u
->fd
>= 0);
337 pa_log_info("Suspending...");
339 ioctl(u
->fd
, AUDIO_DRAIN
, NULL
);
343 if (u
->rtpoll_item
) {
344 pa_rtpoll_item_free(u
->rtpoll_item
);
345 u
->rtpoll_item
= NULL
;
348 pa_log_info("Device suspended.");
353 static int unsuspend(struct userdata
*u
) {
355 pa_assert(u
->fd
< 0);
357 pa_log_info("Resuming...");
359 if (open_audio_device(u
, u
->sink
? &u
->sink
->sample_spec
: &u
->source
->sample_spec
) < 0)
364 pa_log_info("Device resumed.");
369 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
370 struct userdata
*u
= PA_SINK(o
)->userdata
;
374 case PA_SINK_MESSAGE_GET_LATENCY
:
375 *((pa_usec_t
*) data
) = sink_get_latency(u
, &PA_SINK(o
)->sample_spec
);
378 case PA_SINK_MESSAGE_SET_STATE
:
380 switch ((pa_sink_state_t
) PA_PTR_TO_UINT(data
)) {
382 case PA_SINK_SUSPENDED
:
384 pa_assert(PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
));
386 if (!u
->source
|| u
->source_suspended
) {
390 u
->sink_suspended
= TRUE
;
394 case PA_SINK_RUNNING
:
396 if (u
->sink
->thread_info
.state
== PA_SINK_SUSPENDED
) {
397 if (!u
->source
|| u
->source_suspended
) {
398 if (unsuspend(u
) < 0)
400 u
->sink
->get_volume(u
->sink
);
401 u
->sink
->get_mute(u
->sink
);
403 u
->sink_suspended
= FALSE
;
407 case PA_SINK_INVALID_STATE
:
408 case PA_SINK_UNLINKED
:
416 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
419 static int source_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
420 struct userdata
*u
= PA_SOURCE(o
)->userdata
;
424 case PA_SOURCE_MESSAGE_GET_LATENCY
:
425 *((pa_usec_t
*) data
) = source_get_latency(u
, &PA_SOURCE(o
)->sample_spec
);
428 case PA_SOURCE_MESSAGE_SET_STATE
:
430 switch ((pa_source_state_t
) PA_PTR_TO_UINT(data
)) {
432 case PA_SOURCE_SUSPENDED
:
434 pa_assert(PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
));
436 if (!u
->sink
|| u
->sink_suspended
) {
440 u
->source_suspended
= TRUE
;
444 case PA_SOURCE_RUNNING
:
446 if (u
->source
->thread_info
.state
== PA_SOURCE_SUSPENDED
) {
447 if (!u
->sink
|| u
->sink_suspended
) {
448 if (unsuspend(u
) < 0)
450 u
->source
->get_volume(u
->source
);
452 u
->source_suspended
= FALSE
;
456 case PA_SOURCE_UNLINKED
:
458 case PA_SOURCE_INVALID_STATE
:
466 return pa_source_process_msg(o
, code
, data
, offset
, chunk
);
469 static void sink_set_volume(pa_sink
*s
) {
473 pa_assert_se(u
= s
->userdata
);
476 AUDIO_INITINFO(&info
);
478 info
.play
.gain
= pa_cvolume_max(&s
->virtual_volume
) * AUDIO_MAX_GAIN
/ PA_VOLUME_NORM
;
479 assert(info
.play
.gain
<= AUDIO_MAX_GAIN
);
481 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0) {
483 pa_log("AUDIO_SETINFO: Unsupported volume.");
485 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
490 static void sink_get_volume(pa_sink
*s
) {
494 pa_assert_se(u
= s
->userdata
);
497 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
498 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
500 pa_cvolume_set(&s
->virtual_volume
, s
->sample_spec
.channels
,
501 info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
505 static void source_set_volume(pa_source
*s
) {
509 pa_assert_se(u
= s
->userdata
);
512 AUDIO_INITINFO(&info
);
514 info
.play
.gain
= pa_cvolume_max(&s
->virtual_volume
) * AUDIO_MAX_GAIN
/ PA_VOLUME_NORM
;
515 assert(info
.play
.gain
<= AUDIO_MAX_GAIN
);
517 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0) {
519 pa_log("AUDIO_SETINFO: Unsupported volume.");
521 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
526 static void source_get_volume(pa_source
*s
) {
530 pa_assert_se(u
= s
->userdata
);
533 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
534 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
536 pa_cvolume_set(&s
->virtual_volume
, s
->sample_spec
.channels
,
537 info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
541 static void sink_set_mute(pa_sink
*s
) {
542 struct userdata
*u
= s
->userdata
;
548 AUDIO_INITINFO(&info
);
550 info
.output_muted
= !!s
->muted
;
552 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
553 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
557 static void sink_get_mute(pa_sink
*s
) {
558 struct userdata
*u
= s
->userdata
;
564 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
565 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
567 s
->muted
= !!info
.output_muted
;
571 static void process_rewind(struct userdata
*u
) {
572 size_t rewind_nbytes
;
576 /* Figure out how much we shall rewind and reset the counter */
577 rewind_nbytes
= u
->sink
->thread_info
.rewind_nbytes
;
578 u
->sink
->thread_info
.rewind_nbytes
= 0;
580 if (rewind_nbytes
> 0) {
581 pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes
);
582 rewind_nbytes
= PA_MIN(u
->memchunk
.length
, rewind_nbytes
);
583 u
->memchunk
.length
-= rewind_nbytes
;
584 pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes
);
587 pa_sink_process_rewind(u
->sink
, rewind_nbytes
);
590 static void thread_func(void *userdata
) {
591 struct userdata
*u
= userdata
;
592 unsigned short revents
= 0;
598 pa_log_debug("Thread starting up");
600 if (u
->core
->realtime_scheduling
)
601 pa_make_realtime(u
->core
->realtime_priority
);
603 pa_thread_mq_install(&u
->thread_mq
);
604 pa_rtpoll_install(u
->rtpoll
);
607 /* Render some data and write it to the dsp */
609 if (u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
)) {
611 uint64_t buffered_bytes
;
613 if (u
->sink
->thread_info
.rewind_requested
)
616 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
618 pa_log("AUDIO_GETINFO ioctl failed: %s", pa_cstrerror(errno
));
622 if (info
.play
.error
) {
623 pa_log_debug("buffer under-run!");
625 AUDIO_INITINFO(&info
);
627 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
628 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
637 * Since we cannot modify the size of the output buffer we fake it
638 * by not filling it more than u->buffer_size.
640 xtime0
= pa_rtclock_usec();
641 buffered_bytes
= get_playback_buffered_bytes(u
);
642 if (buffered_bytes
>= (uint64_t)u
->buffer_size
)
645 len
= u
->buffer_size
- buffered_bytes
;
646 len
-= len
% u
->frame_size
;
648 if (len
< (size_t) u
->minimum_request
)
651 if (u
->memchunk
.length
< len
)
652 pa_sink_render(u
->sink
, u
->sink
->thread_info
.max_request
, &u
->memchunk
);
654 p
= pa_memblock_acquire(u
->memchunk
.memblock
);
655 w
= pa_write(u
->fd
, (uint8_t*) p
+ u
->memchunk
.index
, u
->memchunk
.length
, NULL
);
656 pa_memblock_release(u
->memchunk
.memblock
);
663 /* If the buffer_size is too big, we get EAGAIN. Avoiding that limit by trial and error
664 * is not ideal, but I don't know how to get the system to tell me what the limit is.
666 u
->buffer_size
= u
->buffer_size
* 18 / 25;
667 u
->buffer_size
-= u
->buffer_size
% u
->frame_size
;
668 u
->buffer_size
= PA_MAX(u
->buffer_size
, 2 * u
->minimum_request
);
669 pa_sink_set_max_request_within_thread(u
->sink
, u
->buffer_size
);
670 pa_sink_set_max_rewind_within_thread(u
->sink
, u
->buffer_size
);
671 pa_log("EAGAIN. Buffer size is now %u bytes (%llu buffered)", u
->buffer_size
, buffered_bytes
);
674 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno
));
678 pa_assert(w
% u
->frame_size
== 0);
680 u
->written_bytes
+= w
;
681 u
->memchunk
.length
-= w
;
683 u
->memchunk
.index
+= w
;
684 if (u
->memchunk
.length
<= 0) {
685 pa_memblock_unref(u
->memchunk
.memblock
);
686 pa_memchunk_reset(&u
->memchunk
);
691 pa_rtpoll_set_timer_absolute(u
->rtpoll
, xtime0
+ pa_bytes_to_usec(buffered_bytes
/ 2, &u
->sink
->sample_spec
));
693 pa_rtpoll_set_timer_disabled(u
->rtpoll
);
695 /* Try to read some data and pass it on to the source driver */
697 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
) && (revents
& POLLIN
)) {
698 pa_memchunk memchunk
;
703 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
706 if (info
.record
.error
) {
707 pa_log_debug("buffer overflow!");
709 AUDIO_INITINFO(&info
);
710 info
.record
.error
= 0;
711 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
712 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
715 err
= ioctl(u
->fd
, I_NREAD
, &len
);
719 memchunk
.memblock
= pa_memblock_new(u
->core
->mempool
, len
);
720 pa_assert(memchunk
.memblock
);
722 p
= pa_memblock_acquire(memchunk
.memblock
);
723 r
= pa_read(u
->fd
, p
, len
, NULL
);
724 pa_memblock_release(memchunk
.memblock
);
727 pa_memblock_unref(memchunk
.memblock
);
731 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno
));
740 pa_source_post(u
->source
, &memchunk
);
741 pa_memblock_unref(memchunk
.memblock
);
748 if (u
->rtpoll_item
) {
749 struct pollfd
*pollfd
;
751 pa_assert(u
->fd
>= 0);
753 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
754 pollfd
->events
= (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
)) ? POLLIN
: 0;
757 /* Hmm, nothing to do. Let's sleep */
758 if ((ret
= pa_rtpoll_run(u
->rtpoll
, TRUE
)) < 0)
764 if (u
->rtpoll_item
) {
765 struct pollfd
*pollfd
;
767 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
769 if (pollfd
->revents
& ~(POLLOUT
|POLLIN
)) {
770 pa_log("DSP shutdown.");
774 revents
= pollfd
->revents
;
780 /* We have to continue processing messages until we receive the
781 * SHUTDOWN message */
782 pa_asyncmsgq_post(u
->thread_mq
.outq
, PA_MSGOBJECT(u
->core
), PA_CORE_MESSAGE_UNLOAD_MODULE
, u
->module
, 0, NULL
, NULL
);
783 pa_asyncmsgq_wait_for(u
->thread_mq
.inq
, PA_MESSAGE_SHUTDOWN
);
786 pa_log_debug("Thread shutting down");
789 static void sig_callback(pa_mainloop_api
*api
, pa_signal_event
*e
, int sig
, void *userdata
) {
790 struct userdata
*u
= userdata
;
794 pa_log_debug("caught signal");
797 pa_sink_get_volume(u
->sink
, TRUE
);
798 pa_sink_get_mute(u
->sink
, TRUE
);
802 pa_source_get_volume(u
->source
, TRUE
);
805 int pa__init(pa_module
*m
) {
806 struct userdata
*u
= NULL
;
807 pa_bool_t record
= TRUE
, playback
= TRUE
;
810 pa_modargs
*ma
= NULL
;
811 uint32_t buffer_length_msec
;
813 pa_sink_new_data sink_new_data
;
814 pa_source_new_data source_new_data
;
817 pa_bool_t namereg_fail
;
821 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
822 pa_log("failed to parse module arguments.");
826 if (pa_modargs_get_value_boolean(ma
, "record", &record
) < 0 || pa_modargs_get_value_boolean(ma
, "playback", &playback
) < 0) {
827 pa_log("record= and playback= expect a boolean argument.");
831 if (!playback
&& !record
) {
832 pa_log("neither playback nor record enabled for device.");
836 u
= pa_xnew0(struct userdata
, 1);
839 * For a process (or several processes) to use the same audio device for both
840 * record and playback at the same time, the device's mixer must be enabled.
841 * See mixerctl(1). It may be turned off for playback only or record only.
843 u
->mode
= (playback
&& record
) ? O_RDWR
: (playback
? O_WRONLY
: (record
? O_RDONLY
: 0));
845 ss
= m
->core
->default_sample_spec
;
846 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
847 pa_log("failed to parse sample specification");
850 u
->frame_size
= pa_frame_size(&ss
);
852 u
->minimum_request
= pa_usec_to_bytes(PA_USEC_PER_SEC
/ MAX_RENDER_HZ
, &ss
);
854 buffer_length_msec
= 100;
855 if (pa_modargs_get_value_u32(ma
, "buffer_length", &buffer_length_msec
) < 0) {
856 pa_log("failed to parse buffer_length argument");
859 u
->buffer_size
= pa_usec_to_bytes(1000 * buffer_length_msec
, &ss
);
860 if (u
->buffer_size
< 2 * u
->minimum_request
) {
861 pa_log("supplied buffer size argument is too small");
865 u
->device_name
= pa_xstrdup(pa_modargs_get_value(ma
, "device", DEFAULT_DEVICE
));
867 if ((fd
= open_audio_device(u
, &ss
)) < 0)
874 pa_memchunk_reset(&u
->memchunk
);
876 u
->rtpoll
= pa_rtpoll_new();
877 pa_thread_mq_init(&u
->thread_mq
, m
->core
->mainloop
, u
->rtpoll
);
879 u
->rtpoll_item
= NULL
;
882 if (u
->mode
!= O_WRONLY
) {
886 if (!(name
= pa_modargs_get_value(ma
, "source_name", NULL
))) {
887 name
= name_buf
= pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u
->device_name
));
888 namereg_fail
= FALSE
;
891 pa_source_new_data_init(&source_new_data
);
892 source_new_data
.driver
= __FILE__
;
893 source_new_data
.module
= m
;
894 pa_source_new_data_set_name(&source_new_data
, name
);
895 source_new_data
.namereg_fail
= namereg_fail
;
896 pa_source_new_data_set_sample_spec(&source_new_data
, &ss
);
897 pa_source_new_data_set_channel_map(&source_new_data
, &map
);
898 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
899 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
900 pa_proplist_setf(source_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM source");
901 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
902 pa_proplist_setf(source_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE
, "%lu", (unsigned long) u
->buffer_size
);
904 u
->source
= pa_source_new(m
->core
, &source_new_data
, PA_SOURCE_HARDWARE
|PA_SOURCE_LATENCY
|PA_SOURCE_HW_VOLUME_CTRL
);
905 pa_source_new_data_done(&source_new_data
);
909 pa_log("Failed to create source object");
913 u
->source
->userdata
= u
;
914 u
->source
->parent
.process_msg
= source_process_msg
;
916 pa_source_set_asyncmsgq(u
->source
, u
->thread_mq
.inq
);
917 pa_source_set_rtpoll(u
->source
, u
->rtpoll
);
919 u
->source
->get_volume
= source_get_volume
;
920 u
->source
->set_volume
= source_set_volume
;
921 u
->source
->refresh_volume
= TRUE
;
925 if (u
->mode
!= O_RDONLY
) {
928 if (!(name
= pa_modargs_get_value(ma
, "sink_name", NULL
))) {
929 name
= name_buf
= pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u
->device_name
));
930 namereg_fail
= FALSE
;
933 pa_sink_new_data_init(&sink_new_data
);
934 sink_new_data
.driver
= __FILE__
;
935 sink_new_data
.module
= m
;
936 pa_sink_new_data_set_name(&sink_new_data
, name
);
937 sink_new_data
.namereg_fail
= namereg_fail
;
938 pa_sink_new_data_set_sample_spec(&sink_new_data
, &ss
);
939 pa_sink_new_data_set_channel_map(&sink_new_data
, &map
);
940 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
941 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
942 pa_proplist_setf(sink_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM sink");
943 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
945 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
);
946 pa_sink_new_data_done(&sink_new_data
);
949 u
->sink
->userdata
= u
;
950 u
->sink
->parent
.process_msg
= sink_process_msg
;
952 pa_sink_set_asyncmsgq(u
->sink
, u
->thread_mq
.inq
);
953 pa_sink_set_rtpoll(u
->sink
, u
->rtpoll
);
955 u
->sink
->get_volume
= sink_get_volume
;
956 u
->sink
->set_volume
= sink_set_volume
;
957 u
->sink
->get_mute
= sink_get_mute
;
958 u
->sink
->set_mute
= sink_set_mute
;
959 u
->sink
->refresh_volume
= u
->sink
->refresh_muted
= TRUE
;
961 pa_sink_set_max_request(u
->sink
, u
->buffer_size
);
962 pa_sink_set_max_rewind(u
->sink
, u
->buffer_size
);
966 pa_assert(u
->source
|| u
->sink
);
968 u
->sig
= pa_signal_new(SIGPOLL
, sig_callback
, u
);
970 ioctl(u
->fd
, I_SETSIG
, S_MSG
);
972 pa_log_warn("Could not register SIGPOLL handler");
974 if (!(u
->thread
= pa_thread_new(thread_func
, u
))) {
975 pa_log("Failed to create thread.");
979 /* Read mixer settings */
981 if (sink_new_data
.volume_is_set
)
982 u
->sink
->set_volume(u
->sink
);
984 u
->sink
->get_volume(u
->sink
);
986 if (sink_new_data
.muted_is_set
)
987 u
->sink
->set_mute(u
->sink
);
989 u
->sink
->get_mute(u
->sink
);
991 pa_sink_put(u
->sink
);
995 if (source_new_data
.volume_is_set
)
996 u
->source
->set_volume(u
->source
);
998 u
->source
->get_volume(u
->source
);
1000 pa_source_put(u
->source
);
1003 pa_modargs_free(ma
);
1014 pa_modargs_free(ma
);
1019 void pa__done(pa_module
*m
) {
1024 if (!(u
= m
->userdata
))
1028 ioctl(u
->fd
, I_SETSIG
, 0);
1029 pa_signal_free(u
->sig
);
1033 pa_sink_unlink(u
->sink
);
1036 pa_source_unlink(u
->source
);
1039 pa_asyncmsgq_send(u
->thread_mq
.inq
, NULL
, PA_MESSAGE_SHUTDOWN
, NULL
, 0, NULL
);
1040 pa_thread_free(u
->thread
);
1043 pa_thread_mq_done(&u
->thread_mq
);
1046 pa_sink_unref(u
->sink
);
1049 pa_source_unref(u
->source
);
1051 if (u
->memchunk
.memblock
)
1052 pa_memblock_unref(u
->memchunk
.memblock
);
1055 pa_rtpoll_item_free(u
->rtpoll_item
);
1058 pa_rtpoll_free(u
->rtpoll
);
1063 pa_xfree(u
->device_name
);