~ubuntu-branches/ubuntu/oneiric/oss4/oneiric-proposed

« back to all changes in this revision

Viewing changes to kernel/framework/vmix_core/vmix_input.c

  • Committer: Bazaar Package Importer
  • Author(s): Stefano Rivera
  • Date: 2011-06-16 20:37:48 UTC
  • mfrom: (5.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110616203748-jbrxik6ql33z54co
Tags: 4.2-build2004-1ubuntu1
* Merge from Debian unstable.
  - Supports our current kernel (LP: #746048)
  Remaining changes:
  - debian/oss4-dkms.dkms.in: s/source/build/ in Kernel headers paths.
* ld-as-needed.patch: Re-order CC arguments to enable building with ld
  --as-needed (LP: #770972)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Purpose: Virtual mixing audio driver recording routines
 
3
 */
 
4
/*
 
5
 *
 
6
 * This file is part of Open Sound System.
 
7
 *
 
8
 * Copyright (C) 4Front Technologies 1996-2008.
 
9
 *
 
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.
 
13
 *
 
14
 */
 
15
 
 
16
#define SWAP_SUPPORT
 
17
#include <oss_config.h>
 
18
#include "vmix.h"
 
19
 
 
20
#if 0
 
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)
 
25
#else
 
26
# define UP_STATUS(v)
 
27
# define DOWN_STATUS(v)
 
28
#endif
 
29
 
 
30
#undef SINE_DEBUG
 
31
 
 
32
#ifndef CONFIG_OSS_VMIX_FLOAT
 
33
#undef SINE_DEBUG
 
34
#endif
 
35
 
 
36
#ifdef SINE_DEBUG
 
37
#define SINE_SIZE       48
 
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
 
51
};
 
52
static int sine_phase[2] = { 0 };
 
53
#endif
 
54
 
 
55
/*
 
56
 * Recording import functions (from the physical devices)
 
57
 */
 
58
#undef  INT_IMPORT
 
59
#define INT_IMPORT(x) (x * 256)
 
60
 
 
61
static void
 
62
import16ne (vmix_engine_t * eng, void *inbuf, vmix_sample_t * chbufs[],
 
63
            int channels, int samples)
 
64
{
 
65
  short *op;
 
66
#define SAMPLE_TYPE     short
 
67
#define SAMPLE_RANGE    32768.0
 
68
#undef VMIX_BYTESWAP
 
69
#define VMIX_BYTESWAP(x) x
 
70
 
 
71
#include "vmix_import.inc"
 
72
}
 
73
 
 
74
static void
 
75
import16oe (vmix_engine_t * eng, void *inbuf, vmix_sample_t * chbufs[],
 
76
            int channels, int samples)
 
77
{
 
78
  short *op;
 
79
#undef  SAMPLE_TYPE
 
80
#undef  SAMPLE_RANGE
 
81
#define SAMPLE_TYPE     short
 
82
#define SAMPLE_RANGE    32768.0
 
83
#undef VMIX_BYTESWAP
 
84
#define VMIX_BYTESWAP(x) bswap16(x)
 
85
 
 
86
#include "vmix_import.inc"
 
87
}
 
88
 
 
89
#undef  INT_IMPORT
 
90
#define INT_IMPORT(x) (x / 256)
 
91
 
 
92
static void
 
93
import32ne (vmix_engine_t * eng, void *inbuf, vmix_sample_t * chbufs[],
 
94
            int channels, int samples)
 
95
{
 
96
  int *op;
 
97
#undef  SAMPLE_TYPE
 
98
#undef  SAMPLE_RANGE
 
99
#define SAMPLE_TYPE     int
 
100
#define SAMPLE_RANGE    2147483648.0
 
101
#undef VMIX_BYTESWAP
 
102
#define VMIX_BYTESWAP(x) x
 
103
 
 
104
#include "vmix_import.inc"
 
105
}
 
106
 
 
107
static void
 
108
import32oe (vmix_engine_t * eng, void *inbuf, vmix_sample_t * chbufs[],
 
109
            int channels, int samples)
 
110
{
 
111
  int *op;
 
112
#define SAMPLE_TYPE     int
 
113
#define SAMPLE_RANGE    2147483648.0
 
114
#undef VMIX_BYTESWAP
 
115
#define VMIX_BYTESWAP(x) bswap32(x)
 
116
 
 
117
#include "vmix_import.inc"
 
118
}
 
119
 
 
120
/*
 
121
 * recording export functions to virtual devices
 
122
 */
 
123
#undef  BUFFER_TYPE
 
124
#define BUFFER_TYPE short *
 
125
 
 
126
#undef  INT_EXPORT
 
127
#define INT_EXPORT(x) (x / 256)
 
128
 
 
129
void
 
130
vmix_rec_export_16ne (vmix_portc_t * portc, int nsamples)
 
131
{
 
132
  short *outp;
 
133
#undef VMIX_BYTESWAP
 
134
#define VMIX_BYTESWAP(x) x
 
135
#ifdef CONFIG_OSS_VMIX_FLOAT
 
136
  double range = 32767.0;
 
137
#endif
 
138
#include "rec_export.inc"
 
139
}
 
140
 
 
141
void
 
142
vmix_rec_export_16oe (vmix_portc_t * portc, int nsamples)
 
143
{
 
144
  short *outp;
 
145
#undef VMIX_BYTESWAP
 
146
#define VMIX_BYTESWAP(x) bswap16(x)
 
147
#ifdef CONFIG_OSS_VMIX_FLOAT
 
148
  double range = 32767.0;
 
149
#endif
 
150
#include "rec_export.inc"
 
151
}
 
152
 
 
153
#undef BUFFER_TYPE
 
154
#define BUFFER_TYPE int *
 
155
#undef  INT_EXPORT
 
156
#define INT_EXPORT(x) (x * 256)
 
157
 
 
158
void
 
159
vmix_rec_export_32ne (vmix_portc_t * portc, int nsamples)
 
160
{
 
161
  int *outp;
 
162
#undef VMIX_BYTESWAP
 
163
#define VMIX_BYTESWAP(x) x
 
164
#ifdef CONFIG_OSS_VMIX_FLOAT
 
165
  double range = 2147483647.0;
 
166
#endif
 
167
#include "rec_export.inc"
 
168
}
 
169
 
 
170
void
 
171
vmix_rec_export_32oe (vmix_portc_t * portc, int nsamples)
 
172
{
 
173
  int *outp;
 
174
#undef VMIX_BYTESWAP
 
175
#define VMIX_BYTESWAP(x) bswap32(x)
 
176
#ifdef CONFIG_OSS_VMIX_FLOAT
 
177
  double range = 2147483647.0;
 
178
#endif
 
179
#include "rec_export.inc"
 
180
}
 
181
 
 
182
#ifdef CONFIG_OSS_VMIX_FLOAT
 
183
void
 
184
vmix_rec_export_float (vmix_portc_t * portc, int nsamples)
 
185
{
 
186
  float *outp;
 
187
#undef BUFFER_TYPE
 
188
#define BUFFER_TYPE float *
 
189
#undef VMIX_BYTESWAP
 
190
#define VMIX_BYTESWAP(x) x
 
191
  double range = 1.0;
 
192
#include "rec_export.inc"
 
193
}
 
194
#endif
 
195
 
 
196
static void
 
197
vmix_record_callback (int dev, int parm)
 
198
{
 
199
  int i, n;
 
200
  int do_input = 0;
 
201
 
 
202
  adev_t *adev = audio_engines[dev];
 
203
  dmap_t *dmap = adev->dmap_in;
 
204
  oss_native_word flags;
 
205
 
 
206
  vmix_mixer_t *mixer = adev->vmix_mixer;
 
207
  vmix_engine_t *eng = &mixer->record_engine;
 
208
 
 
209
#ifdef CONFIG_OSS_VMIX_FLOAT
 
210
  fp_env_t fp_buf;
 
211
  short *fp_env = fp_buf;
 
212
  fp_flags_t fp_flags;
 
213
#endif
 
214
 
 
215
  if (mixer == NULL) /* Houston, we have a problem. */
 
216
     return;
 
217
 
 
218
  /*
 
219
   * Check if any input applications are active. Skip input processing
 
220
   * if it's not needed (to save CPU cycles).
 
221
   */
 
222
 
 
223
  for (i = 0; i < mixer->num_clientdevs; i++)
 
224
    if (mixer->client_portc[i]->trigger_bits & PCM_ENABLE_INPUT)
 
225
      do_input = 1;
 
226
 
 
227
  if (!do_input) /* Skip all input processing */
 
228
     {
 
229
          n = 0;
 
230
          while (n++ < dmap->nfrags
 
231
                 && (int) (dmap->byte_counter - dmap->user_counter) >=
 
232
                 dmap->fragment_size)
 
233
            {
 
234
                  dmap->user_counter += dmap->fragment_size;
 
235
            }
 
236
          return;
 
237
     }
 
238
 
 
239
  UP_STATUS (0x02);
 
240
  MUTEX_ENTER_IRQDISABLE (mixer->mutex, flags);
 
241
#ifdef CONFIG_OSS_VMIX_FLOAT
 
242
  {
 
243
    /*
 
244
     * Align the FP save buffer to 16 byte boundary
 
245
     */
 
246
    oss_native_word p;
 
247
    p = (oss_native_word) fp_buf;
 
248
 
 
249
    p = ((p + 15ULL) / 16) * 16;
 
250
    fp_env = (short *) p;
 
251
  }
 
252
 
 
253
  FP_SAVE (fp_env, fp_flags);
 
254
#endif
 
255
 
 
256
  n = 0;
 
257
  while (n++ < dmap->nfrags
 
258
         && (int) (dmap->byte_counter - dmap->user_counter) >=
 
259
         dmap->fragment_size)
 
260
    {
 
261
      int i, p;
 
262
      unsigned char *inbuf;
 
263
 
 
264
      if (!do_input)
 
265
        {
 
266
          /*
 
267
           * Just skip the recorded data becaus nobody needs it.
 
268
           */
 
269
          dmap->user_counter += dmap->fragment_size;
 
270
          continue;
 
271
        }
 
272
 
 
273
      for (i = 0; i < eng->channels; i++)
 
274
        {
 
275
          memset (eng->chbufs[i], 0, CHBUF_SAMPLES * sizeof (vmix_sample_t));
 
276
        }
 
277
 
 
278
      p = (int) (dmap->user_counter % dmap->bytes_in_use);
 
279
      inbuf = dmap->dmabuf + p;
 
280
 
 
281
      eng->converter (eng, inbuf, eng->chbufs, eng->channels,
 
282
                      eng->samples_per_frag);
 
283
 
 
284
      for (i = 0; i < mixer->num_clientdevs; i++)
 
285
        {
 
286
          vmix_portc_t *portc = mixer->client_portc[i];
 
287
 
 
288
          if (portc->trigger_bits & PCM_ENABLE_INPUT)
 
289
            {
 
290
              if (portc->rec_mixing_func == NULL)
 
291
                continue;
 
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);
 
297
            }
 
298
        }
 
299
 
 
300
      dmap->user_counter += dmap->fragment_size;
 
301
    }
 
302
 
 
303
#ifdef CONFIG_OSS_VMIX_FLOAT
 
304
  FP_RESTORE (fp_env, fp_flags);
 
305
#endif
 
306
  MUTEX_EXIT_IRQRESTORE (mixer->mutex, flags);
 
307
 
 
308
/*
 
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.
 
312
 */
 
313
  for (i = 0; i < mixer->num_clientdevs; i++)
 
314
    if (mixer->client_portc[i]->trigger_bits & PCM_ENABLE_INPUT)
 
315
      {
 
316
        vmix_portc_t *portc = mixer->client_portc[i];
 
317
        oss_audio_inputintr (portc->audio_dev, 0);
 
318
      }
 
319
  DOWN_STATUS (0x02);
 
320
}
 
