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 avilable 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>
58 #include <pulse/xmalloc.h>
59 #include <pulse/util.h>
61 #include <pulsecore/core-error.h>
62 #include <pulsecore/thread.h>
63 #include <pulsecore/sink.h>
64 #include <pulsecore/source.h>
65 #include <pulsecore/module.h>
66 #include <pulsecore/sample-util.h>
67 #include <pulsecore/core-util.h>
68 #include <pulsecore/modargs.h>
69 #include <pulsecore/log.h>
70 #include <pulsecore/macro.h>
71 #include <pulsecore/thread-mq.h>
72 #include <pulsecore/rtpoll.h>
74 #if defined(__NetBSD__) && !defined(SNDCTL_DSP_GETODELAY)
75 #include <sys/audioio.h>
76 #include <sys/syscall.h>
80 #include "module-oss-symdef.h"
82 PA_MODULE_AUTHOR("Lennart Poettering");
83 PA_MODULE_DESCRIPTION("OSS Sink/Source");
84 PA_MODULE_VERSION(PACKAGE_VERSION
);
85 PA_MODULE_LOAD_ONCE(FALSE
);
87 "sink_name=<name for the sink> "
88 "source_name=<name for the source> "
89 "device=<OSS device> "
90 "record=<enable source?> "
91 "playback=<enable sink?> "
92 "format=<sample format> "
93 "channels=<number of channels> "
95 "fragments=<number of fragments> "
96 "fragment_size=<fragment size> "
97 "channel_map=<channel map> "
98 "mmap=<enable memory mapping?>");
100 #define DEFAULT_DEVICE "/dev/dsp"
109 pa_thread_mq thread_mq
;
114 pa_memchunk memchunk
;
117 uint32_t in_fragment_size
, out_fragment_size
, in_nfrags
, out_nfrags
, in_hwbuf_size
, out_hwbuf_size
;
118 pa_bool_t use_getospace
, use_getispace
;
119 pa_bool_t use_getodelay
;
121 pa_bool_t sink_suspended
, source_suspended
;
129 int nfrags
, frag_size
, orig_frag_size
;
132 unsigned out_mmap_current
, in_mmap_current
;
133 void *in_mmap
, *out_mmap
;
134 pa_memblock
**in_mmap_memblocks
, **out_mmap_memblocks
;
136 int in_mmap_saved_nfrags
, out_mmap_saved_nfrags
;
138 pa_rtpoll_item
*rtpoll_item
;
141 static const char* const valid_modargs
[] = {
157 static void trigger(struct userdata
*u
, pa_bool_t quick
) {
158 int enable_bits
= 0, zero
= 0;
165 pa_log_debug("trigger");
167 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
))
168 enable_bits
|= PCM_ENABLE_INPUT
;
170 if (u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
))
171 enable_bits
|= PCM_ENABLE_OUTPUT
;
173 pa_log_debug("trigger: %i", enable_bits
);
179 ioctl(u
->fd
, SNDCTL_DSP_SETTRIGGER
, &zero
);
181 #ifdef SNDCTL_DSP_HALT
182 if (enable_bits
== 0)
183 if (ioctl(u
->fd
, SNDCTL_DSP_HALT
, NULL
) < 0)
184 pa_log_warn("SNDCTL_DSP_HALT: %s", pa_cstrerror(errno
));
187 if (ioctl(u
->fd
, SNDCTL_DSP_SETTRIGGER
, &enable_bits
) < 0)
188 pa_log_warn("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno
));
190 if (u
->sink
&& !(enable_bits
& PCM_ENABLE_OUTPUT
)) {
191 pa_log_debug("clearing playback buffer");
192 pa_silence_memory(u
->out_mmap
, u
->out_hwbuf_size
, &u
->sink
->sample_spec
);
198 if (ioctl(u
->fd
, SNDCTL_DSP_POST
, NULL
) < 0)
199 pa_log_warn("SNDCTL_DSP_POST: %s", pa_cstrerror(errno
));
203 * Some crappy drivers do not start the recording until we
204 * read something. Without this snippet, poll will never
205 * register the fd as ready.
208 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
)) {
209 uint8_t *buf
= pa_xnew(uint8_t, u
->in_fragment_size
);
210 pa_read(u
->fd
, buf
, u
->in_fragment_size
, NULL
);
217 static void mmap_fill_memblocks(struct userdata
*u
, unsigned n
) {
219 pa_assert(u
->out_mmap_memblocks
);
221 /* pa_log("Mmmap writing %u blocks", n); */
226 if (u
->out_mmap_memblocks
[u
->out_mmap_current
])
227 pa_memblock_unref_fixed(u
->out_mmap_memblocks
[u
->out_mmap_current
]);
229 chunk
.memblock
= u
->out_mmap_memblocks
[u
->out_mmap_current
] =
230 pa_memblock_new_fixed(
232 (uint8_t*) u
->out_mmap
+ u
->out_fragment_size
* u
->out_mmap_current
,
233 u
->out_fragment_size
,
236 chunk
.length
= pa_memblock_get_length(chunk
.memblock
);
239 pa_sink_render_into_full(u
->sink
, &chunk
);
241 u
->out_mmap_current
++;
242 while (u
->out_mmap_current
>= u
->out_nfrags
)
243 u
->out_mmap_current
-= u
->out_nfrags
;
249 static int mmap_write(struct userdata
*u
) {
250 struct count_info info
;
255 /* pa_log("Mmmap writing..."); */
257 if (ioctl(u
->fd
, SNDCTL_DSP_GETOPTR
, &info
) < 0) {
258 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno
));
262 info
.blocks
+= u
->out_mmap_saved_nfrags
;
263 u
->out_mmap_saved_nfrags
= 0;
266 mmap_fill_memblocks(u
, (unsigned) info
.blocks
);
271 static void mmap_post_memblocks(struct userdata
*u
, unsigned n
) {
273 pa_assert(u
->in_mmap_memblocks
);
275 /* pa_log("Mmmap reading %u blocks", n); */
280 if (!u
->in_mmap_memblocks
[u
->in_mmap_current
]) {
282 chunk
.memblock
= u
->in_mmap_memblocks
[u
->in_mmap_current
] =
283 pa_memblock_new_fixed(
285 (uint8_t*) u
->in_mmap
+ u
->in_fragment_size
*u
->in_mmap_current
,
289 chunk
.length
= pa_memblock_get_length(chunk
.memblock
);
292 pa_source_post(u
->source
, &chunk
);
295 u
->in_mmap_current
++;
296 while (u
->in_mmap_current
>= u
->in_nfrags
)
297 u
->in_mmap_current
-= u
->in_nfrags
;
303 static void mmap_clear_memblocks(struct userdata
*u
, unsigned n
) {
304 unsigned i
= u
->in_mmap_current
;
307 pa_assert(u
->in_mmap_memblocks
);
309 if (n
> u
->in_nfrags
)
313 if (u
->in_mmap_memblocks
[i
]) {
314 pa_memblock_unref_fixed(u
->in_mmap_memblocks
[i
]);
315 u
->in_mmap_memblocks
[i
] = NULL
;
319 while (i
>= u
->in_nfrags
)
326 static int mmap_read(struct userdata
*u
) {
327 struct count_info info
;
329 pa_assert(u
->source
);
331 /* pa_log("Mmmap reading..."); */
333 if (ioctl(u
->fd
, SNDCTL_DSP_GETIPTR
, &info
) < 0) {
334 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno
));
338 /* pa_log("... %i", info.blocks); */
340 info
.blocks
+= u
->in_mmap_saved_nfrags
;
341 u
->in_mmap_saved_nfrags
= 0;
343 if (info
.blocks
> 0) {
344 mmap_post_memblocks(u
, (unsigned) info
.blocks
);
345 mmap_clear_memblocks(u
, u
->in_nfrags
/2);
351 static pa_usec_t
mmap_sink_get_latency(struct userdata
*u
) {
352 struct count_info info
;
357 if (ioctl(u
->fd
, SNDCTL_DSP_GETOPTR
, &info
) < 0) {
358 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno
));
362 u
->out_mmap_saved_nfrags
+= info
.blocks
;
364 bpos
= ((u
->out_mmap_current
+ (unsigned) u
->out_mmap_saved_nfrags
) * u
->out_fragment_size
) % u
->out_hwbuf_size
;
366 if (bpos
<= (size_t) info
.ptr
)
367 n
= u
->out_hwbuf_size
- ((size_t) info
.ptr
- bpos
);
369 n
= bpos
- (size_t) info
.ptr
;
371 /* 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); */
373 return pa_bytes_to_usec(n
, &u
->sink
->sample_spec
);
376 static pa_usec_t
mmap_source_get_latency(struct userdata
*u
) {
377 struct count_info info
;
382 if (ioctl(u
->fd
, SNDCTL_DSP_GETIPTR
, &info
) < 0) {
383 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno
));
387 u
->in_mmap_saved_nfrags
+= info
.blocks
;
388 bpos
= ((u
->in_mmap_current
+ (unsigned) u
->in_mmap_saved_nfrags
) * u
->in_fragment_size
) % u
->in_hwbuf_size
;
390 if (bpos
<= (size_t) info
.ptr
)
391 n
= (size_t) info
.ptr
- bpos
;
393 n
= u
->in_hwbuf_size
- bpos
+ (size_t) info
.ptr
;
395 /* 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); */
397 return pa_bytes_to_usec(n
, &u
->source
->sample_spec
);
400 static pa_usec_t
io_sink_get_latency(struct userdata
*u
) {
405 if (u
->use_getodelay
) {
407 #if defined(__NetBSD__) && !defined(SNDCTL_DSP_GETODELAY)
408 #if defined(AUDIO_GETBUFINFO)
409 struct audio_info info
;
410 if (syscall(SYS_ioctl
, u
->fd
, AUDIO_GETBUFINFO
, &info
) < 0) {
411 pa_log_info("Device doesn't support AUDIO_GETBUFINFO: %s", pa_cstrerror(errno
));
412 u
->use_getodelay
= 0;
414 arg
= info
.play
.seek
+ info
.blocksize
/ 2;
415 r
= pa_bytes_to_usec((size_t) arg
, &u
->sink
->sample_spec
);
418 pa_log_info("System doesn't support AUDIO_GETBUFINFO");
419 u
->use_getodelay
= 0;
422 if (ioctl(u
->fd
, SNDCTL_DSP_GETODELAY
, &arg
) < 0) {
423 pa_log_info("Device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno
));
424 u
->use_getodelay
= 0;
426 r
= pa_bytes_to_usec((size_t) arg
, &u
->sink
->sample_spec
);
430 if (!u
->use_getodelay
&& u
->use_getospace
) {
431 struct audio_buf_info info
;
433 if (ioctl(u
->fd
, SNDCTL_DSP_GETOSPACE
, &info
) < 0) {
434 pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno
));
435 u
->use_getospace
= 0;
437 r
= pa_bytes_to_usec((size_t) info
.bytes
, &u
->sink
->sample_spec
);
440 if (u
->memchunk
.memblock
)
441 r
+= pa_bytes_to_usec(u
->memchunk
.length
, &u
->sink
->sample_spec
);
446 static pa_usec_t
io_source_get_latency(struct userdata
*u
) {
451 if (u
->use_getispace
) {
452 struct audio_buf_info info
;
454 if (ioctl(u
->fd
, SNDCTL_DSP_GETISPACE
, &info
) < 0) {
455 pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno
));
456 u
->use_getispace
= 0;
458 r
= pa_bytes_to_usec((size_t) info
.bytes
, &u
->source
->sample_spec
);
464 static void build_pollfd(struct userdata
*u
) {
465 struct pollfd
*pollfd
;
468 pa_assert(u
->fd
>= 0);
471 pa_rtpoll_item_free(u
->rtpoll_item
);
473 u
->rtpoll_item
= pa_rtpoll_item_new(u
->rtpoll
, PA_RTPOLL_NEVER
, 1);
474 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
480 static int suspend(struct userdata
*u
) {
482 pa_assert(u
->fd
>= 0);
484 pa_log_info("Suspending...");
486 if (u
->out_mmap_memblocks
) {
488 for (i
= 0; i
< u
->out_nfrags
; i
++)
489 if (u
->out_mmap_memblocks
[i
]) {
490 pa_memblock_unref_fixed(u
->out_mmap_memblocks
[i
]);
491 u
->out_mmap_memblocks
[i
] = NULL
;
495 if (u
->in_mmap_memblocks
) {
497 for (i
= 0; i
< u
->in_nfrags
; i
++)
498 if (u
->in_mmap_memblocks
[i
]) {
499 pa_memblock_unref_fixed(u
->in_mmap_memblocks
[i
]);
500 u
->in_mmap_memblocks
[i
] = NULL
;
504 if (u
->in_mmap
&& u
->in_mmap
!= MAP_FAILED
) {
505 munmap(u
->in_mmap
, u
->in_hwbuf_size
);
509 if (u
->out_mmap
&& u
->out_mmap
!= MAP_FAILED
) {
510 munmap(u
->out_mmap
, u
->out_hwbuf_size
);
515 ioctl(u
->fd
, SNDCTL_DSP_SYNC
, NULL
);
519 if (u
->rtpoll_item
) {
520 pa_rtpoll_item_free(u
->rtpoll_item
);
521 u
->rtpoll_item
= NULL
;
524 pa_log_info("Device suspended...");
529 static int unsuspend(struct userdata
*u
) {
531 pa_sample_spec ss
, *ss_original
;
532 int frag_size
, in_frag_size
, out_frag_size
;
533 int in_nfrags
, out_nfrags
;
534 struct audio_buf_info info
;
537 pa_assert(u
->fd
< 0);
541 pa_log_info("Trying resume...");
543 if ((u
->fd
= pa_oss_open(u
->device_name
, &m
, NULL
)) < 0) {
544 pa_log_warn("Resume failed, device busy (%s)", pa_cstrerror(errno
));
549 pa_log_warn("Resume failed, couldn't open device with original access mode.");
553 if (u
->nfrags
>= 2 && u
->frag_size
>= 1)
554 if (pa_oss_set_fragments(u
->fd
, u
->nfrags
, u
->orig_frag_size
) < 0) {
555 pa_log_warn("Resume failed, couldn't set original fragment settings.");
559 ss
= *(ss_original
= u
->sink
? &u
->sink
->sample_spec
: &u
->source
->sample_spec
);
560 if (pa_oss_auto_format(u
->fd
, &ss
) < 0 || !pa_sample_spec_equal(&ss
, ss_original
)) {
561 pa_log_warn("Resume failed, couldn't set original sample format settings.");
565 if (ioctl(u
->fd
, SNDCTL_DSP_GETBLKSIZE
, &frag_size
) < 0) {
566 pa_log_warn("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno
));
570 in_frag_size
= out_frag_size
= frag_size
;
571 in_nfrags
= out_nfrags
= u
->nfrags
;
573 if (ioctl(u
->fd
, SNDCTL_DSP_GETISPACE
, &info
) >= 0) {
574 in_frag_size
= info
.fragsize
;
575 in_nfrags
= info
.fragstotal
;
578 if (ioctl(u
->fd
, SNDCTL_DSP_GETOSPACE
, &info
) >= 0) {
579 out_frag_size
= info
.fragsize
;
580 out_nfrags
= info
.fragstotal
;
583 if ((u
->source
&& (in_frag_size
!= (int) u
->in_fragment_size
|| in_nfrags
!= (int) u
->in_nfrags
)) ||
584 (u
->sink
&& (out_frag_size
!= (int) u
->out_fragment_size
|| out_nfrags
!= (int) u
->out_nfrags
))) {
585 pa_log_warn("Resume failed, input fragment settings don't match.");
591 if ((u
->in_mmap
= mmap(NULL
, u
->in_hwbuf_size
, PROT_READ
, MAP_SHARED
, u
->fd
, 0)) == MAP_FAILED
) {
592 pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno
));
598 if ((u
->out_mmap
= mmap(NULL
, u
->out_hwbuf_size
, PROT_WRITE
, MAP_SHARED
, u
->fd
, 0)) == MAP_FAILED
) {
599 pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno
));
600 if (u
->in_mmap
&& u
->in_mmap
!= MAP_FAILED
) {
601 munmap(u
->in_mmap
, u
->in_hwbuf_size
);
608 pa_silence_memory(u
->out_mmap
, u
->out_hwbuf_size
, &ss
);
612 u
->out_mmap_current
= u
->in_mmap_current
= 0;
613 u
->out_mmap_saved_nfrags
= u
->in_mmap_saved_nfrags
= 0;
615 pa_assert(!u
->rtpoll_item
);
620 pa_sink_get_volume(u
->sink
, TRUE
, FALSE
);
622 pa_source_get_volume(u
->source
, TRUE
);
624 pa_log_info("Resumed successfully...");
634 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
635 struct userdata
*u
= PA_SINK(o
)->userdata
;
637 pa_bool_t do_trigger
= FALSE
, quick
= TRUE
;
641 case PA_SINK_MESSAGE_GET_LATENCY
: {
646 r
= mmap_sink_get_latency(u
);
648 r
= io_sink_get_latency(u
);
651 *((pa_usec_t
*) data
) = r
;
656 case PA_SINK_MESSAGE_SET_STATE
:
658 switch ((pa_sink_state_t
) PA_PTR_TO_UINT(data
)) {
660 case PA_SINK_SUSPENDED
:
661 pa_assert(PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
));
663 if (!u
->source
|| u
->source_suspended
) {
670 u
->sink_suspended
= TRUE
;
674 case PA_SINK_RUNNING
:
676 if (u
->sink
->thread_info
.state
== PA_SINK_INIT
) {
678 quick
= u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
);
681 if (u
->sink
->thread_info
.state
== PA_SINK_SUSPENDED
) {
683 if (!u
->source
|| u
->source_suspended
) {
684 if (unsuspend(u
) < 0)
691 u
->out_mmap_current
= 0;
692 u
->out_mmap_saved_nfrags
= 0;
694 u
->sink_suspended
= FALSE
;
699 case PA_SINK_INVALID_STATE
:
700 case PA_SINK_UNLINKED
:
709 ret
= pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
717 static int source_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
718 struct userdata
*u
= PA_SOURCE(o
)->userdata
;
720 int do_trigger
= FALSE
, quick
= TRUE
;
724 case PA_SOURCE_MESSAGE_GET_LATENCY
: {
729 r
= mmap_source_get_latency(u
);
731 r
= io_source_get_latency(u
);
734 *((pa_usec_t
*) data
) = r
;
738 case PA_SOURCE_MESSAGE_SET_STATE
:
740 switch ((pa_source_state_t
) PA_PTR_TO_UINT(data
)) {
741 case PA_SOURCE_SUSPENDED
:
742 pa_assert(PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
));
744 if (!u
->sink
|| u
->sink_suspended
) {
751 u
->source_suspended
= TRUE
;
755 case PA_SOURCE_RUNNING
:
757 if (u
->source
->thread_info
.state
== PA_SOURCE_INIT
) {
759 quick
= u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
);
762 if (u
->source
->thread_info
.state
== PA_SOURCE_SUSPENDED
) {
764 if (!u
->sink
|| u
->sink_suspended
) {
765 if (unsuspend(u
) < 0)
772 u
->in_mmap_current
= 0;
773 u
->in_mmap_saved_nfrags
= 0;
775 u
->source_suspended
= FALSE
;
779 case PA_SOURCE_UNLINKED
:
781 case PA_SOURCE_INVALID_STATE
:
789 ret
= pa_source_process_msg(o
, code
, data
, offset
, chunk
);
797 static void sink_get_volume(pa_sink
*s
) {
800 pa_assert_se(u
= s
->userdata
);
802 pa_assert(u
->mixer_devmask
& (SOUND_MASK_VOLUME
|SOUND_MASK_PCM
));
804 if (u
->mixer_devmask
& SOUND_MASK_VOLUME
)
805 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_READ_VOLUME
, &s
->sample_spec
, &s
->virtual_volume
) >= 0)
808 if (u
->mixer_devmask
& SOUND_MASK_PCM
)
809 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_READ_PCM
, &s
->sample_spec
, &s
->virtual_volume
) >= 0)
812 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno
));
815 static void sink_set_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_set_volume(u
->mixer_fd
, SOUND_MIXER_WRITE_VOLUME
, &s
->sample_spec
, &s
->virtual_volume
) >= 0)
826 if (u
->mixer_devmask
& SOUND_MASK_PCM
)
827 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_WRITE_PCM
, &s
->sample_spec
, &s
->virtual_volume
) >= 0)
830 pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno
));
833 static void source_get_volume(pa_source
*s
) {
836 pa_assert_se(u
= s
->userdata
);
838 pa_assert(u
->mixer_devmask
& (SOUND_MASK_IGAIN
|SOUND_MASK_RECLEV
));
840 if (u
->mixer_devmask
& SOUND_MASK_IGAIN
)
841 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_READ_IGAIN
, &s
->sample_spec
, &s
->virtual_volume
) >= 0)
844 if (u
->mixer_devmask
& SOUND_MASK_RECLEV
)
845 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_READ_RECLEV
, &s
->sample_spec
, &s
->virtual_volume
) >= 0)
848 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno
));
851 static void source_set_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_set_volume(u
->mixer_fd
, SOUND_MIXER_WRITE_IGAIN
, &s
->sample_spec
, &s
->virtual_volume
) >= 0)
862 if (u
->mixer_devmask
& SOUND_MASK_RECLEV
)
863 if (pa_oss_get_volume(u
->mixer_fd
, SOUND_MIXER_WRITE_RECLEV
, &s
->sample_spec
, &s
->virtual_volume
) >= 0)
866 pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno
));
869 static void thread_func(void *userdata
) {
870 struct userdata
*u
= userdata
;
871 int write_type
= 0, read_type
= 0;
876 pa_log_debug("Thread starting up");
878 if (u
->core
->realtime_scheduling
)
879 pa_make_realtime(u
->core
->realtime_priority
);
881 pa_thread_mq_install(&u
->thread_mq
);
882 pa_rtpoll_install(u
->rtpoll
);
887 /* pa_log("loop"); */
889 if (u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
))
890 if (u
->sink
->thread_info
.rewind_requested
)
891 pa_sink_process_rewind(u
->sink
, 0);
893 /* Render some data and write it to the dsp */
895 if (u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
) && ((revents
& POLLOUT
) || u
->use_mmap
|| u
->use_getospace
)) {
899 if ((ret
= mmap_write(u
)) < 0)
909 pa_bool_t loop
= FALSE
, work_done
= FALSE
;
911 l
= (ssize_t
) u
->out_fragment_size
;
913 if (u
->use_getospace
) {
916 if (ioctl(u
->fd
, SNDCTL_DSP_GETOSPACE
, &info
) < 0) {
917 pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno
));
918 u
->use_getospace
= FALSE
;
922 /* We loop only if GETOSPACE worked and we
923 * actually *know* that we can write more than
924 * one fragment at a time */
929 /* Round down to multiples of the fragment size,
930 * because OSS needs that (at least some versions
932 l
= (l
/(ssize_t
) u
->out_fragment_size
) * (ssize_t
) u
->out_fragment_size
;
934 /* Hmm, so poll() signalled us that we can read
935 * something, but GETOSPACE told us there was nothing?
936 * Hmm, make the best of it, try to read some data, to
937 * avoid spinning forever. */
938 if (l
<= 0 && (revents
& POLLOUT
)) {
939 l
= (ssize_t
) u
->out_fragment_size
;
947 if (u
->memchunk
.length
<= 0)
948 pa_sink_render(u
->sink
, (size_t) l
, &u
->memchunk
);
950 pa_assert(u
->memchunk
.length
> 0);
952 p
= pa_memblock_acquire(u
->memchunk
.memblock
);
953 t
= pa_write(u
->fd
, (uint8_t*) p
+ u
->memchunk
.index
, u
->memchunk
.length
, &write_type
);
954 pa_memblock_release(u
->memchunk
.memblock
);
956 /* pa_log("wrote %i bytes of %u", t, l); */
965 else if (errno
== EAGAIN
) {
966 pa_log_debug("EAGAIN");
972 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno
));
978 u
->memchunk
.index
+= (size_t) t
;
979 u
->memchunk
.length
-= (size_t) t
;
981 if (u
->memchunk
.length
<= 0) {
982 pa_memblock_unref(u
->memchunk
.memblock
);
983 pa_memchunk_reset(&u
->memchunk
);
1001 /* Try to read some data and pass it on to the source driver. */
1003 if (u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
) && ((revents
& POLLIN
) || u
->use_mmap
|| u
->use_getispace
)) {
1007 if ((ret
= mmap_read(u
)) < 0)
1019 pa_memchunk memchunk
;
1020 pa_bool_t loop
= FALSE
, work_done
= FALSE
;
1022 l
= (ssize_t
) u
->in_fragment_size
;
1024 if (u
->use_getispace
) {
1025 audio_buf_info info
;
1027 if (ioctl(u
->fd
, SNDCTL_DSP_GETISPACE
, &info
) < 0) {
1028 pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno
));
1029 u
->use_getispace
= FALSE
;
1036 l
= (l
/(ssize_t
) u
->in_fragment_size
) * (ssize_t
) u
->in_fragment_size
;
1038 if (l
<= 0 && (revents
& POLLIN
)) {
1039 l
= (ssize_t
) u
->in_fragment_size
;
1049 memchunk
.memblock
= pa_memblock_new(u
->core
->mempool
, (size_t) -1);
1051 k
= pa_memblock_get_length(memchunk
.memblock
);
1056 k
= (k
/u
->frame_size
)*u
->frame_size
;
1058 p
= pa_memblock_acquire(memchunk
.memblock
);
1059 t
= pa_read(u
->fd
, p
, k
, &read_type
);
1060 pa_memblock_release(memchunk
.memblock
);
1062 pa_assert(t
!= 0); /* EOF cannot happen */
1064 /* pa_log("read %i bytes of %u", t, l); */
1067 pa_memblock_unref(memchunk
.memblock
);
1072 else if (errno
== EAGAIN
) {
1073 pa_log_debug("EAGAIN");
1079 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno
));
1085 memchunk
.length
= (size_t) t
;
1087 pa_source_post(u
->source
, &memchunk
);
1088 pa_memblock_unref(memchunk
.memblock
);
1105 /* pa_log("loop2 revents=%i", revents); */
1107 if (u
->rtpoll_item
) {
1108 struct pollfd
*pollfd
;
1110 pa_assert(u
->fd
>= 0);
1112 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
1113 pollfd
->events
= (short)
1114 (((u
->source
&& PA_SOURCE_IS_OPENED(u
->source
->thread_info
.state
)) ? POLLIN
: 0) |
1115 ((u
->sink
&& PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
)) ? POLLOUT
: 0));
1118 /* Hmm, nothing to do. Let's sleep */
1119 if ((ret
= pa_rtpoll_run(u
->rtpoll
, TRUE
)) < 0)
1125 if (u
->rtpoll_item
) {
1126 struct pollfd
*pollfd
;
1128 pollfd
= pa_rtpoll_item_get_pollfd(u
->rtpoll_item
, NULL
);
1130 if (pollfd
->revents
& ~(POLLOUT
|POLLIN
)) {
1131 pa_log("DSP shutdown.");
1135 revents
= pollfd
->revents
;
1141 /* If this was no regular exit from the loop we have to continue
1142 * processing messages until we received PA_MESSAGE_SHUTDOWN */
1143 pa_asyncmsgq_post(u
->thread_mq
.outq
, PA_MSGOBJECT(u
->core
), PA_CORE_MESSAGE_UNLOAD_MODULE
, u
->module
, 0, NULL
, NULL
);
1144 pa_asyncmsgq_wait_for(u
->thread_mq
.inq
, PA_MESSAGE_SHUTDOWN
);
1147 pa_log_debug("Thread shutting down");
1150 int pa__init(pa_module
*m
) {
1152 struct audio_buf_info info
;
1153 struct userdata
*u
= NULL
;
1156 int nfrags
, orig_frag_size
, frag_size
;
1158 pa_bool_t record
= TRUE
, playback
= TRUE
, use_mmap
= TRUE
;
1161 pa_modargs
*ma
= NULL
;
1164 pa_bool_t namereg_fail
;
1165 pa_sink_new_data sink_new_data
;
1166 pa_source_new_data source_new_data
;
1170 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
1171 pa_log("Failed to parse module arguments.");
1175 if (pa_modargs_get_value_boolean(ma
, "record", &record
) < 0 || pa_modargs_get_value_boolean(ma
, "playback", &playback
) < 0) {
1176 pa_log("record= and playback= expect boolean argument.");
1180 if (!playback
&& !record
) {
1181 pa_log("Neither playback nor record enabled for device.");
1185 mode
= (playback
&& record
) ? O_RDWR
: (playback
? O_WRONLY
: (record
? O_RDONLY
: 0));
1187 ss
= m
->core
->default_sample_spec
;
1188 map
= m
->core
->default_channel_map
;
1189 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_OSS
) < 0) {
1190 pa_log("Failed to parse sample specification or channel map");
1194 nfrags
= (int) m
->core
->default_n_fragments
;
1195 frag_size
= (int) pa_usec_to_bytes(m
->core
->default_fragment_size_msec
*1000, &ss
);
1197 frag_size
= (int) pa_frame_size(&ss
);
1199 if (pa_modargs_get_value_s32(ma
, "fragments", &nfrags
) < 0 || pa_modargs_get_value_s32(ma
, "fragment_size", &frag_size
) < 0) {
1200 pa_log("Failed to parse fragments arguments");
1204 if (pa_modargs_get_value_boolean(ma
, "mmap", &use_mmap
) < 0) {
1205 pa_log("Failed to parse mmap argument.");
1209 if ((fd
= pa_oss_open(dev
= pa_modargs_get_value(ma
, "device", DEFAULT_DEVICE
), &mode
, &caps
)) < 0)
1212 if (use_mmap
&& (!(caps
& DSP_CAP_MMAP
) || !(caps
& DSP_CAP_TRIGGER
))) {
1213 pa_log_info("OSS device not mmap capable, falling back to UNIX read/write mode.");
1217 if (use_mmap
&& mode
== O_WRONLY
) {
1218 pa_log_info("Device opened for playback only, cannot do memory mapping, falling back to UNIX write() mode.");
1222 if (pa_oss_get_hw_description(dev
, hwdesc
, sizeof(hwdesc
)) >= 0)
1223 pa_log_info("Hardware name is '%s'.", hwdesc
);
1227 pa_log_info("Device opened in %s mode.", mode
== O_WRONLY
? "O_WRONLY" : (mode
== O_RDONLY
? "O_RDONLY" : "O_RDWR"));
1229 orig_frag_size
= frag_size
;
1230 if (nfrags
>= 2 && frag_size
>= 1)
1231 if (pa_oss_set_fragments(fd
, nfrags
, frag_size
) < 0)
1234 if (pa_oss_auto_format(fd
, &ss
) < 0)
1237 if (ioctl(fd
, SNDCTL_DSP_GETBLKSIZE
, &frag_size
) < 0) {
1238 pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno
));
1241 pa_assert(frag_size
> 0);
1243 u
= pa_xnew0(struct userdata
, 1);
1249 u
->mixer_devmask
= 0;
1250 u
->use_getospace
= u
->use_getispace
= TRUE
;
1251 u
->use_getodelay
= TRUE
;
1253 u
->frame_size
= pa_frame_size(&ss
);
1254 u
->device_name
= pa_xstrdup(dev
);
1255 u
->in_nfrags
= u
->out_nfrags
= (uint32_t) (u
->nfrags
= nfrags
);
1256 u
->out_fragment_size
= u
->in_fragment_size
= (uint32_t) (u
->frag_size
= frag_size
);
1257 u
->orig_frag_size
= orig_frag_size
;
1258 u
->use_mmap
= use_mmap
;
1259 u
->rtpoll
= pa_rtpoll_new();
1260 pa_thread_mq_init(&u
->thread_mq
, m
->core
->mainloop
, u
->rtpoll
);
1261 u
->rtpoll_item
= NULL
;
1264 if (ioctl(fd
, SNDCTL_DSP_GETISPACE
, &info
) >= 0) {
1265 pa_log_info("Input -- %u fragments of size %u.", info
.fragstotal
, info
.fragsize
);
1266 u
->in_fragment_size
= (uint32_t) info
.fragsize
;
1267 u
->in_nfrags
= (uint32_t) info
.fragstotal
;
1268 u
->use_getispace
= TRUE
;
1271 if (ioctl(fd
, SNDCTL_DSP_GETOSPACE
, &info
) >= 0) {
1272 pa_log_info("Output -- %u fragments of size %u.", info
.fragstotal
, info
.fragsize
);
1273 u
->out_fragment_size
= (uint32_t) info
.fragsize
;
1274 u
->out_nfrags
= (uint32_t) info
.fragstotal
;
1275 u
->use_getospace
= TRUE
;
1278 u
->in_hwbuf_size
= u
->in_nfrags
* u
->in_fragment_size
;
1279 u
->out_hwbuf_size
= u
->out_nfrags
* u
->out_fragment_size
;
1281 if (mode
!= O_WRONLY
) {
1282 char *name_buf
= NULL
;
1285 if ((u
->in_mmap
= mmap(NULL
, u
->in_hwbuf_size
, PROT_READ
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
1286 pa_log_warn("mmap(PROT_READ) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno
));
1287 use_mmap
= u
->use_mmap
= FALSE
;
1290 pa_log_debug("Successfully mmap()ed input buffer.");
1293 if ((name
= pa_modargs_get_value(ma
, "source_name", NULL
)))
1294 namereg_fail
= TRUE
;
1296 name
= name_buf
= pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(dev
));
1297 namereg_fail
= FALSE
;
1300 pa_source_new_data_init(&source_new_data
);
1301 source_new_data
.driver
= __FILE__
;
1302 source_new_data
.module
= m
;
1303 pa_source_new_data_set_name(&source_new_data
, name
);
1304 source_new_data
.namereg_fail
= namereg_fail
;
1305 pa_source_new_data_set_sample_spec(&source_new_data
, &ss
);
1306 pa_source_new_data_set_channel_map(&source_new_data
, &map
);
1307 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_STRING
, dev
);
1308 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_API
, "oss");
1309 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, hwdesc
[0] ? hwdesc
: dev
);
1310 pa_proplist_sets(source_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, use_mmap
? "mmap" : "serial");
1311 pa_proplist_setf(source_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE
, "%lu", (unsigned long) (u
->in_hwbuf_size
));
1312 pa_proplist_setf(source_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE
, "%lu", (unsigned long) (u
->in_fragment_size
));
1314 u
->source
= pa_source_new(m
->core
, &source_new_data
, PA_SOURCE_HARDWARE
|PA_SOURCE_LATENCY
);
1315 pa_source_new_data_done(&source_new_data
);
1319 pa_log("Failed to create source object");
1323 u
->source
->parent
.process_msg
= source_process_msg
;
1324 u
->source
->userdata
= u
;
1326 pa_source_set_asyncmsgq(u
->source
, u
->thread_mq
.inq
);
1327 pa_source_set_rtpoll(u
->source
, u
->rtpoll
);
1328 pa_source_set_fixed_latency(u
->source
, pa_bytes_to_usec(u
->in_hwbuf_size
, &u
->source
->sample_spec
));
1329 u
->source
->refresh_volume
= TRUE
;
1332 u
->in_mmap_memblocks
= pa_xnew0(pa_memblock
*, u
->in_nfrags
);
1335 if (mode
!= O_RDONLY
) {
1336 char *name_buf
= NULL
;
1339 if ((u
->out_mmap
= mmap(NULL
, u
->out_hwbuf_size
, PROT_WRITE
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
1340 if (mode
== O_RDWR
) {
1341 pa_log_debug("mmap() failed for input. Changing to O_WRONLY mode.");
1345 pa_log_warn("mmap(PROT_WRITE) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno
));
1346 u
->use_mmap
= use_mmap
= FALSE
;
1350 pa_log_debug("Successfully mmap()ed output buffer.");
1351 pa_silence_memory(u
->out_mmap
, u
->out_hwbuf_size
, &ss
);
1355 if ((name
= pa_modargs_get_value(ma
, "sink_name", NULL
)))
1356 namereg_fail
= TRUE
;
1358 name
= name_buf
= pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(dev
));
1359 namereg_fail
= FALSE
;
1362 pa_sink_new_data_init(&sink_new_data
);
1363 sink_new_data
.driver
= __FILE__
;
1364 sink_new_data
.module
= m
;
1365 pa_sink_new_data_set_name(&sink_new_data
, name
);
1366 sink_new_data
.namereg_fail
= namereg_fail
;
1367 pa_sink_new_data_set_sample_spec(&sink_new_data
, &ss
);
1368 pa_sink_new_data_set_channel_map(&sink_new_data
, &map
);
1369 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_STRING
, dev
);
1370 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_API
, "oss");
1371 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, hwdesc
[0] ? hwdesc
: dev
);
1372 pa_proplist_sets(sink_new_data
.proplist
, PA_PROP_DEVICE_ACCESS_MODE
, use_mmap
? "mmap" : "serial");
1373 pa_proplist_setf(sink_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE
, "%lu", (unsigned long) (u
->out_hwbuf_size
));
1374 pa_proplist_setf(sink_new_data
.proplist
, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE
, "%lu", (unsigned long) (u
->out_fragment_size
));
1376 u
->sink
= pa_sink_new(m
->core
, &sink_new_data
, PA_SINK_HARDWARE
|PA_SINK_LATENCY
);
1377 pa_sink_new_data_done(&sink_new_data
);
1381 pa_log("Failed to create sink object");
1385 u
->sink
->parent
.process_msg
= sink_process_msg
;
1386 u
->sink
->userdata
= u
;
1388 pa_sink_set_asyncmsgq(u
->sink
, u
->thread_mq
.inq
);
1389 pa_sink_set_rtpoll(u
->sink
, u
->rtpoll
);
1390 pa_sink_set_fixed_latency(u
->sink
, pa_bytes_to_usec(u
->out_hwbuf_size
, &u
->sink
->sample_spec
));
1391 u
->sink
->refresh_volume
= TRUE
;
1393 pa_sink_set_max_request(u
->sink
, u
->out_hwbuf_size
);
1396 u
->out_mmap_memblocks
= pa_xnew0(pa_memblock
*, u
->out_nfrags
);
1399 if ((u
->mixer_fd
= pa_oss_open_mixer_for_device(u
->device_name
)) >= 0) {
1400 pa_bool_t do_close
= TRUE
;
1402 if (ioctl(fd
, SOUND_MIXER_READ_DEVMASK
, &u
->mixer_devmask
) < 0)
1403 pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno
));
1406 if (u
->sink
&& (u
->mixer_devmask
& (SOUND_MASK_VOLUME
|SOUND_MASK_PCM
))) {
1407 pa_log_debug("Found hardware mixer track for playback.");
1408 u
->sink
->flags
|= PA_SINK_HW_VOLUME_CTRL
;
1409 u
->sink
->get_volume
= sink_get_volume
;
1410 u
->sink
->set_volume
= sink_set_volume
;
1411 u
->sink
->n_volume_steps
= 101;
1415 if (u
->source
&& (u
->mixer_devmask
& (SOUND_MASK_RECLEV
|SOUND_MASK_IGAIN
))) {
1416 pa_log_debug("Found hardware mixer track for recording.");
1417 u
->source
->flags
|= PA_SOURCE_HW_VOLUME_CTRL
;
1418 u
->source
->get_volume
= source_get_volume
;
1419 u
->source
->set_volume
= source_set_volume
;
1420 u
->source
->n_volume_steps
= 101;
1426 pa_close(u
->mixer_fd
);
1428 u
->mixer_devmask
= 0;
1434 pa_assert(u
->source
|| u
->sink
);
1436 pa_memchunk_reset(&u
->memchunk
);
1438 if (!(u
->thread
= pa_thread_new(thread_func
, u
))) {
1439 pa_log("Failed to create thread.");
1443 /* Read mixer settings */
1445 if (sink_new_data
.volume_is_set
) {
1446 if (u
->sink
->set_volume
)
1447 u
->sink
->set_volume(u
->sink
);
1449 if (u
->sink
->get_volume
)
1450 u
->sink
->get_volume(u
->sink
);
1455 if (source_new_data
.volume_is_set
) {
1456 if (u
->source
->set_volume
)
1457 u
->source
->set_volume(u
->source
);
1459 if (u
->source
->get_volume
)
1460 u
->source
->get_volume(u
->source
);
1465 pa_sink_put(u
->sink
);
1467 pa_source_put(u
->source
);
1469 pa_modargs_free(ma
);
1481 pa_modargs_free(ma
);
1486 void pa__done(pa_module
*m
) {
1491 if (!(u
= m
->userdata
))
1495 pa_sink_unlink(u
->sink
);
1498 pa_source_unlink(u
->source
);
1501 pa_asyncmsgq_send(u
->thread_mq
.inq
, NULL
, PA_MESSAGE_SHUTDOWN
, NULL
, 0, NULL
);
1502 pa_thread_free(u
->thread
);
1505 pa_thread_mq_done(&u
->thread_mq
);
1508 pa_sink_unref(u
->sink
);
1511 pa_source_unref(u
->source
);
1513 if (u
->memchunk
.memblock
)
1514 pa_memblock_unref(u
->memchunk
.memblock
);
1517 pa_rtpoll_item_free(u
->rtpoll_item
);
1520 pa_rtpoll_free(u
->rtpoll
);
1522 if (u
->out_mmap_memblocks
) {
1524 for (i
= 0; i
< u
->out_nfrags
; i
++)
1525 if (u
->out_mmap_memblocks
[i
])
1526 pa_memblock_unref_fixed(u
->out_mmap_memblocks
[i
]);
1527 pa_xfree(u
->out_mmap_memblocks
);
1530 if (u
->in_mmap_memblocks
) {
1532 for (i
= 0; i
< u
->in_nfrags
; i
++)
1533 if (u
->in_mmap_memblocks
[i
])
1534 pa_memblock_unref_fixed(u
->in_mmap_memblocks
[i
]);
1535 pa_xfree(u
->in_mmap_memblocks
);
1538 if (u
->in_mmap
&& u
->in_mmap
!= MAP_FAILED
)
1539 munmap(u
->in_mmap
, u
->in_hwbuf_size
);
1541 if (u
->out_mmap
&& u
->out_mmap
!= MAP_FAILED
)
1542 munmap(u
->out_mmap
, u
->out_hwbuf_size
);
1547 if (u
->mixer_fd
>= 0)
1548 pa_close(u
->mixer_fd
);
1550 pa_xfree(u
->device_name
);