2
* Purpose: Virtual mixing audio driver recording routines
6
* This file is part of Open Sound System.
8
* Copyright (C) 4Front Technologies 1996-2008.
10
* This this source file is released under GPL v2 license (no other versions).
11
* See the COPYING file included in the main directory of this source
12
* distribution for the license terms and conditions.
17
#include <oss_config.h>
21
/* Debugging macros */
22
extern unsigned char tmp_status;
23
# define UP_STATUS(v) OUTB(NULL, (tmp_status=tmp_status|(v)), 0x378)
24
# define DOWN_STATUS(v) OUTB(NULL, (tmp_status=tmp_status&~(v)), 0x378)
27
# define DOWN_STATUS(v)
32
#ifndef CONFIG_OSS_VMIX_FLOAT
38
static const float sine_table[SINE_SIZE] = {
39
0.000000, 0.130526, 0.258819, 0.382683,
40
0.500000, 0.608761, 0.707107, 0.793353,
41
0.866025, 0.923880, 0.965926, 0.991445,
42
1.000000, 0.991445, 0.965926, 0.923880,
43
0.866025, 0.793353, 0.707107, 0.608761,
44
0.500000, 0.382683, 0.258819, 0.130526,
45
0.000000, -0.130526, -0.258819, -0.382683,
46
-0.500000, -0.608761, -0.707107, -0.793353,
47
-0.866025, -0.923880, -0.965926, -0.991445,
48
-1.000000, -0.991445, -0.965926, -0.923880,
49
-0.866025, -0.793353, -0.707107, -0.608761,
50
-0.500000, -0.382683, -0.258819, -0.130526
52
static int sine_phase[2] = { 0 };
56
* Recording import functions (from the physical devices)
59
#define INT_IMPORT(x) (x * 256)
62
import16ne (vmix_engine_t * eng, void *inbuf, vmix_sample_t * chbufs[],
63
int channels, int samples)
66
#define SAMPLE_TYPE short
67
#define SAMPLE_RANGE 32768.0
69
#define VMIX_BYTESWAP(x) x
71
#include "vmix_import.inc"
75
import16oe (vmix_engine_t * eng, void *inbuf, vmix_sample_t * chbufs[],
76
int channels, int samples)
81
#define SAMPLE_TYPE short
82
#define SAMPLE_RANGE 32768.0
84
#define VMIX_BYTESWAP(x) bswap16(x)
86
#include "vmix_import.inc"
90
#define INT_IMPORT(x) (x / 256)
93
import32ne (vmix_engine_t * eng, void *inbuf, vmix_sample_t * chbufs[],
94
int channels, int samples)
99
#define SAMPLE_TYPE int
100
#define SAMPLE_RANGE 2147483648.0
102
#define VMIX_BYTESWAP(x) x
104
#include "vmix_import.inc"
108
import32oe (vmix_engine_t * eng, void *inbuf, vmix_sample_t * chbufs[],
109
int channels, int samples)
112
#define SAMPLE_TYPE int
113
#define SAMPLE_RANGE 2147483648.0
115
#define VMIX_BYTESWAP(x) bswap32(x)
117
#include "vmix_import.inc"
121
* recording export functions to virtual devices
124
#define BUFFER_TYPE short *
127
#define INT_EXPORT(x) (x / 256)
130
vmix_rec_export_16ne (vmix_portc_t * portc, int nsamples)
134
#define VMIX_BYTESWAP(x) x
135
#ifdef CONFIG_OSS_VMIX_FLOAT
136
double range = 32767.0;
138
#include "rec_export.inc"
142
vmix_rec_export_16oe (vmix_portc_t * portc, int nsamples)
146
#define VMIX_BYTESWAP(x) bswap16(x)
147
#ifdef CONFIG_OSS_VMIX_FLOAT
148
double range = 32767.0;
150
#include "rec_export.inc"
154
#define BUFFER_TYPE int *
156
#define INT_EXPORT(x) (x * 256)
159
vmix_rec_export_32ne (vmix_portc_t * portc, int nsamples)
163
#define VMIX_BYTESWAP(x) x
164
#ifdef CONFIG_OSS_VMIX_FLOAT
165
double range = 2147483647.0;
167
#include "rec_export.inc"
171
vmix_rec_export_32oe (vmix_portc_t * portc, int nsamples)
175
#define VMIX_BYTESWAP(x) bswap32(x)
176
#ifdef CONFIG_OSS_VMIX_FLOAT
177
double range = 2147483647.0;
179
#include "rec_export.inc"
182
#ifdef CONFIG_OSS_VMIX_FLOAT
184
vmix_rec_export_float (vmix_portc_t * portc, int nsamples)
188
#define BUFFER_TYPE float *
190
#define VMIX_BYTESWAP(x) x
192
#include "rec_export.inc"
197
vmix_record_callback (int dev, int parm)
202
adev_t *adev = audio_engines[dev];
203
dmap_t *dmap = adev->dmap_in;
204
oss_native_word flags;
206
vmix_mixer_t *mixer = adev->vmix_mixer;
207
vmix_engine_t *eng = &mixer->record_engine;
209
#ifdef CONFIG_OSS_VMIX_FLOAT
211
short *fp_env = fp_buf;
215
if (mixer == NULL) /* Houston, we have a problem. */
219
* Check if any input applications are active. Skip input processing
220
* if it's not needed (to save CPU cycles).
223
for (i = 0; i < mixer->num_clientdevs; i++)
224
if (mixer->client_portc[i]->trigger_bits & PCM_ENABLE_INPUT)
227
if (!do_input) /* Skip all input processing */
230
while (n++ < dmap->nfrags
231
&& (int) (dmap->byte_counter - dmap->user_counter) >=
234
dmap->user_counter += dmap->fragment_size;
240
MUTEX_ENTER_IRQDISABLE (mixer->mutex, flags);
241
#ifdef CONFIG_OSS_VMIX_FLOAT
244
* Align the FP save buffer to 16 byte boundary
247
p = (oss_native_word) fp_buf;
249
p = ((p + 15ULL) / 16) * 16;
250
fp_env = (short *) p;
253
FP_SAVE (fp_env, fp_flags);
257
while (n++ < dmap->nfrags
258
&& (int) (dmap->byte_counter - dmap->user_counter) >=
262
unsigned char *inbuf;
267
* Just skip the recorded data becaus nobody needs it.
269
dmap->user_counter += dmap->fragment_size;
273
for (i = 0; i < eng->channels; i++)
275
memset (eng->chbufs[i], 0, CHBUF_SAMPLES * sizeof (vmix_sample_t));
278
p = (int) (dmap->user_counter % dmap->bytes_in_use);
279
inbuf = dmap->dmabuf + p;
281
eng->converter (eng, inbuf, eng->chbufs, eng->channels,
282
eng->samples_per_frag);
284
for (i = 0; i < mixer->num_clientdevs; i++)
286
vmix_portc_t *portc = mixer->client_portc[i];
288
if (portc->trigger_bits & PCM_ENABLE_INPUT)
290
if (portc->rec_mixing_func == NULL)
292
if (portc->rec_choffs + portc->channels >
293
mixer->record_engine.channels)
294
portc->rec_choffs = 0;
295
portc->rec_mixing_func (portc,
296
mixer->record_engine.samples_per_frag);
300
dmap->user_counter += dmap->fragment_size;
303
#ifdef CONFIG_OSS_VMIX_FLOAT
304
FP_RESTORE (fp_env, fp_flags);
306
MUTEX_EXIT_IRQRESTORE (mixer->mutex, flags);
309
* Call oss_audio_inputintr outside FP mode because it may
310
* cause a task switch (under Solaris). Task switch may turn on CR0.TS under
311
* x86 which in turn will cause #nm exception.
313
for (i = 0; i < mixer->num_clientdevs; i++)
314
if (mixer->client_portc[i]->trigger_bits & PCM_ENABLE_INPUT)
316
vmix_portc_t *portc = mixer->client_portc[i];
317
oss_audio_inputintr (portc->audio_dev, 0);
323
finalize_record_engine (vmix_mixer_t * mixer, int fmt, adev_t * adev,
331
mixer->record_engine.bits = 16;
332
mixer->record_engine.converter = import16ne;
336
mixer->record_engine.bits = 16;
337
mixer->record_engine.converter = import16oe;
341
mixer->record_engine.bits = 32;
342
mixer->record_engine.converter = import32ne;
346
mixer->record_engine.bits = 32;
347
mixer->record_engine.converter = import32oe;
351
cmn_err (CE_CONT, "Unrecognized recording sample format %x\n", fmt);
355
mixer->record_engine.fragsize = dmap->fragment_size;
357
mixer->record_engine.samples_per_frag =
358
mixer->record_engine.fragsize / mixer->record_engine.channels /
359
(mixer->record_engine.bits / 8);
361
if (mixer->record_engine.samples_per_frag > CHBUF_SAMPLES)
363
cmn_err (CE_WARN, "Too many samples per fragment (%d,%d)\n",
364
mixer->record_engine.samples_per_frag, CHBUF_SAMPLES);
368
for (i = 0; i < mixer->record_engine.channels; i++)
369
if (mixer->record_engine.chbufs[i] == NULL) /* Not allocated yet */
371
mixer->record_engine.chbufs[i] =
372
PMALLOC (mixer->master_osdev,
373
CHBUF_SAMPLES * sizeof (vmix_sample_t));
374
if (mixer->record_engine.chbufs[i] == NULL)
376
cmn_err (CE_WARN, "Out of memory\n");
381
dmap->audio_callback = vmix_record_callback; /* Enable conversions */
382
dmap->callback_parm = mixer->instance_num;
383
dmap->dma_mode = PCM_ENABLE_INPUT;
385
if (mixer->num_clientdevs > 1)
387
adev->redirect_out = mixer->client_portc[0]->audio_dev;
388
adev->vmix_mixer = mixer;
390
vmix_record_callback (mixer->inputdev, mixer->instance_num);
394
vmix_setup_record_engine (vmix_mixer_t * mixer, adev_t * adev, dmap_t * dmap)
398
int frags = 0x7fff0007; /* fragment size of 128 bytes */
401
* Sample format (and endianess) setup
405
// First make sure a sane format is selected before starting to probe
406
fmt = adev->d->adrv_set_format (mixer->inputdev, AFMT_S16_LE);
407
fmt = adev->d->adrv_set_format (mixer->inputdev, AFMT_S16_NE);
409
// Find out the "best" sample format supported by the device
411
if (adev->iformat_mask & AFMT_S16_OE)
413
if (adev->iformat_mask & AFMT_S16_NE)
415
if (mixer->multich_enable)
417
if (adev->iformat_mask & AFMT_S32_OE)
419
if (adev->iformat_mask & AFMT_S32_NE)
423
fmt = adev->d->adrv_set_format (mixer->inputdev, fmt);
424
mixer->record_engine.fmt = fmt;
429
mixer->record_engine.channels = mixer->max_channels;
431
if (mixer->record_engine.channels > MAX_REC_CHANNELS)
432
mixer->record_engine.channels = MAX_REC_CHANNELS;
434
if (!mixer->multich_enable)
435
mixer->record_engine.channels = 2;
437
/* Force the device to stereo before trying with (possibly) imultiple channels */
438
adev->d->adrv_set_channels (mixer->inputdev, 2);
440
mixer->record_engine.channels =
441
adev->d->adrv_set_channels (mixer->inputdev,
442
mixer->record_engine.channels);
444
if (mixer->record_engine.channels > MAX_REC_CHANNELS)
447
"Number of channels (%d) is larger than maximum (%d)\n",
448
mixer->record_engine.channels, MAX_REC_CHANNELS);
453
* Try to set the same rate than for playback.
455
mixer->record_engine.rate =
456
oss_audio_set_rate (mixer->inputdev, mixer->play_engine.rate);
458
if (mixer->record_engine.rate <= 22050)
459
frags = 0x7fff0004; /* Use smaller fragments */
461
audio_engines[mixer->inputdev]->hw_parms.channels =
462
mixer->record_engine.channels;
463
audio_engines[mixer->inputdev]->hw_parms.rate = mixer->record_engine.rate;
464
audio_engines[mixer->inputdev]->dmap_in->data_rate =
465
mixer->record_engine.rate * mixer->record_engine.channels *
466
mixer->record_engine.bits / 8;
467
audio_engines[mixer->inputdev]->dmap_in->frame_size =
468
mixer->record_engine.channels * mixer->record_engine.bits / 8;
470
old_min = adev->min_fragments;
473
if ((adev->max_fragments == 0 || adev->max_fragments >= 4)
474
&& adev->min_block == 0)
475
adev->min_fragments = 4;
478
oss_audio_ioctl (mixer->inputdev, NULL, SNDCTL_DSP_SETFRAGMENT,
479
(ioctl_arg) & frags);
480
oss_audio_ioctl (mixer->inputdev, NULL, SNDCTL_DSP_GETBLKSIZE,
481
(ioctl_arg) & mixer->record_engine.fragsize);
483
dmap->bytes_in_use = dmap->fragment_size * dmap->nfrags;
485
oss_audio_ioctl (mixer->inputdev, NULL, SNDCTL_DSP_GETBLKSIZE,
486
(ioctl_arg) & mixer->record_engine.fragsize);
487
mixer->record_engine.fragsize = dmap->fragment_size;
488
adev->min_fragments = old_min;
490
if (mixer->record_engine.channels > 2)
493
(CE_CONT, "Enabling multi channel rec mode, %d hw channels\n",
494
mixer->record_engine.channels));
496
else if (mixer->record_engine.channels != 2)
499
"Master device doesn't support suitable channel configuration\n");
504
finalize_record_engine (mixer, fmt, adev, dmap);