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