321
 
 
322
void
 
323
finalize_record_engine (vmix_mixer_t * mixer, int fmt, adev_t * adev,
 
324
                        dmap_p dmap)
 
325
{
 
326
  int i;
 
327
 
 
328
  switch (fmt)
 
329
    {
 
330
    case AFMT_S16_NE:
 
331
      mixer->record_engine.bits = 16;
 
332
      mixer->record_engine.converter = import16ne;
 
333
      break;
 
334
 
 
335
    case AFMT_S16_OE:
 
336
      mixer->record_engine.bits = 16;
 
337
      mixer->record_engine.converter = import16oe;
 
338
      break;
 
339
 
 
340
    case AFMT_S32_NE:
 
341
      mixer->record_engine.bits = 32;
 
342
      mixer->record_engine.converter = import32ne;
 
343
      break;
 
344
 
 
345
    case AFMT_S32_OE:
 
346
      mixer->record_engine.bits = 32;
 
347
      mixer->record_engine.converter = import32oe;
 
348
      break;
 
349
 
 
350
    default:
 
351
      cmn_err (CE_CONT, "Unrecognized recording sample format %x\n", fmt);
 
352
      return;
 
353
    }
 
354
 
 
355
  mixer->record_engine.fragsize = dmap->fragment_size;
 
356
 
 
357
  mixer->record_engine.samples_per_frag =
 
358
    mixer->record_engine.fragsize / mixer->record_engine.channels /
 
359
    (mixer->record_engine.bits / 8);
 
360
 
 
361
  if (mixer->record_engine.samples_per_frag > CHBUF_SAMPLES)
 
362
    {
 
363
      cmn_err (CE_WARN, "Too many samples per fragment (%d,%d)\n",
 
364
               mixer->record_engine.samples_per_frag, CHBUF_SAMPLES);
 
365
      return;
 
366
    }
 
367
 
 
368
  for (i = 0; i < mixer->record_engine.channels; i++)
 
369
    if (mixer->record_engine.chbufs[i] == NULL) /* Not allocated yet */
 
370
      {
 
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)
 
375
          {
 
376
            cmn_err (CE_WARN, "Out of memory\n");
 
377
            return;
 
378
          }
 
379
      }
 
