xref: /freebsd/usr.sbin/virtual_oss/virtual_oss/main.c (revision 0532cd2d771372d3266b97aebf4043d5b31b64bd)
1 /*-
2  * Copyright (c) 2012-2022 Hans Petter Selasky
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include <sys/queue.h>
27 #include <sys/types.h>
28 #include <sys/filio.h>
29 #include <sys/rtprio.h>
30 #include <sys/nv.h>
31 #include <sys/sndstat.h>
32 #include <sys/soundcard.h>
33 
34 #include <dlfcn.h>
35 #include <stdio.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <err.h>
41 #include <sysexits.h>
42 #include <signal.h>
43 #include <fcntl.h>
44 #include <paths.h>
45 
46 #include <cuse.h>
47 #include <pthread.h>
48 
49 #include "backend.h"
50 #include "int.h"
51 #include "utils.h"
52 #include "virtual_oss.h"
53 
54 pthread_mutex_t atomic_mtx;
55 pthread_cond_t atomic_cv;
56 
57 static void
58 atomic_init(void)
59 {
60 	if (pthread_mutex_init(&atomic_mtx, NULL) != 0)
61 		err(1, "pthread_mutex_init");
62 	if (pthread_cond_init(&atomic_cv, NULL) != 0)
63 		err(1, "pthread_cond_init");
64 }
65 
66 uint32_t
67 vclient_sample_bytes(vclient_t *pvc)
68 {
69 	uint32_t fmt = pvc->format;
70 
71 	if (fmt & AFMT_16BIT)
72 		return (2);
73 	else if (fmt & AFMT_24BIT)
74 		return (3);
75 	else if (fmt & AFMT_32BIT)
76 		return (4);
77 	else if (fmt & AFMT_8BIT)
78 		return (1);
79 	else
80 		return (0);
81 	/* TODO AFMT_BPS */
82 }
83 
84 static uint32_t
85 vclient_output_delay(vclient_t *pvc)
86 {
87 	uint64_t size;
88 	uint64_t mod;
89 
90 	if (pvc->tx_busy == 0)
91 		vclient_import_write_locked(pvc);
92 
93 	mod = pvc->channels * vclient_sample_bytes(pvc);
94 
95 	size = vring_total_read_len(&pvc->tx_ring[0]);
96 	size = (size / 8) * vclient_sample_bytes(pvc);
97 
98 	size = (size * (uint64_t)pvc->sample_rate) /
99 	    (uint64_t)voss_dsp_sample_rate;
100 	size += vring_total_read_len(&pvc->tx_ring[1]);
101 	size -= size % mod;
102 
103 	return (size);
104 }
105 
106 static uint32_t
107 vclient_input_delay(vclient_t *pvc)
108 {
109 	if (pvc->rx_busy == 0)
110 		vclient_export_read_locked(pvc);
111 	return (vring_total_read_len(&pvc->rx_ring[1]));
112 }
113 
114 uint32_t
115 vclient_bufsize_scaled(vclient_t *pvc)
116 {
117 	uint32_t samples_scaled = ((uint64_t)voss_dsp_samples *
118 	    (uint64_t)pvc->sample_rate) / (uint64_t)voss_dsp_sample_rate;
119 	if (samples_scaled == 0)
120 		samples_scaled = 1;
121 	return (pvc->channels * samples_scaled * vclient_sample_bytes(pvc));
122 }
123 
124 static uint64_t
125 vclient_bufsize_consumed(vclient_t *pvc, uint64_t ts)
126 {
127 	int64_t delta;
128 	int64_t samples_scaled;
129 	int64_t retval;
130 
131 	delta = virtual_oss_timestamp() - ts;
132 	if (delta < 0)
133 		delta = 0;
134 	samples_scaled = (delta * (uint64_t)pvc->sample_rate) / 1000000000ULL;
135 	if (samples_scaled < 0)
136 		samples_scaled = 0;
137 	retval = pvc->channels * samples_scaled * vclient_sample_bytes(pvc);
138 	if (retval < 0)
139 		retval = 0;
140 	return (retval);
141 }
142 
143 /*
144  * VLC and some other audio player use this value for jitter
145  * computations and expect it to be very accurate. VirtualOSS is block
146  * based and does not have sample accuracy. Use the system clock to
147  * update this value as we go along instead:
148  */
149 static uint32_t
150 vclient_output_delay_adjusted(vclient_t *pvc)
151 {
152 	int64_t retval = vclient_output_delay(pvc) -
153 	    vclient_bufsize_consumed(pvc, pvc->tx_timestamp);
154 	if (retval < 0)
155 		retval = 0;
156 	return (retval);
157 }
158 
159 vmonitor_t *
160 vmonitor_alloc(int *pid, vmonitor_head_t *phead)
161 {
162 	int id = 0;
163 	vmonitor_t *pvm;
164 
165 	TAILQ_FOREACH(pvm, phead, entry)
166 	    id++;
167 
168 	if (id >= 64) {
169 		*pid = 0;
170 		return (NULL);
171 	}
172 	pvm = malloc(sizeof(*pvm));
173 	if (pvm == NULL) {
174 		*pid = 0;
175 		return (NULL);
176 	}
177 	memset(pvm, 0, sizeof(*pvm));
178 
179 	pvm->mute = 1;
180 
181 	TAILQ_INSERT_TAIL(phead, pvm, entry);
182 
183 	*pid = id;
184 	return (pvm);
185 }
186 
187 int64_t
188 vclient_noise(uint32_t *pnoise, int64_t volume, int8_t shift)
189 {
190 	const uint32_t prime = 0xFFFF1DU;
191 	int64_t temp;
192 
193 	/* compute next noise sample */
194 	temp = *pnoise;
195 	if (temp & 1)
196 		temp += prime;
197 	temp /= 2;
198 	*pnoise = temp;
199 
200 	/* unsigned to signed conversion */
201 	temp ^= 0x800000ULL;
202 	if (temp & 0x800000U)
203 		temp |= -0x800000ULL;
204 
205 	/* properly amplify */
206 	temp *= volume;
207 
208 	/* bias shift */
209 	shift -= 23 + VVOLUME_UNIT_SHIFT;
210 
211 	/* range check and shift noise */
212 	if (__predict_false(shift < -63 || shift > 63))
213 		temp = 0;
214 	else if (shift < 0)
215 		temp >>= -shift;
216 	else
217 		temp <<= shift;
218 
219 	return (temp);
220 }
221 
222 static void
223 vresample_free(vresample_t *pvr)
224 {
225 	if (pvr->state != NULL)
226 		src_delete(pvr->state);
227 	free(pvr->data_in);
228 	free(pvr->data_out);
229 	memset(pvr, 0, sizeof(*pvr));
230 }
231 
232 static int
233 vresample_setup(vclient_t *pvc, vresample_t *pvr, int samples)
234 {
235 	int code = 0;
236 
237 	if (pvr->state != NULL)
238 		return (0);
239 	pvr->state = src_new(voss_libsamplerate_quality, pvc->channels, &code);
240 	if (pvr->state == NULL)
241 		goto error;
242 	pvr->data_in = malloc(sizeof(float) * samples);
243 	if (pvr->data_in == NULL)
244 		goto error;
245 	pvr->data_out = malloc(sizeof(float) * samples);
246 	if (pvr->data_out == NULL)
247 		goto error;
248 	pvr->data.data_in = pvr->data_in;
249 	pvr->data.data_out = pvr->data_out;
250 	return (0);
251 error:
252 	vresample_free(pvr);
253 	return (CUSE_ERR_NO_MEMORY);
254 }
255 
256 void
257 vclient_free(vclient_t *pvc)
258 {
259 	vresample_free(&pvc->rx_resample);
260 	vresample_free(&pvc->tx_resample);
261 
262 	/* free equalizer */
263 	vclient_eq_free(pvc);
264 
265 	/* free ring buffers */
266 	vring_free(&pvc->rx_ring[0]);
267 	vring_free(&pvc->rx_ring[1]);
268 	vring_free(&pvc->tx_ring[0]);
269 	vring_free(&pvc->tx_ring[1]);
270 
271 	free(pvc);
272 }
273 
274 vclient_t *
275 vclient_alloc(void)
276 {
277 	vclient_t *pvc;
278 
279 	pvc = malloc(sizeof(*pvc));
280 	if (pvc == NULL)
281 		return (NULL);
282 
283 	memset(pvc, 0, sizeof(*pvc));
284 
285 	pvc->rx_noise_rem = 1;
286 	pvc->tx_noise_rem = 1;
287 	pvc->rx_volume = 1 << VVOLUME_UNIT_SHIFT;
288 	pvc->tx_volume = 1 << VVOLUME_UNIT_SHIFT;
289 
290 	return (pvc);
291 }
292 
293 int
294 vclient_get_default_fmt(vprofile_t *pvp, int type)
295 {
296 	int retval;
297 
298 	if (type == VTYPE_WAV_HDR) {
299 		switch (pvp->bits) {
300 		case 16:
301 			retval = AFMT_S16_LE;
302 			break;
303 		case 24:
304 			retval = AFMT_S24_LE;
305 			break;
306 		case 32:
307 			retval = AFMT_S32_LE;
308 			break;
309 		default:
310 			retval = AFMT_S8;
311 			break;
312 		}
313 	} else {
314 		switch (pvp->bits) {
315 		case 16:
316 			retval = AFMT_S16_NE;
317 			break;
318 		case 24:
319 			retval = AFMT_S24_NE;
320 			break;
321 		case 32:
322 			retval = AFMT_S32_NE;
323 			break;
324 		default:
325 			retval = AFMT_S8;
326 			break;
327 		}
328 	}
329 	return (retval);
330 }
331 
332 int
333 vclient_setup_buffers(vclient_t *pvc, int size, int frags,
334     int channels, int format, int sample_rate)
335 {
336 	size_t bufsize_internal;
337 	size_t bufsize_min;
338 	size_t mod_internal;
339 	size_t mod;
340 	uint64_t ts;
341 	int bufsize;
342 
343 	/* check we are not busy */
344 	if (pvc->rx_busy || pvc->tx_busy)
345 		return (CUSE_ERR_BUSY);
346 
347 	/* free equalizer */
348 	vclient_eq_free(pvc);
349 
350 	/* free existing ring buffers */
351 	vring_free(&pvc->rx_ring[0]);
352 	vring_free(&pvc->rx_ring[1]);
353 	vring_free(&pvc->tx_ring[0]);
354 	vring_free(&pvc->tx_ring[1]);
355 
356 	/* reset resampler */
357 	vresample_free(&pvc->rx_resample);
358 	vresample_free(&pvc->tx_resample);
359 
360 	if (sample_rate > 0)
361 		pvc->sample_rate = sample_rate;
362 	if (format != 0)
363 		pvc->format = format;
364 	if (channels > 0)
365 		pvc->channels = channels;
366 
367 	mod = pvc->channels * vclient_sample_bytes(pvc);
368 	mod_internal = pvc->channels * 8;
369 
370 	if (size > 0) {
371 		size += mod - 1;
372 		size -= size % mod;
373 
374 		pvc->buffer_size = size;
375 		pvc->buffer_size_set = 1;
376 	} else if (pvc->buffer_size_set == 0)
377 		pvc->buffer_size = vclient_bufsize_scaled(pvc);
378 
379 	pvc->low_water = pvc->buffer_size;
380 
381 	if (frags > 0) {
382 		pvc->buffer_frags = frags;
383 		pvc->buffer_frags_set = 1;
384 	} else if (pvc->buffer_frags_set == 0)
385 		pvc->buffer_frags = 2;
386 
387 	/* sanity checks */
388 	if (frags < 0 || size < 0)
389 		return (CUSE_ERR_INVALID);
390 	if (pvc->format == 0)
391 		return (CUSE_ERR_INVALID);
392 	if (pvc->buffer_frags <= 0 || pvc->buffer_frags >= 1024)
393 		return (CUSE_ERR_INVALID);
394 	if (pvc->buffer_size <= 0 || pvc->buffer_size >= (1024 * 1024))
395 		return (CUSE_ERR_INVALID);
396 	if ((pvc->buffer_size * pvc->buffer_frags) >= (128 * 1024 * 1024))
397 		return (CUSE_ERR_INVALID);
398 	if (pvc->channels <= 0 || pvc->channels > pvc->profile->channels)
399 		return (CUSE_ERR_INVALID);
400 
401 	/* get buffer sizes */
402 	bufsize = pvc->buffer_frags * pvc->buffer_size;
403 	bufsize_internal = ((uint64_t)bufsize * (uint64_t)voss_dsp_sample_rate * 8ULL) /
404 	  ((uint64_t)pvc->sample_rate * (uint64_t)vclient_sample_bytes(pvc));
405 
406 	bufsize_min = voss_dsp_samples * pvc->channels * 8;
407 
408 	/* check for too small buffer size */
409 	if (bufsize_internal < bufsize_min)
410 		return (CUSE_ERR_INVALID);
411 
412 	/* allow for jitter */
413 	bufsize_internal *= 2ULL;
414 
415 	/* align buffer size */
416 	bufsize_internal += (mod_internal - 1);
417 	bufsize_internal -= (bufsize_internal % mod_internal);
418 
419 	/* allocate new buffers */
420 	if (vring_alloc(&pvc->rx_ring[0], bufsize_internal))
421 		goto err_0;
422 	if (vring_alloc(&pvc->rx_ring[1], bufsize))
423 		goto err_1;
424 	if (vring_alloc(&pvc->tx_ring[0], bufsize_internal))
425 		goto err_2;
426 	if (vring_alloc(&pvc->tx_ring[1], bufsize))
427 		goto err_3;
428 	if (vclient_eq_alloc(pvc))
429 		goto err_4;
430 
431 	ts = virtual_oss_timestamp();
432 
433 	pvc->rx_samples = 0;
434 	pvc->tx_samples = 0;
435 	pvc->tx_timestamp = ts;
436 	pvc->rx_timestamp = ts;
437 
438 	return (0);
439 
440 err_4:
441 	vring_free(&pvc->tx_ring[1]);
442 err_3:
443 	vring_free(&pvc->tx_ring[0]);
444 err_2:
445 	vring_free(&pvc->rx_ring[1]);
446 err_1:
447 	vring_free(&pvc->rx_ring[0]);
448 err_0:
449 	return (CUSE_ERR_NO_MEMORY);
450 }
451 
452 static int
453 vclient_open_sub(struct cuse_dev *pdev, int fflags __unused, int type)
454 {
455 	vclient_t *pvc;
456 	vprofile_t *pvp;
457 	int error;
458 
459 	pvp = cuse_dev_get_priv0(pdev);
460 
461 	pvc = vclient_alloc();
462 	if (pvc == NULL)
463 		return (CUSE_ERR_NO_MEMORY);
464 
465 	pvc->profile = pvp;
466 
467 	/* setup buffers */
468 	error = vclient_setup_buffers(pvc, 0, 0, pvp->channels,
469 	    vclient_get_default_fmt(pvp, type), voss_dsp_sample_rate);
470 	if (error != 0) {
471 		vclient_free(pvc);
472 		return (error);
473 	}
474 
475 	pvc->type = type;
476 
477 	cuse_dev_set_per_file_handle(pdev, pvc);
478 
479 	atomic_lock();
480 	/* only allow one synchronization source at a time */
481 	if (pvc->profile->synchronized) {
482 		if (voss_has_synchronization != 0)
483 			error = CUSE_ERR_BUSY;
484 		else
485 			voss_has_synchronization++;
486 	}
487 	if (error == 0)
488 		TAILQ_INSERT_TAIL(&pvc->profile->head, pvc, entry);
489 	atomic_unlock();
490 
491 	return (error);
492 }
493 
494 static int
495 vclient_open_wav(struct cuse_dev *pdev, int fflags)
496 {
497 	return (vclient_open_sub(pdev, fflags, VTYPE_WAV_HDR));
498 }
499 
500 static int
501 vclient_open_oss(struct cuse_dev *pdev, int fflags)
502 {
503 	return (vclient_open_sub(pdev, fflags, VTYPE_OSS_DAT));
504 }
505 
506 static int
507 vclient_close(struct cuse_dev *pdev, int fflags __unused)
508 {
509 	vclient_t *pvc;
510 
511 	pvc = cuse_dev_get_per_file_handle(pdev);
512 	if (pvc == NULL)
513 		return (CUSE_ERR_INVALID);
514 
515 	atomic_lock();
516 	if (pvc->profile->synchronized) {
517 		voss_has_synchronization--;
518 
519 		/* wait for virtual_oss_process(), if any */
520 		while (pvc->sync_busy) {
521 			pvc->sync_wakeup = 1;
522 			atomic_wakeup();
523 			atomic_wait();
524 		}
525 	}
526 	TAILQ_REMOVE(&pvc->profile->head, pvc, entry);
527 	atomic_unlock();
528 
529 	vclient_free(pvc);
530 
531 	return (0);
532 }
533 
534 static int
535 vclient_read_silence_locked(vclient_t *pvc)
536 {
537 	size_t size;
538 	int delta_in;
539 
540 	delta_in = pvc->profile->rec_delay - pvc->rec_delay;
541 	if (delta_in < 1)
542 		return (0);
543 
544 	size = delta_in * pvc->channels * 8;
545 	size = vring_write_zero(&pvc->rx_ring[0], size);
546 	pvc->rec_delay += size / (pvc->channels * 8);
547 
548 	delta_in = pvc->profile->rec_delay - pvc->rec_delay;
549 	if (delta_in < 1)
550 		return (0);
551 
552 	return (1);
553 }
554 
555 static int
556 vclient_generate_wav_header_locked(vclient_t *pvc)
557 {
558 	uint8_t *ptr;
559 	size_t mod;
560 	size_t len;
561 
562 	vring_get_write(&pvc->rx_ring[1], &ptr, &len);
563 
564 	mod = pvc->channels * vclient_sample_bytes(pvc);
565 
566 	if (mod == 0 || len < (44 + mod - 1))
567 		return (CUSE_ERR_INVALID);
568 
569 	/* align to next sample */
570 	len = 44 + mod - 1;
571 	len -= len % mod;
572 
573 	/* pre-advance write pointer */
574 	vring_inc_write(&pvc->rx_ring[1], len);
575 
576 	/* clear block */
577 	memset(ptr, 0, len);
578 
579 	/* fill out data header */
580 	ptr[len - 8] = 'd';
581 	ptr[len - 7] = 'a';
582 	ptr[len - 6] = 't';
583 	ptr[len - 5] = 'a';
584 
585 	/* magic for unspecified length */
586 	ptr[len - 4] = 0x00;
587 	ptr[len - 3] = 0xF0;
588 	ptr[len - 2] = 0xFF;
589 	ptr[len - 1] = 0x7F;
590 
591 	/* fill out header */
592 	*ptr++ = 'R';
593 	*ptr++ = 'I';
594 	*ptr++ = 'F';
595 	*ptr++ = 'F';
596 
597 	/* total chunk size - unknown */
598 
599 	*ptr++ = 0;
600 	*ptr++ = 0;
601 	*ptr++ = 0;
602 	*ptr++ = 0;
603 
604 	*ptr++ = 'W';
605 	*ptr++ = 'A';
606 	*ptr++ = 'V';
607 	*ptr++ = 'E';
608 	*ptr++ = 'f';
609 	*ptr++ = 'm';
610 	*ptr++ = 't';
611 	*ptr++ = ' ';
612 
613 	/* make sure header fits in PCM block */
614 	len -= 28;
615 
616 	*ptr++ = len;
617 	*ptr++ = len >> 8;
618 	*ptr++ = len >> 16;
619 	*ptr++ = len >> 24;
620 
621 	/* audioformat = PCM */
622 
623 	*ptr++ = 0x01;
624 	*ptr++ = 0x00;
625 
626 	/* number of channels */
627 
628 	len = pvc->channels;
629 
630 	*ptr++ = len;
631 	*ptr++ = len >> 8;
632 
633 	/* sample rate */
634 
635 	len = pvc->sample_rate;
636 
637 	*ptr++ = len;
638 	*ptr++ = len >> 8;
639 	*ptr++ = len >> 16;
640 	*ptr++ = len >> 24;
641 
642 	/* byte rate */
643 
644 	len = pvc->sample_rate * pvc->channels * vclient_sample_bytes(pvc);
645 
646 	*ptr++ = len;
647 	*ptr++ = len >> 8;
648 	*ptr++ = len >> 16;
649 	*ptr++ = len >> 24;
650 
651 	/* block align */
652 
653 	len = pvc->channels * vclient_sample_bytes(pvc);
654 
655 	*ptr++ = len;
656 	*ptr++ = len >> 8;
657 
658 	/* bits per sample */
659 
660 	len = vclient_sample_bytes(pvc) * 8;
661 
662 	*ptr++ = len;
663 	*ptr++ = len >> 8;
664 
665 	return (0);
666 }
667 
668 int
669 vclient_export_read_locked(vclient_t *pvc) __requires_exclusive(atomic_mtx)
670 {
671 	enum { MAX_FRAME = 1024 };
672 	size_t dst_mod;
673 	size_t src_mod;
674 	int error;
675 
676 	if (pvc->type == VTYPE_WAV_HDR) {
677 		error = vclient_generate_wav_header_locked(pvc);
678 		if (error != 0)
679 			return (error);
680 		/* only write header once */
681 		pvc->type = VTYPE_WAV_DAT;
682 	}
683 	error = vclient_read_silence_locked(pvc);
684 	if (error != 0)
685 		return (0);
686 
687 	dst_mod = pvc->channels * vclient_sample_bytes(pvc);
688 	src_mod = pvc->channels * 8;
689 
690 	if (pvc->sample_rate == (int)voss_dsp_sample_rate) {
691 		while (1) {
692 			uint8_t *src_ptr;
693 			size_t src_len;
694 			uint8_t *dst_ptr;
695 			size_t dst_len;
696 
697 			vring_get_read(&pvc->rx_ring[0], &src_ptr, &src_len);
698 			vring_get_write(&pvc->rx_ring[1], &dst_ptr, &dst_len);
699 
700 			src_len /= src_mod;
701 			dst_len /= dst_mod;
702 
703 			/* compare number of samples */
704 			if (dst_len > src_len)
705 				dst_len = src_len;
706 			else
707 				src_len = dst_len;
708 
709 			if (dst_len == 0)
710 				break;
711 
712 			src_len *= src_mod;
713 			dst_len *= dst_mod;
714 
715 			format_export(pvc->format,
716 			    (const int64_t *)(uintptr_t)src_ptr,
717 			    dst_ptr, dst_len);
718 
719 			vring_inc_read(&pvc->rx_ring[0], src_len);
720 			vring_inc_write(&pvc->rx_ring[1], dst_len);
721 		}
722 	} else {
723 		vresample_t *pvr = &pvc->rx_resample;
724 
725 		if (vresample_setup(pvc, pvr, MAX_FRAME * pvc->channels) != 0)
726 			return (CUSE_ERR_NO_MEMORY);
727 
728 		while (1) {
729 			uint8_t *src_ptr;
730 			size_t src_len;
731 			uint8_t *dst_ptr;
732 			size_t dst_len;
733 			int64_t temp[MAX_FRAME * pvc->channels];
734 			size_t samples;
735 			size_t y;
736 
737 			vring_get_read(&pvc->rx_ring[0], &src_ptr, &src_len);
738 			vring_get_write(&pvc->rx_ring[1], &dst_ptr, &dst_len);
739 
740 			src_len /= src_mod;
741 			dst_len /= dst_mod;
742 
743 			/* compare number of samples */
744 			if (dst_len > src_len)
745 				dst_len = src_len;
746 			else
747 				src_len = dst_len;
748 
749 			if (dst_len > MAX_FRAME)
750 				dst_len = src_len = MAX_FRAME;
751 
752 			if (dst_len == 0)
753 				break;
754 
755 			src_len *= src_mod;
756 			dst_len *= dst_mod;
757 
758 			for (y = 0; y != src_len; y += 8) {
759 				pvr->data_in[y / 8] =
760 				    *(int64_t *)(uintptr_t)(src_ptr + y);
761 			}
762 
763 			/* setup parameters for transform */
764 			pvr->data.input_frames = src_len / src_mod;
765 			pvr->data.output_frames = dst_len / dst_mod;
766 			pvr->data.src_ratio = (float)pvc->sample_rate / (float)voss_dsp_sample_rate;
767 
768 			pvc->rx_busy = 1;
769 			atomic_unlock();
770 			error = src_process(pvr->state, &pvr->data);
771 			atomic_lock();
772 			pvc->rx_busy = 0;
773 
774 			if (error != 0)
775 				break;
776 
777 			src_len = pvr->data.input_frames_used * src_mod;
778 			dst_len = pvr->data.output_frames_gen * dst_mod;
779 
780 			samples = pvr->data.output_frames_gen * pvc->channels;
781 
782 			for (y = 0; y != samples; y++)
783 				temp[y] = pvr->data_out[y];
784 
785 			format_export(pvc->format, temp, dst_ptr, dst_len);
786 
787 			vring_inc_read(&pvc->rx_ring[0], src_len);
788 			vring_inc_write(&pvc->rx_ring[1], dst_len);
789 
790 			/* check if no data was moved */
791 			if (src_len == 0 && dst_len == 0)
792 				break;
793 		}
794 	}
795 	if (pvc->sync_busy)
796 		atomic_wakeup();
797 	return (0);
798 }
799 
800 static int
801 vclient_read(struct cuse_dev *pdev, int fflags,
802     void *peer_ptr, int len)
803 {
804 	vclient_t *pvc;
805 
806 	int error;
807 	int retval;
808 
809 	pvc = cuse_dev_get_per_file_handle(pdev);
810 	if (pvc == NULL)
811 		return (CUSE_ERR_INVALID);
812 
813 	atomic_lock();
814 
815 	if (pvc->rx_busy) {
816 		atomic_unlock();
817 		return (CUSE_ERR_BUSY);
818 	}
819 	pvc->rx_enabled = 1;
820 
821 	retval = 0;
822 
823 	while (len > 0) {
824 		uint8_t *buf_ptr;
825 		size_t buf_len;
826 
827 		error = vclient_export_read_locked(pvc);
828 		if (error != 0) {
829 			retval = error;
830 			break;
831 		}
832 
833 		vring_get_read(&pvc->rx_ring[1], &buf_ptr, &buf_len);
834 
835 		if (buf_len == 0) {
836 			/* out of data */
837 			if (fflags & CUSE_FFLAG_NONBLOCK) {
838 				if (retval == 0)
839 					retval = CUSE_ERR_WOULDBLOCK;
840 				break;
841 			}
842 			pvc->rx_busy = 1;
843 			atomic_wait();
844 			pvc->rx_busy = 0;
845 			if (cuse_got_peer_signal() == 0) {
846 				if (retval == 0)
847 					retval = CUSE_ERR_SIGNAL;
848 				break;
849 			}
850 			continue;
851 		}
852 		if ((int)buf_len > len)
853 			buf_len = len;
854 
855 		pvc->rx_busy = 1;
856 		atomic_unlock();
857 		error = cuse_copy_out(buf_ptr, peer_ptr, buf_len);
858 		atomic_lock();
859 		pvc->rx_busy = 0;
860 
861 		if (error != 0) {
862 			retval = error;
863 			break;
864 		}
865 		peer_ptr = ((uint8_t *)peer_ptr) + buf_len;
866 		retval += buf_len;
867 		len -= buf_len;
868 
869 		vring_inc_read(&pvc->rx_ring[1], buf_len);
870 	}
871 	atomic_unlock();
872 
873 	return (retval);
874 }
875 
876 void
877 vclient_import_write_locked(vclient_t *pvc) __requires_exclusive(atomic_mtx)
878 {
879 	enum { MAX_FRAME = 1024 };
880 	size_t dst_mod;
881 	size_t src_mod;
882 
883 	dst_mod = pvc->channels * 8;
884 	src_mod = pvc->channels * vclient_sample_bytes(pvc);
885 
886 	if (pvc->sample_rate == (int)voss_dsp_sample_rate) {
887 		while (1) {
888 			uint8_t *src_ptr;
889 			size_t src_len;
890 			uint8_t *dst_ptr;
891 			size_t dst_len;
892 
893 			vring_get_read(&pvc->tx_ring[1], &src_ptr, &src_len);
894 			vring_get_write(&pvc->tx_ring[0], &dst_ptr, &dst_len);
895 
896 			src_len /= src_mod;
897 			dst_len /= dst_mod;
898 
899 			/* compare number of samples */
900 			if (dst_len > src_len)
901 				dst_len = src_len;
902 			else
903 				src_len = dst_len;
904 
905 			if (dst_len == 0)
906 				break;
907 
908 			src_len *= src_mod;
909 			dst_len *= dst_mod;
910 
911 			format_import(pvc->format, src_ptr, src_len,
912 			    (int64_t *)(uintptr_t)dst_ptr);
913 
914 			vring_inc_read(&pvc->tx_ring[1], src_len);
915 			vring_inc_write(&pvc->tx_ring[0], dst_len);
916 		}
917 	} else {
918 		vresample_t *pvr = &pvc->tx_resample;
919 
920 		if (vresample_setup(pvc, pvr, MAX_FRAME * pvc->channels) != 0)
921 			return;
922 
923 		while (1) {
924 			uint8_t *src_ptr;
925 			size_t src_len;
926 			uint8_t *dst_ptr;
927 			size_t dst_len;
928 			int64_t temp[MAX_FRAME * pvc->channels];
929 			size_t samples;
930 			size_t y;
931 			int error;
932 
933 			vring_get_read(&pvc->tx_ring[1], &src_ptr, &src_len);
934 			vring_get_write(&pvc->tx_ring[0], &dst_ptr, &dst_len);
935 
936 			src_len /= src_mod;
937 			dst_len /= dst_mod;
938 
939 			/* compare number of samples */
940 			if (dst_len > src_len)
941 				dst_len = src_len;
942 			else
943 				src_len = dst_len;
944 
945 			if (dst_len > MAX_FRAME)
946 				dst_len = src_len = MAX_FRAME;
947 
948 			if (dst_len == 0)
949 				break;
950 
951 			src_len *= src_mod;
952 			dst_len *= dst_mod;
953 
954 			format_import(pvc->format, src_ptr, src_len, temp);
955 
956 			src_len /= vclient_sample_bytes(pvc);
957 
958 			for (y = 0; y != src_len; y++)
959 				pvr->data_in[y] = temp[y];
960 
961 			src_len *= vclient_sample_bytes(pvc);
962 
963 			/* setup parameters for transform */
964 			pvr->data.input_frames = src_len / src_mod;
965 			pvr->data.output_frames = dst_len / dst_mod;
966 			pvr->data.src_ratio = (float)voss_dsp_sample_rate / (float)pvc->sample_rate;
967 
968 			pvc->tx_busy = 1;
969 			atomic_unlock();
970 			error = src_process(pvr->state, &pvr->data);
971 			atomic_lock();
972 			pvc->tx_busy = 0;
973 
974 			if (error != 0)
975 				break;
976 
977 			src_len = pvr->data.input_frames_used * src_mod;
978 			dst_len = pvr->data.output_frames_gen * dst_mod;
979 
980 			samples = pvr->data.output_frames_gen * pvc->channels;
981 
982 			for (y = 0; y != samples; y++) {
983 				((int64_t *)(uintptr_t)dst_ptr)[y] =
984 				    pvr->data_out[y];
985 			}
986 
987 			vring_inc_read(&pvc->tx_ring[1], src_len);
988 			vring_inc_write(&pvc->tx_ring[0], dst_len);
989 
990 			/* check if no data was moved */
991 			if (src_len == 0 && dst_len == 0)
992 				break;
993 		}
994 	}
995 	if (pvc->sync_busy)
996 		atomic_wakeup();
997 }
998 
999 static int
1000 vclient_write_oss(struct cuse_dev *pdev, int fflags,
1001     const void *peer_ptr, int len)
1002 {
1003 	vclient_t *pvc;
1004 
1005 	int error;
1006 	int retval;
1007 
1008 	pvc = cuse_dev_get_per_file_handle(pdev);
1009 	if (pvc == NULL)
1010 		return (CUSE_ERR_INVALID);
1011 
1012 	retval = 0;
1013 
1014 	atomic_lock();
1015 
1016 	if (pvc->tx_busy) {
1017 		atomic_unlock();
1018 		return (CUSE_ERR_BUSY);
1019 	}
1020 	pvc->tx_enabled = 1;
1021 
1022 	while (1) {
1023 		uint8_t *buf_ptr;
1024 		size_t buf_len;
1025 
1026 		vclient_import_write_locked(pvc);
1027 
1028 		if (len < 1)
1029 			break;
1030 
1031 		vring_get_write(&pvc->tx_ring[1], &buf_ptr, &buf_len);
1032 
1033 		if (buf_len == 0) {
1034 			/* out of data */
1035 			if (fflags & CUSE_FFLAG_NONBLOCK) {
1036 				if (retval == 0)
1037 					retval = CUSE_ERR_WOULDBLOCK;
1038 				break;
1039 			}
1040 			pvc->tx_busy = 1;
1041 			atomic_wait();
1042 			pvc->tx_busy = 0;
1043 			if (cuse_got_peer_signal() == 0) {
1044 				if (retval == 0)
1045 					retval = CUSE_ERR_SIGNAL;
1046 				break;
1047 			}
1048 			continue;
1049 		}
1050 		if ((int)buf_len > len)
1051 			buf_len = len;
1052 
1053 		pvc->tx_busy = 1;
1054 		atomic_unlock();
1055 		error = cuse_copy_in(peer_ptr, buf_ptr, buf_len);
1056 		atomic_lock();
1057 		pvc->tx_busy = 0;
1058 
1059 		if (error != 0) {
1060 			retval = error;
1061 			break;
1062 		}
1063 		peer_ptr = ((const uint8_t *)peer_ptr) + buf_len;
1064 		retval += buf_len;
1065 		len -= buf_len;
1066 
1067 		vring_inc_write(&pvc->tx_ring[1], buf_len);
1068 	}
1069 	atomic_unlock();
1070 
1071 	return (retval);
1072 }
1073 
1074 static int
1075 vclient_write_wav(struct cuse_dev *pdev __unused, int fflags __unused,
1076     const void *peer_ptr __unused, int len __unused)
1077 {
1078 	return (CUSE_ERR_INVALID);
1079 }
1080 
1081 static int
1082 vclient_set_channels(vclient_t *pvc, int channels)
1083 {
1084 	if (pvc->channels == channels)
1085 		return (0);
1086 	return (vclient_setup_buffers(pvc, 0, 0, channels, 0, 0));
1087 }
1088 
1089 /* greatest common divisor, Euclid equation */
1090 static uint64_t
1091 vclient_gcd_64(uint64_t a, uint64_t b)
1092 {
1093 	uint64_t an;
1094 	uint64_t bn;
1095 
1096 	while (b != 0) {
1097 		an = b;
1098 		bn = a % b;
1099 		a = an;
1100 		b = bn;
1101 	}
1102 	return (a);
1103 }
1104 
1105 static uint64_t
1106 vclient_scale(uint64_t value, uint64_t mul, uint64_t div)
1107 {
1108 	uint64_t gcd = vclient_gcd_64(mul, div);
1109 
1110 	mul /= gcd;
1111 	div /= gcd;
1112 
1113 	return ((value * mul) / div);
1114 }
1115 
1116 static int
1117 vclient_ioctl_oss(struct cuse_dev *pdev, int fflags __unused,
1118     unsigned long cmd, void *peer_data)
1119 {
1120 	union {
1121 		int	val;
1122 		unsigned long long lval;
1123 		oss_sysinfo sysinfo;
1124 		oss_card_info card_info;
1125 		oss_audioinfo audioinfo;
1126 		audio_buf_info buf_info;
1127 		oss_count_t oss_count;
1128 		count_info oss_count_info;
1129 		audio_errinfo errinfo;
1130 		oss_label_t label;
1131 		oss_longname_t longname;
1132 	}     data;
1133 
1134 	vclient_t *pvc;
1135 
1136 	uint64_t bytes;
1137 
1138 	int len;
1139 	int error;
1140 	int temp;
1141 
1142 	pvc = cuse_dev_get_per_file_handle(pdev);
1143 	if (pvc == NULL)
1144 		return (CUSE_ERR_INVALID);
1145 
1146 	len = IOCPARM_LEN(cmd);
1147 
1148 	if (len < 0 || len > (int)sizeof(data))
1149 		return (CUSE_ERR_INVALID);
1150 
1151 	if (cmd & IOC_IN) {
1152 		error = cuse_copy_in(peer_data, &data, len);
1153 		if (error)
1154 			return (error);
1155 	} else {
1156 		error = 0;
1157 	}
1158 
1159 	atomic_lock();
1160 
1161 	switch (cmd) {
1162 	case OSS_GETVERSION:
1163 		data.val = SOUND_VERSION;
1164 		break;
1165 	case SNDCTL_SYSINFO:
1166 		memset(&data.sysinfo, 0, sizeof(data.sysinfo));
1167 		strcpy(data.sysinfo.product, "VOSS");
1168 		strcpy(data.sysinfo.version, "1.0");
1169 		data.sysinfo.versionnum = SOUND_VERSION;
1170 		data.sysinfo.numaudios = 1;
1171 		data.sysinfo.numcards = 1;
1172 		data.sysinfo.numaudioengines = 1;
1173 		strcpy(data.sysinfo.license, "BSD");
1174 		memset(data.sysinfo.filler, -1, sizeof(data.sysinfo.filler));
1175 		break;
1176 	case SNDCTL_CARDINFO:
1177 		memset(&data.card_info, 0, sizeof(data.card_info));
1178 		strlcpy(data.card_info.shortname, pvc->profile->oss_name,
1179 		    sizeof(data.card_info.shortname));
1180 		break;
1181 	case SNDCTL_AUDIOINFO:
1182 	case SNDCTL_AUDIOINFO_EX:
1183 	case SNDCTL_ENGINEINFO:
1184 		memset(&data.audioinfo, 0, sizeof(data.audioinfo));
1185 		strlcpy(data.audioinfo.name, pvc->profile->oss_name,
1186 		    sizeof(data.audioinfo.name));
1187 		snprintf(data.audioinfo.devnode, sizeof(data.audioinfo.devnode),
1188 		    "/dev/%s", pvc->profile->oss_name);
1189 		data.audioinfo.caps = DSP_CAP_INPUT | DSP_CAP_OUTPUT;
1190 		data.audioinfo.iformats = VSUPPORTED_AFMT;
1191 		data.audioinfo.oformats = VSUPPORTED_AFMT;
1192 		data.audioinfo.enabled = 1;
1193 		data.audioinfo.min_rate = (int)8000;
1194 		data.audioinfo.max_rate = (int)voss_dsp_sample_rate;
1195 		data.audioinfo.max_channels = pvc->profile->channels;
1196 		/* range check */
1197 		if (voss_libsamplerate_enable == 0 ||
1198 		    data.audioinfo.min_rate > data.audioinfo.max_rate)
1199 			data.audioinfo.min_rate = data.audioinfo.max_rate;
1200 		data.audioinfo.nrates = 1;
1201 		data.audioinfo.rates[0] = (int)voss_dsp_sample_rate;
1202 		if (voss_libsamplerate_enable != 0 &&
1203 		    96000 != voss_dsp_sample_rate)
1204 			data.audioinfo.rates[data.audioinfo.nrates++] = 96000;
1205 		if (voss_libsamplerate_enable != 0 &&
1206 		    48000 != voss_dsp_sample_rate)
1207 			data.audioinfo.rates[data.audioinfo.nrates++] = 48000;
1208 		if (voss_libsamplerate_enable != 0 &&
1209 		    44100 != voss_dsp_sample_rate)
1210 			data.audioinfo.rates[data.audioinfo.nrates++] = 44100;
1211 		if (voss_libsamplerate_enable != 0 &&
1212 		    24000 != voss_dsp_sample_rate)
1213 			data.audioinfo.rates[data.audioinfo.nrates++] = 24000;
1214 		if (voss_libsamplerate_enable != 0 &&
1215 		    16000 != voss_dsp_sample_rate)
1216 			data.audioinfo.rates[data.audioinfo.nrates++] = 16000;
1217 		if (voss_libsamplerate_enable != 0 &&
1218 		    8000 != voss_dsp_sample_rate)
1219 			data.audioinfo.rates[data.audioinfo.nrates++] = 8000;
1220 		data.audioinfo.latency = -1;
1221 		break;
1222 	case FIONREAD:
1223 		data.val = vclient_input_delay(pvc);
1224 		break;
1225 	case FIONWRITE:
1226 		data.val = vring_total_read_len(&pvc->tx_ring[1]);
1227 		break;
1228 	case FIOASYNC:
1229 	case SNDCTL_DSP_NONBLOCK:
1230 	case FIONBIO:
1231 		break;
1232 	case SNDCTL_DSP_SETBLKSIZE:
1233 	case _IOWR('P', 4, int):
1234 		error = vclient_setup_buffers(pvc, data.val, 0, 0, 0, 0);
1235 		/* FALLTHROUGH */
1236 	case SNDCTL_DSP_GETBLKSIZE:
1237 		data.val = pvc->buffer_size;
1238 		break;
1239 	case SNDCTL_DSP_SETFRAGMENT:
1240 		if ((data.val & 0xFFFF) < 4) {
1241 			/* need at least 16 bytes of buffer */
1242 			data.val &= ~0xFFFF;
1243 			data.val |= 4;
1244 		} else if ((data.val & 0xFFFF) > 24) {
1245 			/* no more than 16MBytes of buffer */
1246 			data.val &= ~0xFFFF;
1247 			data.val |= 24;
1248 		}
1249 		error = vclient_setup_buffers(pvc,
1250 		    (1 << (data.val & 0xFFFF)), (data.val >> 16), 0, 0, 0);
1251 		if (error) {
1252 			/* fallback to defaults */
1253 			pvc->buffer_size_set = 0;
1254 			pvc->buffer_frags_set = 0;
1255 			error = vclient_setup_buffers(pvc, 0, 0, 0, 0, 0);
1256 			if (error)
1257 				break;
1258 			/* figure out log2() of actual buffer size */
1259 			for (data.val = 0;
1260 			     data.val < 24 && (1U << data.val) < pvc->buffer_size;
1261 			     data.val++)
1262 				;
1263 			/* or in the actual number of fragments */
1264 			data.val |= (pvc->buffer_frags << 16);
1265 		}
1266 		break;
1267 	case SNDCTL_DSP_RESET:
1268 		error = vclient_setup_buffers(pvc, 0, 0, 0, 0, 0);
1269 		break;
1270 	case SNDCTL_DSP_SYNC:
1271 		break;
1272 	case SNDCTL_DSP_SPEED:
1273 		if (data.val >= 8000 && data.val <= 96000 &&
1274 		    voss_libsamplerate_enable != 0) {
1275 			error = vclient_setup_buffers(pvc, 0, 0, 0, 0, data.val);
1276 		}
1277 		/* return current speed */
1278 		data.val = (int)pvc->sample_rate;
1279 		break;
1280 	case SOUND_PCM_READ_RATE:
1281 		data.val = (int)pvc->sample_rate;
1282 		break;
1283 	case SNDCTL_DSP_STEREO:
1284 		if (data.val != 0) {
1285 			error = vclient_set_channels(pvc, 2);
1286 		} else {
1287 			error = vclient_set_channels(pvc, 1);
1288 		}
1289 		data.val = (pvc->channels == 2);
1290 		break;
1291 	case SOUND_PCM_WRITE_CHANNELS:
1292 		if (data.val < 0) {
1293 			data.val = 0;
1294 			error = CUSE_ERR_INVALID;
1295 			break;
1296 		}
1297 		if (data.val == 0) {
1298 			data.val = pvc->channels;
1299 		} else {
1300 			error = vclient_set_channels(pvc, data.val);
1301 		}
1302 		break;
1303 	case SOUND_PCM_READ_CHANNELS:
1304 		data.val = pvc->channels;
1305 		break;
1306 	case AIOGFMT:
1307 	case SNDCTL_DSP_GETFMTS:
1308 		data.val = VSUPPORTED_AFMT | AFMT_FULLDUPLEX |
1309 		    (pvc->profile->channels > 1 ? AFMT_STEREO : 0);
1310 		break;
1311 	case AIOSFMT:
1312 	case SNDCTL_DSP_SETFMT:
1313 		if (data.val != AFMT_QUERY) {
1314 			temp = data.val & VSUPPORTED_AFMT;
1315 			if (temp == 0 || (temp & (temp - 1)) != 0) {
1316 				error = CUSE_ERR_INVALID;
1317 			} else {
1318 				error = vclient_setup_buffers(pvc, 0, 0, 0, temp, 0);
1319 			}
1320 		} else {
1321 			data.val = pvc->format;
1322 		}
1323 		break;
1324 	case SNDCTL_DSP_GETISPACE:
1325 		memset(&data.buf_info, 0, sizeof(data.buf_info));
1326 		data.buf_info.fragsize = pvc->buffer_size;
1327 		data.buf_info.fragstotal = pvc->buffer_frags;
1328 		bytes = (pvc->buffer_size * pvc->buffer_frags);
1329 		temp = vclient_input_delay(pvc);
1330 		if (temp < 0 || (uint64_t)temp > bytes)
1331 			temp = bytes;
1332 		data.buf_info.fragments = temp / pvc->buffer_size;
1333 		data.buf_info.bytes = temp;
1334 		break;
1335 	case SNDCTL_DSP_GETOSPACE:
1336 		memset(&data.buf_info, 0, sizeof(data.buf_info));
1337 		data.buf_info.fragsize = pvc->buffer_size;
1338 		data.buf_info.fragstotal = pvc->buffer_frags;
1339 		bytes = (pvc->buffer_size * pvc->buffer_frags);
1340 		temp = vclient_output_delay(pvc);
1341 		if (temp < 0 || (uint64_t)temp >= bytes) {
1342 			/* buffer is full */
1343 			data.buf_info.fragments = 0;
1344 			data.buf_info.bytes = 0;
1345 		} else {
1346 			/* buffer is not full */
1347 			bytes -= temp;
1348 			data.buf_info.fragments = bytes / pvc->buffer_size;
1349 			data.buf_info.bytes = bytes;
1350 		}
1351 		break;
1352 	case SNDCTL_DSP_GETCAPS:
1353 		data.val = PCM_CAP_REALTIME | PCM_CAP_DUPLEX |
1354 		    PCM_CAP_INPUT | PCM_CAP_OUTPUT | PCM_CAP_TRIGGER |
1355 		    PCM_CAP_VIRTUAL;
1356 		break;
1357 	case SOUND_PCM_READ_BITS:
1358 		data.val = vclient_sample_bytes(pvc) * 8;
1359 		break;
1360 	case SNDCTL_DSP_SETTRIGGER:
1361 		if (data.val & PCM_ENABLE_INPUT) {
1362 			pvc->rx_enabled = 1;
1363 		} else {
1364 			pvc->rx_enabled = 0;
1365 			vring_reset(&pvc->rx_ring[1]);
1366 		}
1367 
1368 		if (data.val & PCM_ENABLE_OUTPUT) {
1369 			pvc->tx_enabled = 1;
1370 		} else {
1371 			pvc->tx_enabled = 0;
1372 			vring_reset(&pvc->tx_ring[1]);
1373 		}
1374 		break;
1375 	case SNDCTL_DSP_GETTRIGGER:
1376 		data.val = 0;
1377 		if (pvc->rx_enabled)
1378 			data.val |= PCM_ENABLE_INPUT;
1379 		if (pvc->tx_enabled)
1380 			data.val |= PCM_ENABLE_OUTPUT;
1381 		break;
1382 	case SNDCTL_DSP_GETODELAY:
1383 		data.val = vclient_output_delay_adjusted(pvc);
1384 		break;
1385 	case SNDCTL_DSP_POST:
1386 		break;
1387 	case SNDCTL_DSP_SETDUPLEX:
1388 		break;
1389 	case SNDCTL_DSP_GETRECVOL:
1390 		temp = (pvc->rx_volume * 100) >> VVOLUME_UNIT_SHIFT;
1391 		data.val = (temp & 0x00FF) |
1392 		    ((temp << 8) & 0xFF00);
1393 		break;
1394 	case SNDCTL_DSP_SETRECVOL:
1395 		pvc->rx_volume = ((data.val & 0xFF) << VVOLUME_UNIT_SHIFT) / 100;
1396 		break;
1397 	case SNDCTL_DSP_GETPLAYVOL:
1398 		temp = (pvc->tx_volume * 100) >> VVOLUME_UNIT_SHIFT;
1399 		data.val = (temp & 0x00FF) |
1400 		    ((temp << 8) & 0xFF00);
1401 		break;
1402 	case SNDCTL_DSP_SETPLAYVOL:
1403 		pvc->tx_volume = ((data.val & 0xFF) << VVOLUME_UNIT_SHIFT) / 100;
1404 		break;
1405 	case SNDCTL_DSP_CURRENT_IPTR:
1406 		memset(&data.oss_count, 0, sizeof(data.oss_count));
1407 		/* compute input samples per channel */
1408 		data.oss_count.samples =
1409 		    vclient_scale(pvc->rx_samples, pvc->sample_rate, voss_dsp_sample_rate);
1410 		data.oss_count.samples /= pvc->channels;
1411 		data.oss_count.fifo_samples =
1412 		    vclient_input_delay(pvc) / (pvc->channels * vclient_sample_bytes(pvc));
1413 		break;
1414 	case SNDCTL_DSP_CURRENT_OPTR:
1415 		memset(&data.oss_count, 0, sizeof(data.oss_count));
1416 		/* compute output samples per channel */
1417 		data.oss_count.samples =
1418 		    vclient_scale(pvc->tx_samples, pvc->sample_rate, voss_dsp_sample_rate);
1419 		data.oss_count.samples /= pvc->channels;
1420 		data.oss_count.fifo_samples =
1421 		    vclient_output_delay(pvc) / (pvc->channels * vclient_sample_bytes(pvc));
1422 		break;
1423 	case SNDCTL_DSP_GETIPTR:
1424 		memset(&data.oss_count_info, 0, sizeof(data.oss_count_info));
1425 		/* compute input bytes */
1426 		bytes =
1427 		    vclient_scale(pvc->rx_samples, pvc->sample_rate, voss_dsp_sample_rate) *
1428 		    vclient_sample_bytes(pvc);
1429 		data.oss_count_info.bytes = bytes;
1430 		data.oss_count_info.blocks = bytes / pvc->buffer_size;
1431 		data.oss_count_info.ptr = bytes % (pvc->buffer_size * pvc->buffer_frags);
1432 		break;
1433 	case SNDCTL_DSP_GETOPTR:
1434 		memset(&data.oss_count_info, 0, sizeof(data.oss_count_info));
1435 		/* compute output bytes */
1436 		bytes =
1437 		    vclient_scale(pvc->tx_samples, pvc->sample_rate, voss_dsp_sample_rate) *
1438 		    vclient_sample_bytes(pvc);
1439 		data.oss_count_info.bytes = bytes;
1440 		data.oss_count_info.blocks = bytes / pvc->buffer_size;
1441 		data.oss_count_info.ptr = bytes % (pvc->buffer_size * pvc->buffer_frags);
1442 		break;
1443 	case SNDCTL_DSP_HALT_OUTPUT:
1444 		pvc->tx_enabled = 0;
1445 		break;
1446 	case SNDCTL_DSP_HALT_INPUT:
1447 		pvc->rx_enabled = 0;
1448 		break;
1449 	case SNDCTL_DSP_LOW_WATER:
1450 		if (data.val > 0 && data.val <
1451 		    (int)(pvc->buffer_frags * pvc->buffer_size)) {
1452 			pvc->low_water = data.val;
1453 		} else {
1454 			error = CUSE_ERR_INVALID;
1455 		}
1456 		break;
1457 	case SNDCTL_DSP_GETERROR:
1458 		memset(&data.errinfo, 0, sizeof(data.errinfo));
1459 		break;
1460 	case SNDCTL_DSP_SYNCGROUP:
1461 	case SNDCTL_DSP_SYNCSTART:
1462 		break;
1463 	case SNDCTL_DSP_POLICY:
1464 		break;
1465 	case SNDCTL_DSP_COOKEDMODE:
1466 		break;
1467 	case SNDCTL_DSP_GET_CHNORDER:
1468 		data.lval = CHNORDER_NORMAL;
1469 		break;
1470 	case SNDCTL_DSP_GETCHANNELMASK:
1471 		data.val = DSP_BIND_FRONT;
1472 		break;
1473 	case SNDCTL_DSP_BIND_CHANNEL:
1474 		break;
1475 	case SNDCTL_GETLABEL:
1476 		memset(&data.label, 0, sizeof(data.label));
1477 		break;
1478 	case SNDCTL_SETLABEL:
1479 		break;
1480 	case SNDCTL_GETSONG:
1481 		memset(&data.longname, 0, sizeof(data.longname));
1482 		break;
1483 	case SNDCTL_SETSONG:
1484 		break;
1485 	case SNDCTL_SETNAME:
1486 		break;
1487 	default:
1488 		error = CUSE_ERR_INVALID;
1489 		break;
1490 	}
1491 	atomic_unlock();
1492 
1493 	if (error == 0) {
1494 		if (cmd & IOC_OUT)
1495 			error = cuse_copy_out(&data, peer_data, len);
1496 	}
1497 	return (error);
1498 }
1499 
1500 static int
1501 vclient_ioctl_wav(struct cuse_dev *pdev, int fflags __unused,
1502     unsigned long cmd, void *peer_data)
1503 {
1504 	union {
1505 		int	val;
1506 	}     data;
1507 
1508 	vclient_t *pvc;
1509 	int len;
1510 	int error;
1511 
1512 	pvc = cuse_dev_get_per_file_handle(pdev);
1513 	if (pvc == NULL)
1514 		return (CUSE_ERR_INVALID);
1515 
1516 	len = IOCPARM_LEN(cmd);
1517 
1518 	if (len < 0 || len > (int)sizeof(data))
1519 		return (CUSE_ERR_INVALID);
1520 
1521 	if (cmd & IOC_IN) {
1522 		error = cuse_copy_in(peer_data, &data, len);
1523 		if (error)
1524 			return (error);
1525 	} else {
1526 		error = 0;
1527 	}
1528 
1529 	atomic_lock();
1530 	switch (cmd) {
1531 	case FIONREAD:
1532 		data.val = vclient_input_delay(pvc);
1533 		break;
1534 	case FIOASYNC:
1535 	case SNDCTL_DSP_NONBLOCK:
1536 	case FIONBIO:
1537 		break;
1538 	default:
1539 		error = CUSE_ERR_INVALID;
1540 		break;
1541 	}
1542 	atomic_unlock();
1543 
1544 	if (error == 0) {
1545 		if (cmd & IOC_OUT)
1546 			error = cuse_copy_out(&data, peer_data, len);
1547 	}
1548 	return (error);
1549 }
1550 
1551 static int
1552 vclient_poll(struct cuse_dev *pdev, int fflags, int events)
1553 {
1554 	vclient_t *pvc;
1555 
1556 	int retval = CUSE_POLL_NONE;
1557 
1558 	pvc = cuse_dev_get_per_file_handle(pdev);
1559 	if (pvc == NULL)
1560 		return (retval);
1561 
1562 	atomic_lock();
1563 	if ((events & CUSE_POLL_READ) && (fflags & CUSE_FFLAG_READ)) {
1564 		pvc->rx_enabled = 1;
1565 		if (vclient_input_delay(pvc) >= pvc->low_water)
1566 			retval |= CUSE_POLL_READ;
1567 	}
1568 	if ((events & CUSE_POLL_WRITE) && (fflags & CUSE_FFLAG_WRITE)) {
1569 		const uint32_t out_dly = vclient_output_delay(pvc);
1570 		const uint32_t out_buf = (pvc->buffer_frags * pvc->buffer_size);
1571 
1572 		if (out_dly < out_buf && (out_buf - out_dly) >= pvc->low_water)
1573 			retval |= CUSE_POLL_WRITE;
1574 	}
1575 	atomic_unlock();
1576 
1577 	return (retval);
1578 }
1579 
1580 static const struct cuse_methods vclient_oss_methods = {
1581 	.cm_open = vclient_open_oss,
1582 	.cm_close = vclient_close,
1583 	.cm_read = vclient_read,
1584 	.cm_write = vclient_write_oss,
1585 	.cm_ioctl = vclient_ioctl_oss,
1586 	.cm_poll = vclient_poll,
1587 };
1588 
1589 static const struct cuse_methods vclient_wav_methods = {
1590 	.cm_open = vclient_open_wav,
1591 	.cm_close = vclient_close,
1592 	.cm_read = vclient_read,
1593 	.cm_write = vclient_write_wav,
1594 	.cm_ioctl = vclient_ioctl_wav,
1595 	.cm_poll = vclient_poll,
1596 };
1597 
1598 vprofile_head_t virtual_profile_client_head;
1599 vprofile_head_t virtual_profile_loopback_head;
1600 
1601 vmonitor_head_t virtual_monitor_input;
1602 vmonitor_head_t virtual_monitor_output;
1603 vmonitor_head_t virtual_monitor_local;
1604 
1605 uint32_t voss_max_channels;
1606 uint32_t voss_mix_channels;
1607 uint32_t voss_dsp_samples;
1608 uint32_t voss_dsp_max_channels;
1609 uint32_t voss_dsp_sample_rate;
1610 uint32_t voss_dsp_bits;
1611 uint8_t	voss_libsamplerate_enable;
1612 uint8_t	voss_libsamplerate_quality = SRC_SINC_FASTEST;
1613 int	voss_is_recording = 1;
1614 int	voss_has_synchronization;
1615 volatile sig_atomic_t voss_exit = 0;
1616 
1617 static int voss_dsp_perm = 0666;
1618 static int voss_do_background;
1619 static const char *voss_pid_path;
1620 
1621 uint32_t voss_dsp_rx_refresh;
1622 uint32_t voss_dsp_tx_refresh;
1623 char voss_dsp_rx_device[VMAX_STRING];
1624 char voss_dsp_tx_device[VMAX_STRING];
1625 char voss_ctl_device[VMAX_STRING];
1626 
1627 uint32_t voss_jitter_up;
1628 uint32_t voss_jitter_down;
1629 
1630 struct voss_backend *voss_rx_backend;
1631 struct voss_backend *voss_tx_backend;
1632 
1633 static int voss_dups;
1634 static int voss_ntds;
1635 static pthread_t *voss_tds;
1636 
1637 /* XXX I do not like the prefix argument... */
1638 static struct voss_backend *
1639 voss_load_backend(const char *prefix, const char *name, const char *dir)
1640 {
1641 	struct voss_backend *backend;
1642 	void *hdl;
1643 	char lpath[64], bsym[64];
1644 
1645 	snprintf(lpath, sizeof(lpath), "%s/lib/virtual_oss/voss_%s.so",
1646 	    prefix, name);
1647 	snprintf(bsym, sizeof(bsym), "voss_backend_%s_%s", name, dir);
1648 
1649 	if ((hdl = dlopen(lpath, RTLD_NOW)) == NULL)
1650 		errx(1, "%s", dlerror());
1651 	if ((backend = dlsym(hdl, bsym)) == NULL) {
1652 		warnx("%s", dlerror());
1653 		dlclose(hdl);
1654 		exit(EXIT_FAILURE);
1655 	}
1656 
1657 	return (backend);
1658 }
1659 
1660 static void
1661 voss_rx_backend_refresh(void)
1662 {
1663 	/* setup RX backend */
1664 	if (strcmp(voss_dsp_rx_device, "/dev/null") == 0) {
1665 		voss_rx_backend = voss_load_backend("/usr", "null", "rec");
1666 	} else if (strstr(voss_dsp_rx_device, "/dev/bluetooth/") == voss_dsp_rx_device) {
1667 		voss_rx_backend = voss_load_backend("/usr/local", "bt", "rec");
1668 	} else if (strstr(voss_dsp_rx_device, "/dev/sndio/") == voss_dsp_rx_device) {
1669 		voss_rx_backend = voss_load_backend("/usr/local", "sndio", "rec");
1670 	} else {
1671 		voss_rx_backend = voss_load_backend("/usr", "oss", "rec");
1672 	}
1673 }
1674 
1675 static void
1676 voss_tx_backend_refresh(void)
1677 {
1678 	/* setup TX backend */
1679 	if (strcmp(voss_dsp_tx_device, "/dev/null") == 0) {
1680 		voss_tx_backend = voss_load_backend("/usr", "null", "play");
1681 	} else if (strstr(voss_dsp_tx_device, "/dev/bluetooth/") == voss_dsp_tx_device) {
1682 		voss_tx_backend = voss_load_backend("/usr/local", "bt", "play");
1683 	} else if (strstr(voss_dsp_tx_device, "/dev/sndio/") == voss_dsp_tx_device) {
1684 		voss_tx_backend = voss_load_backend("/usr/local", "sndio", "play");
1685 	} else {
1686 		voss_tx_backend = voss_load_backend("/usr", "oss", "play");
1687 	}
1688 }
1689 
1690 static void
1691 usage(void)
1692 {
1693 	fprintf(stderr, "Usage: virtual_oss [options...] [device] \\\n"
1694 	    "\t" "-C 2 -c 2 -r 48000 -b 16 -s 100.0ms -f /dev/dsp3 \\\n"
1695 	    "\t" "-P /dev/dsp3 -R /dev/dsp1 \\\n"
1696 	    "\t" "-O /dev/dsp3 -R /dev/null \\\n"
1697 	    "\t" "-c 1 -m 0,0 [-w wav.0] -d dsp100.0 \\\n"
1698 	    "\t" "-c 1 -m 0,0 [-w wav.0] -d vdsp.0 \\\n"
1699 	    "\t" "-c 2 -m 0,0,1,1 [-w wav.1] -d vdsp.1 \\\n"
1700 	    "\t" "-c 2 -m 0,0,1,1 [-w wav.loopback] -l vdsp.loopback \\\n"
1701 	    "\t" "-c 2 -m 0,0,1,1 [-w wav.loopback] -L vdsp.loopback \\\n"
1702 	    "\t" "-B # run in background \\\n"
1703 	    "\t" "-s <samples> or <milliseconds>ms \\\n"
1704 	    "\t" "-S # enable automatic resampling using libsamplerate \\\n"
1705 	    "\t" "-Q <0,1,2> # quality of resampling 0=best,1=medium,2=fastest (default) \\\n"
1706 	    "\t" "-b <bits> \\\n"
1707 	    "\t" "-r <rate> \\\n"
1708 	    "\t" "-i <rtprio> \\\n"
1709 	    "\t" "-a <amp -63..63> \\\n"
1710 	    "\t" "-a i,<rx_amp -63..63> \\\n"
1711 	    "\t" "-a o,<tx_amp -63..63> \\\n"
1712 	    "\t" "-g <knee,attack,decay> # enable device RX compressor\\\n"
1713 	    "\t" "-x <knee,attack,decay> # enable output compressor\\\n"
1714 	    "\t" "-p <pol 0..1> \\\n"
1715 	    "\t" "-e <rxtx_mute 0..1> \\\n"
1716 	    "\t" "-e <rx_mute 0..1>,<tx_mute 0..1> \\\n"
1717 	    "\t" "-m <mapping> \\\n"
1718 	    "\t" "-m <rx0,tx0,rx1,tx1...rxN,txN> \\\n"
1719 	    "\t" "-C <mixchans>\\\n"
1720 	    "\t" "-c <dspchans> \\\n"
1721 	    "\t" "-M <monitorfilter> \\\n"
1722 	    "\t" "-M i,<src>,<dst>,<pol>,<mute>,<amp> \\\n"
1723 	    "\t" "-M o,<src>,<dst>,<pol>,<mute>,<amp> \\\n"
1724 	    "\t" "-M x,<src>,<dst>,<pol>,<mute>,<amp> \\\n"
1725 	    "\t" "-F <rx_filter_samples> or <milliseconds>ms \\\n"
1726 	    "\t" "-G <tx_filter_samples> or <milliseconds>ms \\\n"
1727 	    "\t" "-E <enable_recording, 0 or 1> \\\n"
1728 	    "\t" "-N <max HTTP connections, default is 1> \\\n"
1729 	    "\t" "-H <bind HTTP server to this host> \\\n"
1730 	    "\t" "-o <bind HTTP server to this port, default is 80> \\\n"
1731 	    "\t" "-J <bind RTP server to this network interface> \\\n"
1732 	    "\t" "-k <bind RTP server to this port, default is 8080> \\\n"
1733 	    "\t" "-t vdsp.ctl \n"
1734 	    "\t" "Left channel = 0\n"
1735 	    "\t" "Right channel = 1\n"
1736 	    "\t" "Max channels = %d\n", VMAX_CHAN);
1737 
1738 	exit(EX_USAGE);
1739 }
1740 
1741 static void
1742 init_compressor(struct virtual_profile *pvp)
1743 {
1744 	int x;
1745 
1746 	memset(&pvp->rx_compressor_param, 0, sizeof(pvp->rx_compressor_param));
1747 
1748 	pvp->rx_compressor_param.knee = 85;
1749 	pvp->rx_compressor_param.attack = 3;
1750 	pvp->rx_compressor_param.decay = 20;
1751 
1752 	for (x = 0; x != VMAX_CHAN; x++)
1753 		pvp->rx_compressor_gain[x] = 1.0;
1754 }
1755 
1756 static void
1757 init_mapping(struct virtual_profile *pvp)
1758 {
1759 	int x;
1760 
1761 	for (x = 0; x != VMAX_CHAN; x++) {
1762 		pvp->rx_src[x] = x;
1763 		pvp->tx_dst[x] = x;
1764 	}
1765 }
1766 
1767 static void
1768 init_sndstat(vprofile_t *ptr)
1769 {
1770 	int err;
1771 	nvlist_t *nvl;
1772 	nvlist_t *di = NULL, *dichild = NULL;
1773 	struct sndstioc_nv_arg arg;
1774 	unsigned int min_rate, max_rate;
1775 
1776 	nvl = nvlist_create(0);
1777 	if (nvl == NULL) {
1778 		warn("Failed to create nvlist");
1779 		goto done;
1780 	}
1781 
1782 	di = nvlist_create(0);
1783 	if (di == NULL) {
1784 		warn("Failed to create nvlist");
1785 		goto done;
1786 	}
1787 
1788 	dichild = nvlist_create(0);
1789 	if (dichild == NULL) {
1790 		warn("Failed to create nvlist");
1791 		goto done;
1792 	}
1793 
1794 	nvlist_add_string(di, SNDST_DSPS_PROVIDER, "virtual_oss");
1795 	nvlist_add_string(di, SNDST_DSPS_DESC, "virtual_oss device");
1796 	nvlist_add_number(di, SNDST_DSPS_PCHAN, 1);
1797 	nvlist_add_number(di, SNDST_DSPS_RCHAN, 1);
1798 	min_rate = 8000;
1799 	max_rate = voss_dsp_sample_rate;
1800 	if (voss_libsamplerate_enable == 0 ||
1801 	    min_rate > max_rate)
1802 		min_rate = max_rate;
1803 	if (voss_libsamplerate_enable != 0 && max_rate < 96000)
1804 		max_rate = 96000;
1805 	nvlist_add_number(dichild, SNDST_DSPS_INFO_MIN_RATE, min_rate);
1806 	nvlist_add_number(dichild, SNDST_DSPS_INFO_MAX_RATE, max_rate);
1807 	nvlist_add_number(dichild, SNDST_DSPS_INFO_FORMATS, VSUPPORTED_AFMT);
1808 	nvlist_add_number(dichild, SNDST_DSPS_INFO_MIN_CHN, ptr->channels);
1809 	nvlist_add_number(dichild, SNDST_DSPS_INFO_MAX_CHN, ptr->channels);
1810 	nvlist_add_nvlist(di, SNDST_DSPS_INFO_PLAY, dichild);
1811 	nvlist_add_nvlist(di, SNDST_DSPS_INFO_REC, dichild);
1812 
1813 	nvlist_add_string(di, SNDST_DSPS_DEVNODE,
1814 	    ptr->oss_name);
1815 	nvlist_append_nvlist_array(nvl, SNDST_DSPS, di);
1816 
1817 	if (nvlist_error(nvl)) {
1818 		warn("Failed building nvlist");
1819 		goto done;
1820 	}
1821 
1822 	arg.buf = nvlist_pack(nvl, &arg.nbytes);
1823 	if (arg.buf == NULL) {
1824 		warn("Failed to pack nvlist");
1825 		goto done;
1826 	}
1827 	err = ioctl(ptr->fd_sta, SNDSTIOC_ADD_USER_DEVS, &arg);
1828 	free(arg.buf);
1829 	if (err != 0) {
1830 		warn("Failed to issue ioctl(SNDSTIOC_ADD_USER_DEVS)");
1831 		goto done;
1832 	}
1833 
1834 done:
1835 	nvlist_destroy(di);
1836 	nvlist_destroy(dichild);
1837 	nvlist_destroy(nvl);
1838 }
1839 
1840 static const char *
1841 dup_profile(vprofile_t *pvp, int *pamp, int pol, int rx_mute,
1842     int tx_mute, int synchronized, int is_client)
1843 {
1844 	vprofile_t *ptr;
1845 	struct cuse_dev *pdev;
1846 	int x;
1847 
1848 	rx_mute = rx_mute ? 1 : 0;
1849 	tx_mute = tx_mute ? 1 : 0;
1850 	pol = pol ? 1 : 0;
1851 
1852 	/* Range check amplitude argument. */
1853 	for (x = 0; x != 2; x++) {
1854 		if (pamp[x] < -63)
1855 			pamp[x] = -63;
1856 		else if (pamp[x] > 63)
1857 			pamp[x] = 63;
1858 	}
1859 
1860 	ptr = malloc(sizeof(*ptr));
1861 	if (ptr == NULL)
1862 		return ("Out of memory");
1863 
1864 	memcpy(ptr, pvp, sizeof(*ptr));
1865 
1866 	ptr->synchronized = synchronized;
1867 	ptr->fd_sta = -1;
1868 	TAILQ_INIT(&ptr->head);
1869 
1870 	for (x = 0; x != ptr->channels; x++) {
1871 		ptr->tx_mute[x] = tx_mute;
1872 		ptr->rx_mute[x] = rx_mute;
1873 		ptr->tx_shift[x] = pamp[1];
1874 		ptr->rx_shift[x] = pamp[0];
1875 		ptr->tx_pol[x] = pol;
1876 		ptr->rx_pol[x] = pol;
1877 	}
1878 
1879 	/* create DSP device */
1880 	if (ptr->oss_name[0] != 0) {
1881 		/*
1882 		 * Detect /dev/dsp creation and try to disable system
1883 		 * basename cloning automatically:
1884 		 */
1885 		if (strcmp(ptr->oss_name, "dsp") == 0)
1886 			system("sysctl hw.snd.basename_clone=0");
1887 
1888 		/* create DSP character device */
1889 		pdev = cuse_dev_create(&vclient_oss_methods, ptr, NULL,
1890 		    0, 0, voss_dsp_perm, ptr->oss_name);
1891 		if (pdev == NULL) {
1892 			free(ptr);
1893 			return ("Could not create CUSE DSP device");
1894 		}
1895 
1896 		/* register to sndstat */
1897 		ptr->fd_sta = open("/dev/sndstat", O_WRONLY);
1898 		if (ptr->fd_sta < 0) {
1899 			warn("Could not open /dev/sndstat");
1900 		} else {
1901 			init_sndstat(ptr);
1902 		}
1903 	}
1904 	/* create WAV device */
1905 	if (ptr->wav_name[0] != 0) {
1906 		pdev = cuse_dev_create(&vclient_wav_methods, ptr, NULL,
1907 		    0, 0, voss_dsp_perm, ptr->wav_name);
1908 		if (pdev == NULL) {
1909 			free(ptr);
1910 			return ("Could not create CUSE WAV device");
1911 		}
1912 	}
1913 
1914 	atomic_lock();
1915 	if (is_client)
1916 		TAILQ_INSERT_TAIL(&virtual_profile_client_head, ptr, entry);
1917 	else
1918 		TAILQ_INSERT_TAIL(&virtual_profile_loopback_head, ptr, entry);
1919 	atomic_unlock();
1920 
1921 	voss_dups++;
1922 
1923 	/* need new names next time */
1924 	memset(pvp->oss_name, 0, sizeof(pvp->oss_name));
1925 	memset(pvp->wav_name, 0, sizeof(pvp->wav_name));
1926 
1927 	/* need to set new filter sizes */
1928 	pvp->rx_filter_size = 0;
1929 	pvp->tx_filter_size = 0;
1930 
1931 	/* need to specify new HTTP parameters next time */
1932 	pvp->http.host = NULL;
1933 	pvp->http.port = NULL;
1934 	pvp->http.nstate = 0;
1935 	pvp->http.rtp_ifname = NULL;
1936 	pvp->http.rtp_port = NULL;
1937 
1938 	/* need to specify new amplification next time */
1939 	pamp[0] = 0;
1940 	pamp[1] = 0;
1941 
1942 	/* need to set new compressor parameters next time */
1943 	init_compressor(pvp);
1944 
1945 	return (voss_httpd_start(ptr));
1946 }
1947 
1948 static void
1949 virtual_pipe(int sig __unused)
1950 {
1951 	voss_dsp_tx_refresh = 1;
1952 	voss_dsp_rx_refresh = 1;
1953 }
1954 
1955 static void
1956 virtual_cuse_hup(int sig __unused)
1957 {
1958 	atomic_wakeup();
1959 }
1960 
1961 static void *
1962 virtual_cuse_process(void *arg __unused)
1963 {
1964 	signal(SIGHUP, &virtual_cuse_hup);
1965 
1966 	while (1) {
1967 		if (cuse_wait_and_process() != 0)
1968 			break;
1969 	}
1970 	return (NULL);
1971 }
1972 
1973 static void
1974 virtual_cuse_init_profile(struct virtual_profile *pvp)
1975 {
1976 	memset(pvp, 0, sizeof(*pvp));
1977 
1978 	init_compressor(pvp);
1979 	init_mapping(pvp);
1980 }
1981 
1982 static void
1983 virtual_sig_exit(int sig __unused)
1984 {
1985 	voss_exit = 1;
1986 }
1987 
1988 static const char *
1989 parse_options(int narg, char **pparg, int is_main)
1990 {
1991 	const char *ptr;
1992 	int a, b, c;
1993 	int val;
1994 	int idx;
1995 	int type;
1996 	int opt_mute[2] = {0, 0};
1997 	int opt_amp[2] = {0, 0};
1998 	int opt_pol = 0;
1999 	const char *optstr;
2000 	struct virtual_profile profile;
2001 	struct rtprio rtp;
2002 	float samples_ms;
2003 
2004 	if (is_main)
2005 		optstr = "N:J:k:H:o:F:G:w:e:p:a:C:c:r:b:f:g:x:i:m:M:d:l:L:s:t:h?O:P:Q:R:SBD:E:";
2006 	else
2007 		optstr = "F:G:w:e:p:a:c:b:f:m:M:d:l:L:s:O:P:R:E:";
2008 
2009 	virtual_cuse_init_profile(&profile);
2010 
2011 	/* reset getopt parsing */
2012 	optreset = 1;
2013 	optind = 1;
2014 
2015 	while ((c = getopt(narg, pparg, optstr)) != -1) {
2016 		switch (c) {
2017 		case 'B':
2018 			voss_do_background = 1;
2019 			break;
2020 		case 'D':
2021 			voss_pid_path = optarg;
2022 			break;
2023 		case 'C':
2024 			if (voss_mix_channels != 0) {
2025 				return ("The -C argument may only be used once");
2026 			}
2027 			voss_mix_channels = atoi(optarg);
2028 			if (voss_mix_channels >= VMAX_CHAN) {
2029 				return ("Number of mixing channels is too high");
2030 			}
2031 			break;
2032 		case 'a':
2033 			switch (optarg[0]) {
2034 			case '-':
2035 			case '0':
2036 			case '1':
2037 			case '2':
2038 			case '3':
2039 			case '4':
2040 			case '5':
2041 			case '6':
2042 			case '7':
2043 			case '8':
2044 			case '9':
2045 				opt_amp[0] = -(opt_amp[1] = atoi(optarg));
2046 				break;
2047 			case 'i':
2048 				if (optarg[1] != ',')
2049 					return ("Expected comma after 'i'");
2050 				opt_amp[0] = atoi(optarg + 2);
2051 				break;
2052 			case 'o':
2053 				if (optarg[1] != ',')
2054 					return ("Expected comma after 'o'");
2055 				opt_amp[1] = atoi(optarg + 2);
2056 				break;
2057 			default:
2058 				return ("Invalid syntax for amplitude argument");
2059 			}
2060 			break;
2061 		case 'E':
2062 			voss_is_recording = (atoi(optarg) != 0);
2063 			break;
2064 		case 'e':
2065 			idx = 0;
2066 			ptr = optarg;
2067 			memset(opt_mute, 0, sizeof(opt_mute));
2068 			while (1) {
2069 				c = *ptr++;
2070 				if (c == ',' || c == 0) {
2071 					idx++;
2072 					if (c == 0)
2073 						break;
2074 					continue;
2075 				}
2076 				if (idx < 2 && c >= '0' && c <= '1') {
2077 					opt_mute[idx] = c - '0';
2078 				} else {
2079 					return ("Invalid -e parameter");
2080 				}
2081 			}
2082 			switch (idx) {
2083 			case 1:
2084 				opt_mute[1] = opt_mute[0];
2085 				break;
2086 			case 2:
2087 				break;
2088 			default:
2089 				return ("Invalid -e parameter");
2090 			}
2091 			break;
2092 		case 'p':
2093 			opt_pol = atoi(optarg);
2094 			break;
2095 		case 'c':
2096 			profile.channels = atoi(optarg);
2097 			if (profile.channels == 0)
2098 				return ("Number of channels is zero");
2099 			if (profile.channels > VMAX_CHAN)
2100 				return ("Number of channels is too high");
2101 			break;
2102 		case 'r':
2103 			voss_dsp_sample_rate = atoi(optarg);
2104 			if (voss_dsp_sample_rate < 8000)
2105 				return ("Sample rate is too low, 8000 Hz");
2106 			if (voss_dsp_sample_rate > 0xFFFFFF)
2107 				return ("Sample rate is too high");
2108 			break;
2109 		case 'i':
2110 			memset(&rtp, 0, sizeof(rtp));
2111 			rtp.type = RTP_PRIO_REALTIME;
2112 			rtp.prio = atoi(optarg);
2113 			if (rtprio(RTP_SET, getpid(), &rtp) != 0)
2114 				printf("Cannot set realtime priority\n");
2115 			break;
2116 		case 'b':
2117 			profile.bits = atoi(optarg);
2118 			switch (profile.bits) {
2119 			case 8:
2120 			case 16:
2121 			case 24:
2122 			case 32:
2123 				break;
2124 			default:
2125 				return ("Invalid number of sample bits");
2126 			}
2127 			break;
2128 		case 'g':
2129 			if (profile.rx_compressor_param.enabled)
2130 				return ("Compressor already enabled for this device");
2131 			if (sscanf(optarg, "%d,%d,%d", &a, &b, &c) != 3 ||
2132 			    a < VIRTUAL_OSS_KNEE_MIN ||
2133 			    a > VIRTUAL_OSS_KNEE_MAX ||
2134 			    b < VIRTUAL_OSS_ATTACK_MIN ||
2135 			    b > VIRTUAL_OSS_ATTACK_MAX ||
2136 			    c < VIRTUAL_OSS_DECAY_MIN ||
2137 			    c > VIRTUAL_OSS_DECAY_MAX)
2138 				return ("Invalid device compressor argument(s)");
2139 			profile.rx_compressor_param.enabled = 1;
2140 			profile.rx_compressor_param.knee = a;
2141 			profile.rx_compressor_param.attack = b;
2142 			profile.rx_compressor_param.decay = c;
2143 			break;
2144 		case 'x':
2145 			if (voss_output_compressor_param.enabled)
2146 				return ("Compressor already enabled for output");
2147 			if (sscanf(optarg, "%d,%d,%d", &a, &b, &c) != 3 ||
2148 			    a < VIRTUAL_OSS_KNEE_MIN ||
2149 			    a > VIRTUAL_OSS_KNEE_MAX ||
2150 			    b < VIRTUAL_OSS_ATTACK_MIN ||
2151 			    b > VIRTUAL_OSS_ATTACK_MAX ||
2152 			    c < VIRTUAL_OSS_DECAY_MIN ||
2153 			    c > VIRTUAL_OSS_DECAY_MAX)
2154 				return ("Invalid output compressor argument(s)");
2155 			voss_output_compressor_param.enabled = 1;
2156 			voss_output_compressor_param.knee = a;
2157 			voss_output_compressor_param.attack = b;
2158 			voss_output_compressor_param.decay = c;
2159 			break;
2160 		case 'f':
2161 		case 'O':
2162 		case 'P':
2163 		case 'R':
2164 			if (voss_dsp_sample_rate == 0 || voss_dsp_samples == 0)
2165 				return ("Missing -r or -s parameters");
2166 			if (voss_dsp_bits == 0) {
2167 				if (profile.bits == 0)
2168 					return ("Missing -b parameter");
2169 				voss_dsp_bits = profile.bits;
2170 			}
2171 			if (voss_dsp_max_channels == 0) {
2172 				if (profile.channels == 0)
2173 					return ("Missing -c parameter");
2174 				voss_dsp_max_channels = profile.channels;
2175 			}
2176 			if (c == 'f' || c == 'R') {
2177 				if (strlen(optarg) > VMAX_STRING - 1)
2178 					return ("Device name too long");
2179 				strncpy(voss_dsp_rx_device, optarg, sizeof(voss_dsp_rx_device));
2180 				voss_rx_backend_refresh();
2181 				voss_dsp_rx_refresh = 1;
2182 			}
2183 			if (c == 'f' || c == 'P' || c == 'O') {
2184 				if (strlen(optarg) > VMAX_STRING - 1)
2185 					return ("Device name too long");
2186 				strncpy(voss_dsp_tx_device, optarg, sizeof(voss_dsp_tx_device));
2187 				voss_tx_backend_refresh();
2188 				voss_dsp_tx_refresh = 1;
2189 
2190 				if (c == 'O' && voss_has_synchronization == 0)
2191 					voss_has_synchronization++;
2192 			}
2193 			break;
2194 		case 'w':
2195 			if (strlen(optarg) > VMAX_STRING - 1)
2196 				return ("Device name too long");
2197 			strncpy(profile.wav_name, optarg, sizeof(profile.wav_name));
2198 			break;
2199 		case 'd':
2200 			if (strlen(optarg) > VMAX_STRING - 1)
2201 				return ("Device name too long");
2202 			strncpy(profile.oss_name, optarg, sizeof(profile.oss_name));
2203 
2204 			if (profile.bits == 0 || voss_dsp_sample_rate == 0 ||
2205 			    profile.channels == 0 || voss_dsp_samples == 0)
2206 				return ("Missing -b, -r, -c or -s parameters");
2207 
2208 			val = (voss_dsp_samples *
2209 			    profile.bits * profile.channels) / 8;
2210 			if (val <= 0 || val >= (1024 * 1024))
2211 				return ("-s option value is too big");
2212 
2213 			ptr = dup_profile(&profile, opt_amp, opt_pol,
2214 			    opt_mute[0], opt_mute[1], 0, 1);
2215 			if (ptr != NULL)
2216 				return (ptr);
2217 			break;
2218 		case 'L':
2219 		case 'l':
2220 			if (strlen(optarg) > VMAX_STRING - 1)
2221 				return ("Device name too long");
2222 			strncpy(profile.oss_name, optarg, sizeof(profile.oss_name));
2223 
2224 			if (profile.bits == 0 || voss_dsp_sample_rate == 0 ||
2225 			    profile.channels == 0 || voss_dsp_samples == 0)
2226 				return ("Missing -b, -r, -r or -s parameters");
2227 
2228 			val = (voss_dsp_samples *
2229 			    profile.bits * profile.channels) / 8;
2230 			if (val <= 0 || val >= (1024 * 1024))
2231 				return ("-s option value is too big");
2232 
2233 			ptr = dup_profile(&profile, opt_amp, opt_pol,
2234 			    opt_mute[0], opt_mute[1], c == 'L', 0);
2235 			if (ptr != NULL)
2236 				return (ptr);
2237 			break;
2238 		case 'S':
2239 			voss_libsamplerate_enable = 1;
2240 			break;
2241 		case 'Q':
2242 			c = atoi(optarg);
2243 			switch (c) {
2244 			case 0:
2245 				voss_libsamplerate_quality = SRC_SINC_BEST_QUALITY;
2246 				break;
2247 			case 1:
2248 				voss_libsamplerate_quality = SRC_SINC_MEDIUM_QUALITY;
2249 				break;
2250 			default:
2251 				voss_libsamplerate_quality = SRC_SINC_FASTEST;
2252 				break;
2253 			}
2254 			break;
2255 		case 's':
2256 			if (voss_dsp_samples != 0)
2257 				return ("-s option may only be used once");
2258 			if (profile.bits == 0 || profile.channels == 0)
2259 				return ("-s option requires -b and -c options");
2260 			if (strlen(optarg) > 2 &&
2261 			    sscanf(optarg, "%f", &samples_ms) == 1 &&
2262 			    strcmp(optarg + strlen(optarg) - 2, "ms") == 0) {
2263 				if (voss_dsp_sample_rate == 0)
2264 					return ("-s <X>ms option requires -r option");
2265 				if (samples_ms < 0.125 || samples_ms >= 1000.0)
2266 					return ("-s <X>ms option has invalid value");
2267 				voss_dsp_samples = voss_dsp_sample_rate * samples_ms / 1000.0;
2268 			} else {
2269 				voss_dsp_samples = atoi(optarg);
2270 			}
2271 			if (voss_dsp_samples >= (1U << 24))
2272 				return ("-s option requires a non-zero positive value");
2273 			break;
2274 		case 't':
2275 			if (voss_ctl_device[0])
2276 				return ("-t parameter may only be used once");
2277 
2278 			strlcpy(voss_ctl_device, optarg, sizeof(voss_ctl_device));
2279 			break;
2280 		case 'm':
2281 			ptr = optarg;
2282 			val = 0;
2283 			idx = 0;
2284 			init_mapping(&profile);
2285 			while (1) {
2286 				c = *ptr++;
2287 				if (c == ',' || c == 0) {
2288 					if (idx >= (2 * VMAX_CHAN))
2289 						return ("Too many channels in mask");
2290 					if (idx & 1)
2291 						profile.tx_dst[idx / 2] = val;
2292 					else
2293 						profile.rx_src[idx / 2] = val;
2294 					if (c == 0)
2295 						break;
2296 					val = 0;
2297 					idx++;
2298 					continue;
2299 				}
2300 				if (c >= '0' && c <= '9') {
2301 					val *= 10;
2302 					val += c - '0';
2303 				}
2304 			}
2305 			break;
2306 		case 'M':
2307 			ptr = optarg;
2308 			type = *ptr;
2309 			if (type == 'i' || type == 'o' || type == 'x') {
2310 				vmonitor_t *pvm;
2311 
2312 				int src = 0;
2313 				int dst = 0;
2314 				int pol = 0;
2315 				int mute = 0;
2316 				int amp = 0;
2317 				int neg;
2318 
2319 				ptr++;
2320 				if (*ptr == ',')
2321 					ptr++;
2322 				else if (type == 'i')
2323 					return ("Expected comma after 'i'");
2324 				else if (type == 'o')
2325 					return ("Expected comma after 'o'");
2326 				else
2327 					return ("Expected comma after 'x'");
2328 
2329 				val = 0;
2330 				neg = 0;
2331 				idx = 0;
2332 				while (1) {
2333 					c = *ptr++;
2334 					if (c == '-') {
2335 						neg = 1;
2336 						continue;
2337 					}
2338 					if (c == ',' || c == 0) {
2339 						switch (idx) {
2340 						case 0:
2341 							src = val;
2342 							break;
2343 						case 1:
2344 							dst = val;
2345 							break;
2346 						case 2:
2347 							pol = val ? 1 : 0;
2348 							break;
2349 						case 3:
2350 							mute = val ? 1 : 0;
2351 							break;
2352 						case 4:
2353 							if (val > 31) {
2354 								return ("Absolute amplitude "
2355 								    "for -M parameter "
2356 								    "cannot exceed 31");
2357 							}
2358 							amp = neg ? -val : val;
2359 							break;
2360 						default:
2361 							break;
2362 						}
2363 						if (c == 0)
2364 							break;
2365 						val = 0;
2366 						neg = 0;
2367 						idx++;
2368 						continue;
2369 					}
2370 					if (c >= '0' && c <= '9') {
2371 						val *= 10;
2372 						val += c - '0';
2373 					}
2374 				}
2375 				if (idx < 4)
2376 					return ("Too few parameters for -M");
2377 
2378 				pvm = vmonitor_alloc(&idx,
2379 				    (type == 'i') ? &virtual_monitor_input :
2380 				    (type == 'x') ? &virtual_monitor_local :
2381 				    &virtual_monitor_output);
2382 
2383 				if (pvm == NULL)
2384 					return ("Out of memory");
2385 
2386 				pvm->src_chan = src;
2387 				pvm->dst_chan = dst;
2388 				pvm->pol = pol;
2389 				pvm->mute = mute;
2390 				pvm->shift = amp;
2391 			} else {
2392 				return ("Invalid -M parameter");
2393 			}
2394 			break;
2395 		case 'F':
2396 			if (strlen(optarg) > 2 &&
2397 			    sscanf(optarg, "%f", &samples_ms) == 1 &&
2398 			    strcmp(optarg + strlen(optarg) - 2, "ms") == 0) {
2399 				if (voss_dsp_sample_rate == 0)
2400 					return ("-F <X>ms option requires -r option");
2401 				if (samples_ms < 0.125 || samples_ms >= 1000.0)
2402 					return ("-F <X>ms option has invalid value");
2403 				profile.rx_filter_size = voss_dsp_sample_rate * samples_ms / 1000.0;
2404 			} else {
2405 				profile.rx_filter_size = atoi(optarg);
2406 			}
2407 			/* make value power of two */
2408 			while ((profile.rx_filter_size - 1) & profile.rx_filter_size)
2409 				profile.rx_filter_size += ~(profile.rx_filter_size - 1) & profile.rx_filter_size;
2410 			/* range check */
2411 			if (profile.rx_filter_size > VIRTUAL_OSS_FILTER_MAX)
2412 				return ("Invalid -F parameter is out of range");
2413 			break;
2414 		case 'G':
2415 			if (strlen(optarg) > 2 &&
2416 			    sscanf(optarg, "%f", &samples_ms) == 1 &&
2417 			    strcmp(optarg + strlen(optarg) - 2, "ms") == 0) {
2418 				if (voss_dsp_sample_rate == 0)
2419 					return ("-G <X>ms option requires -r option");
2420 				if (samples_ms < 0.125 || samples_ms >= 1000.0)
2421 					return ("-G <X>ms option has invalid value");
2422 				profile.tx_filter_size = voss_dsp_sample_rate * samples_ms / 1000.0;
2423 			} else {
2424 				profile.tx_filter_size = atoi(optarg);
2425 			}
2426 			/* make value power of two */
2427 			while ((profile.tx_filter_size - 1) & profile.tx_filter_size)
2428 				profile.tx_filter_size += ~(profile.tx_filter_size - 1) & profile.tx_filter_size;
2429 			/* range check */
2430 			if (profile.tx_filter_size > VIRTUAL_OSS_FILTER_MAX)
2431 				return ("Invalid -F parameter is out of range");
2432 			break;
2433 		case 'N':
2434 			profile.http.nstate = atoi(optarg);
2435 			break;
2436 		case 'H':
2437 			profile.http.host = optarg;
2438 			if (profile.http.port == NULL)
2439 				profile.http.port = "80";
2440 			if (profile.http.nstate == 0)
2441 				profile.http.nstate = 1;
2442 			break;
2443 		case 'o':
2444 			profile.http.port = optarg;
2445 			break;
2446 		case 'J':
2447 			profile.http.rtp_ifname = optarg;
2448 			if (profile.http.rtp_port == NULL)
2449 				profile.http.rtp_port = "8080";
2450 			break;
2451 		case 'k':
2452 			profile.http.rtp_port = optarg;
2453 			break;
2454 		default:
2455 			if (is_main)
2456 				usage();
2457 			else
2458 				return ("Invalid option detected");
2459 			break;
2460 		}
2461 	}
2462 	return (NULL);
2463 }
2464 
2465 static void
2466 create_threads(void)
2467 {
2468 	int idx;
2469 
2470 	/* Give each DSP device 4 threads */
2471 	voss_ntds = voss_dups * 4;
2472 	voss_tds = malloc(voss_ntds * sizeof(pthread_t));
2473 	if (voss_tds == NULL)
2474 		err(1, "malloc");
2475 
2476 	for (idx = 0; idx < voss_ntds; idx++) {
2477 		if (pthread_create(&voss_tds[idx], NULL, &virtual_cuse_process,
2478 		    NULL) != 0)
2479 			err(1, "pthread_create");
2480 	}
2481 
2482 	/* Reset until next time called */
2483 	voss_dups = 0;
2484 }
2485 
2486 static void
2487 destroy_threads(void)
2488 {
2489 	int idx;
2490 
2491 	for (idx = 0; idx < voss_ntds; idx++)
2492 		pthread_cancel(voss_tds[idx]);
2493 	free(voss_tds);
2494 }
2495 
2496 void
2497 voss_add_options(char *str)
2498 {
2499 	static char name[] = { "virtual_oss" };
2500 	const char sep[] = "\t ";
2501 	const char *ptrerr;
2502 	char *parg[64];
2503 	char *word;
2504 	char *brkt;
2505 	int narg = 0;
2506 
2507 	parg[narg++] = name;
2508 
2509 	for (word = strtok_r(str, sep, &brkt); word != NULL;
2510 	     word = strtok_r(NULL, sep, &brkt)) {
2511 		if (narg >= 64) {
2512 			ptrerr = "Too many arguments";
2513 			goto done;
2514 		}
2515 		parg[narg++] = word;
2516 	}
2517 	ptrerr = parse_options(narg, parg, 0);
2518 done:
2519 	if (ptrerr != NULL) {
2520 		strlcpy(str, ptrerr, VIRTUAL_OSS_OPTIONS_MAX);
2521 	} else {
2522 		str[0] = 0;
2523 		create_threads();
2524 	}
2525 }
2526 
2527 int
2528 main(int argc, char **argv)
2529 {
2530 	const char *ptrerr;
2531 	struct sigaction sa;
2532 	struct cuse_dev *pdev = NULL;
2533 
2534 	TAILQ_INIT(&virtual_profile_client_head);
2535 	TAILQ_INIT(&virtual_profile_loopback_head);
2536 
2537 	TAILQ_INIT(&virtual_monitor_input);
2538 	TAILQ_INIT(&virtual_monitor_output);
2539 	TAILQ_INIT(&virtual_monitor_local);
2540 
2541 	atomic_init();
2542 
2543 	/* automagically load the cuse.ko module, if any */
2544 	if (feature_present("cuse") == 0) {
2545 		if (system("kldload cuse") == -1)
2546 			warn("Failed to kldload cuse");
2547 	}
2548 
2549 	if (cuse_init() != 0)
2550 		errx(EX_USAGE, "Could not connect to cuse module");
2551 
2552 	signal(SIGPIPE, &virtual_pipe);
2553 
2554 	memset(&sa, 0, sizeof(sa));
2555 	sigfillset(&sa.sa_mask);
2556 	sa.sa_handler = virtual_sig_exit;
2557 	if (sigaction(SIGINT, &sa, NULL) < 0)
2558 		err(1, "sigaction(SIGINT)");
2559 	if (sigaction(SIGTERM, &sa, NULL) < 0)
2560 		err(1, "sigaction(SIGTERM)");
2561 
2562 	ptrerr = parse_options(argc, argv, 1);
2563 	if (ptrerr != NULL)
2564 		errx(EX_USAGE, "%s", ptrerr);
2565 
2566 	if (voss_dsp_rx_device[0] == 0 || voss_dsp_tx_device[0] == 0)
2567 		errx(EX_USAGE, "Missing -f argument");
2568 
2569 	/* use DSP channels as default */
2570 	if (voss_mix_channels == 0)
2571 		voss_mix_channels = voss_dsp_max_channels;
2572 
2573 	if (voss_mix_channels > voss_dsp_max_channels)
2574 		voss_max_channels = voss_mix_channels;
2575 	else
2576 		voss_max_channels = voss_dsp_max_channels;
2577 
2578 	if (voss_dsp_samples > (voss_dsp_sample_rate / 4))
2579 		errx(EX_USAGE, "Too many buffer samples given by -s argument");
2580 
2581 	/* check if daemon mode is requested */
2582 	if (voss_do_background != 0 && daemon(0, 0) != 0)
2583 		errx(EX_SOFTWARE, "Cannot become daemon");
2584 
2585 	if (voss_pid_path != NULL) {
2586 		int pidfile = open(voss_pid_path, O_RDWR | O_CREAT | O_TRUNC, 0600);
2587 		pid_t mypid = getpid();
2588 		char mypidstr[8];
2589 		snprintf(mypidstr, sizeof(mypidstr), "%d\n", mypid);
2590 		if (pidfile < 0)
2591 			errx(EX_SOFTWARE, "Cannot create PID file '%s'", voss_pid_path);
2592 		if (write(pidfile, mypidstr, strlen(mypidstr)) !=
2593 		    (ssize_t)strlen(mypidstr))
2594 			errx(EX_SOFTWARE, "Cannot write PID file");
2595 		close(pidfile);
2596 	}
2597 
2598 	/* setup audio delay unit */
2599 	voss_ad_init(voss_dsp_sample_rate);
2600 
2601 	/* Create CTL device */
2602 
2603 	if (voss_ctl_device[0] != 0) {
2604 		pdev = cuse_dev_create(&vctl_methods, NULL, NULL,
2605 		    0, 0, voss_dsp_perm, voss_ctl_device);
2606 		if (pdev == NULL)
2607 			errx(EX_USAGE, "Could not create '/dev/%s'", voss_ctl_device);
2608 
2609 		voss_dups++;
2610 	}
2611 
2612 	/* Create worker threads */
2613 	create_threads();
2614 
2615 	/* Run DSP threads */
2616 
2617 	virtual_oss_process(NULL);
2618 
2619 	destroy_threads();
2620 
2621 	if (voss_ctl_device[0] != 0)
2622 		cuse_dev_destroy(pdev);
2623 
2624 	return (0);
2625 }
2626