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