380
 
 
381
  dmap->audio_callback = vmix_record_callback;  /* Enable conversions */
 
382
  dmap->callback_parm = mixer->instance_num;
 
383
  dmap->dma_mode = PCM_ENABLE_INPUT;
 
384
 
 
385
  if (mixer->num_clientdevs > 1)
 
386
  {
 
387
    adev->redirect_out = mixer->client_portc[0]->audio_dev;
 
388
    adev->vmix_mixer = mixer;
 
389
  }
 
390
  vmix_record_callback (mixer->inputdev, mixer->instance_num);
 
391
}
 
392
 
 
393
void
 
394
vmix_setup_record_engine (vmix_mixer_t * mixer, adev_t * adev, dmap_t * dmap)
 
395
{
 
396
  int fmt;
 
397
  int old_min;
 
398
  int frags = 0x7fff0007;       /* fragment size of 128 bytes */
 
399
 
 
400
/*
 
401
 * Sample format (and endianess) setup 
 
402
 *
 
403
 */
 
404
 
 
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);
 
408
 
 
409
  // Find out the "best" sample format supported by the device
 
410
 
 
411
  if (adev->iformat_mask & AFMT_S16_OE)
 
412
    fmt = AFMT_S16_OE;
 
413
  if (adev->iformat_mask & AFMT_S16_NE)
 
