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