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>
63 #include <pulsecore/time-smoother.h>
65 #include "module-solaris-symdef.h"
67 PA_MODULE_AUTHOR("Pierre Ossman");
68 PA_MODULE_DESCRIPTION("Solaris Sink/Source");
69 PA_MODULE_VERSION(PACKAGE_VERSION
);
71 "sink_name=<name for the sink> "
72 "sink_properties=<properties for the sink> "
73 "source_name=<name for the source> "
74 "source_properties=<properties for the source> "
75 "device=<audio device file name> "
76 "record=<enable source?> "
77 "playback=<enable sink?> "
78 "format=<sample format> "
79 "channels=<number of channels> "
81 "buffer_length=<milliseconds> "
82 "channel_map=<channel map>");
83 PA_MODULE_LOAD_ONCE(FALSE
);
91 pa_thread_mq thread_mq
;
100 uint64_t written_bytes
, read_bytes
;
105 pa_rtpoll_item
*rtpoll_item
;
108 pa_bool_t sink_suspended
, source_suspended
;
110 uint32_t play_samples_msw
, record_samples_msw
;
111 uint32_t prev_playback_samples
, prev_record_samples
;
113 int32_t minimum_request
;
115 pa_smoother
*smoother
;
118 static const char* const valid_modargs
[] = {
134 #define DEFAULT_DEVICE "/dev/audio"
136 #define MAX_RENDER_HZ (300)
137 /* This render rate limit imposes a minimum latency, but without it we waste too much CPU time. */
139 static uint64_t get_playback_buffered_bytes(struct userdata
*u
) {
141 uint64_t played_bytes
;
146 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
149 /* Handle wrap-around of the device's sample counter, which is a uint_32. */
150 if (u
->prev_playback_samples
> info
.play
.samples
) {
152 * Unfortunately info.play.samples can sometimes go backwards, even before it wraps!
153 * The bug seems to be absent on Solaris x86 nv117 with audio810 driver, at least on this (UP) machine.
154 * The bug is present on a different (SMP) machine running Solaris x86 nv103 with audioens driver.
155 * An earlier revision of this file mentions the same bug independently (unknown configuration).
157 if (u
->prev_playback_samples
+ info
.play
.samples
< 240000) {
158 ++u
->play_samples_msw
;
160 pa_log_debug("play.samples went backwards %d bytes", u
->prev_playback_samples
- info
.play
.samples
);
163 u
->prev_playback_samples
= info
.play
.samples
;
164 played_bytes
= (((uint64_t)u
->play_samples_msw
<< 32) + info
.play
.samples
) * u
->frame_size
;
166 pa_smoother_put(u
->smoother
, pa_rtclock_now(), pa_bytes_to_usec(played_bytes
, &u
->sink
->sample_spec
));
168 return u
->written_bytes
- played_bytes
;
171 static pa_usec_t
sink_get_latency(struct userdata
*u
, pa_sample_spec
*ss
) {
178 r
= pa_bytes_to_usec(get_playback_buffered_bytes(u
), ss
);
179 if (u
->memchunk
.memblock
)
180 r
+= pa_bytes_to_usec(u
->memchunk
.length
, ss
);
185 static uint64_t get_recorded_bytes(struct userdata
*u
) {
190 pa_assert(u
->source
);
192 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
195 if (u
->prev_record_samples
> info
.record
.samples
)
196 ++u
->record_samples_msw
;
197 u
->prev_record_samples
= info
.record
.samples
;
198 result
= (((uint64_t)u
->record_samples_msw
<< 32) + info
.record
.samples
) * u
->frame_size
;
203 static pa_usec_t
source_get_latency(struct userdata
*u
, pa_sample_spec
*ss
) {
211 int err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
214 r
= pa_bytes_to_usec(get_recorded_bytes(u
), ss
) - pa_bytes_to_usec(u
->read_bytes
, ss
);
219 static void build_pollfd(struct userdata
*u
) {
220 struct pollfd
*pollfd
;
223 pa_assert(!u
->rtpoll_item
);
224 u
->rtpoll_item
= pa_rtpoll_item_new(u
->rtpoll
, PA_RTPOLL_NEVER
, 1);
226 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
232 static int set_buffer(int fd
, int buffer_size
) {
237 AUDIO_INITINFO(&info
);
238 info
.play
.buffer_size
= buffer_size
;
239 info
.record
.buffer_size
= buffer_size
;
241 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0) {
243 pa_log("AUDIO_SETINFO: Unsupported buffer size.");
245 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
252 static int auto_format(int fd
, int mode
, pa_sample_spec
*ss
) {
258 AUDIO_INITINFO(&info
);
260 if (mode
!= O_RDONLY
) {
261 info
.play
.sample_rate
= ss
->rate
;
262 info
.play
.channels
= ss
->channels
;
263 switch (ss
->format
) {
265 info
.play
.precision
= 8;
266 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
269 info
.play
.precision
= 8;
270 info
.play
.encoding
= AUDIO_ENCODING_ALAW
;
273 info
.play
.precision
= 8;
274 info
.play
.encoding
= AUDIO_ENCODING_ULAW
;
276 case PA_SAMPLE_S16NE
:
277 info
.play
.precision
= 16;
278 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
281 pa_log("AUDIO_SETINFO: Unsupported sample format.");
286 if (mode
!= O_WRONLY
) {
287 info
.record
.sample_rate
= ss
->rate
;
288 info
.record
.channels
= ss
->channels
;
289 switch (ss
->format
) {
291 info
.record
.precision
= 8;
292 info
.record
.encoding
= AUDIO_ENCODING_LINEAR
;
295 info
.record
.precision
= 8;
296 info
.record
.encoding
= AUDIO_ENCODING_ALAW
;
299 info
.record
.precision
= 8;
300 info
.record
.encoding
= AUDIO_ENCODING_ULAW
;
302 case PA_SAMPLE_S16NE
:
303 info
.record
.precision
= 16;
304 info
.record
.encoding
= AUDIO_ENCODING_LINEAR
;
307 pa_log("AUDIO_SETINFO: Unsupported sample format.");
312 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0) {
314 pa_log("AUDIO_SETINFO: Failed to set sample format.");
316 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
323 static int open_audio_device(struct userdata
*u
, pa_sample_spec
*ss
) {
327 if ((u
->fd
= open(u
->device_name
, u
->mode
| O_NONBLOCK
)) < 0) {
328 pa_log_warn("open %s failed (%s)", u
->device_name
, pa_cstrerror(errno
));
332 pa_log_info("device opened in %s mode.", u
->mode
== O_WRONLY
? "O_WRONLY" : (u
->mode
== O_RDONLY
? "O_RDONLY" : "O_RDWR"));
334 if (auto_format(u
->fd
, u
->mode
, ss
) < 0)
337 if (set_buffer(u
->fd
, u
->buffer_size
) < 0)
340 u
->written_bytes
= u
->read_bytes
= 0;
341 u
->play_samples_msw
= u
->record_samples_msw
= 0;
342 u
->prev_playback_samples
= u
->prev_record_samples
= 0;
347 static int suspend(struct userdata
*u
) {
349 pa_assert(u
->fd
>= 0);
351 pa_log_info("Suspending...");
353 ioctl(u
->fd
, AUDIO_DRAIN
, NULL
);
357 if (u
->rtpoll_item
) {
358 pa_rtpoll_item_free(u
->rtpoll_item
);
359 u
->rtpoll_item
= NULL
;
362 pa_log_info("Device suspended.");
367 static int unsuspend(struct userdata
*u
) {
369 pa_assert(u
->fd
< 0);
371 pa_log_info("Resuming...");
373 if (open_audio_device(u
, u
->sink
? &u
->sink
->sample_spec
: &u
->source
->sample_spec
) < 0)
378 pa_log_info("Device resumed.");
383 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
384 struct userdata
*u
= PA_SINK(o
)->userdata
;
388 case PA_SINK_MESSAGE_GET_LATENCY
:
389 *((pa_usec_t
*) data
) = sink_get_latency(u
, &PA_SINK(o
)->sample_spec
);
392 case PA_SINK_MESSAGE_SET_STATE
:
394 switch ((pa_sink_state_t
) PA_PTR_TO_UINT(data
)) {
396 case PA_SINK_SUSPENDED
:
398 pa_assert(PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
));
400 pa_smoother_pause(u
->smoother
, pa_rtclock_now());
402 if (!u
->source
|| u
->source_suspended
) {
406 u
->sink_suspended
= TRUE
;
410 case PA_SINK_RUNNING
:
412 if (u
->sink
->thread_info
.state
== PA_SINK_SUSPENDED
) {
413 pa_smoother_resume(u
->smoother
, pa_rtclock_now(), TRUE
);
415 if (!u
->source
|| u
->source_suspended
) {
416 if (unsuspend(u
) < 0)
418 u
->sink
->get_volume(u
->sink
);
419 u
->sink
->get_mute(u
->sink
);
421 u
->sink_suspended
= FALSE
;
425 case PA_SINK_INVALID_STATE
:
426 case PA_SINK_UNLINKED
:
434 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
437 static int source_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
438 struct userdata
*u
= PA_SOURCE(o
)->userdata
;
442 case PA_SOURCE_MESSAGE_GET_LATENCY
:
443 *((pa_usec_t
*) data
) = source_get_latency(u
, &PA_SOURCE(o
)->sample_spec
);
446 case PA_SOURCE_MESSAGE_SET_STATE
:
448 switch ((pa_source_state_t
) PA_PTR_TO_UINT(data
)) {
450 case PA_SOURCE_SUSPENDED
:
452 pa_assert(PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
));
454 if (!u
->sink
|| u
->sink_suspended
) {
458 u
->source_suspended
= TRUE
;
462 case PA_SOURCE_RUNNING
:
464 if (u
->source
->thread_info
.state
== PA_SOURCE_SUSPENDED
) {
465 if (!u
->sink
|| u
->sink_suspended
) {
466 if (unsuspend(u
) < 0)
468 u
->source
->get_volume(u
->source
);
470 u
->source_suspended
= FALSE
;
474 case PA_SOURCE_UNLINKED
:
476 case PA_SOURCE_INVALID_STATE
:
484 return pa_source_process_msg(o
, code
, data
, offset
, chunk
);
487 static void sink_set_volume(pa_sink
*s
) {
491 pa_assert_se(u
= s
->userdata
);
494 AUDIO_INITINFO(&info
);
496 info
.play
.gain
= pa_cvolume_max(&s
->real_volume
) * AUDIO_MAX_GAIN
/ PA_VOLUME_NORM
;
497 assert(info
.play
.gain
<= AUDIO_MAX_GAIN
);
499 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0) {
501 pa_log("AUDIO_SETINFO: Unsupported volume.");
503 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
508 static void sink_get_volume(pa_sink
*s
) {
512 pa_assert_se(u
= s
->userdata
);
515 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
516 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
518 pa_cvolume_set(&s
->real_volume
, s
->sample_spec
.channels
, info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
522 static void source_set_volume(pa_source
*s
) {
526 pa_assert_se(u
= s
->userdata
);
529 AUDIO_INITINFO(&info
);
531 info
.play
.gain
= pa_cvolume_max(&s
->volume
) * AUDIO_MAX_GAIN
/ PA_VOLUME_NORM
;
532 assert(info
.play
.gain
<= AUDIO_MAX_GAIN
);
534 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0) {
536 pa_log("AUDIO_SETINFO: Unsupported volume.");
538 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
543 static void source_get_volume(pa_source
*s
) {
547 pa_assert_se(u
= s
->userdata
);
550 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
551 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
553 pa_cvolume_set(&s
->volume
, s
->sample_spec
.channels
, info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
557 static void sink_set_mute(pa_sink
*s
) {
558 struct userdata
*u
= s
->userdata
;
564 AUDIO_INITINFO(&info
);
566 info
.output_muted
= !!s
->muted
;
568 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
569 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
573 static void sink_get_mute(pa_sink
*s
) {
574 struct userdata
*u
= s
->userdata
;
580 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
581 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
583 s
->muted
= !!info
.output_muted
;
587 static void process_rewind(struct userdata
*u
) {
588 size_t rewind_nbytes
;
592 /* Figure out how much we shall rewind and reset the counter */
593 rewind_nbytes
= u
->sink
->thread_info
.rewind_nbytes
;
594 u
->sink
->thread_info
.rewind_nbytes
= 0;
596 if (rewind_nbytes
> 0) {
597 pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes
);
598 rewind_nbytes
= PA_MIN(u
->memchunk
.length
, rewind_nbytes
);
599 u
->memchunk
.length
-= rewind_nbytes
;
600 pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes
);
603 pa_sink_process_rewind(u
->sink
, rewind_nbytes
);
606 static void thread_func(void *userdata
) {
607 struct userdata
*u
= userdata
;
608 unsigned short revents
= 0;
614 pa_log_debug("Thread starting up");
616 if (u
->core
->realtime_scheduling
)
617 pa_make_realtime(u
->core
->realtime_priority
);
619 pa_thread_mq_install(&u
->thread_mq
);
621 pa_smoother_set_time_offset(u
->smoother
, pa_rtclock_now());
624 /* Render some data and write it to the dsp */
626 if (u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
)) {
627 pa_usec_t xtime0
, ysleep_interval
, xsleep_interval
;
628 uint64_t buffered_bytes
;
630 if (u
->sink
->thread_info
.rewind_requested
)
633 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
635 pa_log("AUDIO_GETINFO ioctl failed: %s", pa_cstrerror(errno
));
639 if (info
.play
.error
) {
640 pa_log_debug("buffer under-run!");
642 AUDIO_INITINFO(&info
);
644 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
645 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
647 pa_smoother_reset(u
->smoother
, pa_rtclock_now(), TRUE
);
656 * Since we cannot modify the size of the output buffer we fake it
657 * by not filling it more than u->buffer_size.
659 xtime0
= pa_rtclock_now();
660 buffered_bytes
= get_playback_buffered_bytes(u
);
661 if (buffered_bytes
>= (uint64_t)u
->buffer_size
)
664 len
= u
->buffer_size
- buffered_bytes
;
665 len
-= len
% u
->frame_size
;
667 if (len
< (size_t) u
->minimum_request
)
670 if (u
->memchunk
.length
< len
)
671 pa_sink_render(u
->sink
, u
->sink
->thread_info
.max_request
, &u
->memchunk
);
673 p
= pa_memblock_acquire(u
->memchunk
.memblock
);
674 w
= pa_write(u
->fd
, (uint8_t*) p
+ u
->memchunk
.index
, u
->memchunk
.length
, NULL
);
675 pa_memblock_release(u
->memchunk
.memblock
);
682 /* If the buffer_size is too big, we get EAGAIN. Avoiding that limit by trial and error
683 * is not ideal, but I don't know how to get the system to tell me what the limit is.
685 u
->buffer_size
= u
->buffer_size
* 18 / 25;
686 u
->buffer_size
-= u
->buffer_size
% u
->frame_size
;
687 u
->buffer_size
= PA_MAX(u
->buffer_size
, 2 * u
->minimum_request
);
688 pa_sink_set_max_request_within_thread(u
->sink
, u
->buffer_size
);
689 pa_sink_set_max_rewind_within_thread(u
->sink
, u
->buffer_size
);
690 pa_log("EAGAIN. Buffer size is now %u bytes (%llu buffered)", u
->buffer_size
, buffered_bytes
);
693 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno
));
697 pa_assert(w
% u
->frame_size
== 0);
699 u
->written_bytes
+= w
;
700 u
->memchunk
.length
-= w
;
702 u
->memchunk
.index
+= w
;
703 if (u
->memchunk
.length
<= 0) {
704 pa_memblock_unref(u
->memchunk
.memblock
);
705 pa_memchunk_reset(&u
->memchunk
);
710 ysleep_interval
= pa_bytes_to_usec(buffered_bytes
/ 2, &u
->sink
->sample_spec
);
711 xsleep_interval
= pa_smoother_translate(u
->smoother
, xtime0
, ysleep_interval
);
712 pa_rtpoll_set_timer_absolute(u
->rtpoll
, xtime0
+ PA_MIN(xsleep_interval
, ysleep_interval
));
714 pa_rtpoll_set_timer_disabled(u
->rtpoll
);
716 /* Try to read some data and pass it on to the source driver */
718 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
) && (revents
& POLLIN
)) {
719 pa_memchunk memchunk
;
724 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
727 if (info
.record
.error
) {
728 pa_log_debug("buffer overflow!");
730 AUDIO_INITINFO(&info
);
731 info
.record
.error
= 0;
732 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
733 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
736 err
= ioctl(u
->fd
, I_NREAD
, &len
);
740 memchunk
.memblock
= pa_memblock_new(u
->core
->mempool
, len
);
741 pa_assert(memchunk
.memblock
);
743 p
= pa_memblock_acquire(memchunk
.memblock
);
744 r
= pa_read(u
->fd
, p
, len
, NULL
);
745 pa_memblock_release(memchunk
.memblock
);
748 pa_memblock_unref(memchunk
.memblock
);
752 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno
));
761 pa_source_post(u
->source
, &memchunk
);
762 pa_memblock_unref(memchunk
.memblock
);
769 if (u
->rtpoll_item
) {
770 struct pollfd
*pollfd
;
772 pa_assert(u
->fd
>= 0);
774 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
775 pollfd
->events
= (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
)) ? POLLIN
: 0;
778 /* Hmm, nothing to do. Let's sleep */
779 if ((ret
= pa_rtpoll_run(u
->rtpoll
, TRUE
)) < 0)
785 if (u
->rtpoll_item
) {
786 struct pollfd
*pollfd
;
788 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
790 if (pollfd
->revents
& ~(POLLOUT
|POLLIN
)) {
791 pa_log("DSP shutdown.");
795 revents
= pollfd
->revents
;
801 /* We have to continue processing messages until we receive the
802 * SHUTDOWN message */
803 pa_asyncmsgq_post(u
->thread_mq
.outq
, PA_MSGOBJECT(u
->core
), PA_CORE_MESSAGE_UNLOAD_MODULE
, u
->module
, 0, NULL
, NULL
);
804 pa_asyncmsgq_wait_for(u
->thread_mq
.inq
, PA_MESSAGE_SHUTDOWN
);
807 pa_log_debug("Thread shutting down");
810 static void sig_callback(pa_mainloop_api
*api
, pa_signal_event
*e
, int sig
, void *userdata
) {
811 struct userdata
*u
= userdata
;
815 pa_log_debug("caught signal");
818 pa_sink_get_volume(u
->sink
, TRUE
);
819 pa_sink_get_mute(u
->sink
, TRUE
);
823 pa_source_get_volume(u
->source
, TRUE
);
826 int pa__init(pa_module
*m
) {
827 struct userdata
*u
= NULL
;
828 pa_bool_t record
= TRUE
, playback
= TRUE
;
831 pa_modargs
*ma
= NULL
;
832 uint32_t buffer_length_msec
;
834 pa_sink_new_data sink_new_data
;
835 pa_source_new_data source_new_data
;
838 pa_bool_t namereg_fail
;
842 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
843 pa_log("failed to parse module arguments.");
847 if (pa_modargs_get_value_boolean(ma
, "record", &record
) < 0 || pa_modargs_get_value_boolean(ma
, "playback", &playback
) < 0) {
848 pa_log("record= and playback= expect a boolean argument.");
852 if (!playback
&& !record
) {
853 pa_log("neither playback nor record enabled for device.");
857 u
= pa_xnew0(struct userdata
, 1);
859 if (!(u
->smoother
= pa_smoother_new(PA_USEC_PER_SEC
, PA_USEC_PER_SEC
* 2, TRUE
, TRUE
, 10, pa_rtclock_now(), TRUE
)))
863 * For a process (or several processes) to use the same audio device for both
864 * record and playback at the same time, the device's mixer must be enabled.
865 * See mixerctl(1). It may be turned off for playback only or record only.
867 u
->mode
= (playback
&& record
) ? O_RDWR
: (playback
? O_WRONLY
: (record
? O_RDONLY
: 0));
869 ss
= m
->core
->default_sample_spec
;
870 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
871 pa_log("failed to parse sample specification");
874 u
->frame_size
= pa_frame_size(&ss
);
876 u
->minimum_request
= pa_usec_to_bytes(PA_USEC_PER_SEC
/ MAX_RENDER_HZ
, &ss
);
878 buffer_length_msec
= 100;
879 if (pa_modargs_get_value_u32(ma
, "buffer_length", &buffer_length_msec
) < 0) {
880 pa_log("failed to parse buffer_length argument");
883 u
->buffer_size
= pa_usec_to_bytes(1000 * buffer_length_msec
, &ss
);
884 if (u
->buffer_size
< 2 * u
->minimum_request
) {
885 pa_log("supplied buffer size argument is too small");
889 u
->device_name
= pa_xstrdup(pa_modargs_get_value(ma
, "device", DEFAULT_DEVICE
));
891 if ((fd
= open_audio_device(u
, &ss
)) < 0)
898 pa_memchunk_reset(&u
->memchunk
);
900 u
->rtpoll
= pa_rtpoll_new();
901 pa_thread_mq_init(&u
->thread_mq
, m
->core
->mainloop
, u
->rtpoll
);
903 u
->rtpoll_item
= NULL
;
906 if (u
->mode
!= O_WRONLY
) {
910 if (!(name
= pa_modargs_get_value(ma
, "source_name", NULL
))) {
911 name
= name_buf
= pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u
->device_name
));
912 namereg_fail
= FALSE
;
915 pa_source_new_data_init(&source_new_data
);
916 source_new_data
.driver
= __FILE__
;
917 source_new_data
.module
= m
;
918 pa_source_new_data_set_name(&source_new_data
, name
);
919 source_new_data
.namereg_fail
= namereg_fail
;
920 pa_source_new_data_set_sample_spec(&source_new_data
, &ss
);
921 pa_source_new_data_set_channel_map(&source_new_data
, &map
);
922 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
923 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
924 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM source");
925 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
926 pa_proplist_setf(source_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE
, "%lu", (unsigned long) u
->buffer_size
);
928 if (pa_modargs_get_proplist(ma
, "source_properties", source_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
929 pa_log("Invalid properties");
930 pa_source_new_data_done(&source_new_data
);
934 u
->source
= pa_source_new(m
->core
, &source_new_data
, PA_SOURCE_HARDWARE
|PA_SOURCE_LATENCY
|PA_SOURCE_HW_VOLUME_CTRL
);
935 pa_source_new_data_done(&source_new_data
);
939 pa_log("Failed to create source object");
943 u
->source
->userdata
= u
;
944 u
->source
->parent
.process_msg
= source_process_msg
;
946 pa_source_set_asyncmsgq(u
->source
, u
->thread_mq
.inq
);
947 pa_source_set_rtpoll(u
->source
, u
->rtpoll
);
949 u
->source
->get_volume
= source_get_volume
;
950 u
->source
->set_volume
= source_set_volume
;
951 u
->source
->refresh_volume
= TRUE
;
955 if (u
->mode
!= O_RDONLY
) {
958 if (!(name
= pa_modargs_get_value(ma
, "sink_name", NULL
))) {
959 name
= name_buf
= pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u
->device_name
));
960 namereg_fail
= FALSE
;
963 pa_sink_new_data_init(&sink_new_data
);
964 sink_new_data
.driver
= __FILE__
;
965 sink_new_data
.module
= m
;
966 pa_sink_new_data_set_name(&sink_new_data
, name
);
967 sink_new_data
.namereg_fail
= namereg_fail
;
968 pa_sink_new_data_set_sample_spec(&sink_new_data
, &ss
);
969 pa_sink_new_data_set_channel_map(&sink_new_data
, &map
);
970 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
971 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
972 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM sink");
973 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
975 if (pa_modargs_get_proplist(ma
, "sink_properties", sink_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
976 pa_log("Invalid properties");
977 pa_sink_new_data_done(&sink_new_data
);
981 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
);
982 pa_sink_new_data_done(&sink_new_data
);
985 u
->sink
->userdata
= u
;
986 u
->sink
->parent
.process_msg
= sink_process_msg
;
988 pa_sink_set_asyncmsgq(u
->sink
, u
->thread_mq
.inq
);
989 pa_sink_set_rtpoll(u
->sink
, u
->rtpoll
);
991 u
->sink
->get_volume
= sink_get_volume
;
992 u
->sink
->set_volume
= sink_set_volume
;
993 u
->sink
->get_mute
= sink_get_mute
;
994 u
->sink
->set_mute
= sink_set_mute
;
995 u
->sink
->refresh_volume
= u
->sink
->refresh_muted
= TRUE
;
997 pa_sink_set_max_request(u
->sink
, u
->buffer_size
);
998 pa_sink_set_max_rewind(u
->sink
, u
->buffer_size
);
1002 pa_assert(u
->source
|| u
->sink
);
1004 u
->sig
= pa_signal_new(SIGPOLL
, sig_callback
, u
);
1006 ioctl(u
->fd
, I_SETSIG
, S_MSG
);
1008 pa_log_warn("Could not register SIGPOLL handler");
1010 if (!(u
->thread
= pa_thread_new(thread_func
, u
))) {
1011 pa_log("Failed to create thread.");
1015 /* Read mixer settings */
1017 if (sink_new_data
.volume_is_set
)
1018 u
->sink
->set_volume(u
->sink
);
1020 u
->sink
->get_volume(u
->sink
);
1022 if (sink_new_data
.muted_is_set
)
1023 u
->sink
->set_mute(u
->sink
);
1025 u
->sink
->get_mute(u
->sink
);
1027 pa_sink_put(u
->sink
);
1031 if (source_new_data
.volume_is_set
)
1032 u
->source
->set_volume(u
->source
);
1034 u
->source
->get_volume(u
->source
);
1036 pa_source_put(u
->source
);
1039 pa_modargs_free(ma
);
1050 pa_modargs_free(ma
);
1055 void pa__done(pa_module
*m
) {
1060 if (!(u
= m
->userdata
))
1064 ioctl(u
->fd
, I_SETSIG
, 0);
1065 pa_signal_free(u
->sig
);
1069 pa_sink_unlink(u
->sink
);
1072 pa_source_unlink(u
->source
);
1075 pa_asyncmsgq_send(u
->thread_mq
.inq
, NULL
, PA_MESSAGE_SHUTDOWN
, NULL
, 0, NULL
);
1076 pa_thread_free(u
->thread
);
1079 pa_thread_mq_done(&u
->thread_mq
);
1082 pa_sink_unref(u
->sink
);
1085 pa_source_unref(u
->source
);
1087 if (u
->memchunk
.memblock
)
1088 pa_memblock_unref(u
->memchunk
.memblock
);
1091 pa_rtpoll_item_free(u
->rtpoll_item
);
1094 pa_rtpoll_free(u
->rtpoll
);
1100 pa_smoother_free(u
->smoother
);
1102 pa_xfree(u
->device_name
);