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
->virtual_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
->virtual_volume
, s
->sample_spec
.channels
,
505 info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
509 static void source_set_volume(pa_source
*s
) {
513 pa_assert_se(u
= s
->userdata
);
516 AUDIO_INITINFO(&info
);
518 info
.play
.gain
= pa_cvolume_max(&s
->virtual_volume
) * AUDIO_MAX_GAIN
/ PA_VOLUME_NORM
;
519 assert(info
.play
.gain
<= AUDIO_MAX_GAIN
);
521 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0) {
523 pa_log("AUDIO_SETINFO: Unsupported volume.");
525 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
530 static void source_get_volume(pa_source
*s
) {
534 pa_assert_se(u
= s
->userdata
);
537 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
538 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
540 pa_cvolume_set(&s
->virtual_volume
, s
->sample_spec
.channels
,
541 info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
545 static void sink_set_mute(pa_sink
*s
) {
546 struct userdata
*u
= s
->userdata
;
552 AUDIO_INITINFO(&info
);
554 info
.output_muted
= !!s
->muted
;
556 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
557 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
561 static void sink_get_mute(pa_sink
*s
) {
562 struct userdata
*u
= s
->userdata
;
568 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
569 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
571 s
->muted
= !!info
.output_muted
;
575 static void process_rewind(struct userdata
*u
) {
576 size_t rewind_nbytes
;
580 /* Figure out how much we shall rewind and reset the counter */
581 rewind_nbytes
= u
->sink
->thread_info
.rewind_nbytes
;
582 u
->sink
->thread_info
.rewind_nbytes
= 0;
584 if (rewind_nbytes
> 0) {
585 pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes
);
586 rewind_nbytes
= PA_MIN(u
->memchunk
.length
, rewind_nbytes
);
587 u
->memchunk
.length
-= rewind_nbytes
;
588 pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes
);
591 pa_sink_process_rewind(u
->sink
, rewind_nbytes
);
594 static void thread_func(void *userdata
) {
595 struct userdata
*u
= userdata
;
596 unsigned short revents
= 0;
602 pa_log_debug("Thread starting up");
604 if (u
->core
->realtime_scheduling
)
605 pa_make_realtime(u
->core
->realtime_priority
);
607 pa_thread_mq_install(&u
->thread_mq
);
610 /* Render some data and write it to the dsp */
612 if (u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
)) {
614 uint64_t buffered_bytes
;
616 if (u
->sink
->thread_info
.rewind_requested
)
619 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
621 pa_log("AUDIO_GETINFO ioctl failed: %s", pa_cstrerror(errno
));
625 if (info
.play
.error
) {
626 pa_log_debug("buffer under-run!");
628 AUDIO_INITINFO(&info
);
630 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
631 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
640 * Since we cannot modify the size of the output buffer we fake it
641 * by not filling it more than u->buffer_size.
643 xtime0
= pa_rtclock_now();
644 buffered_bytes
= get_playback_buffered_bytes(u
);
645 if (buffered_bytes
>= (uint64_t)u
->buffer_size
)
648 len
= u
->buffer_size
- buffered_bytes
;
649 len
-= len
% u
->frame_size
;
651 if (len
< (size_t) u
->minimum_request
)
654 if (u
->memchunk
.length
< len
)
655 pa_sink_render(u
->sink
, u
->sink
->thread_info
.max_request
, &u
->memchunk
);
657 p
= pa_memblock_acquire(u
->memchunk
.memblock
);
658 w
= pa_write(u
->fd
, (uint8_t*) p
+ u
->memchunk
.index
, u
->memchunk
.length
, NULL
);
659 pa_memblock_release(u
->memchunk
.memblock
);
666 /* If the buffer_size is too big, we get EAGAIN. Avoiding that limit by trial and error
667 * is not ideal, but I don't know how to get the system to tell me what the limit is.
669 u
->buffer_size
= u
->buffer_size
* 18 / 25;
670 u
->buffer_size
-= u
->buffer_size
% u
->frame_size
;
671 u
->buffer_size
= PA_MAX(u
->buffer_size
, 2 * u
->minimum_request
);
672 pa_sink_set_max_request_within_thread(u
->sink
, u
->buffer_size
);
673 pa_sink_set_max_rewind_within_thread(u
->sink
, u
->buffer_size
);
674 pa_log("EAGAIN. Buffer size is now %u bytes (%llu buffered)", u
->buffer_size
, buffered_bytes
);
677 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno
));
681 pa_assert(w
% u
->frame_size
== 0);
683 u
->written_bytes
+= w
;
684 u
->memchunk
.length
-= w
;
686 u
->memchunk
.index
+= w
;
687 if (u
->memchunk
.length
<= 0) {
688 pa_memblock_unref(u
->memchunk
.memblock
);
689 pa_memchunk_reset(&u
->memchunk
);
694 pa_rtpoll_set_timer_absolute(u
->rtpoll
, xtime0
+ pa_bytes_to_usec(buffered_bytes
/ 2, &u
->sink
->sample_spec
));
696 pa_rtpoll_set_timer_disabled(u
->rtpoll
);
698 /* Try to read some data and pass it on to the source driver */
700 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
) && (revents
& POLLIN
)) {
701 pa_memchunk memchunk
;
706 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
709 if (info
.record
.error
) {
710 pa_log_debug("buffer overflow!");
712 AUDIO_INITINFO(&info
);
713 info
.record
.error
= 0;
714 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
715 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
718 err
= ioctl(u
->fd
, I_NREAD
, &len
);
722 memchunk
.memblock
= pa_memblock_new(u
->core
->mempool
, len
);
723 pa_assert(memchunk
.memblock
);
725 p
= pa_memblock_acquire(memchunk
.memblock
);
726 r
= pa_read(u
->fd
, p
, len
, NULL
);
727 pa_memblock_release(memchunk
.memblock
);
730 pa_memblock_unref(memchunk
.memblock
);
734 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno
));
743 pa_source_post(u
->source
, &memchunk
);
744 pa_memblock_unref(memchunk
.memblock
);
751 if (u
->rtpoll_item
) {
752 struct pollfd
*pollfd
;
754 pa_assert(u
->fd
>= 0);
756 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
757 pollfd
->events
= (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
)) ? POLLIN
: 0;
760 /* Hmm, nothing to do. Let's sleep */
761 if ((ret
= pa_rtpoll_run(u
->rtpoll
, TRUE
)) < 0)
767 if (u
->rtpoll_item
) {
768 struct pollfd
*pollfd
;
770 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
772 if (pollfd
->revents
& ~(POLLOUT
|POLLIN
)) {
773 pa_log("DSP shutdown.");
777 revents
= pollfd
->revents
;
783 /* We have to continue processing messages until we receive the
784 * SHUTDOWN message */
785 pa_asyncmsgq_post(u
->thread_mq
.outq
, PA_MSGOBJECT(u
->core
), PA_CORE_MESSAGE_UNLOAD_MODULE
, u
->module
, 0, NULL
, NULL
);
786 pa_asyncmsgq_wait_for(u
->thread_mq
.inq
, PA_MESSAGE_SHUTDOWN
);
789 pa_log_debug("Thread shutting down");
792 static void sig_callback(pa_mainloop_api
*api
, pa_signal_event
*e
, int sig
, void *userdata
) {
793 struct userdata
*u
= userdata
;
797 pa_log_debug("caught signal");
800 pa_sink_get_volume(u
->sink
, TRUE
, FALSE
);
801 pa_sink_get_mute(u
->sink
, TRUE
);
805 pa_source_get_volume(u
->source
, TRUE
);
808 int pa__init(pa_module
*m
) {
809 struct userdata
*u
= NULL
;
810 pa_bool_t record
= TRUE
, playback
= TRUE
;
813 pa_modargs
*ma
= NULL
;
814 uint32_t buffer_length_msec
;
816 pa_sink_new_data sink_new_data
;
817 pa_source_new_data source_new_data
;
820 pa_bool_t namereg_fail
;
824 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
825 pa_log("failed to parse module arguments.");
829 if (pa_modargs_get_value_boolean(ma
, "record", &record
) < 0 || pa_modargs_get_value_boolean(ma
, "playback", &playback
) < 0) {
830 pa_log("record= and playback= expect a boolean argument.");
834 if (!playback
&& !record
) {
835 pa_log("neither playback nor record enabled for device.");
839 u
= pa_xnew0(struct userdata
, 1);
842 * For a process (or several processes) to use the same audio device for both
843 * record and playback at the same time, the device's mixer must be enabled.
844 * See mixerctl(1). It may be turned off for playback only or record only.
846 u
->mode
= (playback
&& record
) ? O_RDWR
: (playback
? O_WRONLY
: (record
? O_RDONLY
: 0));
848 ss
= m
->core
->default_sample_spec
;
849 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
850 pa_log("failed to parse sample specification");
853 u
->frame_size
= pa_frame_size(&ss
);
855 u
->minimum_request
= pa_usec_to_bytes(PA_USEC_PER_SEC
/ MAX_RENDER_HZ
, &ss
);
857 buffer_length_msec
= 100;
858 if (pa_modargs_get_value_u32(ma
, "buffer_length", &buffer_length_msec
) < 0) {
859 pa_log("failed to parse buffer_length argument");
862 u
->buffer_size
= pa_usec_to_bytes(1000 * buffer_length_msec
, &ss
);
863 if (u
->buffer_size
< 2 * u
->minimum_request
) {
864 pa_log("supplied buffer size argument is too small");
868 u
->device_name
= pa_xstrdup(pa_modargs_get_value(ma
, "device", DEFAULT_DEVICE
));
870 if ((fd
= open_audio_device(u
, &ss
)) < 0)
877 pa_memchunk_reset(&u
->memchunk
);
879 u
->rtpoll
= pa_rtpoll_new();
880 pa_thread_mq_init(&u
->thread_mq
, m
->core
->mainloop
, u
->rtpoll
);
882 u
->rtpoll_item
= NULL
;
885 if (u
->mode
!= O_WRONLY
) {
889 if (!(name
= pa_modargs_get_value(ma
, "source_name", NULL
))) {
890 name
= name_buf
= pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u
->device_name
));
891 namereg_fail
= FALSE
;
894 pa_source_new_data_init(&source_new_data
);
895 source_new_data
.driver
= __FILE__
;
896 source_new_data
.module
= m
;
897 pa_source_new_data_set_name(&source_new_data
, name
);
898 source_new_data
.namereg_fail
= namereg_fail
;
899 pa_source_new_data_set_sample_spec(&source_new_data
, &ss
);
900 pa_source_new_data_set_channel_map(&source_new_data
, &map
);
901 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
902 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
903 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM source");
904 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
905 pa_proplist_setf(source_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE
, "%lu", (unsigned long) u
->buffer_size
);
907 if (pa_modargs_get_proplist(ma
, "source_properties", source_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
908 pa_log("Invalid properties");
909 pa_source_new_data_done(&source_new_data
);
913 u
->source
= pa_source_new(m
->core
, &source_new_data
, PA_SOURCE_HARDWARE
|PA_SOURCE_LATENCY
|PA_SOURCE_HW_VOLUME_CTRL
);
914 pa_source_new_data_done(&source_new_data
);
918 pa_log("Failed to create source object");
922 u
->source
->userdata
= u
;
923 u
->source
->parent
.process_msg
= source_process_msg
;
925 pa_source_set_asyncmsgq(u
->source
, u
->thread_mq
.inq
);
926 pa_source_set_rtpoll(u
->source
, u
->rtpoll
);
928 u
->source
->get_volume
= source_get_volume
;
929 u
->source
->set_volume
= source_set_volume
;
930 u
->source
->refresh_volume
= TRUE
;
934 if (u
->mode
!= O_RDONLY
) {
937 if (!(name
= pa_modargs_get_value(ma
, "sink_name", NULL
))) {
938 name
= name_buf
= pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u
->device_name
));
939 namereg_fail
= FALSE
;
942 pa_sink_new_data_init(&sink_new_data
);
943 sink_new_data
.driver
= __FILE__
;
944 sink_new_data
.module
= m
;
945 pa_sink_new_data_set_name(&sink_new_data
, name
);
946 sink_new_data
.namereg_fail
= namereg_fail
;
947 pa_sink_new_data_set_sample_spec(&sink_new_data
, &ss
);
948 pa_sink_new_data_set_channel_map(&sink_new_data
, &map
);
949 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
950 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
951 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM sink");
952 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
954 if (pa_modargs_get_proplist(ma
, "sink_properties", sink_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
955 pa_log("Invalid properties");
956 pa_sink_new_data_done(&sink_new_data
);
960 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
);
961 pa_sink_new_data_done(&sink_new_data
);
964 u
->sink
->userdata
= u
;
965 u
->sink
->parent
.process_msg
= sink_process_msg
;
967 pa_sink_set_asyncmsgq(u
->sink
, u
->thread_mq
.inq
);
968 pa_sink_set_rtpoll(u
->sink
, u
->rtpoll
);
970 u
->sink
->get_volume
= sink_get_volume
;
971 u
->sink
->set_volume
= sink_set_volume
;
972 u
->sink
->get_mute
= sink_get_mute
;
973 u
->sink
->set_mute
= sink_set_mute
;
974 u
->sink
->refresh_volume
= u
->sink
->refresh_muted
= TRUE
;
976 pa_sink_set_max_request(u
->sink
, u
->buffer_size
);
977 pa_sink_set_max_rewind(u
->sink
, u
->buffer_size
);
981 pa_assert(u
->source
|| u
->sink
);
983 u
->sig
= pa_signal_new(SIGPOLL
, sig_callback
, u
);
985 ioctl(u
->fd
, I_SETSIG
, S_MSG
);
987 pa_log_warn("Could not register SIGPOLL handler");
989 if (!(u
->thread
= pa_thread_new(thread_func
, u
))) {
990 pa_log("Failed to create thread.");
994 /* Read mixer settings */
996 if (sink_new_data
.volume_is_set
)
997 u
->sink
->set_volume(u
->sink
);
999 u
->sink
->get_volume(u
->sink
);
1001 if (sink_new_data
.muted_is_set
)
1002 u
->sink
->set_mute(u
->sink
);
1004 u
->sink
->get_mute(u
->sink
);
1006 pa_sink_put(u
->sink
);
1010 if (source_new_data
.volume_is_set
)
1011 u
->source
->set_volume(u
->source
);
1013 u
->source
->get_volume(u
->source
);
1015 pa_source_put(u
->source
);
1018 pa_modargs_free(ma
);
1029 pa_modargs_free(ma
);
1034 void pa__done(pa_module
*m
) {
1039 if (!(u
= m
->userdata
))
1043 ioctl(u
->fd
, I_SETSIG
, 0);
1044 pa_signal_free(u
->sig
);
1048 pa_sink_unlink(u
->sink
);
1051 pa_source_unlink(u
->source
);
1054 pa_asyncmsgq_send(u
->thread_mq
.inq
, NULL
, PA_MESSAGE_SHUTDOWN
, NULL
, 0, NULL
);
1055 pa_thread_free(u
->thread
);
1058 pa_thread_mq_done(&u
->thread_mq
);
1061 pa_sink_unref(u
->sink
);
1064 pa_source_unref(u
->source
);
1066 if (u
->memchunk
.memblock
)
1067 pa_memblock_unref(u
->memchunk
.memblock
);
1070 pa_rtpoll_item_free(u
->rtpoll_item
);
1073 pa_rtpoll_free(u
->rtpoll
);
1078 pa_xfree(u
->device_name
);