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 pa_bool_t 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 return u
->written_bytes
- played_bytes
;
169 static pa_usec_t
sink_get_latency(struct userdata
*u
, pa_sample_spec
*ss
) {
176 r
= pa_bytes_to_usec(get_playback_buffered_bytes(u
), ss
);
177 if (u
->memchunk
.memblock
)
178 r
+= pa_bytes_to_usec(u
->memchunk
.length
, ss
);
183 static uint64_t get_recorded_bytes(struct userdata
*u
) {
188 pa_assert(u
->source
);
190 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
193 if (u
->prev_record_samples
> info
.record
.samples
)
194 ++u
->record_samples_msw
;
195 u
->prev_record_samples
= info
.record
.samples
;
196 result
= (((uint64_t)u
->record_samples_msw
<< 32) + info
.record
.samples
) * u
->frame_size
;
201 static pa_usec_t
source_get_latency(struct userdata
*u
, pa_sample_spec
*ss
) {
209 int err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
212 r
= pa_bytes_to_usec(get_recorded_bytes(u
), ss
) - pa_bytes_to_usec(u
->read_bytes
, ss
);
217 static void build_pollfd(struct userdata
*u
) {
218 struct pollfd
*pollfd
;
221 pa_assert(!u
->rtpoll_item
);
222 u
->rtpoll_item
= pa_rtpoll_item_new(u
->rtpoll
, PA_RTPOLL_NEVER
, 1);
224 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
230 static int set_buffer(int fd
, int buffer_size
) {
235 AUDIO_INITINFO(&info
);
236 info
.play
.buffer_size
= buffer_size
;
237 info
.record
.buffer_size
= buffer_size
;
239 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0) {
241 pa_log("AUDIO_SETINFO: Unsupported buffer size.");
243 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
250 static int auto_format(int fd
, int mode
, pa_sample_spec
*ss
) {
256 AUDIO_INITINFO(&info
);
258 if (mode
!= O_RDONLY
) {
259 info
.play
.sample_rate
= ss
->rate
;
260 info
.play
.channels
= ss
->channels
;
261 switch (ss
->format
) {
263 info
.play
.precision
= 8;
264 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
267 info
.play
.precision
= 8;
268 info
.play
.encoding
= AUDIO_ENCODING_ALAW
;
271 info
.play
.precision
= 8;
272 info
.play
.encoding
= AUDIO_ENCODING_ULAW
;
274 case PA_SAMPLE_S16NE
:
275 info
.play
.precision
= 16;
276 info
.play
.encoding
= AUDIO_ENCODING_LINEAR
;
279 pa_log("AUDIO_SETINFO: Unsupported sample format.");
284 if (mode
!= O_WRONLY
) {
285 info
.record
.sample_rate
= ss
->rate
;
286 info
.record
.channels
= ss
->channels
;
287 switch (ss
->format
) {
289 info
.record
.precision
= 8;
290 info
.record
.encoding
= AUDIO_ENCODING_LINEAR
;
293 info
.record
.precision
= 8;
294 info
.record
.encoding
= AUDIO_ENCODING_ALAW
;
297 info
.record
.precision
= 8;
298 info
.record
.encoding
= AUDIO_ENCODING_ULAW
;
300 case PA_SAMPLE_S16NE
:
301 info
.record
.precision
= 16;
302 info
.record
.encoding
= AUDIO_ENCODING_LINEAR
;
305 pa_log("AUDIO_SETINFO: Unsupported sample format.");
310 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0) {
312 pa_log("AUDIO_SETINFO: Failed to set sample format.");
314 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
321 static int open_audio_device(struct userdata
*u
, pa_sample_spec
*ss
) {
325 if ((u
->fd
= pa_open_cloexec(u
->device_name
, u
->mode
| O_NONBLOCK
, 0)) < 0) {
326 pa_log_warn("open %s failed (%s)", u
->device_name
, pa_cstrerror(errno
));
330 pa_log_info("device opened in %s mode.", u
->mode
== O_WRONLY
? "O_WRONLY" : (u
->mode
== O_RDONLY
? "O_RDONLY" : "O_RDWR"));
332 if (auto_format(u
->fd
, u
->mode
, ss
) < 0)
335 if (set_buffer(u
->fd
, u
->buffer_size
) < 0)
338 u
->written_bytes
= u
->read_bytes
= 0;
339 u
->play_samples_msw
= u
->record_samples_msw
= 0;
340 u
->prev_playback_samples
= u
->prev_record_samples
= 0;
345 static int suspend(struct userdata
*u
) {
347 pa_assert(u
->fd
>= 0);
349 pa_log_info("Suspending...");
351 ioctl(u
->fd
, AUDIO_DRAIN
, NULL
);
355 if (u
->rtpoll_item
) {
356 pa_rtpoll_item_free(u
->rtpoll_item
);
357 u
->rtpoll_item
= NULL
;
360 pa_log_info("Device suspended.");
365 static int unsuspend(struct userdata
*u
) {
367 pa_assert(u
->fd
< 0);
369 pa_log_info("Resuming...");
371 if (open_audio_device(u
, u
->sink
? &u
->sink
->sample_spec
: &u
->source
->sample_spec
) < 0)
376 pa_log_info("Device resumed.");
381 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
382 struct userdata
*u
= PA_SINK(o
)->userdata
;
386 case PA_SINK_MESSAGE_GET_LATENCY
:
387 *((pa_usec_t
*) data
) = sink_get_latency(u
, &PA_SINK(o
)->sample_spec
);
390 case PA_SINK_MESSAGE_SET_STATE
:
392 switch ((pa_sink_state_t
) PA_PTR_TO_UINT(data
)) {
394 case PA_SINK_SUSPENDED
:
396 pa_assert(PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
));
398 pa_smoother_pause(u
->smoother
, pa_rtclock_now());
400 if (!u
->source
|| u
->source_suspended
) {
404 u
->sink_suspended
= TRUE
;
408 case PA_SINK_RUNNING
:
410 if (u
->sink
->thread_info
.state
== PA_SINK_SUSPENDED
) {
411 pa_smoother_resume(u
->smoother
, pa_rtclock_now(), TRUE
);
413 if (!u
->source
|| u
->source_suspended
) {
414 if (unsuspend(u
) < 0)
416 u
->sink
->get_volume(u
->sink
);
417 u
->sink
->get_mute(u
->sink
);
419 u
->sink_suspended
= FALSE
;
423 case PA_SINK_INVALID_STATE
:
424 case PA_SINK_UNLINKED
:
432 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
435 static int source_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
436 struct userdata
*u
= PA_SOURCE(o
)->userdata
;
440 case PA_SOURCE_MESSAGE_GET_LATENCY
:
441 *((pa_usec_t
*) data
) = source_get_latency(u
, &PA_SOURCE(o
)->sample_spec
);
444 case PA_SOURCE_MESSAGE_SET_STATE
:
446 switch ((pa_source_state_t
) PA_PTR_TO_UINT(data
)) {
448 case PA_SOURCE_SUSPENDED
:
450 pa_assert(PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
));
452 if (!u
->sink
|| u
->sink_suspended
) {
456 u
->source_suspended
= TRUE
;
460 case PA_SOURCE_RUNNING
:
462 if (u
->source
->thread_info
.state
== PA_SOURCE_SUSPENDED
) {
463 if (!u
->sink
|| u
->sink_suspended
) {
464 if (unsuspend(u
) < 0)
466 u
->source
->get_volume(u
->source
);
468 u
->source_suspended
= FALSE
;
472 case PA_SOURCE_UNLINKED
:
474 case PA_SOURCE_INVALID_STATE
:
482 return pa_source_process_msg(o
, code
, data
, offset
, chunk
);
485 static void sink_set_volume(pa_sink
*s
) {
489 pa_assert_se(u
= s
->userdata
);
492 AUDIO_INITINFO(&info
);
494 info
.play
.gain
= pa_cvolume_max(&s
->real_volume
) * AUDIO_MAX_GAIN
/ PA_VOLUME_NORM
;
495 assert(info
.play
.gain
<= AUDIO_MAX_GAIN
);
497 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0) {
499 pa_log("AUDIO_SETINFO: Unsupported volume.");
501 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
506 static void sink_get_volume(pa_sink
*s
) {
510 pa_assert_se(u
= s
->userdata
);
513 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
514 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
516 pa_cvolume_set(&s
->real_volume
, s
->sample_spec
.channels
, info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
520 static void source_set_volume(pa_source
*s
) {
524 pa_assert_se(u
= s
->userdata
);
527 AUDIO_INITINFO(&info
);
529 info
.play
.gain
= pa_cvolume_max(&s
->real_volume
) * AUDIO_MAX_GAIN
/ PA_VOLUME_NORM
;
530 assert(info
.play
.gain
<= AUDIO_MAX_GAIN
);
532 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0) {
534 pa_log("AUDIO_SETINFO: Unsupported volume.");
536 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
541 static void source_get_volume(pa_source
*s
) {
545 pa_assert_se(u
= s
->userdata
);
548 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
549 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
551 pa_cvolume_set(&s
->real_volume
, s
->sample_spec
.channels
, info
.play
.gain
* PA_VOLUME_NORM
/ AUDIO_MAX_GAIN
);
555 static void sink_set_mute(pa_sink
*s
) {
556 struct userdata
*u
= s
->userdata
;
562 AUDIO_INITINFO(&info
);
564 info
.output_muted
= !!s
->muted
;
566 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
567 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
571 static void sink_get_mute(pa_sink
*s
) {
572 struct userdata
*u
= s
->userdata
;
578 if (ioctl(u
->fd
, AUDIO_GETINFO
, &info
) < 0)
579 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
581 s
->muted
= !!info
.output_muted
;
585 static void process_rewind(struct userdata
*u
) {
586 size_t rewind_nbytes
;
590 if (!PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
)) {
591 pa_sink_process_rewind(u
->sink
, 0);
595 rewind_nbytes
= u
->sink
->thread_info
.rewind_nbytes
;
597 if (rewind_nbytes
> 0) {
598 pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes
);
599 rewind_nbytes
= PA_MIN(u
->memchunk
.length
, rewind_nbytes
);
600 u
->memchunk
.length
-= rewind_nbytes
;
601 if (u
->memchunk
.length
<= 0 && u
->memchunk
.memblock
) {
602 pa_memblock_unref(u
->memchunk
.memblock
);
603 pa_memchunk_reset(&u
->memchunk
);
605 pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes
);
608 pa_sink_process_rewind(u
->sink
, rewind_nbytes
);
611 static void thread_func(void *userdata
) {
612 struct userdata
*u
= userdata
;
613 unsigned short revents
= 0;
619 pa_log_debug("Thread starting up");
621 if (u
->core
->realtime_scheduling
)
622 pa_make_realtime(u
->core
->realtime_priority
);
624 pa_thread_mq_install(&u
->thread_mq
);
626 pa_smoother_set_time_offset(u
->smoother
, pa_rtclock_now());
629 /* Render some data and write it to the dsp */
631 if (PA_UNLIKELY(u
->sink
->thread_info
.rewind_requested
))
634 if (u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
)) {
635 pa_usec_t xtime0
, ysleep_interval
, xsleep_interval
;
636 uint64_t buffered_bytes
;
638 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
640 pa_log("AUDIO_GETINFO ioctl failed: %s", pa_cstrerror(errno
));
644 if (info
.play
.error
) {
645 pa_log_debug("buffer under-run!");
647 AUDIO_INITINFO(&info
);
649 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
650 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
652 pa_smoother_reset(u
->smoother
, pa_rtclock_now(), TRUE
);
662 * Since we cannot modify the size of the output buffer we fake it
663 * by not filling it more than u->buffer_size.
665 xtime0
= pa_rtclock_now();
666 buffered_bytes
= get_playback_buffered_bytes(u
);
667 if (buffered_bytes
>= (uint64_t)u
->buffer_size
)
670 len
= u
->buffer_size
- buffered_bytes
;
671 len
-= len
% u
->frame_size
;
673 if (len
< (size_t) u
->minimum_request
)
676 if (!u
->memchunk
.length
)
677 pa_sink_render(u
->sink
, u
->sink
->thread_info
.max_request
, &u
->memchunk
);
679 len
= PA_MIN(u
->memchunk
.length
, len
);
681 p
= pa_memblock_acquire(u
->memchunk
.memblock
);
682 w
= pa_write(u
->fd
, (uint8_t*) p
+ u
->memchunk
.index
, len
, &write_type
);
683 pa_memblock_release(u
->memchunk
.memblock
);
686 if (errno
== EINTR
) {
688 } else if (errno
== EAGAIN
) {
689 /* We may have realtime priority so yield the CPU to ensure that fd can become writable again. */
690 pa_log_debug("EAGAIN with %llu bytes buffered.", 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
.index
+= w
;
701 u
->memchunk
.length
-= w
;
702 if (u
->memchunk
.length
<= 0) {
703 pa_memblock_unref(u
->memchunk
.memblock
);
704 pa_memchunk_reset(&u
->memchunk
);
709 ysleep_interval
= pa_bytes_to_usec(buffered_bytes
/ 2, &u
->sink
->sample_spec
);
710 xsleep_interval
= pa_smoother_translate(u
->smoother
, xtime0
, ysleep_interval
);
711 pa_rtpoll_set_timer_absolute(u
->rtpoll
, xtime0
+ PA_MIN(xsleep_interval
, ysleep_interval
));
713 pa_rtpoll_set_timer_disabled(u
->rtpoll
);
715 /* Try to read some data and pass it on to the source driver */
717 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
) && (revents
& POLLIN
)) {
718 pa_memchunk memchunk
;
723 err
= ioctl(u
->fd
, AUDIO_GETINFO
, &info
);
726 if (info
.record
.error
) {
727 pa_log_debug("buffer overflow!");
729 AUDIO_INITINFO(&info
);
730 info
.record
.error
= 0;
731 if (ioctl(u
->fd
, AUDIO_SETINFO
, &info
) < 0)
732 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno
));
735 err
= ioctl(u
->fd
, I_NREAD
, &len
);
739 memchunk
.memblock
= pa_memblock_new(u
->core
->mempool
, len
);
740 pa_assert(memchunk
.memblock
);
742 p
= pa_memblock_acquire(memchunk
.memblock
);
743 r
= pa_read(u
->fd
, p
, len
, NULL
);
744 pa_memblock_release(memchunk
.memblock
);
747 pa_memblock_unref(memchunk
.memblock
);
751 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno
));
760 pa_source_post(u
->source
, &memchunk
);
761 pa_memblock_unref(memchunk
.memblock
);
768 if (u
->rtpoll_item
) {
769 struct pollfd
*pollfd
;
771 pa_assert(u
->fd
>= 0);
773 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
774 pollfd
->events
= (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
)) ? POLLIN
: 0;
777 /* Hmm, nothing to do. Let's sleep */
778 if ((ret
= pa_rtpoll_run(u
->rtpoll
, TRUE
)) < 0)
784 if (u
->rtpoll_item
) {
785 struct pollfd
*pollfd
;
787 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
789 if (pollfd
->revents
& ~(POLLOUT
|POLLIN
)) {
790 pa_log("DSP shutdown.");
794 revents
= pollfd
->revents
;
800 /* We have to continue processing messages until we receive the
801 * SHUTDOWN message */
802 pa_asyncmsgq_post(u
->thread_mq
.outq
, PA_MSGOBJECT(u
->core
), PA_CORE_MESSAGE_UNLOAD_MODULE
, u
->module
, 0, NULL
, NULL
);
803 pa_asyncmsgq_wait_for(u
->thread_mq
.inq
, PA_MESSAGE_SHUTDOWN
);
806 pa_log_debug("Thread shutting down");
809 static void sig_callback(pa_mainloop_api
*api
, pa_signal_event
*e
, int sig
, void *userdata
) {
810 struct userdata
*u
= userdata
;
814 pa_log_debug("caught signal");
817 pa_sink_get_volume(u
->sink
, TRUE
);
818 pa_sink_get_mute(u
->sink
, TRUE
);
822 pa_source_get_volume(u
->source
, TRUE
);
825 int pa__init(pa_module
*m
) {
826 struct userdata
*u
= NULL
;
827 pa_bool_t record
= TRUE
, playback
= TRUE
;
830 pa_modargs
*ma
= NULL
;
831 uint32_t buffer_length_msec
;
833 pa_sink_new_data sink_new_data
;
834 pa_source_new_data source_new_data
;
837 pa_bool_t namereg_fail
;
841 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
842 pa_log("failed to parse module arguments.");
846 if (pa_modargs_get_value_boolean(ma
, "record", &record
) < 0 || pa_modargs_get_value_boolean(ma
, "playback", &playback
) < 0) {
847 pa_log("record= and playback= expect a boolean argument.");
851 if (!playback
&& !record
) {
852 pa_log("neither playback nor record enabled for device.");
856 u
= pa_xnew0(struct userdata
, 1);
858 if (!(u
->smoother
= pa_smoother_new(PA_USEC_PER_SEC
, PA_USEC_PER_SEC
* 2, TRUE
, TRUE
, 10, pa_rtclock_now(), TRUE
)))
862 * For a process (or several processes) to use the same audio device for both
863 * record and playback at the same time, the device's mixer must be enabled.
864 * See mixerctl(1). It may be turned off for playback only or record only.
866 u
->mode
= (playback
&& record
) ? O_RDWR
: (playback
? O_WRONLY
: (record
? O_RDONLY
: 0));
868 ss
= m
->core
->default_sample_spec
;
869 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
870 pa_log("failed to parse sample specification");
873 u
->frame_size
= pa_frame_size(&ss
);
875 u
->minimum_request
= pa_usec_to_bytes(PA_USEC_PER_SEC
/ MAX_RENDER_HZ
, &ss
);
877 buffer_length_msec
= 100;
878 if (pa_modargs_get_value_u32(ma
, "buffer_length", &buffer_length_msec
) < 0) {
879 pa_log("failed to parse buffer_length argument");
882 u
->buffer_size
= pa_usec_to_bytes(1000 * buffer_length_msec
, &ss
);
883 if (u
->buffer_size
< 2 * u
->minimum_request
) {
884 pa_log("buffer_length argument cannot be smaller than %u",
885 (unsigned)(pa_bytes_to_usec(2 * u
->minimum_request
, &ss
) / 1000));
888 if (u
->buffer_size
> MAX_BUFFER_SIZE
) {
889 pa_log("buffer_length argument cannot be greater than %u",
890 (unsigned)(pa_bytes_to_usec(MAX_BUFFER_SIZE
, &ss
) / 1000));
894 u
->device_name
= pa_xstrdup(pa_modargs_get_value(ma
, "device", DEFAULT_DEVICE
));
896 if ((fd
= open_audio_device(u
, &ss
)) < 0)
903 pa_memchunk_reset(&u
->memchunk
);
905 u
->rtpoll
= pa_rtpoll_new();
906 pa_thread_mq_init(&u
->thread_mq
, m
->core
->mainloop
, u
->rtpoll
);
908 u
->rtpoll_item
= NULL
;
911 if (u
->mode
!= O_WRONLY
) {
915 if (!(name
= pa_modargs_get_value(ma
, "source_name", NULL
))) {
916 name
= name_buf
= pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u
->device_name
));
917 namereg_fail
= FALSE
;
920 pa_source_new_data_init(&source_new_data
);
921 source_new_data
.driver
= __FILE__
;
922 source_new_data
.module
= m
;
923 pa_source_new_data_set_name(&source_new_data
, name
);
924 source_new_data
.namereg_fail
= namereg_fail
;
925 pa_source_new_data_set_sample_spec(&source_new_data
, &ss
);
926 pa_source_new_data_set_channel_map(&source_new_data
, &map
);
927 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
928 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
929 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM source");
930 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
931 pa_proplist_setf(source_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE
, "%lu", (unsigned long) u
->buffer_size
);
933 if (pa_modargs_get_proplist(ma
, "source_properties", source_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
934 pa_log("Invalid properties");
935 pa_source_new_data_done(&source_new_data
);
939 u
->source
= pa_source_new(m
->core
, &source_new_data
, PA_SOURCE_HARDWARE
|PA_SOURCE_LATENCY
);
940 pa_source_new_data_done(&source_new_data
);
944 pa_log("Failed to create source object");
948 u
->source
->userdata
= u
;
949 u
->source
->parent
.process_msg
= source_process_msg
;
951 pa_source_set_asyncmsgq(u
->source
, u
->thread_mq
.inq
);
952 pa_source_set_rtpoll(u
->source
, u
->rtpoll
);
953 pa_source_set_fixed_latency(u
->source
, pa_bytes_to_usec(u
->buffer_size
, &u
->source
->sample_spec
));
955 pa_source_set_get_volume_callback(u
->source
, source_get_volume
);
956 pa_source_set_set_volume_callback(u
->source
, source_set_volume
);
957 u
->source
->refresh_volume
= TRUE
;
961 if (u
->mode
!= O_RDONLY
) {
964 if (!(name
= pa_modargs_get_value(ma
, "sink_name", NULL
))) {
965 name
= name_buf
= pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u
->device_name
));
966 namereg_fail
= FALSE
;
969 pa_sink_new_data_init(&sink_new_data
);
970 sink_new_data
.driver
= __FILE__
;
971 sink_new_data
.module
= m
;
972 pa_sink_new_data_set_name(&sink_new_data
, name
);
973 sink_new_data
.namereg_fail
= namereg_fail
;
974 pa_sink_new_data_set_sample_spec(&sink_new_data
, &ss
);
975 pa_sink_new_data_set_channel_map(&sink_new_data
, &map
);
976 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_STRING
, u
->device_name
);
977 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_API
, "solaris");
978 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Solaris PCM sink");
979 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, "serial");
981 if (pa_modargs_get_proplist(ma
, "sink_properties", sink_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
982 pa_log("Invalid properties");
983 pa_sink_new_data_done(&sink_new_data
);
987 u
->sink
= pa_sink_new(m
->core
, &sink_new_data
, PA_SINK_HARDWARE
|PA_SINK_LATENCY
);
988 pa_sink_new_data_done(&sink_new_data
);
991 u
->sink
->userdata
= u
;
992 u
->sink
->parent
.process_msg
= sink_process_msg
;
994 pa_sink_set_asyncmsgq(u
->sink
, u
->thread_mq
.inq
);
995 pa_sink_set_rtpoll(u
->sink
, u
->rtpoll
);
996 pa_sink_set_fixed_latency(u
->sink
, pa_bytes_to_usec(u
->buffer_size
, &u
->sink
->sample_spec
));
997 pa_sink_set_max_request(u
->sink
, u
->buffer_size
);
998 pa_sink_set_max_rewind(u
->sink
, u
->buffer_size
);
1000 pa_sink_set_get_volume_callback(u
->sink
, sink_get_volume
);
1001 pa_sink_set_set_volume_callback(u
->sink
, sink_set_volume
);
1002 pa_sink_set_get_mute_callback(u
->sink
, sink_get_mute
);
1003 pa_sink_set_set_mute_callback(u
->sink
, sink_set_mute
);
1004 u
->sink
->refresh_volume
= u
->sink
->refresh_muted
= TRUE
;
1008 pa_assert(u
->source
|| u
->sink
);
1010 u
->sig
= pa_signal_new(SIGPOLL
, sig_callback
, u
);
1012 ioctl(u
->fd
, I_SETSIG
, S_MSG
);
1014 pa_log_warn("Could not register SIGPOLL handler");
1016 if (!(u
->thread
= pa_thread_new("solaris", thread_func
, u
))) {
1017 pa_log("Failed to create thread.");
1021 /* Read mixer settings */
1023 if (sink_new_data
.volume_is_set
)
1024 u
->sink
->set_volume(u
->sink
);
1026 u
->sink
->get_volume(u
->sink
);
1028 if (sink_new_data
.muted_is_set
)
1029 u
->sink
->set_mute(u
->sink
);
1031 u
->sink
->get_mute(u
->sink
);
1033 pa_sink_put(u
->sink
);
1037 if (source_new_data
.volume_is_set
)
1038 u
->source
->set_volume(u
->source
);
1040 u
->source
->get_volume(u
->source
);
1042 pa_source_put(u
->source
);
1045 pa_modargs_free(ma
);
1056 pa_modargs_free(ma
);
1061 void pa__done(pa_module
*m
) {
1066 if (!(u
= m
->userdata
))
1070 ioctl(u
->fd
, I_SETSIG
, 0);
1071 pa_signal_free(u
->sig
);
1075 pa_sink_unlink(u
->sink
);
1078 pa_source_unlink(u
->source
);
1081 pa_asyncmsgq_send(u
->thread_mq
.inq
, NULL
, PA_MESSAGE_SHUTDOWN
, NULL
, 0, NULL
);
1082 pa_thread_free(u
->thread
);
1085 pa_thread_mq_done(&u
->thread_mq
);
1088 pa_sink_unref(u
->sink
);
1091 pa_source_unref(u
->source
);
1093 if (u
->memchunk
.memblock
)
1094 pa_memblock_unref(u
->memchunk
.memblock
);
1097 pa_rtpoll_item_free(u
->rtpoll_item
);
1100 pa_rtpoll_free(u
->rtpoll
);
1106 pa_smoother_free(u
->smoother
);
1108 pa_xfree(u
->device_name
);