414
    fmt = AFMT_S16_NE;
 
415
  if (mixer->multich_enable)
 
416
    {
 
417
      if (adev->iformat_mask & AFMT_S32_OE)
 
418
        fmt = AFMT_S32_OE;
 
419
      if (adev->iformat_mask & AFMT_S32_NE)
 
420
        fmt = AFMT_S32_NE;
 
421
    }
 
422
 
 
423
  fmt = adev->d->adrv_set_format (mixer->inputdev, fmt);
 
424
  mixer->record_engine.fmt = fmt;
 
425
 
 
426
/*
 
427
 * Number of channels
 
428
 */
 
429
  mixer->record_engine.channels = mixer->max_channels;
 
430
 
 
431
  if (mixer->record_engine.channels > MAX_REC_CHANNELS)
 
432
     mixer->record_engine.channels = MAX_REC_CHANNELS;
 
433
 
 
434
  if (!mixer->multich_enable)
 
435
    mixer->record_engine.channels = 2;
 
436
 
 
437
  /* Force the device to stereo before trying with (possibly) imultiple channels */
 
438
  adev->d->adrv_set_channels (mixer->inputdev, 2);
 
439
 
 
440
  mixer->record_engine.channels = 
 
441
    adev->d->adrv_set_channels (mixer->inputdev,
 
442
                                mixer->record_engine.channels);
 
443
 
 
444
  if (mixer->record_engine.channels > MAX_REC_CHANNELS)
 
445
    {
 
446
      cmn_err (CE_WARN,
 
447
               "Number of channels (%d) is larger than maximum (%d)\n",
 
448
               mixer->record_engine.channels, MAX_REC_CHANNELS);
 
449
      return;
 
450
    }
 
451
 
 
452
  /*
 
453
   * Try to set the same rate than for playback.
 
454
   */
 
455
  mixer->record_engine.rate =
 
456
    oss_audio_set_rate (mixer->inputdev, mixer->play_engine.rate);
 
457
 
 
458
  if (mixer->record_engine.rate <= 22050)
 
459
    frags = 0x7fff0004;         /* Use smaller fragments */
 
460
 
 
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;
 
469
 
 
470
  old_min = adev->min_fragments;
 
471
 
 
472
#if 0
 
473
  if ((adev->max_fragments == 0 || adev->max_fragments >= 4)
 
474
      && adev->min_block == 0)
 
475
    adev->min_fragments = 4;
 
476
#endif
 
477
 
 
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);
 
482
 
 
483
  dmap->bytes_in_use = dmap->fragment_size * dmap->nfrags;
 
484
 
 
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;
 
489
 
 
490
  if (mixer->record_engine.channels > 2)
 
491
    {
 
492
      DDB (cmn_err
 
493
           (CE_CONT, "Enabling multi channel rec mode, %d hw channels\n",
 
494
            mixer->record_engine.channels));
 
495
    }
 
496
  else if (mixer->record_engine.channels != 2)
 
497
    {
 
498
      cmn_err (CE_WARN,
 
499
               "Master device doesn't support suitable channel configuration\n");
 
500
 
 
501
      return;
 
502
    }
 
503
 
 
504
  finalize_record_engine (mixer, fmt, adev, dmap);
 
505
}