2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 /* General power management rules:
25 * When SUSPENDED we close the audio device.
27 * We make no difference between IDLE and RUNNING in our handling.
29 * As long as we are in RUNNING/IDLE state we will *always* write data to
30 * the device. If none is available from the inputs, we write silence
33 * If power should be saved on IDLE module-suspend-on-idle should be used.
41 #ifdef HAVE_SYS_MMAN_H
45 #include <sys/soundcard.h>
46 #include <sys/ioctl.h>
53 #include <pulse/xmalloc.h>
54 #include <pulse/util.h>
56 #include <pulsecore/core-error.h>
57 #include <pulsecore/thread.h>
58 #include <pulsecore/sink.h>
59 #include <pulsecore/source.h>
60 #include <pulsecore/module.h>
61 #include <pulsecore/sample-util.h>
62 #include <pulsecore/core-util.h>
63 #include <pulsecore/modargs.h>
64 #include <pulsecore/log.h>
65 #include <pulsecore/macro.h>
66 #include <pulsecore/thread-mq.h>
67 #include <pulsecore/rtpoll.h>
68 #include <pulsecore/poll.h>
70 #if defined(__NetBSD__) && !defined(SNDCTL_DSP_GETODELAY)
71 #include <sys/audioio.h>
72 #include <sys/syscall.h>
76 #include "module-oss-symdef.h"
78 PA_MODULE_AUTHOR("Lennart Poettering");
79 PA_MODULE_DESCRIPTION("OSS Sink/Source");
80 PA_MODULE_VERSION(PACKAGE_VERSION
);
81 PA_MODULE_LOAD_ONCE(FALSE
);
83 "sink_name=<name for the sink> "
84 "sink_properties=<properties for the sink> "
85 "source_name=<name for the source> "
86 "source_properties=<properties for the source> "
87 "device=<OSS device> "
88 "record=<enable source?> "
89 "playback=<enable sink?> "
90 "format=<sample format> "
92 "channels=<number of channels> "
93 "channel_map=<channel map> "
94 "fragments=<number of fragments> "
95 "fragment_size=<fragment size> "
96 "mmap=<enable memory mapping?>");
98 PA_MODULE_DEPRECATED("Please use module-alsa-card instead of module-oss!");
101 #define DEFAULT_DEVICE "/dev/dsp"
110 pa_thread_mq thread_mq
;
115 pa_memchunk memchunk
;
118 uint32_t in_fragment_size
, out_fragment_size
, in_nfrags
, out_nfrags
, in_hwbuf_size
, out_hwbuf_size
;
119 pa_bool_t use_getospace
, use_getispace
;
120 pa_bool_t use_getodelay
;
122 pa_bool_t sink_suspended
, source_suspended
;
130 int nfrags
, frag_size
, orig_frag_size
;
133 unsigned out_mmap_current
, in_mmap_current
;
134 void *in_mmap
, *out_mmap
;
135 pa_memblock
**in_mmap_memblocks
, **out_mmap_memblocks
;
137 int in_mmap_saved_nfrags
, out_mmap_saved_nfrags
;
139 pa_rtpoll_item
*rtpoll_item
;
142 static const char* const valid_modargs
[] = {
160 static int trigger(struct userdata
*u
, pa_bool_t quick
) {
161 int enable_bits
= 0, zero
= 0;
168 pa_log_debug("trigger");
170 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
))
171 enable_bits
|= PCM_ENABLE_INPUT
;
173 if (u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
))
174 enable_bits
|= PCM_ENABLE_OUTPUT
;
176 pa_log_debug("trigger: %i", enable_bits
);
182 ioctl(u
->fd
, SNDCTL_DSP_SETTRIGGER
, &zero
);
184 #ifdef SNDCTL_DSP_HALT
185 if (enable_bits
== 0)
186 if (ioctl(u
->fd
, SNDCTL_DSP_HALT
, NULL
) < 0)
187 pa_log_warn("SNDCTL_DSP_HALT: %s", pa_cstrerror(errno
));
190 if (ioctl(u
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable_bits
) < 0)
191 pa_log_warn("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno
));
193 if (u
->sink
&& !(enable_bits
& PCM_ENABLE_OUTPUT
)) {
194 pa_log_debug("clearing playback buffer");
195 pa_silence_memory(u
->out_mmap
, u
->out_hwbuf_size
, &u
->sink
->sample_spec
);
201 if (ioctl(u
->fd
, SNDCTL_DSP_POST
, NULL
) < 0)
202 pa_log_warn("SNDCTL_DSP_POST: %s", pa_cstrerror(errno
));
206 * Some crappy drivers do not start the recording until we
207 * read something. Without this snippet, poll will never
208 * register the fd as ready.
211 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
)) {
212 uint8_t *buf
= pa_xnew(uint8_t, u
->in_fragment_size
);
214 if (pa_read(u
->fd
, buf
, u
->in_fragment_size
, NULL
) < 0) {
215 pa_log("pa_read() failed: %s", pa_cstrerror(errno
));
228 static void mmap_fill_memblocks(struct userdata
*u
, unsigned n
) {
230 pa_assert(u
->out_mmap_memblocks
);
232 /* pa_log("Mmmap writing %u blocks", n); */
237 if (u
->out_mmap_memblocks
[u
->out_mmap_current
])
238 pa_memblock_unref_fixed(u
->out_mmap_memblocks
[u
->out_mmap_current
]);
240 chunk
.memblock
= u
->out_mmap_memblocks
[u
->out_mmap_current
] =
241 pa_memblock_new_fixed(
243 (uint8_t*) u
->out_mmap
+ u
->out_fragment_size
* u
->out_mmap_current
,
244 u
->out_fragment_size
,
247 chunk
.length
= pa_memblock_get_length(chunk
.memblock
);
250 pa_sink_render_into_full(u
->sink
, &chunk
);
252 u
->out_mmap_current
++;
253 while (u
->out_mmap_current
>= u
->out_nfrags
)
254 u
->out_mmap_current
-= u
->out_nfrags
;
260 static int mmap_write(struct userdata
*u
) {
261 struct count_info info
;
266 /* pa_log("Mmmap writing..."); */
268 if (ioctl(u
->fd
, SNDCTL_DSP_GETOPTR
, &info
) < 0) {
269 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno
));
273 info
.blocks
+= u
->out_mmap_saved_nfrags
;
274 u
->out_mmap_saved_nfrags
= 0;
277 mmap_fill_memblocks(u
, (unsigned) info
.blocks
);
282 static void mmap_post_memblocks(struct userdata
*u
, unsigned n
) {
284 pa_assert(u
->in_mmap_memblocks
);
286 /* pa_log("Mmmap reading %u blocks", n); */
291 if (!u
->in_mmap_memblocks
[u
->in_mmap_current
]) {
293 chunk
.memblock
= u
->in_mmap_memblocks
[u
->in_mmap_current
] =
294 pa_memblock_new_fixed(
296 (uint8_t*) u
->in_mmap
+ u
->in_fragment_size
*u
->in_mmap_current
,
300 chunk
.length
= pa_memblock_get_length(chunk
.memblock
);
303 pa_source_post(u
->source
, &chunk
);
306 u
->in_mmap_current
++;
307 while (u
->in_mmap_current
>= u
->in_nfrags
)
308 u
->in_mmap_current
-= u
->in_nfrags
;
314 static void mmap_clear_memblocks(struct userdata
*u
, unsigned n
) {
315 unsigned i
= u
->in_mmap_current
;
318 pa_assert(u
->in_mmap_memblocks
);
320 if (n
> u
->in_nfrags
)
324 if (u
->in_mmap_memblocks
[i
]) {
325 pa_memblock_unref_fixed(u
->in_mmap_memblocks
[i
]);
326 u
->in_mmap_memblocks
[i
] = NULL
;
330 while (i
>= u
->in_nfrags
)
337 static int mmap_read(struct userdata
*u
) {
338 struct count_info info
;
340 pa_assert(u
->source
);
342 /* pa_log("Mmmap reading..."); */
344 if (ioctl(u
->fd
, SNDCTL_DSP_GETIPTR
, &info
) < 0) {
345 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno
));
349 /* pa_log("... %i", info.blocks); */
351 info
.blocks
+= u
->in_mmap_saved_nfrags
;
352 u
->in_mmap_saved_nfrags
= 0;
354 if (info
.blocks
> 0) {
355 mmap_post_memblocks(u
, (unsigned) info
.blocks
);
356 mmap_clear_memblocks(u
, u
->in_nfrags
/2);
362 static pa_usec_t
mmap_sink_get_latency(struct userdata
*u
) {
363 struct count_info info
;
368 if (ioctl(u
->fd
, SNDCTL_DSP_GETOPTR
, &info
) < 0) {
369 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno
));
373 u
->out_mmap_saved_nfrags
+= info
.blocks
;
375 bpos
= ((u
->out_mmap_current
+ (unsigned) u
->out_mmap_saved_nfrags
) * u
->out_fragment_size
) % u
->out_hwbuf_size
;
377 if (bpos
<= (size_t) info
.ptr
)
378 n
= u
->out_hwbuf_size
- ((size_t) info
.ptr
- bpos
);
380 n
= bpos
- (size_t) info
.ptr
;
382 /* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->out_fragment_size, u->out_fragments); */
384 return pa_bytes_to_usec(n
, &u
->sink
->sample_spec
);
387 static pa_usec_t
mmap_source_get_latency(struct userdata
*u
) {
388 struct count_info info
;
393 if (ioctl(u
->fd
, SNDCTL_DSP_GETIPTR
, &info
) < 0) {
394 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno
));
398 u
->in_mmap_saved_nfrags
+= info
.blocks
;
399 bpos
= ((u
->in_mmap_current
+ (unsigned) u
->in_mmap_saved_nfrags
) * u
->in_fragment_size
) % u
->in_hwbuf_size
;
401 if (bpos
<= (size_t) info
.ptr
)
402 n
= (size_t) info
.ptr
- bpos
;
404 n
= u
->in_hwbuf_size
- bpos
+ (size_t) info
.ptr
;
406 /* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->in_fragment_size, u->in_fragments); */
408 return pa_bytes_to_usec(n
, &u
->source
->sample_spec
);
411 static pa_usec_t
io_sink_get_latency(struct userdata
*u
) {
416 if (u
->use_getodelay
) {
418 #if defined(__NetBSD__) && !defined(SNDCTL_DSP_GETODELAY)
419 #if defined(AUDIO_GETBUFINFO)
420 struct audio_info info
;
421 if (syscall(SYS_ioctl
, u
->fd
, AUDIO_GETBUFINFO
, &info
) < 0) {
422 pa_log_info("Device doesn't support AUDIO_GETBUFINFO: %s", pa_cstrerror(errno
));
423 u
->use_getodelay
= 0;
425 arg
= info
.play
.seek
+ info
.blocksize
/ 2;
426 r
= pa_bytes_to_usec((size_t) arg
, &u
->sink
->sample_spec
);
429 pa_log_info("System doesn't support AUDIO_GETBUFINFO");
430 u
->use_getodelay
= 0;
433 if (ioctl(u
->fd
, SNDCTL_DSP_GETODELAY
, &arg
) < 0) {
434 pa_log_info("Device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno
));
435 u
->use_getodelay
= 0;
437 r
= pa_bytes_to_usec((size_t) arg
, &u
->sink
->sample_spec
);
441 if (!u
->use_getodelay
&& u
->use_getospace
) {
442 struct audio_buf_info info
;
444 if (ioctl(u
->fd
, SNDCTL_DSP_GETOSPACE
, &info
) < 0) {
445 pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno
));
446 u
->use_getospace
= 0;
448 r
= pa_bytes_to_usec((size_t) info
.bytes
, &u
->sink
->sample_spec
);
451 if (u
->memchunk
.memblock
)
452 r
+= pa_bytes_to_usec(u
->memchunk
.length
, &u
->sink
->sample_spec
);
457 static pa_usec_t
io_source_get_latency(struct userdata
*u
) {
462 if (u
->use_getispace
) {
463 struct audio_buf_info info
;
465 if (ioctl(u
->fd
, SNDCTL_DSP_GETISPACE
, &info
) < 0) {
466 pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno
));
467 u
->use_getispace
= 0;
469 r
= pa_bytes_to_usec((size_t) info
.bytes
, &u
->source
->sample_spec
);
475 static void build_pollfd(struct userdata
*u
) {
476 struct pollfd
*pollfd
;
479 pa_assert(u
->fd
>= 0);
482 pa_rtpoll_item_free(u
->rtpoll_item
);
484 u
->rtpoll_item
= pa_rtpoll_item_new(u
->rtpoll
, PA_RTPOLL_NEVER
, 1);
485 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
491 /* Called from IO context */
492 static int suspend(struct userdata
*u
) {
494 pa_assert(u
->fd
>= 0);
496 pa_log_info("Suspending...");
498 if (u
->out_mmap_memblocks
) {
500 for (i
= 0; i
< u
->out_nfrags
; i
++)
501 if (u
->out_mmap_memblocks
[i
]) {
502 pa_memblock_unref_fixed(u
->out_mmap_memblocks
[i
]);
503 u
->out_mmap_memblocks
[i
] = NULL
;
507 if (u
->in_mmap_memblocks
) {
509 for (i
= 0; i
< u
->in_nfrags
; i
++)
510 if (u
->in_mmap_memblocks
[i
]) {
511 pa_memblock_unref_fixed(u
->in_mmap_memblocks
[i
]);
512 u
->in_mmap_memblocks
[i
] = NULL
;
516 if (u
->in_mmap
&& u
->in_mmap
!= MAP_FAILED
) {
517 munmap(u
->in_mmap
, u
->in_hwbuf_size
);
521 if (u
->out_mmap
&& u
->out_mmap
!= MAP_FAILED
) {
522 munmap(u
->out_mmap
, u
->out_hwbuf_size
);
527 ioctl(u
->fd
, SNDCTL_DSP_SYNC
, NULL
);
531 if (u
->rtpoll_item
) {
532 pa_rtpoll_item_free(u
->rtpoll_item
);
533 u
->rtpoll_item
= NULL
;
536 pa_log_info("Device suspended...");
541 /* Called from IO context */
542 static int unsuspend(struct userdata
*u
) {
544 pa_sample_spec ss
, *ss_original
;
545 int frag_size
, in_frag_size
, out_frag_size
;
546 int in_nfrags
, out_nfrags
;
547 struct audio_buf_info info
;
550 pa_assert(u
->fd
< 0);
554 pa_log_info("Trying resume...");
556 if ((u
->fd
= pa_oss_open(u
->device_name
, &m
, NULL
)) < 0) {
557 pa_log_warn("Resume failed, device busy (%s)", pa_cstrerror(errno
));
562 pa_log_warn("Resume failed, couldn't open device with original access mode.");
566 if (u
->nfrags
>= 2 && u
->frag_size
>= 1)
567 if (pa_oss_set_fragments(u
->fd
, u
->nfrags
, u
->orig_frag_size
) < 0) {
568 pa_log_warn("Resume failed, couldn't set original fragment settings.");
572 ss
= *(ss_original
= u
->sink
? &u
->sink
->sample_spec
: &u
->source
->sample_spec
);
573 if (pa_oss_auto_format(u
->fd
, &ss
) < 0 || !pa_sample_spec_equal(&ss
, ss_original
)) {
574 pa_log_warn("Resume failed, couldn't set original sample format settings.");
578 if (ioctl(u
->fd
, SNDCTL_DSP_GETBLKSIZE
, &frag_size
) < 0) {
579 pa_log_warn("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno
));
583 in_frag_size
= out_frag_size
= frag_size
;
584 in_nfrags
= out_nfrags
= u
->nfrags
;
586 if (ioctl(u
->fd
, SNDCTL_DSP_GETISPACE
, &info
) >= 0) {
587 in_frag_size
= info
.fragsize
;
588 in_nfrags
= info
.fragstotal
;
591 if (ioctl(u
->fd
, SNDCTL_DSP_GETOSPACE
, &info
) >= 0) {
592 out_frag_size
= info
.fragsize
;
593 out_nfrags
= info
.fragstotal
;
596 if ((u
->source
&& (in_frag_size
!= (int) u
->in_fragment_size
|| in_nfrags
!= (int) u
->in_nfrags
)) ||
597 (u
->sink
&& (out_frag_size
!= (int) u
->out_fragment_size
|| out_nfrags
!= (int) u
->out_nfrags
))) {
598 pa_log_warn("Resume failed, input fragment settings don't match.");
604 if ((u
->in_mmap
= mmap(NULL
, u
->in_hwbuf_size
, PROT_READ
, MAP_SHARED
, u
->fd
, 0)) == MAP_FAILED
) {
605 pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno
));
611 if ((u
->out_mmap
= mmap(NULL
, u
->out_hwbuf_size
, PROT_WRITE
, MAP_SHARED
, u
->fd
, 0)) == MAP_FAILED
) {
612 pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno
));
613 if (u
->in_mmap
&& u
->in_mmap
!= MAP_FAILED
) {
614 munmap(u
->in_mmap
, u
->in_hwbuf_size
);
621 pa_silence_memory(u
->out_mmap
, u
->out_hwbuf_size
, &ss
);
625 u
->out_mmap_current
= u
->in_mmap_current
= 0;
626 u
->out_mmap_saved_nfrags
= u
->in_mmap_saved_nfrags
= 0;
628 pa_assert(!u
->rtpoll_item
);
632 if (u
->sink
&& u
->sink
->get_volume
)
633 u
->sink
->get_volume(u
->sink
);
634 if (u
->source
&& u
->source
->get_volume
)
635 u
->source
->get_volume(u
->source
);
637 pa_log_info("Resumed successfully...");
647 /* Called from IO context */
648 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
649 struct userdata
*u
= PA_SINK(o
)->userdata
;
651 pa_bool_t do_trigger
= FALSE
, quick
= TRUE
;
655 case PA_SINK_MESSAGE_GET_LATENCY
: {
660 r
= mmap_sink_get_latency(u
);
662 r
= io_sink_get_latency(u
);
665 *((pa_usec_t
*) data
) = r
;
670 case PA_SINK_MESSAGE_SET_STATE
:
672 switch ((pa_sink_state_t
) PA_PTR_TO_UINT(data
)) {
674 case PA_SINK_SUSPENDED
:
675 pa_assert(PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
));
677 if (!u
->source
|| u
->source_suspended
) {
684 u
->sink_suspended
= TRUE
;
688 case PA_SINK_RUNNING
:
690 if (u
->sink
->thread_info
.state
== PA_SINK_INIT
) {
692 quick
= u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
);
695 if (u
->sink
->thread_info
.state
== PA_SINK_SUSPENDED
) {
697 if (!u
->source
|| u
->source_suspended
) {
698 if (unsuspend(u
) < 0)
705 u
->out_mmap_current
= 0;
706 u
->out_mmap_saved_nfrags
= 0;
708 u
->sink_suspended
= FALSE
;
713 case PA_SINK_INVALID_STATE
:
714 case PA_SINK_UNLINKED
:
723 ret
= pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
725 if (ret
>= 0 && do_trigger
) {
726 if (trigger(u
, quick
) < 0)
733 static int source_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
734 struct userdata
*u
= PA_SOURCE(o
)->userdata
;
736 int do_trigger
= FALSE
, quick
= TRUE
;
740 case PA_SOURCE_MESSAGE_GET_LATENCY
: {
745 r
= mmap_source_get_latency(u
);
747 r
= io_source_get_latency(u
);
750 *((pa_usec_t
*) data
) = r
;
754 case PA_SOURCE_MESSAGE_SET_STATE
:
756 switch ((pa_source_state_t
) PA_PTR_TO_UINT(data
)) {
757 case PA_SOURCE_SUSPENDED
:
758 pa_assert(PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
));
760 if (!u
->sink
|| u
->sink_suspended
) {
767 u
->source_suspended
= TRUE
;
771 case PA_SOURCE_RUNNING
:
773 if (u
->source
->thread_info
.state
== PA_SOURCE_INIT
) {
775 quick
= u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
);
778 if (u
->source
->thread_info
.state
== PA_SOURCE_SUSPENDED
) {
780 if (!u
->sink
|| u
->sink_suspended
) {
781 if (unsuspend(u
) < 0)
788 u
->in_mmap_current
= 0;
789 u
->in_mmap_saved_nfrags
= 0;
791 u
->source_suspended
= FALSE
;
795 case PA_SOURCE_UNLINKED
:
797 case PA_SOURCE_INVALID_STATE
:
805 ret
= pa_source_process_msg(o
, code
, data
, offset
, chunk
);
807 if (ret
>= 0 && do_trigger
) {
808 if (trigger(u
, quick
) < 0)
815 static void sink_get_volume(pa_sink
*s
) {
818 pa_assert_se(u
= s
->userdata
);
820 pa_assert(u
->mixer_devmask
& (SOUND_MASK_VOLUME
|SOUND_MASK_PCM
));
822 if (u
->mixer_devmask
& SOUND_MASK_VOLUME
)
823 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_READ_VOLUME
, &s
->sample_spec
, &s
->real_volume
) >= 0)
826 if (u
->mixer_devmask
& SOUND_MASK_PCM
)
827 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_READ_PCM
, &s
->sample_spec
, &s
->real_volume
) >= 0)
830 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno
));
833 static void sink_set_volume(pa_sink
*s
) {
836 pa_assert_se(u
= s
->userdata
);
838 pa_assert(u
->mixer_devmask
& (SOUND_MASK_VOLUME
|SOUND_MASK_PCM
));
840 if (u
->mixer_devmask
& SOUND_MASK_VOLUME
)
841 if (pa_oss_set_volume(u
->mixer_fd
, SOUND_MIXER_WRITE_VOLUME
, &s
->sample_spec
, &s
->real_volume
) >= 0)
844 if (u
->mixer_devmask
& SOUND_MASK_PCM
)
845 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_WRITE_PCM
, &s
->sample_spec
, &s
->real_volume
) >= 0)
848 pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno
));
851 static void source_get_volume(pa_source
*s
) {
854 pa_assert_se(u
= s
->userdata
);
856 pa_assert(u
->mixer_devmask
& (SOUND_MASK_IGAIN
|SOUND_MASK_RECLEV
));
858 if (u
->mixer_devmask
& SOUND_MASK_IGAIN
)
859 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_READ_IGAIN
, &s
->sample_spec
, &s
->real_volume
) >= 0)
862 if (u
->mixer_devmask
& SOUND_MASK_RECLEV
)
863 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_READ_RECLEV
, &s
->sample_spec
, &s
->real_volume
) >= 0)
866 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno
));
869 static void source_set_volume(pa_source
*s
) {
872 pa_assert_se(u
= s
->userdata
);
874 pa_assert(u
->mixer_devmask
& (SOUND_MASK_IGAIN
|SOUND_MASK_RECLEV
));
876 if (u
->mixer_devmask
& SOUND_MASK_IGAIN
)
877 if (pa_oss_set_volume(u
->mixer_fd
, SOUND_MIXER_WRITE_IGAIN
, &s
->sample_spec
, &s
->real_volume
) >= 0)
880 if (u
->mixer_devmask
& SOUND_MASK_RECLEV
)
881 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_WRITE_RECLEV
, &s
->sample_spec
, &s
->real_volume
) >= 0)
884 pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno
));
887 static void thread_func(void *userdata
) {
888 struct userdata
*u
= userdata
;
889 int write_type
= 0, read_type
= 0;
894 pa_log_debug("Thread starting up");
896 if (u
->core
->realtime_scheduling
)
897 pa_make_realtime(u
->core
->realtime_priority
);
899 pa_thread_mq_install(&u
->thread_mq
);
904 /* pa_log("loop"); */
906 if (PA_UNLIKELY(u
->sink
&& u
->sink
->thread_info
.rewind_requested
))
907 pa_sink_process_rewind(u
->sink
, 0);
909 /* Render some data and write it to the dsp */
911 if (u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
) && ((revents
& POLLOUT
) || u
->use_mmap
|| u
->use_getospace
)) {
915 if ((ret
= mmap_write(u
)) < 0)
925 pa_bool_t loop
= FALSE
, work_done
= FALSE
;
927 l
= (ssize_t
) u
->out_fragment_size
;
929 if (u
->use_getospace
) {
932 if (ioctl(u
->fd
, SNDCTL_DSP_GETOSPACE
, &info
) < 0) {
933 pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno
));
934 u
->use_getospace
= FALSE
;
938 /* We loop only if GETOSPACE worked and we
939 * actually *know* that we can write more than
940 * one fragment at a time */
945 /* Round down to multiples of the fragment size,
946 * because OSS needs that (at least some versions
948 l
= (l
/(ssize_t
) u
->out_fragment_size
) * (ssize_t
) u
->out_fragment_size
;
950 /* Hmm, so poll() signalled us that we can read
951 * something, but GETOSPACE told us there was nothing?
952 * Hmm, make the best of it, try to read some data, to
953 * avoid spinning forever. */
954 if (l
<= 0 && (revents
& POLLOUT
)) {
955 l
= (ssize_t
) u
->out_fragment_size
;
963 if (u
->memchunk
.length
<= 0)
964 pa_sink_render(u
->sink
, (size_t) l
, &u
->memchunk
);
966 pa_assert(u
->memchunk
.length
> 0);
968 p
= pa_memblock_acquire(u
->memchunk
.memblock
);
969 t
= pa_write(u
->fd
, (uint8_t*) p
+ u
->memchunk
.index
, u
->memchunk
.length
, &write_type
);
970 pa_memblock_release(u
->memchunk
.memblock
);
972 /* pa_log("wrote %i bytes of %u", t, l); */
981 else if (errno
== EAGAIN
) {
982 pa_log_debug("EAGAIN");
988 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno
));
994 u
->memchunk
.index
+= (size_t) t
;
995 u
->memchunk
.length
-= (size_t) t
;
997 if (u
->memchunk
.length
<= 0) {
998 pa_memblock_unref(u
->memchunk
.memblock
);
999 pa_memchunk_reset(&u
->memchunk
);
1004 revents
&= ~POLLOUT
;
1017 /* Try to read some data and pass it on to the source driver. */
1019 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
) && ((revents
& POLLIN
) || u
->use_mmap
|| u
->use_getispace
)) {
1023 if ((ret
= mmap_read(u
)) < 0)
1035 pa_memchunk memchunk
;
1036 pa_bool_t loop
= FALSE
, work_done
= FALSE
;
1038 l
= (ssize_t
) u
->in_fragment_size
;
1040 if (u
->use_getispace
) {
1041 audio_buf_info info
;
1043 if (ioctl(u
->fd
, SNDCTL_DSP_GETISPACE
, &info
) < 0) {
1044 pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno
));
1045 u
->use_getispace
= FALSE
;
1052 l
= (l
/(ssize_t
) u
->in_fragment_size
) * (ssize_t
) u
->in_fragment_size
;
1054 if (l
<= 0 && (revents
& POLLIN
)) {
1055 l
= (ssize_t
) u
->in_fragment_size
;
1065 memchunk
.memblock
= pa_memblock_new(u
->core
->mempool
, (size_t) -1);
1067 k
= pa_memblock_get_length(memchunk
.memblock
);
1072 k
= (k
/u
->frame_size
)*u
->frame_size
;
1074 p
= pa_memblock_acquire(memchunk
.memblock
);
1075 t
= pa_read(u
->fd
, p
, k
, &read_type
);
1076 pa_memblock_release(memchunk
.memblock
);
1078 pa_assert(t
!= 0); /* EOF cannot happen */
1080 /* pa_log("read %i bytes of %u", t, l); */
1083 pa_memblock_unref(memchunk
.memblock
);
1088 else if (errno
== EAGAIN
) {
1089 pa_log_debug("EAGAIN");
1095 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno
));
1101 memchunk
.length
= (size_t) t
;
1103 pa_source_post(u
->source
, &memchunk
);
1104 pa_memblock_unref(memchunk
.memblock
);
1121 /* pa_log("loop2 revents=%i", revents); */
1123 if (u
->rtpoll_item
) {
1124 struct pollfd
*pollfd
;
1126 pa_assert(u
->fd
>= 0);
1128 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
1129 pollfd
->events
= (short)
1130 (((u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
)) ? POLLIN
: 0) |
1131 ((u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
)) ? POLLOUT
: 0));
1134 /* Hmm, nothing to do. Let's sleep */
1135 if ((ret
= pa_rtpoll_run(u
->rtpoll
, TRUE
)) < 0)
1141 if (u
->rtpoll_item
) {
1142 struct pollfd
*pollfd
;
1144 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
1146 if (pollfd
->revents
& ~(POLLOUT
|POLLIN
)) {
1147 pa_log("DSP shutdown.");
1151 revents
= pollfd
->revents
;
1157 /* If this was no regular exit from the loop we have to continue
1158 * processing messages until we received PA_MESSAGE_SHUTDOWN */
1159 pa_asyncmsgq_post(u
->thread_mq
.outq
, PA_MSGOBJECT(u
->core
), PA_CORE_MESSAGE_UNLOAD_MODULE
, u
->module
, 0, NULL
, NULL
);
1160 pa_asyncmsgq_wait_for(u
->thread_mq
.inq
, PA_MESSAGE_SHUTDOWN
);
1163 pa_log_debug("Thread shutting down");
1166 int pa__init(pa_module
*m
) {
1168 struct audio_buf_info info
;
1169 struct userdata
*u
= NULL
;
1172 int nfrags
, orig_frag_size
, frag_size
;
1174 pa_bool_t record
= TRUE
, playback
= TRUE
, use_mmap
= TRUE
;
1177 pa_modargs
*ma
= NULL
;
1180 pa_bool_t namereg_fail
;
1181 pa_sink_new_data sink_new_data
;
1182 pa_source_new_data source_new_data
;
1186 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
1187 pa_log("Failed to parse module arguments.");
1191 if (pa_modargs_get_value_boolean(ma
, "record", &record
) < 0 || pa_modargs_get_value_boolean(ma
, "playback", &playback
) < 0) {
1192 pa_log("record= and playback= expect boolean argument.");
1196 if (!playback
&& !record
) {
1197 pa_log("Neither playback nor record enabled for device.");
1201 mode
= (playback
&& record
) ? O_RDWR
: (playback
? O_WRONLY
: (record
? O_RDONLY
: 0));
1203 ss
= m
->core
->default_sample_spec
;
1204 map
= m
->core
->default_channel_map
;
1205 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_OSS
) < 0) {
1206 pa_log("Failed to parse sample specification or channel map");
1210 nfrags
= (int) m
->core
->default_n_fragments
;
1211 frag_size
= (int) pa_usec_to_bytes(m
->core
->default_fragment_size_msec
*1000, &ss
);
1213 frag_size
= (int) pa_frame_size(&ss
);
1215 if (pa_modargs_get_value_s32(ma
, "fragments", &nfrags
) < 0 || pa_modargs_get_value_s32(ma
, "fragment_size", &frag_size
) < 0) {
1216 pa_log("Failed to parse fragments arguments");
1220 if (pa_modargs_get_value_boolean(ma
, "mmap", &use_mmap
) < 0) {
1221 pa_log("Failed to parse mmap argument.");
1225 if ((fd
= pa_oss_open(dev
= pa_modargs_get_value(ma
, "device", DEFAULT_DEVICE
), &mode
, &caps
)) < 0)
1228 if (use_mmap
&& (!(caps
& DSP_CAP_MMAP
) || !(caps
& DSP_CAP_TRIGGER
))) {
1229 pa_log_info("OSS device not mmap capable, falling back to UNIX read/write mode.");
1233 if (use_mmap
&& mode
== O_WRONLY
) {
1234 pa_log_info("Device opened for playback only, cannot do memory mapping, falling back to UNIX write() mode.");
1238 if (pa_oss_get_hw_description(dev
, hwdesc
, sizeof(hwdesc
)) >= 0)
1239 pa_log_info("Hardware name is '%s'.", hwdesc
);
1243 pa_log_info("Device opened in %s mode.", mode
== O_WRONLY
? "O_WRONLY" : (mode
== O_RDONLY
? "O_RDONLY" : "O_RDWR"));
1245 orig_frag_size
= frag_size
;
1246 if (nfrags
>= 2 && frag_size
>= 1)
1247 if (pa_oss_set_fragments(fd
, nfrags
, frag_size
) < 0)
1250 if (pa_oss_auto_format(fd
, &ss
) < 0)
1253 if (ioctl(fd
, SNDCTL_DSP_GETBLKSIZE
, &frag_size
) < 0) {
1254 pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno
));
1257 pa_assert(frag_size
> 0);
1259 u
= pa_xnew0(struct userdata
, 1);
1265 u
->mixer_devmask
= 0;
1266 u
->use_getospace
= u
->use_getispace
= TRUE
;
1267 u
->use_getodelay
= TRUE
;
1269 u
->frame_size
= pa_frame_size(&ss
);
1270 u
->device_name
= pa_xstrdup(dev
);
1271 u
->in_nfrags
= u
->out_nfrags
= (uint32_t) (u
->nfrags
= nfrags
);
1272 u
->out_fragment_size
= u
->in_fragment_size
= (uint32_t) (u
->frag_size
= frag_size
);
1273 u
->orig_frag_size
= orig_frag_size
;
1274 u
->use_mmap
= use_mmap
;
1275 u
->rtpoll
= pa_rtpoll_new();
1276 pa_thread_mq_init(&u
->thread_mq
, m
->core
->mainloop
, u
->rtpoll
);
1277 u
->rtpoll_item
= NULL
;
1280 if (ioctl(fd
, SNDCTL_DSP_GETISPACE
, &info
) >= 0) {
1281 pa_log_info("Input -- %u fragments of size %u.", info
.fragstotal
, info
.fragsize
);
1282 u
->in_fragment_size
= (uint32_t) info
.fragsize
;
1283 u
->in_nfrags
= (uint32_t) info
.fragstotal
;
1284 u
->use_getispace
= TRUE
;
1287 if (ioctl(fd
, SNDCTL_DSP_GETOSPACE
, &info
) >= 0) {
1288 pa_log_info("Output -- %u fragments of size %u.", info
.fragstotal
, info
.fragsize
);
1289 u
->out_fragment_size
= (uint32_t) info
.fragsize
;
1290 u
->out_nfrags
= (uint32_t) info
.fragstotal
;
1291 u
->use_getospace
= TRUE
;
1294 u
->in_hwbuf_size
= u
->in_nfrags
* u
->in_fragment_size
;
1295 u
->out_hwbuf_size
= u
->out_nfrags
* u
->out_fragment_size
;
1297 if (mode
!= O_WRONLY
) {
1298 char *name_buf
= NULL
;
1301 if ((u
->in_mmap
= mmap(NULL
, u
->in_hwbuf_size
, PROT_READ
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
1302 pa_log_warn("mmap(PROT_READ) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno
));
1303 use_mmap
= u
->use_mmap
= FALSE
;
1306 pa_log_debug("Successfully mmap()ed input buffer.");
1309 if ((name
= pa_modargs_get_value(ma
, "source_name", NULL
)))
1310 namereg_fail
= TRUE
;
1312 name
= name_buf
= pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(dev
));
1313 namereg_fail
= FALSE
;
1316 pa_source_new_data_init(&source_new_data
);
1317 source_new_data
.driver
= __FILE__
;
1318 source_new_data
.module
= m
;
1319 pa_source_new_data_set_name(&source_new_data
, name
);
1320 source_new_data
.namereg_fail
= namereg_fail
;
1321 pa_source_new_data_set_sample_spec(&source_new_data
, &ss
);
1322 pa_source_new_data_set_channel_map(&source_new_data
, &map
);
1323 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_STRING
, dev
);
1324 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_API
, "oss");
1325 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, hwdesc
[0] ? hwdesc
: dev
);
1326 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, use_mmap
? "mmap" : "serial");
1327 pa_proplist_setf(source_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE
, "%lu", (unsigned long) (u
->in_hwbuf_size
));
1328 pa_proplist_setf(source_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE
, "%lu", (unsigned long) (u
->in_fragment_size
));
1330 if (pa_modargs_get_proplist(ma
, "source_properties", source_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
1331 pa_log("Invalid properties");
1332 pa_source_new_data_done(&source_new_data
);
1336 u
->source
= pa_source_new(m
->core
, &source_new_data
, PA_SOURCE_HARDWARE
|PA_SOURCE_LATENCY
);
1337 pa_source_new_data_done(&source_new_data
);
1341 pa_log("Failed to create source object");
1345 u
->source
->parent
.process_msg
= source_process_msg
;
1346 u
->source
->userdata
= u
;
1348 pa_source_set_asyncmsgq(u
->source
, u
->thread_mq
.inq
);
1349 pa_source_set_rtpoll(u
->source
, u
->rtpoll
);
1350 pa_source_set_fixed_latency(u
->source
, pa_bytes_to_usec(u
->in_hwbuf_size
, &u
->source
->sample_spec
));
1351 u
->source
->refresh_volume
= TRUE
;
1354 u
->in_mmap_memblocks
= pa_xnew0(pa_memblock
*, u
->in_nfrags
);
1357 if (mode
!= O_RDONLY
) {
1358 char *name_buf
= NULL
;
1361 if ((u
->out_mmap
= mmap(NULL
, u
->out_hwbuf_size
, PROT_WRITE
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
1362 if (mode
== O_RDWR
) {
1363 pa_log_debug("mmap() failed for input. Changing to O_WRONLY mode.");
1367 pa_log_warn("mmap(PROT_WRITE) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno
));
1368 u
->use_mmap
= use_mmap
= FALSE
;
1372 pa_log_debug("Successfully mmap()ed output buffer.");
1373 pa_silence_memory(u
->out_mmap
, u
->out_hwbuf_size
, &ss
);
1377 if ((name
= pa_modargs_get_value(ma
, "sink_name", NULL
)))
1378 namereg_fail
= TRUE
;
1380 name
= name_buf
= pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(dev
));
1381 namereg_fail
= FALSE
;
1384 pa_sink_new_data_init(&sink_new_data
);
1385 sink_new_data
.driver
= __FILE__
;
1386 sink_new_data
.module
= m
;
1387 pa_sink_new_data_set_name(&sink_new_data
, name
);
1388 sink_new_data
.namereg_fail
= namereg_fail
;
1389 pa_sink_new_data_set_sample_spec(&sink_new_data
, &ss
);
1390 pa_sink_new_data_set_channel_map(&sink_new_data
, &map
);
1391 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_STRING
, dev
);
1392 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_API
, "oss");
1393 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, hwdesc
[0] ? hwdesc
: dev
);
1394 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, use_mmap
? "mmap" : "serial");
1395 pa_proplist_setf(sink_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE
, "%lu", (unsigned long) (u
->out_hwbuf_size
));
1396 pa_proplist_setf(sink_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE
, "%lu", (unsigned long) (u
->out_fragment_size
));
1398 if (pa_modargs_get_proplist(ma
, "sink_properties", sink_new_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
1399 pa_log("Invalid properties");
1400 pa_sink_new_data_done(&sink_new_data
);
1404 u
->sink
= pa_sink_new(m
->core
, &sink_new_data
, PA_SINK_HARDWARE
|PA_SINK_LATENCY
);
1405 pa_sink_new_data_done(&sink_new_data
);
1409 pa_log("Failed to create sink object");
1413 u
->sink
->parent
.process_msg
= sink_process_msg
;
1414 u
->sink
->userdata
= u
;
1416 pa_sink_set_asyncmsgq(u
->sink
, u
->thread_mq
.inq
);
1417 pa_sink_set_rtpoll(u
->sink
, u
->rtpoll
);
1418 pa_sink_set_fixed_latency(u
->sink
, pa_bytes_to_usec(u
->out_hwbuf_size
, &u
->sink
->sample_spec
));
1419 u
->sink
->refresh_volume
= TRUE
;
1421 pa_sink_set_max_request(u
->sink
, u
->out_hwbuf_size
);
1424 u
->out_mmap_memblocks
= pa_xnew0(pa_memblock
*, u
->out_nfrags
);
1427 if ((u
->mixer_fd
= pa_oss_open_mixer_for_device(u
->device_name
)) >= 0) {
1428 pa_bool_t do_close
= TRUE
;
1430 if (ioctl(fd
, SOUND_MIXER_READ_DEVMASK
, &u
->mixer_devmask
) < 0)
1431 pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno
));
1433 if (u
->sink
&& (u
->mixer_devmask
& (SOUND_MASK_VOLUME
|SOUND_MASK_PCM
))) {
1434 pa_log_debug("Found hardware mixer track for playback.");
1435 pa_sink_set_get_volume_callback(u
->sink
, sink_get_volume
);
1436 pa_sink_set_set_volume_callback(u
->sink
, sink_set_volume
);
1437 u
->sink
->n_volume_steps
= 101;
1441 if (u
->source
&& (u
->mixer_devmask
& (SOUND_MASK_RECLEV
|SOUND_MASK_IGAIN
))) {
1442 pa_log_debug("Found hardware mixer track for recording.");
1443 pa_source_set_get_volume_callback(u
->source
, source_get_volume
);
1444 pa_source_set_set_volume_callback(u
->source
, source_set_volume
);
1445 u
->source
->n_volume_steps
= 101;
1451 pa_close(u
->mixer_fd
);
1453 u
->mixer_devmask
= 0;
1459 pa_assert(u
->source
|| u
->sink
);
1461 pa_memchunk_reset(&u
->memchunk
);
1463 if (!(u
->thread
= pa_thread_new("oss", thread_func
, u
))) {
1464 pa_log("Failed to create thread.");
1468 /* Read mixer settings */
1470 if (sink_new_data
.volume_is_set
) {
1471 if (u
->sink
->set_volume
)
1472 u
->sink
->set_volume(u
->sink
);
1474 if (u
->sink
->get_volume
)
1475 u
->sink
->get_volume(u
->sink
);
1480 if (source_new_data
.volume_is_set
) {
1481 if (u
->source
->set_volume
)
1482 u
->source
->set_volume(u
->source
);
1484 if (u
->source
->get_volume
)
1485 u
->source
->get_volume(u
->source
);
1490 pa_sink_put(u
->sink
);
1492 pa_source_put(u
->source
);
1494 pa_modargs_free(ma
);
1506 pa_modargs_free(ma
);
1511 void pa__done(pa_module
*m
) {
1516 if (!(u
= m
->userdata
))
1520 pa_sink_unlink(u
->sink
);
1523 pa_source_unlink(u
->source
);
1526 pa_asyncmsgq_send(u
->thread_mq
.inq
, NULL
, PA_MESSAGE_SHUTDOWN
, NULL
, 0, NULL
);
1527 pa_thread_free(u
->thread
);
1530 pa_thread_mq_done(&u
->thread_mq
);
1533 pa_sink_unref(u
->sink
);
1536 pa_source_unref(u
->source
);
1538 if (u
->memchunk
.memblock
)
1539 pa_memblock_unref(u
->memchunk
.memblock
);
1542 pa_rtpoll_item_free(u
->rtpoll_item
);
1545 pa_rtpoll_free(u
->rtpoll
);
1547 if (u
->out_mmap_memblocks
) {
1549 for (i
= 0; i
< u
->out_nfrags
; i
++)
1550 if (u
->out_mmap_memblocks
[i
])
1551 pa_memblock_unref_fixed(u
->out_mmap_memblocks
[i
]);
1552 pa_xfree(u
->out_mmap_memblocks
);
1555 if (u
->in_mmap_memblocks
) {
1557 for (i
= 0; i
< u
->in_nfrags
; i
++)
1558 if (u
->in_mmap_memblocks
[i
])
1559 pa_memblock_unref_fixed(u
->in_mmap_memblocks
[i
]);
1560 pa_xfree(u
->in_mmap_memblocks
);
1563 if (u
->in_mmap
&& u
->in_mmap
!= MAP_FAILED
)
1564 munmap(u
->in_mmap
, u
->in_hwbuf_size
);
1566 if (u
->out_mmap
&& u
->out_mmap
!= MAP_FAILED
)
1567 munmap(u
->out_mmap
, u
->out_hwbuf_size
);
1572 if (u
->mixer_fd
>= 0)
1573 pa_close(u
->mixer_fd
);
1575 pa_xfree(u
->device_name
);