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