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
33 #include <sys/ioctl.h>
34 #include <sys/types.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
);
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> "
76 "buffer_length=<milliseconds> "
77 "channel_map=<channel map>");
78 PA_MODULE_LOAD_ONCE(false);
86 pa_thread_mq thread_mq
;
95 uint64_t written_bytes
, read_bytes
;
100 pa_rtpoll_item
*rtpoll_item
;
103 bool 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
[] = {
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
) {
139 uint64_t played_bytes
;
144 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
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
;
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 if (u
->written_bytes
> played_bytes
)
167 return u
->written_bytes
- played_bytes
;
172 static pa_usec_t
sink_get_latency(struct userdata
*u
, pa_sample_spec
*ss
) {
179 r
= pa_bytes_to_usec(get_playback_buffered_bytes(u
), ss
);
180 if (u
->memchunk
.memblock
)
181 r
+= pa_bytes_to_usec(u
->memchunk
.length
, ss
);
186 static uint64_t get_recorded_bytes(struct userdata
*u
) {
191 pa_assert(u
->source
);
193 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
196 if (u
->prev_record_samples
> info
.record
.samples
)
197 ++u
->record_samples_msw
;
198 u
->prev_record_samples
= info
.record
.samples
;
199 result
= (((uint64_t)u
->record_samples_msw
<< 32) + info
.record
.samples
) * u
->frame_size
;
204 static pa_usec_t
source_get_latency(struct userdata
*u
, pa_sample_spec
*ss
) {
212 int err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
215 r
= pa_bytes_to_usec(get_recorded_bytes(u
), ss
) - pa_bytes_to_usec(u
->read_bytes
, ss
);
220 static void build_pollfd(struct userdata
*u
) {
221 struct pollfd
*pollfd
;
224 pa_assert(!u
->rtpoll_item
);
225 u
->rtpoll_item
= pa_rtpoll_item_new(u
->rtpoll
, PA_RTPOLL_NEVER
, 1);
227 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
233 static int set_buffer(int fd
, int buffer_size
) {
238 AUDIO_INITINFO(&info
);
239 info
.play
.buffer_size
= buffer_size
;
240 info
.record
.buffer_size
= buffer_size
;
242 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0) {
244 pa_log("AUDIO_SETINFO: Unsupported buffer size.");
246 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
253 static int auto_format(int fd
, int mode
, pa_sample_spec
*ss
) {
259 AUDIO_INITINFO(&info
);
261 if (mode
!= O_RDONLY
) {
262 info
.play
.sample_rate
= ss
->rate
;
263 info
.play
.channels
= ss
->channels
;
264 switch (ss
->format
) {
266 info
.play
.precision
= 8;
267 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
270 info
.play
.precision
= 8;
271 info
.play
.encoding
= AUDIO_ENCODING_ALAW
;
274 info
.play
.precision
= 8;
275 info
.play
.encoding
= AUDIO_ENCODING_ULAW
;
277 case PA_SAMPLE_S16NE
:
278 info
.play
.precision
= 16;
279 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
282 pa_log("AUDIO_SETINFO: Unsupported sample format.");
287 if (mode
!= O_WRONLY
) {
288 info
.record
.sample_rate
= ss
->rate
;
289 info
.record
.channels
= ss
->channels
;
290 switch (ss
->format
) {
292 info
.record
.precision
= 8;
293 info
.record
.encoding
= AUDIO_ENCODING_LINEAR
;
296 info
.record
.precision
= 8;
297 info
.record
.encoding
= AUDIO_ENCODING_ALAW
;
300 info
.record
.precision
= 8;
301 info
.record
.encoding
= AUDIO_ENCODING_ULAW
;
303 case PA_SAMPLE_S16NE
:
304 info
.record
.precision
= 16;
305 info
.record
.encoding
= AUDIO_ENCODING_LINEAR
;
308 pa_log("AUDIO_SETINFO: Unsupported sample format.");
313 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0) {
315 pa_log("AUDIO_SETINFO: Failed to set sample format.");
317 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
324 static int open_audio_device(struct userdata
*u
, pa_sample_spec
*ss
) {
328 if ((u
->fd
= pa_open_cloexec(u
->device_name
, u
->mode
| O_NONBLOCK
, 0)) < 0) {
329 pa_log_warn("open %s failed (%s)", u
->device_name
, pa_cstrerror(errno
));
333 pa_log_info("device opened in %s mode.", u
->mode
== O_WRONLY
? "O_WRONLY" : (u
->mode
== O_RDONLY
? "O_RDONLY" : "O_RDWR"));
335 if (auto_format(u
->fd
, u
->mode
, ss
) < 0)
338 if (set_buffer(u
->fd
, u
->buffer_size
) < 0)
341 u
->written_bytes
= u
->read_bytes
= 0;
342 u
->play_samples_msw
= u
->record_samples_msw
= 0;
343 u
->prev_playback_samples
= u
->prev_record_samples
= 0;
348 static int suspend(struct userdata
*u
) {
350 pa_assert(u
->fd
>= 0);
352 pa_log_info("Suspending...");
354 ioctl(u
->fd
, I_FLUSH
, FLUSHRW
);
358 if (u
->rtpoll_item
) {
359 pa_rtpoll_item_free(u
->rtpoll_item
);
360 u
->rtpoll_item
= NULL
;
363 pa_log_info("Device suspended.");
368 static int unsuspend(struct userdata
*u
) {
370 pa_assert(u
->fd
< 0);
372 pa_log_info("Resuming...");
374 if (open_audio_device(u
, u
->sink
? &u
->sink
->sample_spec
: &u
->source
->sample_spec
) < 0)
379 pa_log_info("Device resumed.");
384 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
385 struct userdata
*u
= PA_SINK(o
)->userdata
;
389 case PA_SINK_MESSAGE_GET_LATENCY
:
390 *((pa_usec_t
*) data
) = sink_get_latency(u
, &PA_SINK(o
)->sample_spec
);
393 case PA_SINK_MESSAGE_SET_STATE
:
395 switch ((pa_sink_state_t
) PA_PTR_TO_UINT(data
)) {
397 case PA_SINK_SUSPENDED
:
399 pa_assert(PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
));
401 pa_smoother_pause(u
->smoother
, pa_rtclock_now());
403 if (!u
->source
|| u
->source_suspended
) {
407 u
->sink_suspended
= true;
411 case PA_SINK_RUNNING
:
413 if (u
->sink
->thread_info
.state
== PA_SINK_SUSPENDED
) {
414 pa_smoother_resume(u
->smoother
, pa_rtclock_now(), true);
416 if (!u
->source
|| u
->source_suspended
) {
417 if (unsuspend(u
) < 0)
419 u
->sink
->get_volume(u
->sink
);
420 u
->sink
->get_mute(u
->sink
);
422 u
->sink_suspended
= false;
426 case PA_SINK_INVALID_STATE
:
427 case PA_SINK_UNLINKED
:
435 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
438 static int source_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
439 struct userdata
*u
= PA_SOURCE(o
)->userdata
;
443 case PA_SOURCE_MESSAGE_GET_LATENCY
:
444 *((pa_usec_t
*) data
) = source_get_latency(u
, &PA_SOURCE(o
)->sample_spec
);
447 case PA_SOURCE_MESSAGE_SET_STATE
:
449 switch ((pa_source_state_t
) PA_PTR_TO_UINT(data
)) {
451 case PA_SOURCE_SUSPENDED
:
453 pa_assert(PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
));
455 if (!u
->sink
|| u
->sink_suspended
) {
459 u
->source_suspended
= true;
463 case PA_SOURCE_RUNNING
:
465 if (u
->source
->thread_info
.state
== PA_SOURCE_SUSPENDED
) {
466 if (!u
->sink
|| u
->sink_suspended
) {
467 if (unsuspend(u
) < 0)
469 u
->source
->get_volume(u
->source
);
471 u
->source_suspended
= false;
475 case PA_SOURCE_UNLINKED
:
477 case PA_SOURCE_INVALID_STATE
:
485 return pa_source_process_msg(o
, code
, data
, offset
, chunk
);
488 static void sink_set_volume(pa_sink
*s
) {
492 pa_assert_se(u
= s
->userdata
);
495 AUDIO_INITINFO(&info
);
497 info
.play
.gain
= pa_cvolume_max(&s
->real_volume
) * AUDIO_MAX_GAIN
/ PA_VOLUME_NORM
;
498 assert(info
.play
.gain
<= AUDIO_MAX_GAIN
);
500 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0) {
502 pa_log("AUDIO_SETINFO: Unsupported volume.");
504 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
509 static void sink_get_volume(pa_sink
*s
) {
513 pa_assert_se(u
= s
->userdata
);
516 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
517 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
519 pa_cvolume_set(&s
->real_volume
, s
->sample_spec
.channels
, info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
523 static void source_set_volume(pa_source
*s
) {
527 pa_assert_se(u
= s
->userdata
);
530 AUDIO_INITINFO(&info
);
532 info
.play
.gain
= pa_cvolume_max(&s
->real_volume
) * AUDIO_MAX_GAIN
/ PA_VOLUME_NORM
;
533 assert(info
.play
.gain
<= AUDIO_MAX_GAIN
);
535 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0) {
537 pa_log("AUDIO_SETINFO: Unsupported volume.");
539 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
544 static void source_get_volume(pa_source
*s
) {
548 pa_assert_se(u
= s
->userdata
);
551 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
552 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
554 pa_cvolume_set(&s
->real_volume
, s
->sample_spec
.channels
, info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
558 static void sink_set_mute(pa_sink
*s
) {
559 struct userdata
*u
= s
->userdata
;
565 AUDIO_INITINFO(&info
);
567 info
.output_muted
= s
->muted
;
569 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
570 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
574 static int sink_get_mute(pa_sink
*s
, bool *mute
) {
575 struct userdata
*u
= s
->userdata
;
583 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0) {
584 pa_log("AUDIO_GETINFO: %s", pa_cstrerror(errno
));
588 *mute
= info
.output_muted
;
593 static void process_rewind(struct userdata
*u
) {
594 size_t rewind_nbytes
;
598 if (!PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
)) {
599 pa_sink_process_rewind(u
->sink
, 0);
603 rewind_nbytes
= u
->sink
->thread_info
.rewind_nbytes
;
605 if (rewind_nbytes
> 0) {
606 pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes
);
607 rewind_nbytes
= PA_MIN(u
->memchunk
.length
, rewind_nbytes
);
608 u
->memchunk
.length
-= rewind_nbytes
;
609 if (u
->memchunk
.length
<= 0 && u
->memchunk
.memblock
) {
610 pa_memblock_unref(u
->memchunk
.memblock
);
611 pa_memchunk_reset(&u
->memchunk
);
613 pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes
);
616 pa_sink_process_rewind(u
->sink
, rewind_nbytes
);
619 static void thread_func(void *userdata
) {
620 struct userdata
*u
= userdata
;
621 unsigned short revents
= 0;
627 pa_log_debug("Thread starting up");
629 if (u
->core
->realtime_scheduling
)
630 pa_make_realtime(u
->core
->realtime_priority
);
632 pa_thread_mq_install(&u
->thread_mq
);
634 pa_smoother_set_time_offset(u
->smoother
, pa_rtclock_now());
637 /* Render some data and write it to the dsp */
639 if (PA_UNLIKELY(u
->sink
->thread_info
.rewind_requested
))
642 if (u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
)) {
643 pa_usec_t xtime0
, ysleep_interval
, xsleep_interval
;
644 uint64_t buffered_bytes
;
646 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
648 pa_log("AUDIO_GETINFO ioctl failed: %s", pa_cstrerror(errno
));
652 if (info
.play
.error
) {
653 pa_log_debug("buffer under-run!");
655 AUDIO_INITINFO(&info
);
657 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
658 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
660 pa_smoother_reset(u
->smoother
, pa_rtclock_now(), true);
670 * Since we cannot modify the size of the output buffer we fake it
671 * by not filling it more than u->buffer_size.
673 xtime0
= pa_rtclock_now();
674 buffered_bytes
= get_playback_buffered_bytes(u
);
675 if (buffered_bytes
>= (uint64_t)u
->buffer_size
)
678 len
= u
->buffer_size
- buffered_bytes
;
679 len
-= len
% u
->frame_size
;
681 if (len
< (size_t) u
->minimum_request
)
684 if (!u
->memchunk
.length
)
685 pa_sink_render(u
->sink
, u
->sink
->thread_info
.max_request
, &u
->memchunk
);
687 len
= PA_MIN(u
->memchunk
.length
, len
);
689 p
= pa_memblock_acquire(u
->memchunk
.memblock
);
690 w
= pa_write(u
->fd
, (uint8_t*) p
+ u
->memchunk
.index
, len
, &write_type
);
691 pa_memblock_release(u
->memchunk
.memblock
);
694 if (errno
== EINTR
) {
696 } else if (errno
== EAGAIN
) {
697 /* We may have realtime priority so yield the CPU to ensure that fd can become writable again. */
698 pa_log_debug("EAGAIN with %llu bytes buffered.", buffered_bytes
);
701 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno
));
705 pa_assert(w
% u
->frame_size
== 0);
707 u
->written_bytes
+= w
;
708 u
->memchunk
.index
+= w
;
709 u
->memchunk
.length
-= w
;
710 if (u
->memchunk
.length
<= 0) {
711 pa_memblock_unref(u
->memchunk
.memblock
);
712 pa_memchunk_reset(&u
->memchunk
);
717 ysleep_interval
= pa_bytes_to_usec(buffered_bytes
/ 2, &u
->sink
->sample_spec
);
718 xsleep_interval
= pa_smoother_translate(u
->smoother
, xtime0
, ysleep_interval
);
719 pa_rtpoll_set_timer_absolute(u
->rtpoll
, xtime0
+ PA_MIN(xsleep_interval
, ysleep_interval
));
721 pa_rtpoll_set_timer_disabled(u
->rtpoll
);
723 /* Try to read some data and pass it on to the source driver */
725 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
) && (revents
& POLLIN
)) {
726 pa_memchunk memchunk
;
731 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
734 if (info
.record
.error
) {
735 pa_log_debug("buffer overflow!");
737 AUDIO_INITINFO(&info
);
738 info
.record
.error
= 0;
739 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
740 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
743 err
= ioctl(u
->fd
, I_NREAD
, &len
);
747 memchunk
.memblock
= pa_memblock_new(u
->core
->mempool
, len
);
748 pa_assert(memchunk
.memblock
);
750 p
= pa_memblock_acquire(memchunk
.memblock
);
751 r
= pa_read(u
->fd
, p
, len
, NULL
);
752 pa_memblock_release(memchunk
.memblock
);
755 pa_memblock_unref(memchunk
.memblock
);
759 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno
));
768 pa_source_post(u
->source
, &memchunk
);
769 pa_memblock_unref(memchunk
.memblock
);
776 if (u
->rtpoll_item
) {
777 struct pollfd
*pollfd
;
779 pa_assert(u
->fd
>= 0);
781 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
782 pollfd
->events
= (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
)) ? POLLIN
: 0;
785 /* Hmm, nothing to do. Let's sleep */
786 if ((ret
= pa_rtpoll_run(u
->rtpoll
, true)) < 0)
792 if (u
->rtpoll_item
) {
793 struct pollfd
*pollfd
;
795 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
797 if (pollfd
->revents
& ~(POLLOUT
|POLLIN
)) {
798 pa_log("DSP shutdown.");
802 revents
= pollfd
->revents
;
808 /* We have to continue processing messages until we receive the
809 * SHUTDOWN message */
810 pa_asyncmsgq_post(u
->thread_mq
.outq
, PA_MSGOBJECT(u
->core
), PA_CORE_MESSAGE_UNLOAD_MODULE
, u
->module
, 0, NULL
, NULL
);
811 pa_asyncmsgq_wait_for(u
->thread_mq
.inq
, PA_MESSAGE_SHUTDOWN
);
814 pa_log_debug("Thread shutting down");
817 static void sig_callback(pa_mainloop_api
*api
, pa_signal_event
*e
, int sig
, void *userdata
) {
818 struct userdata
*u
= userdata
;
822 pa_log_debug("caught signal");
825 pa_sink_get_volume(u
->sink
, true);
826 pa_sink_get_mute(u
->sink
, true);
830 pa_source_get_volume(u
->source
, true);
833 int pa__init(pa_module
*m
) {
834 struct userdata
*u
= NULL
;
835 bool record
= true, playback
= true;
838 pa_modargs
*ma
= NULL
;
839 uint32_t buffer_length_msec
;
841 pa_sink_new_data sink_new_data
;
842 pa_source_new_data source_new_data
;
849 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
850 pa_log("failed to parse module arguments.");
854 if (pa_modargs_get_value_boolean(ma
, "record", &record
) < 0 || pa_modargs_get_value_boolean(ma
, "playback", &playback
) < 0) {
855 pa_log("record= and playback= expect a boolean argument.");
859 if (!playback
&& !record
) {
860 pa_log("neither playback nor record enabled for device.");
864 u
= pa_xnew0(struct userdata
, 1);
866 if (!(u
->smoother
= pa_smoother_new(PA_USEC_PER_SEC
, PA_USEC_PER_SEC
* 2, true, true, 10, pa_rtclock_now(), true)))
870 * For a process (or several processes) to use the same audio device for both
871 * record and playback at the same time, the device's mixer must be enabled.
872 * See mixerctl(1). It may be turned off for playback only or record only.
874 u
->mode
= (playback
&& record
) ? O_RDWR
: (playback
? O_WRONLY
: (record
? O_RDONLY
: 0));
876 ss
= m
->core
->default_sample_spec
;
877 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
878 pa_log("failed to parse sample specification");
881 u
->frame_size
= pa_frame_size(&ss
);
883 u
->minimum_request
= pa_usec_to_bytes(PA_USEC_PER_SEC
/ MAX_RENDER_HZ
, &ss
);
885 buffer_length_msec
= 100;
886 if (pa_modargs_get_value_u32(ma
, "buffer_length", &buffer_length_msec
) < 0) {
887 pa_log("failed to parse buffer_length argument");
890 u
->buffer_size
= pa_usec_to_bytes(1000 * buffer_length_msec
, &ss
);
891 if (u
->buffer_size
< 2 * u
->minimum_request
) {
892 pa_log("buffer_length argument cannot be smaller than %u",
893 (unsigned)(pa_bytes_to_usec(2 * u
->minimum_request
, &ss
) / 1000));
896 if (u
->buffer_size
> MAX_BUFFER_SIZE
) {
897 pa_log("buffer_length argument cannot be greater than %u",
898 (unsigned)(pa_bytes_to_usec(MAX_BUFFER_SIZE
, &ss
) / 1000));
902 u
->device_name
= pa_xstrdup(pa_modargs_get_value(ma
, "device", DEFAULT_DEVICE
));
904 if ((fd
= open_audio_device(u
, &ss
)) < 0)
911 pa_memchunk_reset(&u
->memchunk
);
913 u
->rtpoll
= pa_rtpoll_new();
914 pa_thread_mq_init(&u
->thread_mq
, m
->core
->mainloop
, u
->rtpoll
);
916 u
->rtpoll_item
= NULL
;
919 if (u
->mode
!= O_WRONLY
) {
923 if (!(name
= pa_modargs_get_value(ma
, "source_name", NULL
))) {
924 name
= name_buf
= pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u
->device_name
));
925 namereg_fail
= false;
928 pa_source_new_data_init(&source_new_data
);
929 source_new_data
.driver
= __FILE__
;
930 source_new_data
.module
= m
;
931 pa_source_new_data_set_name(&source_new_data
, name
);
932 source_new_data
.namereg_fail
= namereg_fail
;
933 pa_source_new_data_set_sample_spec(&source_new_data
, &ss
);
934 pa_source_new_data_set_channel_map(&source_new_data
, &map
);
935 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
936 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
937 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM source");
938 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
939 pa_proplist_setf(source_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE
, "%lu", (unsigned long) u
->buffer_size
);
941 if (pa_modargs_get_proplist(ma
, "source_properties", source_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
942 pa_log("Invalid properties");
943 pa_source_new_data_done(&source_new_data
);
947 u
->source
= pa_source_new(m
->core
, &source_new_data
, PA_SOURCE_HARDWARE
|PA_SOURCE_LATENCY
);
948 pa_source_new_data_done(&source_new_data
);
952 pa_log("Failed to create source object");
956 u
->source
->userdata
= u
;
957 u
->source
->parent
.process_msg
= source_process_msg
;
959 pa_source_set_asyncmsgq(u
->source
, u
->thread_mq
.inq
);
960 pa_source_set_rtpoll(u
->source
, u
->rtpoll
);
961 pa_source_set_fixed_latency(u
->source
, pa_bytes_to_usec(u
->buffer_size
, &u
->source
->sample_spec
));
963 pa_source_set_get_volume_callback(u
->source
, source_get_volume
);
964 pa_source_set_set_volume_callback(u
->source
, source_set_volume
);
965 u
->source
->refresh_volume
= true;
969 if (u
->mode
!= O_RDONLY
) {
972 if (!(name
= pa_modargs_get_value(ma
, "sink_name", NULL
))) {
973 name
= name_buf
= pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u
->device_name
));
974 namereg_fail
= false;
977 pa_sink_new_data_init(&sink_new_data
);
978 sink_new_data
.driver
= __FILE__
;
979 sink_new_data
.module
= m
;
980 pa_sink_new_data_set_name(&sink_new_data
, name
);
981 sink_new_data
.namereg_fail
= namereg_fail
;
982 pa_sink_new_data_set_sample_spec(&sink_new_data
, &ss
);
983 pa_sink_new_data_set_channel_map(&sink_new_data
, &map
);
984 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
985 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
986 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM sink");
987 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
989 if (pa_modargs_get_proplist(ma
, "sink_properties", sink_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
990 pa_log("Invalid properties");
991 pa_sink_new_data_done(&sink_new_data
);
995 u
->sink
= pa_sink_new(m
->core
, &sink_new_data
, PA_SINK_HARDWARE
|PA_SINK_LATENCY
);
996 pa_sink_new_data_done(&sink_new_data
);
999 u
->sink
->userdata
= u
;
1000 u
->sink
->parent
.process_msg
= sink_process_msg
;
1002 pa_sink_set_asyncmsgq(u
->sink
, u
->thread_mq
.inq
);
1003 pa_sink_set_rtpoll(u
->sink
, u
->rtpoll
);
1004 pa_sink_set_fixed_latency(u
->sink
, pa_bytes_to_usec(u
->buffer_size
, &u
->sink
->sample_spec
));
1005 pa_sink_set_max_request(u
->sink
, u
->buffer_size
);
1006 pa_sink_set_max_rewind(u
->sink
, u
->buffer_size
);
1008 pa_sink_set_get_volume_callback(u
->sink
, sink_get_volume
);
1009 pa_sink_set_set_volume_callback(u
->sink
, sink_set_volume
);
1010 pa_sink_set_get_mute_callback(u
->sink
, sink_get_mute
);
1011 pa_sink_set_set_mute_callback(u
->sink
, sink_set_mute
);
1012 u
->sink
->refresh_volume
= u
->sink
->refresh_muted
= true;
1016 pa_assert(u
->source
|| u
->sink
);
1018 u
->sig
= pa_signal_new(SIGPOLL
, sig_callback
, u
);
1020 ioctl(u
->fd
, I_SETSIG
, S_MSG
);
1022 pa_log_warn("Could not register SIGPOLL handler");
1024 if (!(u
->thread
= pa_thread_new("solaris", thread_func
, u
))) {
1025 pa_log("Failed to create thread.");
1029 /* Read mixer settings */
1031 if (sink_new_data
.volume_is_set
)
1032 u
->sink
->set_volume(u
->sink
);
1034 u
->sink
->get_volume(u
->sink
);
1036 if (sink_new_data
.muted_is_set
)
1037 u
->sink
->set_mute(u
->sink
);
1039 u
->sink
->get_mute(u
->sink
);
1041 pa_sink_put(u
->sink
);
1045 if (source_new_data
.volume_is_set
)
1046 u
->source
->set_volume(u
->source
);
1048 u
->source
->get_volume(u
->source
);
1050 pa_source_put(u
->source
);
1053 pa_modargs_free(ma
);
1064 pa_modargs_free(ma
);
1069 void pa__done(pa_module
*m
) {
1074 if (!(u
= m
->userdata
))
1078 ioctl(u
->fd
, I_SETSIG
, 0);
1079 pa_signal_free(u
->sig
);
1083 pa_sink_unlink(u
->sink
);
1086 pa_source_unlink(u
->source
);
1089 pa_asyncmsgq_send(u
->thread_mq
.inq
, NULL
, PA_MESSAGE_SHUTDOWN
, NULL
, 0, NULL
);
1090 pa_thread_free(u
->thread
);
1093 pa_thread_mq_done(&u
->thread_mq
);
1096 pa_sink_unref(u
->sink
);
1099 pa_source_unref(u
->source
);
1101 if (u
->memchunk
.memblock
)
1102 pa_memblock_unref(u
->memchunk
.memblock
);
1105 pa_rtpoll_item_free(u
->rtpoll_item
);
1108 pa_rtpoll_free(u
->rtpoll
);
1114 pa_smoother_free(u
->smoother
);
1116 pa_xfree(u
->device_name
);