xref: /src/usr.sbin/virtual_oss/virtual_oss/virtual_oss.c (revision e75c8faf277dded0a80d469cb8182583716a2211)
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/soundcard.h>
31 
32 #include <stdint.h>
33 #include <stdbool.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <err.h>
38 #include <time.h>
39 #include <assert.h>
40 
41 #include "backend.h"
42 #include "int.h"
43 
44 uint64_t
virtual_oss_timestamp(void)45 virtual_oss_timestamp(void)
46 {
47 	struct timespec ts;
48 	uint64_t nsec;
49 
50 	clock_gettime(CLOCK_MONOTONIC, &ts);
51 
52 	nsec = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
53 	return (nsec);
54 }
55 
56 uint64_t
virtual_oss_delay_ns(void)57 virtual_oss_delay_ns(void)
58 {
59 	uint64_t delay;
60 
61 	delay = voss_dsp_samples;
62 	delay *= 1000000000ULL;
63 	delay /= voss_dsp_sample_rate;
64 
65 	return (delay);
66 }
67 
68 void
virtual_oss_wait(void)69 virtual_oss_wait(void)
70 {
71 	uint64_t delay;
72 	uint64_t nsec;
73 
74 	nsec = virtual_oss_timestamp();
75 
76 	delay = virtual_oss_delay_ns();
77 
78 	usleep((delay - (nsec % delay)) / 1000);
79 }
80 
81 static size_t
vclient_read_linear(struct virtual_client * pvc,struct virtual_ring * pvr,int64_t * dst,size_t total)82 vclient_read_linear(struct virtual_client *pvc, struct virtual_ring *pvr,
83     int64_t *dst, size_t total) __requires_exclusive(atomic_mtx)
84 {
85 	size_t total_read = 0;
86 
87 	pvc->sync_busy = 1;
88 	while (1) {
89 		size_t read = vring_read_linear(pvr, (uint8_t *)dst, 8 * total) / 8;
90 
91 		total_read += read;
92 		dst += read;
93 		total -= read;
94 
95 		if (!pvc->profile->synchronized || pvc->sync_wakeup ||
96 		    total == 0) {
97 			/* fill rest of buffer with silence, if any */
98 			if (total_read != 0 && total != 0)
99 				memset(dst, 0, 8 * total);
100 			break;
101 		}
102 		atomic_wait();
103 	}
104 	pvc->sync_busy = 0;
105 	if (pvc->sync_wakeup)
106 		atomic_wakeup();
107 
108 	vclient_tx_equalizer(pvc, dst - total_read, total_read);
109 
110 	return (total_read);
111 }
112 
113 static size_t
vclient_write_linear(struct virtual_client * pvc,struct virtual_ring * pvr,int64_t * src,size_t total)114 vclient_write_linear(struct virtual_client *pvc, struct virtual_ring *pvr,
115     int64_t *src, size_t total) __requires_exclusive(atomic_mtx)
116 {
117 	size_t total_written = 0;
118 
119 	vclient_rx_equalizer(pvc, src, total);
120 
121 	pvc->sync_busy = 1;
122 	while (1) {
123 		size_t written = vring_write_linear(pvr, (uint8_t *)src, total * 8) / 8;
124 
125 		total_written += written;
126 		src += written;
127 		total -= written;
128 
129 		if (!pvc->profile->synchronized || pvc->sync_wakeup ||
130 		    total == 0)
131 			break;
132 		atomic_wait();
133 	}
134 	pvc->sync_busy = 0;
135 	if (pvc->sync_wakeup)
136 		atomic_wakeup();
137 
138 	return (total_written);
139 }
140 
141 static inline void
virtual_oss_mixer_core_sub(const int64_t * src,int64_t * dst,uint32_t * pnoise,int src_chan,int dst_chan,int num,int64_t volume,int shift,int shift_orig,bool pol,bool assign)142 virtual_oss_mixer_core_sub(const int64_t *src, int64_t *dst,
143     uint32_t *pnoise, int src_chan, int dst_chan, int num,
144     int64_t volume, int shift, int shift_orig, bool pol,
145     bool assign)
146 {
147 	if (pol)
148 		volume = -volume;
149 
150 	if (shift < 0) {
151 		shift = -shift;
152 		while (num--) {
153 			if (assign)
154 				*dst = (*src * volume) >> shift;
155 			else
156 				*dst += (*src * volume) >> shift;
157 			if (__predict_true(pnoise != NULL))
158 				*dst += vclient_noise(pnoise, volume, shift_orig);
159 			src += src_chan;
160 			dst += dst_chan;
161 		}
162 	} else {
163 		while (num--) {
164 			if (assign)
165 				*dst = (*src * volume) << shift;
166 			else
167 				*dst += (*src * volume) << shift;
168 			if (__predict_true(pnoise != NULL))
169 				*dst += vclient_noise(pnoise, volume, shift_orig);
170 			src += src_chan;
171 			dst += dst_chan;
172 		}
173 	}
174 }
175 
176 static inline void
virtual_oss_mixer_core(const int64_t * src,int64_t * dst,uint32_t * pnoise,int src_chan,int dst_chan,int num,int64_t volume,int shift,int shift_orig,bool pol,bool assign)177 virtual_oss_mixer_core(const int64_t *src, int64_t *dst,
178     uint32_t *pnoise, int src_chan, int dst_chan, int num,
179     int64_t volume, int shift, int shift_orig, bool pol,
180     bool assign)
181 {
182 	const uint8_t selector = (shift_orig > 0) + assign * 2;
183 
184 	/* optimize some cases */
185 	switch (selector) {
186 	case 0:
187 		virtual_oss_mixer_core_sub(src, dst, NULL, src_chan, dst_chan,
188 		    num, volume, shift, shift_orig, pol, false);
189 		break;
190 	case 1:
191 		virtual_oss_mixer_core_sub(src, dst, pnoise, src_chan, dst_chan,
192 		    num, volume, shift, shift_orig, pol, false);
193 		break;
194 	case 2:
195 		virtual_oss_mixer_core_sub(src, dst, NULL, src_chan, dst_chan,
196 		    num, volume, shift, shift_orig, pol, true);
197 		break;
198 	case 3:
199 		virtual_oss_mixer_core_sub(src, dst, pnoise, src_chan, dst_chan,
200 		    num, volume, shift, shift_orig, pol, true);
201 		break;
202 	}
203 }
204 
205 void   *
virtual_oss_process(void * arg __unused)206 virtual_oss_process(void *arg __unused)
207 {
208 	vprofile_t *pvp;
209 	vclient_t *pvc;
210 	vmonitor_t *pvm;
211 	struct voss_backend *rx_be = voss_rx_backend;
212 	struct voss_backend *tx_be = voss_tx_backend;
213 	int rx_fmt;
214 	int tx_fmt;
215 	int rx_chn;
216 	int tx_chn;
217 	int off;
218 	int src_chans;
219 	int dst_chans;
220 	int src;
221 	int len;
222 	int samples;
223 	int shift;
224 	int shift_orig;
225 	int shift_fmt;
226 	int buffer_dsp_max_size;
227 	int buffer_dsp_half_size;
228 	int buffer_dsp_rx_sample_size;
229 	int buffer_dsp_rx_size;
230 	int buffer_dsp_tx_size_ref;
231 	int buffer_dsp_tx_size;
232 	uint64_t nice_timeout = 0;
233 	uint64_t last_timestamp;
234 	int blocks;
235 	int volume;
236 	int x_off;
237 	int x;
238 	int y;
239 
240 	uint8_t *buffer_dsp;
241 	int64_t *buffer_monitor;
242 	int64_t *buffer_temp;
243 	int64_t *buffer_data;
244 	int64_t *buffer_local;
245 	int64_t *buffer_orig;
246 
247 	bool need_delay = false;
248 
249 	buffer_dsp_max_size = voss_dsp_samples *
250 	    voss_dsp_max_channels * (voss_dsp_bits / 8);
251 	buffer_dsp_half_size = (voss_dsp_samples / 2) *
252 	    voss_dsp_max_channels * (voss_dsp_bits / 8);
253 
254 	buffer_dsp = malloc(buffer_dsp_max_size);
255 	buffer_temp = malloc(voss_dsp_samples * voss_max_channels * 8);
256 	buffer_monitor = malloc(voss_dsp_samples * voss_max_channels * 8);
257 	buffer_local = malloc(voss_dsp_samples * voss_max_channels * 8);
258 	buffer_data = malloc(voss_dsp_samples * voss_max_channels * 8);
259 	buffer_orig = malloc(voss_dsp_samples * voss_max_channels * 8);
260 
261 	if (buffer_dsp == NULL || buffer_temp == NULL ||
262 	    buffer_monitor == NULL || buffer_local == NULL ||
263 	    buffer_data == NULL || buffer_orig == NULL)
264 		errx(1, "Cannot allocate buffer memory");
265 
266 	while (1) {
267 		rx_be->close(rx_be);
268 		tx_be->close(tx_be);
269 
270 		if (voss_exit)
271 			break;
272 		if (need_delay)
273 			sleep(2);
274 
275 		voss_dsp_rx_refresh = 0;
276 		voss_dsp_tx_refresh = 0;
277 
278 		rx_be = voss_rx_backend;
279 		tx_be = voss_tx_backend;
280 
281 		switch (voss_dsp_bits) {
282 		case 8:
283 			rx_fmt = tx_fmt =
284 			    AFMT_S8 | AFMT_U8;
285 			break;
286 		case 16:
287 			rx_fmt = tx_fmt =
288 			    AFMT_S16_BE | AFMT_S16_LE |
289 			    AFMT_U16_BE | AFMT_U16_LE;
290 			break;
291 		case 24:
292 			rx_fmt = tx_fmt =
293 			    AFMT_S24_BE | AFMT_S24_LE |
294 			    AFMT_U24_BE | AFMT_U24_LE;
295 			break;
296 		case 32:
297 			rx_fmt = tx_fmt =
298 			    AFMT_S32_BE | AFMT_S32_LE |
299 			    AFMT_U32_BE | AFMT_U32_LE |
300 			    AFMT_F32_BE | AFMT_F32_LE;
301 			break;
302 		default:
303 			rx_fmt = tx_fmt = 0;
304 			break;
305 		}
306 
307 		rx_chn = voss_dsp_max_channels;
308 
309 		if (rx_be->open(rx_be, voss_dsp_rx_device, voss_dsp_sample_rate,
310 		    buffer_dsp_half_size, &rx_chn, &rx_fmt) < 0) {
311 			need_delay = true;
312 			continue;
313 		}
314 
315 		buffer_dsp_rx_sample_size = rx_chn * (voss_dsp_bits / 8);
316 		buffer_dsp_rx_size = voss_dsp_samples * buffer_dsp_rx_sample_size;
317 
318 		tx_chn = voss_dsp_max_channels;
319 		if (tx_be->open(tx_be, voss_dsp_tx_device, voss_dsp_sample_rate,
320 		    buffer_dsp_max_size, &tx_chn, &tx_fmt) < 0) {
321 			need_delay = true;
322 			continue;
323 		}
324 
325 		buffer_dsp_tx_size_ref = voss_dsp_samples *
326 		    tx_chn * (voss_dsp_bits / 8);
327 
328 		/* reset compressor gain */
329 		for (x = 0; x != VMAX_CHAN; x++)
330 			voss_output_compressor_gain[x] = 1.0;
331 
332 		/* reset local buffer */
333 		memset(buffer_local, 0, 8 * voss_dsp_samples * voss_max_channels);
334 
335 		while (1) {
336 			uint64_t delta_time;
337 
338 			/* Check if DSP device should be re-opened */
339 			if (voss_exit)
340 				break;
341 			if (voss_dsp_rx_refresh || voss_dsp_tx_refresh) {
342 				need_delay = false;
343 				break;
344 			}
345 			delta_time = nice_timeout - virtual_oss_timestamp();
346 
347 			/* Don't service more than 2x sample rate */
348 			nice_timeout = virtual_oss_delay_ns() / 2;
349 			if (delta_time >= 1000 && delta_time <= nice_timeout) {
350 				/* convert from ns to us */
351 				usleep(delta_time / 1000);
352 			}
353 			/* Compute next timeout */
354 			nice_timeout += virtual_oss_timestamp();
355 
356 			/* Read in samples */
357 			len = rx_be->transfer(rx_be, buffer_dsp, buffer_dsp_rx_size);
358 			if (len < 0 || (len % buffer_dsp_rx_sample_size) != 0) {
359 				need_delay = true;
360 				break;
361 			}
362 			if (len == 0)
363 				continue;
364 
365 			/* Convert to 64-bit samples */
366 			format_import(rx_fmt, buffer_dsp, len, buffer_data);
367 
368 			samples = len / buffer_dsp_rx_sample_size;
369 			src_chans = voss_mix_channels;
370 
371 			/* Compute master input peak values */
372 			format_maximum(buffer_data, voss_input_peak, rx_chn, samples, 0);
373 
374 			/* Remix format */
375 			format_remix(buffer_data, rx_chn, src_chans, samples);
376 
377 			/* Refresh timestamp */
378 			last_timestamp = virtual_oss_timestamp();
379 
380 			atomic_lock();
381 
382 			if (TAILQ_FIRST(&virtual_monitor_input) != NULL) {
383 				/* make a copy of the input data, in case of remote monitoring */
384 				memcpy(buffer_monitor, buffer_data, 8 * samples * src_chans);
385 			}
386 
387 			/* (0) Check for local monitoring of output data */
388 
389 			TAILQ_FOREACH(pvm, &virtual_monitor_local, entry) {
390 
391 				int64_t val;
392 
393 				if (pvm->mute != 0 || pvm->src_chan >= src_chans ||
394 				    pvm->dst_chan >= src_chans)
395 					continue;
396 
397 				src = pvm->src_chan;
398 				shift = pvm->shift;
399 				x = pvm->dst_chan;
400 
401 				if (pvm->pol) {
402 					if (shift < 0) {
403 						shift = -shift;
404 						for (y = 0; y != samples; y++) {
405 							val = -(buffer_local[(y * src_chans) + src] >> shift);
406 							buffer_data[(y * src_chans) + x] += val;
407 							if (val < 0)
408 								val = -val;
409 							if (val > pvm->peak_value)
410 								pvm->peak_value = val;
411 						}
412 					} else {
413 						for (y = 0; y != samples; y++) {
414 							val = -(buffer_local[(y * src_chans) + src] << shift);
415 							buffer_data[(y * src_chans) + x] += val;
416 							if (val < 0)
417 								val = -val;
418 							if (val > pvm->peak_value)
419 								pvm->peak_value = val;
420 						}
421 					}
422 				} else {
423 					if (shift < 0) {
424 						shift = -shift;
425 						for (y = 0; y != samples; y++) {
426 							val = (buffer_local[(y * src_chans) + src] >> shift);
427 							buffer_data[(y * src_chans) + x] += val;
428 							if (val < 0)
429 								val = -val;
430 							if (val > pvm->peak_value)
431 								pvm->peak_value = val;
432 						}
433 					} else {
434 						for (y = 0; y != samples; y++) {
435 							val = (buffer_local[(y * src_chans) + src] << shift);
436 							buffer_data[(y * src_chans) + x] += val;
437 							if (val < 0)
438 								val = -val;
439 							if (val > pvm->peak_value)
440 								pvm->peak_value = val;
441 						}
442 					}
443 				}
444 			}
445 
446 			/* make a copy of the input data */
447 			memcpy(buffer_orig, buffer_data, 8 * samples * src_chans);
448 
449 			/* (1) Distribute input samples to all clients */
450 
451 			TAILQ_FOREACH(pvp, &virtual_profile_client_head, entry) {
452 
453 			    if (TAILQ_FIRST(&pvp->head) == NULL)
454 				continue;
455 
456 			    /* check if compressor should be applied */
457 			    voss_compressor(buffer_data, pvp->rx_compressor_gain,
458 			        &pvp->rx_compressor_param, samples * src_chans,
459 				src_chans, (1ULL << (pvp->bits - 1)) - 1ULL);
460 
461 			    TAILQ_FOREACH(pvc, &pvp->head, entry) {
462 
463 				dst_chans = pvc->channels;
464 
465 				if (dst_chans > (int)voss_max_channels)
466 					continue;
467 
468 				shift_fmt = pvp->bits - (vclient_sample_bytes(pvc) * 8);
469 
470 				for (x = 0; x != dst_chans; x++) {
471 					src = pvp->rx_src[x];
472 					shift_orig = pvp->rx_shift[x] - shift_fmt;
473 					shift = shift_orig - VVOLUME_UNIT_SHIFT;
474 					volume = pvc->rx_volume;
475 
476 					if (pvp->rx_mute[x] || src >= src_chans || volume == 0) {
477 						for (y = 0; y != (samples * dst_chans); y += dst_chans)
478 							buffer_temp[y + x] = 0;
479 						continue;
480 					}
481 
482 					virtual_oss_mixer_core(buffer_data + src, buffer_temp + x,
483 					    &pvc->rx_noise_rem, src_chans, dst_chans, samples,
484 					    volume, shift, shift_orig, pvp->rx_pol[x], true);
485 				}
486 
487 				format_maximum(buffer_temp, pvp->rx_peak_value,
488 				    dst_chans, samples, shift_fmt);
489 
490 				/* check if recording is disabled */
491 				if (pvc->rx_enabled == 0 ||
492 				    (voss_is_recording == 0 && pvc->type != VTYPE_OSS_DAT))
493 					continue;
494 
495 				pvc->rx_timestamp = last_timestamp;
496 				pvc->rx_samples += samples * dst_chans;
497 
498 				/* store data into ring buffer */
499 				vclient_write_linear(pvc, &pvc->rx_ring[0],
500 				    buffer_temp, samples * dst_chans);
501 			    }
502 
503 			    /* restore buffer, if any */
504 			    if (pvp->rx_compressor_param.enabled)
505 				memcpy(buffer_data, buffer_orig, 8 * samples * src_chans);
506 			}
507 
508 			/* fill main output buffer with silence */
509 
510 			memset(buffer_temp, 0, sizeof(buffer_temp[0]) *
511 			    samples * src_chans);
512 
513 			/* (2) Run audio delay locator */
514 
515 			if (voss_ad_enabled != 0) {
516 				y = (samples * voss_mix_channels);
517 				for (x = 0; x != y; x += voss_mix_channels) {
518 					buffer_temp[x + voss_ad_output_channel] +=
519 					    voss_ad_getput_sample(buffer_data
520 					    [x + voss_ad_input_channel]);
521 				}
522 			}
523 
524 			/* (3) Load output samples from all clients */
525 
526 			TAILQ_FOREACH(pvp, &virtual_profile_client_head, entry) {
527 			    TAILQ_FOREACH(pvc, &pvp->head, entry) {
528 
529 				if (pvc->tx_enabled == 0)
530 					continue;
531 
532 				dst_chans = pvc->channels;
533 
534 				if (dst_chans > (int)voss_max_channels)
535 					continue;
536 
537 				/* update counters regardless of data presence */
538 				pvc->tx_timestamp = last_timestamp;
539 				pvc->tx_samples += samples * dst_chans;
540 
541 				/* read data from ring buffer */
542 				if (vclient_read_linear(pvc, &pvc->tx_ring[0],
543 				    buffer_data, samples * dst_chans) == 0)
544 					continue;
545 
546 				shift_fmt = pvp->bits - (vclient_sample_bytes(pvc) * 8);
547 
548 				format_maximum(buffer_data, pvp->tx_peak_value,
549 				    dst_chans, samples, shift_fmt);
550 
551 				for (x = 0; x != pvp->channels; x++) {
552 					src = pvp->tx_dst[x];
553 					shift_orig = pvp->tx_shift[x] + shift_fmt;
554 					shift = shift_orig - VVOLUME_UNIT_SHIFT;
555 					volume = pvc->tx_volume;
556 
557 					if (pvp->tx_mute[x] || src >= src_chans || volume == 0)
558 						continue;
559 
560 					/*
561 					 * Automagically re-map
562 					 * channels when the client is
563 					 * requesting fewer channels
564 					 * than specified in the
565 					 * profile. This typically
566 					 * allows automagic mono to
567 					 * stereo conversion.
568 					 */
569 					if (__predict_false(x >= dst_chans))
570 						x_off = x % dst_chans;
571 					else
572 						x_off = x;
573 
574 					virtual_oss_mixer_core(buffer_data + x_off, buffer_temp + src,
575 					    &pvc->tx_noise_rem, dst_chans, src_chans, samples,
576 					    volume, shift, shift_orig, pvp->tx_pol[x], false);
577 				}
578 			    }
579 			}
580 
581 			/* (4) Load output samples from all loopbacks */
582 
583 			TAILQ_FOREACH(pvp, &virtual_profile_loopback_head, entry) {
584 			    TAILQ_FOREACH(pvc, &pvp->head, entry) {
585 
586 				if (pvc->tx_enabled == 0)
587 					continue;
588 
589 				dst_chans = pvc->channels;
590 
591 				if (dst_chans > (int)voss_max_channels)
592 					continue;
593 
594 				/* read data from ring buffer */
595 				if (vclient_read_linear(pvc, &pvc->tx_ring[0],
596 				    buffer_data, samples * dst_chans) == 0)
597 					continue;
598 
599 				pvc->tx_timestamp = last_timestamp;
600 				pvc->tx_samples += samples * dst_chans;
601 
602 				shift_fmt = pvp->bits - (vclient_sample_bytes(pvc) * 8);
603 
604 				format_maximum(buffer_data, pvp->tx_peak_value,
605 				    dst_chans, samples, shift_fmt);
606 
607 				for (x = 0; x != pvp->channels; x++) {
608 					src = pvp->tx_dst[x];
609 					shift_orig = pvp->tx_shift[x] + shift_fmt;
610 					shift = shift_orig - VVOLUME_UNIT_SHIFT;
611 					volume = pvc->tx_volume;
612 
613 					if (pvp->tx_mute[x] || src >= src_chans || volume == 0)
614 						continue;
615 
616 					/*
617 					 * Automagically re-map
618 					 * channels when the client is
619 					 * requesting fewer channels
620 					 * than specified in the
621 					 * profile. This typically
622 					 * allows automagic mono to
623 					 * stereo conversion.
624 					 */
625 					if (__predict_false(x >= dst_chans))
626 						x_off = x % dst_chans;
627 					else
628 						x_off = x;
629 
630 					virtual_oss_mixer_core(buffer_data + x_off, buffer_temp + src,
631 					    &pvc->tx_noise_rem, dst_chans, src_chans, samples,
632 					    volume, shift, shift_orig, pvp->tx_pol[x], false);
633 				}
634 			    }
635 			}
636 
637 			/* (5) Check for input monitoring */
638 
639 			TAILQ_FOREACH(pvm, &virtual_monitor_input, entry) {
640 
641 				int64_t val;
642 
643 				if (pvm->mute != 0 || pvm->src_chan >= src_chans ||
644 				    pvm->dst_chan >= src_chans)
645 					continue;
646 
647 				src = pvm->src_chan;
648 				shift = pvm->shift;
649 				x = pvm->dst_chan;
650 
651 				if (pvm->pol) {
652 					if (shift < 0) {
653 						shift = -shift;
654 						for (y = 0; y != samples; y++) {
655 							val = -(buffer_monitor[(y * src_chans) + src] >> shift);
656 							buffer_temp[(y * src_chans) + x] += val;
657 							if (val < 0)
658 								val = -val;
659 							if (val > pvm->peak_value)
660 								pvm->peak_value = val;
661 						}
662 					} else {
663 						for (y = 0; y != samples; y++) {
664 							val = -(buffer_monitor[(y * src_chans) + src] << shift);
665 							buffer_temp[(y * src_chans) + x] += val;
666 							if (val < 0)
667 								val = -val;
668 							if (val > pvm->peak_value)
669 								pvm->peak_value = val;
670 						}
671 					}
672 				} else {
673 					if (shift < 0) {
674 						shift = -shift;
675 						for (y = 0; y != samples; y++) {
676 							val = (buffer_monitor[(y * src_chans) + src] >> shift);
677 							buffer_temp[(y * src_chans) + x] += val;
678 							if (val < 0)
679 								val = -val;
680 							if (val > pvm->peak_value)
681 								pvm->peak_value = val;
682 						}
683 					} else {
684 						for (y = 0; y != samples; y++) {
685 							val = (buffer_monitor[(y * src_chans) + src] << shift);
686 							buffer_temp[(y * src_chans) + x] += val;
687 							if (val < 0)
688 								val = -val;
689 							if (val > pvm->peak_value)
690 								pvm->peak_value = val;
691 						}
692 					}
693 				}
694 			}
695 
696 			if (TAILQ_FIRST(&virtual_monitor_output) != NULL) {
697 				memcpy(buffer_monitor, buffer_temp,
698 				    8 * samples * src_chans);
699 			}
700 
701 			/* (6) Check for output monitoring */
702 
703 			TAILQ_FOREACH(pvm, &virtual_monitor_output, entry) {
704 
705 				int64_t val;
706 
707 				if (pvm->mute != 0 || pvm->src_chan >= src_chans ||
708 				    pvm->dst_chan >= src_chans)
709 					continue;
710 
711 				src = pvm->src_chan;
712 				shift = pvm->shift;
713 				x = pvm->dst_chan;
714 
715 				if (pvm->pol) {
716 					if (shift < 0) {
717 						shift = -shift;
718 						for (y = 0; y != samples; y++) {
719 							val = -(buffer_monitor[(y * src_chans) + src] >> shift);
720 							buffer_temp[(y * src_chans) + x] += val;
721 							if (val < 0)
722 								val = -val;
723 							if (val > pvm->peak_value)
724 								pvm->peak_value = val;
725 						}
726 					} else {
727 						for (y = 0; y != samples; y++) {
728 							val = -(buffer_monitor[(y * src_chans) + src] << shift);
729 							buffer_temp[(y * src_chans) + x] += val;
730 							if (val < 0)
731 								val = -val;
732 							if (val > pvm->peak_value)
733 								pvm->peak_value = val;
734 						}
735 					}
736 				} else {
737 					if (shift < 0) {
738 						shift = -shift;
739 						for (y = 0; y != samples; y++) {
740 							val = (buffer_monitor[(y * src_chans) + src] >> shift);
741 							buffer_temp[(y * src_chans) + x] += val;
742 							if (val < 0)
743 								val = -val;
744 							if (val > pvm->peak_value)
745 								pvm->peak_value = val;
746 						}
747 					} else {
748 						for (y = 0; y != samples; y++) {
749 							val = (buffer_monitor[(y * src_chans) + src] << shift);
750 							buffer_temp[(y * src_chans) + x] += val;
751 							if (val < 0)
752 								val = -val;
753 							if (val > pvm->peak_value)
754 								pvm->peak_value = val;
755 						}
756 					}
757 				}
758 			}
759 
760 			/* make a copy of the output data */
761 			memcpy(buffer_data, buffer_temp, 8 * samples * src_chans);
762 
763 			/* make a copy for local monitoring, if any */
764 			if (TAILQ_FIRST(&virtual_monitor_local) != NULL) {
765 				const int end = src_chans * (voss_dsp_samples - samples);
766 				const int offs = src_chans * samples;
767 
768 				assert(end >= 0);
769 
770 				/* shift down samples */
771 				for (int xx = 0; xx != end; xx++)
772 					buffer_local[xx] = buffer_local[xx + offs];
773 				/* copy in new ones */
774 				memcpy(buffer_local + end, buffer_temp, 8 * samples * src_chans);
775 			}
776 
777 			/* (7) Check for output recording */
778 
779 			TAILQ_FOREACH(pvp, &virtual_profile_loopback_head, entry) {
780 
781 			    if (TAILQ_FIRST(&pvp->head) == NULL)
782 				continue;
783 
784 			    /* check if compressor should be applied */
785 			    voss_compressor(buffer_temp, pvp->rx_compressor_gain,
786 				&pvp->rx_compressor_param, samples,
787 			        samples * src_chans, (1ULL << (pvp->bits - 1)) - 1ULL);
788 
789 			    TAILQ_FOREACH(pvc, &pvp->head, entry) {
790 
791 				dst_chans = pvc->channels;
792 
793 				if (dst_chans > (int)voss_max_channels)
794 					continue;
795 
796 				shift_fmt = pvp->bits - (vclient_sample_bytes(pvc) * 8);
797 
798 				for (x = 0; x != dst_chans; x++) {
799 					src = pvp->rx_src[x];
800 					shift_orig = pvp->rx_shift[x] - shift_fmt;
801 					shift = shift_orig - VVOLUME_UNIT_SHIFT;
802 					volume = pvc->rx_volume;
803 
804 					if (pvp->rx_mute[x] || src >= src_chans || volume == 0) {
805 						for (y = 0; y != (samples * dst_chans); y += dst_chans)
806 							buffer_monitor[y + x] = 0;
807 						continue;
808 					}
809 
810 					virtual_oss_mixer_core(buffer_temp + src, buffer_monitor + x,
811 					    &pvc->rx_noise_rem, src_chans, dst_chans, samples,
812 					    volume, shift, shift_orig, pvp->rx_pol[x], true);
813 				}
814 
815 				format_maximum(buffer_monitor, pvp->rx_peak_value,
816 				    dst_chans, samples, shift_fmt);
817 
818 				/* check if recording is disabled */
819 				if (pvc->rx_enabled == 0 ||
820 				    (voss_is_recording == 0 && pvc->type != VTYPE_OSS_DAT))
821 					continue;
822 
823 				pvc->rx_timestamp = last_timestamp;
824 				pvc->rx_samples += samples * dst_chans;
825 
826 				/* store data into ring buffer */
827 				vclient_write_linear(pvc, &pvc->rx_ring[0],
828 				    buffer_monitor, samples * dst_chans);
829 			    }
830 
831 			    /* restore buffer, if any */
832 			    if (pvp->rx_compressor_param.enabled)
833 				memcpy(buffer_temp, buffer_data, 8 * samples * src_chans);
834 			}
835 
836 			atomic_wakeup();
837 
838 			format_remix(buffer_temp, voss_mix_channels, tx_chn, samples);
839 
840 			/* Compute master output peak values */
841 
842 			format_maximum(buffer_temp, voss_output_peak,
843 			    tx_chn, samples, 0);
844 
845 			/* Apply compressor, if any */
846 
847 			voss_compressor(buffer_temp, voss_output_compressor_gain,
848 			    &voss_output_compressor_param, samples * tx_chn,
849 			    tx_chn, format_max(tx_fmt));
850 
851 			/* Recompute buffer DSP transmit size according to received number of samples */
852 
853 			buffer_dsp_tx_size = samples * tx_chn * (voss_dsp_bits / 8);
854 
855 			/* Export and transmit resulting audio */
856 
857 			format_export(tx_fmt, buffer_temp, buffer_dsp,
858 			    buffer_dsp_tx_size);
859 
860 			atomic_unlock();
861 
862 			/* Get output delay in bytes */
863 			tx_be->delay(tx_be, &blocks);
864 
865 			/*
866 			 * Simple fix for jitter: Repeat data when too
867 			 * little. Skip data when too much. This
868 			 * should not happen during normal operation.
869 			 */
870 			if (blocks == 0) {
871 				blocks = 2;	/* buffer is empty */
872 				voss_jitter_up++;
873 			} else if (blocks >= (3 * buffer_dsp_tx_size_ref)) {
874 				blocks = 0;	/* too much data */
875 				voss_jitter_down++;
876 			} else {
877 				blocks = 1;	/* normal */
878 			}
879 
880 			len = 0;
881 			while (blocks--) {
882 				off = 0;
883 				while (off < (int)buffer_dsp_tx_size) {
884 					len = tx_be->transfer(tx_be, buffer_dsp + off,
885 					    buffer_dsp_tx_size - off);
886 					if (len <= 0)
887 						break;
888 					off += len;
889 				}
890 				if (len <= 0)
891 					break;
892 			}
893 
894 			/* check for error only */
895 			if (len < 0) {
896 				need_delay = true;
897 				break;
898 			}
899 		}
900 	}
901 
902 	free(buffer_dsp);
903 	free(buffer_temp);
904 	free(buffer_monitor);
905 	free(buffer_local);
906 	free(buffer_data);
907 	free(buffer_orig);
908 
909 	return (NULL);
910 }
911