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>
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 "sink_properties=<properties for the sink> "
72 "source_name=<name for the source> "
73 "source_properties=<properties for the source> "
74 "device=<audio device file name> "
75 "record=<enable source?> "
76 "playback=<enable sink?> "
77 "format=<sample format> "
78 "channels=<number of channels> "
80 "buffer_length=<milliseconds> "
81 "channel_map=<channel map>");
82 PA_MODULE_LOAD_ONCE(FALSE
);
90 pa_thread_mq thread_mq
;
99 uint64_t written_bytes
, read_bytes
;
104 pa_rtpoll_item
*rtpoll_item
;
107 pa_bool_t sink_suspended
, source_suspended
;
109 uint32_t play_samples_msw
, record_samples_msw
;
110 uint32_t prev_playback_samples
, prev_record_samples
;
112 int32_t minimum_request
;
115 static const char* const valid_modargs
[] = {
131 #define DEFAULT_DEVICE "/dev/audio"
133 #define MAX_RENDER_HZ (300)
134 /* This render rate limit imposes a minimum latency, but without it we waste too much CPU time. */
136 static uint64_t get_playback_buffered_bytes(struct userdata
*u
) {
138 uint64_t played_bytes
;
143 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
146 /* Handle wrap-around of the device's sample counter, which is a uint_32. */
147 if (u
->prev_playback_samples
> info
.play
.samples
) {
148 /* Unfortunately info.play.samples can sometimes go backwards, even before it wraps! */
149 if (u
->prev_playback_samples
+ info
.play
.samples
< 240000) {
150 ++u
->play_samples_msw
;
152 pa_log_debug("play.samples went backwards %d bytes", u
->prev_playback_samples
- info
.play
.samples
);
155 u
->prev_playback_samples
= info
.play
.samples
;
156 played_bytes
= (((uint64_t)u
->play_samples_msw
<< 32) + info
.play
.samples
) * u
->frame_size
;
158 return u
->written_bytes
- played_bytes
;
161 static pa_usec_t
sink_get_latency(struct userdata
*u
, pa_sample_spec
*ss
) {
168 r
= pa_bytes_to_usec(get_playback_buffered_bytes(u
), ss
);
169 if (u
->memchunk
.memblock
)
170 r
+= pa_bytes_to_usec(u
->memchunk
.length
, ss
);
175 static uint64_t get_recorded_bytes(struct userdata
*u
) {
180 pa_assert(u
->source
);
182 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
185 if (u
->prev_record_samples
> info
.record
.samples
)
186 ++u
->record_samples_msw
;
187 u
->prev_record_samples
= info
.record
.samples
;
188 result
= (((uint64_t)u
->record_samples_msw
<< 32) + info
.record
.samples
) * u
->frame_size
;
193 static pa_usec_t
source_get_latency(struct userdata
*u
, pa_sample_spec
*ss
) {
201 int err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
204 r
= pa_bytes_to_usec(get_recorded_bytes(u
), ss
) - pa_bytes_to_usec(u
->read_bytes
, ss
);
209 static void build_pollfd(struct userdata
*u
) {
210 struct pollfd
*pollfd
;
213 pa_assert(!u
->rtpoll_item
);
214 u
->rtpoll_item
= pa_rtpoll_item_new(u
->rtpoll
, PA_RTPOLL_NEVER
, 1);
216 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
222 static int set_buffer(int fd
, int buffer_size
) {
227 AUDIO_INITINFO(&info
);
228 info
.play
.buffer_size
= buffer_size
;
229 info
.record
.buffer_size
= buffer_size
;
231 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0) {
233 pa_log("AUDIO_SETINFO: Unsupported buffer size.");
235 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
242 static int auto_format(int fd
, int mode
, pa_sample_spec
*ss
) {
248 AUDIO_INITINFO(&info
);
250 if (mode
!= O_RDONLY
) {
251 info
.play
.sample_rate
= ss
->rate
;
252 info
.play
.channels
= ss
->channels
;
253 switch (ss
->format
) {
255 info
.play
.precision
= 8;
256 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
259 info
.play
.precision
= 8;
260 info
.play
.encoding
= AUDIO_ENCODING_ALAW
;
263 info
.play
.precision
= 8;
264 info
.play
.encoding
= AUDIO_ENCODING_ULAW
;
266 case PA_SAMPLE_S16NE
:
267 info
.play
.precision
= 16;
268 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
271 pa_log("AUDIO_SETINFO: Unsupported sample format.");
276 if (mode
!= O_WRONLY
) {
277 info
.record
.sample_rate
= ss
->rate
;
278 info
.record
.channels
= ss
->channels
;
279 switch (ss
->format
) {
281 info
.record
.precision
= 8;
282 info
.record
.encoding
= AUDIO_ENCODING_LINEAR
;
285 info
.record
.precision
= 8;
286 info
.record
.encoding
= AUDIO_ENCODING_ALAW
;
289 info
.record
.precision
= 8;
290 info
.record
.encoding
= AUDIO_ENCODING_ULAW
;
292 case PA_SAMPLE_S16NE
:
293 info
.record
.precision
= 16;
294 info
.record
.encoding
= AUDIO_ENCODING_LINEAR
;
297 pa_log("AUDIO_SETINFO: Unsupported sample format.");
302 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0) {
304 pa_log("AUDIO_SETINFO: Failed to set sample format.");
306 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
313 static int open_audio_device(struct userdata
*u
, pa_sample_spec
*ss
) {
317 if ((u
->fd
= open(u
->device_name
, u
->mode
| O_NONBLOCK
)) < 0) {
318 pa_log_warn("open %s failed (%s)", u
->device_name
, pa_cstrerror(errno
));
322 pa_log_info("device opened in %s mode.", u
->mode
== O_WRONLY
? "O_WRONLY" : (u
->mode
== O_RDONLY
? "O_RDONLY" : "O_RDWR"));
324 if (auto_format(u
->fd
, u
->mode
, ss
) < 0)
327 if (set_buffer(u
->fd
, u
->buffer_size
) < 0)
330 u
->written_bytes
= u
->read_bytes
= 0;
331 u
->play_samples_msw
= u
->record_samples_msw
= 0;
332 u
->prev_playback_samples
= u
->prev_record_samples
= 0;
337 static int suspend(struct userdata
*u
) {
339 pa_assert(u
->fd
>= 0);
341 pa_log_info("Suspending...");
343 ioctl(u
->fd
, AUDIO_DRAIN
, NULL
);
347 if (u
->rtpoll_item
) {
348 pa_rtpoll_item_free(u
->rtpoll_item
);
349 u
->rtpoll_item
= NULL
;
352 pa_log_info("Device suspended.");
357 static int unsuspend(struct userdata
*u
) {
359 pa_assert(u
->fd
< 0);
361 pa_log_info("Resuming...");
363 if (open_audio_device(u
, u
->sink
? &u
->sink
->sample_spec
: &u
->source
->sample_spec
) < 0)
368 pa_log_info("Device resumed.");
373 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
374 struct userdata
*u
= PA_SINK(o
)->userdata
;
378 case PA_SINK_MESSAGE_GET_LATENCY
:
379 *((pa_usec_t
*) data
) = sink_get_latency(u
, &PA_SINK(o
)->sample_spec
);
382 case PA_SINK_MESSAGE_SET_STATE
:
384 switch ((pa_sink_state_t
) PA_PTR_TO_UINT(data
)) {
386 case PA_SINK_SUSPENDED
:
388 pa_assert(PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
));
390 if (!u
->source
|| u
->source_suspended
) {
394 u
->sink_suspended
= TRUE
;
398 case PA_SINK_RUNNING
:
400 if (u
->sink
->thread_info
.state
== PA_SINK_SUSPENDED
) {
401 if (!u
->source
|| u
->source_suspended
) {
402 if (unsuspend(u
) < 0)
404 u
->sink
->get_volume(u
->sink
);
405 u
->sink
->get_mute(u
->sink
);
407 u
->sink_suspended
= FALSE
;
411 case PA_SINK_INVALID_STATE
:
412 case PA_SINK_UNLINKED
:
420 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
423 static int source_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
424 struct userdata
*u
= PA_SOURCE(o
)->userdata
;
428 case PA_SOURCE_MESSAGE_GET_LATENCY
:
429 *((pa_usec_t
*) data
) = source_get_latency(u
, &PA_SOURCE(o
)->sample_spec
);
432 case PA_SOURCE_MESSAGE_SET_STATE
:
434 switch ((pa_source_state_t
) PA_PTR_TO_UINT(data
)) {
436 case PA_SOURCE_SUSPENDED
:
438 pa_assert(PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
));
440 if (!u
->sink
|| u
->sink_suspended
) {
444 u
->source_suspended
= TRUE
;
448 case PA_SOURCE_RUNNING
:
450 if (u
->source
->thread_info
.state
== PA_SOURCE_SUSPENDED
) {
451 if (!u
->sink
|| u
->sink_suspended
) {
452 if (unsuspend(u
) < 0)
454 u
->source
->get_volume(u
->source
);
456 u
->source_suspended
= FALSE
;
460 case PA_SOURCE_UNLINKED
:
462 case PA_SOURCE_INVALID_STATE
:
470 return pa_source_process_msg(o
, code
, data
, offset
, chunk
);
473 static void sink_set_volume(pa_sink
*s
) {
477 pa_assert_se(u
= s
->userdata
);
480 AUDIO_INITINFO(&info
);
482 info
.play
.gain
= pa_cvolume_max(&s
->real_volume
) * AUDIO_MAX_GAIN
/ PA_VOLUME_NORM
;
483 assert(info
.play
.gain
<= AUDIO_MAX_GAIN
);
485 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0) {
487 pa_log("AUDIO_SETINFO: Unsupported volume.");
489 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
494 static void sink_get_volume(pa_sink
*s
) {
498 pa_assert_se(u
= s
->userdata
);
501 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
502 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
504 pa_cvolume_set(&s
->real_volume
, s
->sample_spec
.channels
, info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
508 static void source_set_volume(pa_source
*s
) {
512 pa_assert_se(u
= s
->userdata
);
515 AUDIO_INITINFO(&info
);
517 info
.play
.gain
= pa_cvolume_max(&s
->volume
) * AUDIO_MAX_GAIN
/ PA_VOLUME_NORM
;
518 assert(info
.play
.gain
<= AUDIO_MAX_GAIN
);
520 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0) {
522 pa_log("AUDIO_SETINFO: Unsupported volume.");
524 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
529 static void source_get_volume(pa_source
*s
) {
533 pa_assert_se(u
= s
->userdata
);
536 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
537 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
539 pa_cvolume_set(&s
->volume
, s
->sample_spec
.channels
, info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
543 static void sink_set_mute(pa_sink
*s
) {
544 struct userdata
*u
= s
->userdata
;
550 AUDIO_INITINFO(&info
);
552 info
.output_muted
= !!s
->muted
;
554 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
555 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
559 static void sink_get_mute(pa_sink
*s
) {
560 struct userdata
*u
= s
->userdata
;
566 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
567 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
569 s
->muted
= !!info
.output_muted
;
573 static void process_rewind(struct userdata
*u
) {
574 size_t rewind_nbytes
;
578 /* Figure out how much we shall rewind and reset the counter */
579 rewind_nbytes
= u
->sink
->thread_info
.rewind_nbytes
;
580 u
->sink
->thread_info
.rewind_nbytes
= 0;
582 if (rewind_nbytes
> 0) {
583 pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes
);
584 rewind_nbytes
= PA_MIN(u
->memchunk
.length
, rewind_nbytes
);
585 u
->memchunk
.length
-= rewind_nbytes
;
586 pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes
);
589 pa_sink_process_rewind(u
->sink
, rewind_nbytes
);
592 static void thread_func(void *userdata
) {
593 struct userdata
*u
= userdata
;
594 unsigned short revents
= 0;
600 pa_log_debug("Thread starting up");
602 if (u
->core
->realtime_scheduling
)
603 pa_make_realtime(u
->core
->realtime_priority
);
605 pa_thread_mq_install(&u
->thread_mq
);
608 /* Render some data and write it to the dsp */
610 if (u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
)) {
612 uint64_t buffered_bytes
;
614 if (u
->sink
->thread_info
.rewind_requested
)
617 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
619 pa_log("AUDIO_GETINFO ioctl failed: %s", pa_cstrerror(errno
));
623 if (info
.play
.error
) {
624 pa_log_debug("buffer under-run!");
626 AUDIO_INITINFO(&info
);
628 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
629 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
638 * Since we cannot modify the size of the output buffer we fake it
639 * by not filling it more than u->buffer_size.
641 xtime0
= pa_rtclock_now();
642 buffered_bytes
= get_playback_buffered_bytes(u
);
643 if (buffered_bytes
>= (uint64_t)u
->buffer_size
)
646 len
= u
->buffer_size
- buffered_bytes
;
647 len
-= len
% u
->frame_size
;
649 if (len
< (size_t) u
->minimum_request
)
652 if (u
->memchunk
.length
< len
)
653 pa_sink_render(u
->sink
, u
->sink
->thread_info
.max_request
, &u
->memchunk
);
655 p
= pa_memblock_acquire(u
->memchunk
.memblock
);
656 w
= pa_write(u
->fd
, (uint8_t*) p
+ u
->memchunk
.index
, u
->memchunk
.length
, NULL
);
657 pa_memblock_release(u
->memchunk
.memblock
);
664 /* If the buffer_size is too big, we get EAGAIN. Avoiding that limit by trial and error
665 * is not ideal, but I don't know how to get the system to tell me what the limit is.
667 u
->buffer_size
= u
->buffer_size
* 18 / 25;
668 u
->buffer_size
-= u
->buffer_size
% u
->frame_size
;
669 u
->buffer_size
= PA_MAX(u
->buffer_size
, 2 * u
->minimum_request
);
670 pa_sink_set_max_request_within_thread(u
->sink
, u
->buffer_size
);
671 pa_sink_set_max_rewind_within_thread(u
->sink
, u
->buffer_size
);
672 pa_log("EAGAIN. Buffer size is now %u bytes (%llu buffered)", u
->buffer_size
, buffered_bytes
);
675 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno
));
679 pa_assert(w
% u
->frame_size
== 0);
681 u
->written_bytes
+= w
;
682 u
->memchunk
.length
-= w
;
684 u
->memchunk
.index
+= w
;
685 if (u
->memchunk
.length
<= 0) {
686 pa_memblock_unref(u
->memchunk
.memblock
);
687 pa_memchunk_reset(&u
->memchunk
);
692 pa_rtpoll_set_timer_absolute(u
->rtpoll
, xtime0
+ pa_bytes_to_usec(buffered_bytes
/ 2, &u
->sink
->sample_spec
));
694 pa_rtpoll_set_timer_disabled(u
->rtpoll
);
696 /* Try to read some data and pass it on to the source driver */
698 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
) && (revents
& POLLIN
)) {
699 pa_memchunk memchunk
;
704 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
707 if (info
.record
.error
) {
708 pa_log_debug("buffer overflow!");
710 AUDIO_INITINFO(&info
);
711 info
.record
.error
= 0;
712 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
713 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
716 err
= ioctl(u
->fd
, I_NREAD
, &len
);
720 memchunk
.memblock
= pa_memblock_new(u
->core
->mempool
, len
);
721 pa_assert(memchunk
.memblock
);
723 p
= pa_memblock_acquire(memchunk
.memblock
);
724 r
= pa_read(u
->fd
, p
, len
, NULL
);
725 pa_memblock_release(memchunk
.memblock
);
728 pa_memblock_unref(memchunk
.memblock
);
732 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno
));
741 pa_source_post(u
->source
, &memchunk
);
742 pa_memblock_unref(memchunk
.memblock
);
749 if (u
->rtpoll_item
) {
750 struct pollfd
*pollfd
;
752 pa_assert(u
->fd
>= 0);
754 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
755 pollfd
->events
= (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
)) ? POLLIN
: 0;
758 /* Hmm, nothing to do. Let's sleep */
759 if ((ret
= pa_rtpoll_run(u
->rtpoll
, TRUE
)) < 0)
765 if (u
->rtpoll_item
) {
766 struct pollfd
*pollfd
;
768 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
770 if (pollfd
->revents
& ~(POLLOUT
|POLLIN
)) {
771 pa_log("DSP shutdown.");
775 revents
= pollfd
->revents
;
781 /* We have to continue processing messages until we receive the
782 * SHUTDOWN message */
783 pa_asyncmsgq_post(u
->thread_mq
.outq
, PA_MSGOBJECT(u
->core
), PA_CORE_MESSAGE_UNLOAD_MODULE
, u
->module
, 0, NULL
, NULL
);
784 pa_asyncmsgq_wait_for(u
->thread_mq
.inq
, PA_MESSAGE_SHUTDOWN
);
787 pa_log_debug("Thread shutting down");
790 static void sig_callback(pa_mainloop_api
*api
, pa_signal_event
*e
, int sig
, void *userdata
) {
791 struct userdata
*u
= userdata
;
795 pa_log_debug("caught signal");
798 pa_sink_get_volume(u
->sink
, TRUE
);
799 pa_sink_get_mute(u
->sink
, TRUE
);
803 pa_source_get_volume(u
->source
, TRUE
);
806 int pa__init(pa_module
*m
) {
807 struct userdata
*u
= NULL
;
808 pa_bool_t record
= TRUE
, playback
= TRUE
;
811 pa_modargs
*ma
= NULL
;
812 uint32_t buffer_length_msec
;
814 pa_sink_new_data sink_new_data
;
815 pa_source_new_data source_new_data
;
818 pa_bool_t namereg_fail
;
822 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
823 pa_log("failed to parse module arguments.");
827 if (pa_modargs_get_value_boolean(ma
, "record", &record
) < 0 || pa_modargs_get_value_boolean(ma
, "playback", &playback
) < 0) {
828 pa_log("record= and playback= expect a boolean argument.");
832 if (!playback
&& !record
) {
833 pa_log("neither playback nor record enabled for device.");
837 u
= pa_xnew0(struct userdata
, 1);
840 * For a process (or several processes) to use the same audio device for both
841 * record and playback at the same time, the device's mixer must be enabled.
842 * See mixerctl(1). It may be turned off for playback only or record only.
844 u
->mode
= (playback
&& record
) ? O_RDWR
: (playback
? O_WRONLY
: (record
? O_RDONLY
: 0));
846 ss
= m
->core
->default_sample_spec
;
847 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
848 pa_log("failed to parse sample specification");
851 u
->frame_size
= pa_frame_size(&ss
);
853 u
->minimum_request
= pa_usec_to_bytes(PA_USEC_PER_SEC
/ MAX_RENDER_HZ
, &ss
);
855 buffer_length_msec
= 100;
856 if (pa_modargs_get_value_u32(ma
, "buffer_length", &buffer_length_msec
) < 0) {
857 pa_log("failed to parse buffer_length argument");
860 u
->buffer_size
= pa_usec_to_bytes(1000 * buffer_length_msec
, &ss
);
861 if (u
->buffer_size
< 2 * u
->minimum_request
) {
862 pa_log("supplied buffer size argument is too small");
866 u
->device_name
= pa_xstrdup(pa_modargs_get_value(ma
, "device", DEFAULT_DEVICE
));
868 if ((fd
= open_audio_device(u
, &ss
)) < 0)
875 pa_memchunk_reset(&u
->memchunk
);
877 u
->rtpoll
= pa_rtpoll_new();
878 pa_thread_mq_init(&u
->thread_mq
, m
->core
->mainloop
, u
->rtpoll
);
880 u
->rtpoll_item
= NULL
;
883 if (u
->mode
!= O_WRONLY
) {
887 if (!(name
= pa_modargs_get_value(ma
, "source_name", NULL
))) {
888 name
= name_buf
= pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u
->device_name
));
889 namereg_fail
= FALSE
;
892 pa_source_new_data_init(&source_new_data
);
893 source_new_data
.driver
= __FILE__
;
894 source_new_data
.module
= m
;
895 pa_source_new_data_set_name(&source_new_data
, name
);
896 source_new_data
.namereg_fail
= namereg_fail
;
897 pa_source_new_data_set_sample_spec(&source_new_data
, &ss
);
898 pa_source_new_data_set_channel_map(&source_new_data
, &map
);
899 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
900 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
901 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM source");
902 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
903 pa_proplist_setf(source_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE
, "%lu", (unsigned long) u
->buffer_size
);
905 if (pa_modargs_get_proplist(ma
, "source_properties", source_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
906 pa_log("Invalid properties");
907 pa_source_new_data_done(&source_new_data
);
911 u
->source
= pa_source_new(m
->core
, &source_new_data
, PA_SOURCE_HARDWARE
|PA_SOURCE_LATENCY
|PA_SOURCE_HW_VOLUME_CTRL
);
912 pa_source_new_data_done(&source_new_data
);
916 pa_log("Failed to create source object");
920 u
->source
->userdata
= u
;
921 u
->source
->parent
.process_msg
= source_process_msg
;
923 pa_source_set_asyncmsgq(u
->source
, u
->thread_mq
.inq
);
924 pa_source_set_rtpoll(u
->source
, u
->rtpoll
);
926 u
->source
->get_volume
= source_get_volume
;
927 u
->source
->set_volume
= source_set_volume
;
928 u
->source
->refresh_volume
= TRUE
;
932 if (u
->mode
!= O_RDONLY
) {
935 if (!(name
= pa_modargs_get_value(ma
, "sink_name", NULL
))) {
936 name
= name_buf
= pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u
->device_name
));
937 namereg_fail
= FALSE
;
940 pa_sink_new_data_init(&sink_new_data
);
941 sink_new_data
.driver
= __FILE__
;
942 sink_new_data
.module
= m
;
943 pa_sink_new_data_set_name(&sink_new_data
, name
);
944 sink_new_data
.namereg_fail
= namereg_fail
;
945 pa_sink_new_data_set_sample_spec(&sink_new_data
, &ss
);
946 pa_sink_new_data_set_channel_map(&sink_new_data
, &map
);
947 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
948 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
949 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM sink");
950 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
952 if (pa_modargs_get_proplist(ma
, "sink_properties", sink_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
953 pa_log("Invalid properties");
954 pa_sink_new_data_done(&sink_new_data
);
958 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
);
959 pa_sink_new_data_done(&sink_new_data
);
962 u
->sink
->userdata
= u
;
963 u
->sink
->parent
.process_msg
= sink_process_msg
;
965 pa_sink_set_asyncmsgq(u
->sink
, u
->thread_mq
.inq
);
966 pa_sink_set_rtpoll(u
->sink
, u
->rtpoll
);
968 u
->sink
->get_volume
= sink_get_volume
;
969 u
->sink
->set_volume
= sink_set_volume
;
970 u
->sink
->get_mute
= sink_get_mute
;
971 u
->sink
->set_mute
= sink_set_mute
;
972 u
->sink
->refresh_volume
= u
->sink
->refresh_muted
= TRUE
;
974 pa_sink_set_max_request(u
->sink
, u
->buffer_size
);
975 pa_sink_set_max_rewind(u
->sink
, u
->buffer_size
);
979 pa_assert(u
->source
|| u
->sink
);
981 u
->sig
= pa_signal_new(SIGPOLL
, sig_callback
, u
);
983 ioctl(u
->fd
, I_SETSIG
, S_MSG
);
985 pa_log_warn("Could not register SIGPOLL handler");
987 if (!(u
->thread
= pa_thread_new(thread_func
, u
))) {
988 pa_log("Failed to create thread.");
992 /* Read mixer settings */
994 if (sink_new_data
.volume_is_set
)
995 u
->sink
->set_volume(u
->sink
);
997 u
->sink
->get_volume(u
->sink
);
999 if (sink_new_data
.muted_is_set
)
1000 u
->sink
->set_mute(u
->sink
);
1002 u
->sink
->get_mute(u
->sink
);
1004 pa_sink_put(u
->sink
);
1008 if (source_new_data
.volume_is_set
)
1009 u
->source
->set_volume(u
->source
);
1011 u
->source
->get_volume(u
->source
);
1013 pa_source_put(u
->source
);
1016 pa_modargs_free(ma
);
1027 pa_modargs_free(ma
);
1032 void pa__done(pa_module
*m
) {
1037 if (!(u
= m
->userdata
))
1041 ioctl(u
->fd
, I_SETSIG
, 0);
1042 pa_signal_free(u
->sig
);
1046 pa_sink_unlink(u
->sink
);
1049 pa_source_unlink(u
->source
);
1052 pa_asyncmsgq_send(u
->thread_mq
.inq
, NULL
, PA_MESSAGE_SHUTDOWN
, NULL
, 0, NULL
);
1053 pa_thread_free(u
->thread
);
1056 pa_thread_mq_done(&u
->thread_mq
);
1059 pa_sink_unref(u
->sink
);
1062 pa_source_unref(u
->source
);
1064 if (u
->memchunk
.memblock
)
1065 pa_memblock_unref(u
->memchunk
.memblock
);
1068 pa_rtpoll_item_free(u
->rtpoll_item
);
1071 pa_rtpoll_free(u
->rtpoll
);
1076 pa_xfree(u
->device_name
);