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