Statistics
| Branch: | Revision:

root / audio / alsaaudio.c @ c0fe3827

History | View | Annotate | Download (24.7 kB)

1
/*
2
 * QEMU ALSA audio driver
3
 *
4
 * Copyright (c) 2005 Vassili Karpov (malc)
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include <alsa/asoundlib.h>
25
#include "vl.h"
26

    
27
#define AUDIO_CAP "alsa"
28
#include "audio_int.h"
29

    
30
typedef struct ALSAVoiceOut {
31
    HWVoiceOut hw;
32
    void *pcm_buf;
33
    snd_pcm_t *handle;
34
    int can_pause;
35
    int was_enabled;
36
} ALSAVoiceOut;
37

    
38
typedef struct ALSAVoiceIn {
39
    HWVoiceIn hw;
40
    snd_pcm_t *handle;
41
    void *pcm_buf;
42
    int can_pause;
43
} ALSAVoiceIn;
44

    
45
static struct {
46
    int size_in_usec_in;
47
    int size_in_usec_out;
48
    const char *pcm_name_in;
49
    const char *pcm_name_out;
50
    unsigned int buffer_size_in;
51
    unsigned int period_size_in;
52
    unsigned int buffer_size_out;
53
    unsigned int period_size_out;
54
    unsigned int threshold;
55

    
56
    int buffer_size_in_overriden;
57
    int period_size_in_overriden;
58

    
59
    int buffer_size_out_overriden;
60
    int period_size_out_overriden;
61
} conf = {
62
#ifdef HIGH_LATENCY
63
    .size_in_usec_in = 1,
64
    .size_in_usec_out = 1,
65
#endif
66
    .pcm_name_out = "hw:0,0",
67
    .pcm_name_in = "hw:0,0",
68
#ifdef HIGH_LATENCY
69
    .buffer_size_in = 400000,
70
    .period_size_in = 400000 / 4,
71
    .buffer_size_out = 400000,
72
    .period_size_out = 400000 / 4,
73
#else
74
#define DEFAULT_BUFFER_SIZE 1024
75
#define DEFAULT_PERIOD_SIZE 256
76
    .buffer_size_in = DEFAULT_BUFFER_SIZE,
77
    .period_size_in = DEFAULT_PERIOD_SIZE,
78
    .buffer_size_out = DEFAULT_BUFFER_SIZE,
79
    .period_size_out = DEFAULT_PERIOD_SIZE,
80
    .buffer_size_in_overriden = 0,
81
    .buffer_size_out_overriden = 0,
82
    .period_size_in_overriden = 0,
83
    .period_size_out_overriden = 0,
84
#endif
85
    .threshold = 0
86
};
87

    
88
struct alsa_params_req {
89
    int freq;
90
    audfmt_e fmt;
91
    int nchannels;
92
    unsigned int buffer_size;
93
    unsigned int period_size;
94
};
95

    
96
struct alsa_params_obt {
97
    int freq;
98
    audfmt_e fmt;
99
    int nchannels;
100
    int can_pause;
101
    snd_pcm_uframes_t samples;
102
};
103

    
104
static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
105
{
106
    va_list ap;
107

    
108
    va_start (ap, fmt);
109
    AUD_vlog (AUDIO_CAP, fmt, ap);
110
    va_end (ap);
111

    
112
    AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
113
}
114

    
115
static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
116
    int err,
117
    const char *typ,
118
    const char *fmt,
119
    ...
120
    )
121
{
122
    va_list ap;
123

    
124
    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
125

    
126
    va_start (ap, fmt);
127
    AUD_vlog (AUDIO_CAP, fmt, ap);
128
    va_end (ap);
129

    
130
    AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
131
}
132

    
133
static void alsa_anal_close (snd_pcm_t **handlep)
134
{
135
    int err = snd_pcm_close (*handlep);
136
    if (err) {
137
        alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
138
    }
139
    *handlep = NULL;
140
}
141

    
142
static int alsa_write (SWVoiceOut *sw, void *buf, int len)
143
{
144
    return audio_pcm_sw_write (sw, buf, len);
145
}
146

    
147
static int aud_to_alsafmt (audfmt_e fmt)
148
{
149
    switch (fmt) {
150
    case AUD_FMT_S8:
151
        return SND_PCM_FORMAT_S8;
152

    
153
    case AUD_FMT_U8:
154
        return SND_PCM_FORMAT_U8;
155

    
156
    case AUD_FMT_S16:
157
        return SND_PCM_FORMAT_S16_LE;
158

    
159
    case AUD_FMT_U16:
160
        return SND_PCM_FORMAT_U16_LE;
161

    
162
    default:
163
        dolog ("Internal logic error: Bad audio format %d\n", fmt);
164
#ifdef DEBUG_AUDIO
165
        abort ();
166
#endif
167
        return SND_PCM_FORMAT_U8;
168
    }
169
}
170

    
171
static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
172
{
173
    switch (alsafmt) {
174
    case SND_PCM_FORMAT_S8:
175
        *endianness = 0;
176
        *fmt = AUD_FMT_S8;
177
        break;
178

    
179
    case SND_PCM_FORMAT_U8:
180
        *endianness = 0;
181
        *fmt = AUD_FMT_U8;
182
        break;
183

    
184
    case SND_PCM_FORMAT_S16_LE:
185
        *endianness = 0;
186
        *fmt = AUD_FMT_S16;
187
        break;
188

    
189
    case SND_PCM_FORMAT_U16_LE:
190
        *endianness = 0;
191
        *fmt = AUD_FMT_U16;
192
        break;
193

    
194
    case SND_PCM_FORMAT_S16_BE:
195
        *endianness = 1;
196
        *fmt = AUD_FMT_S16;
197
        break;
198

    
199
    case SND_PCM_FORMAT_U16_BE:
200
        *endianness = 1;
201
        *fmt = AUD_FMT_U16;
202
        break;
203

    
204
    default:
205
        dolog ("Unrecognized audio format %d\n", alsafmt);
206
        return -1;
207
    }
208

    
209
    return 0;
210
}
211

    
212
#if defined DEBUG_MISMATCHES || defined DEBUG
213
static void alsa_dump_info (struct alsa_params_req *req,
214
                            struct alsa_params_obt *obt)
215
{
216
    dolog ("parameter | requested value | obtained value\n");
217
    dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
218
    dolog ("channels  |      %10d |     %10d\n",
219
           req->nchannels, obt->nchannels);
220
    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
221
    dolog ("============================================\n");
222
    dolog ("requested: buffer size %d period size %d\n",
223
           req->buffer_size, req->period_size);
224
    dolog ("obtained: samples %ld\n", obt->samples);
225
}
226
#endif
227

    
228
static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
229
{
230
    int err;
231
    snd_pcm_sw_params_t *sw_params;
232

    
233
    snd_pcm_sw_params_alloca (&sw_params);
234

    
235
    err = snd_pcm_sw_params_current (handle, sw_params);
236
    if (err < 0) {
237
        dolog ("Could not fully initialize DAC\n");
238
        alsa_logerr (err, "Failed to get current software parameters\n");
239
        return;
240
    }
241

    
242
    err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
243
    if (err < 0) {
244
        dolog ("Could not fully initialize DAC\n");
245
        alsa_logerr (err, "Failed to set software threshold to %ld\n",
246
                     threshold);
247
        return;
248
    }
249

    
250
    err = snd_pcm_sw_params (handle, sw_params);
251
    if (err < 0) {
252
        dolog ("Could not fully initialize DAC\n");
253
        alsa_logerr (err, "Failed to set software parameters\n");
254
        return;
255
    }
256
}
257

    
258
static int alsa_open (int in, struct alsa_params_req *req,
259
                      struct alsa_params_obt *obt, snd_pcm_t **handlep)
260
{
261
    snd_pcm_t *handle;
262
    snd_pcm_hw_params_t *hw_params;
263
    int err, freq, nchannels;
264
    const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
265
    unsigned int period_size, buffer_size;
266
    snd_pcm_uframes_t obt_buffer_size;
267
    const char *typ = in ? "ADC" : "DAC";
268

    
269
    freq = req->freq;
270
    period_size = req->period_size;
271
    buffer_size = req->buffer_size;
272
    nchannels = req->nchannels;
273

    
274
    snd_pcm_hw_params_alloca (&hw_params);
275

    
276
    err = snd_pcm_open (
277
        &handle,
278
        pcm_name,
279
        in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
280
        SND_PCM_NONBLOCK
281
        );
282
    if (err < 0) {
283
        alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
284
        return -1;
285
    }
286

    
287
    err = snd_pcm_hw_params_any (handle, hw_params);
288
    if (err < 0) {
289
        alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
290
        goto err;
291
    }
292

    
293
    err = snd_pcm_hw_params_set_access (
294
        handle,
295
        hw_params,
296
        SND_PCM_ACCESS_RW_INTERLEAVED
297
        );
298
    if (err < 0) {
299
        alsa_logerr2 (err, typ, "Failed to set access type\n");
300
        goto err;
301
    }
302

    
303
    err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
304
    if (err < 0) {
305
        alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
306
        goto err;
307
    }
308

    
309
    err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
310
    if (err < 0) {
311
        alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
312
        goto err;
313
    }
314

    
315
    err = snd_pcm_hw_params_set_channels_near (
316
        handle,
317
        hw_params,
318
        &nchannels
319
        );
320
    if (err < 0) {
321
        alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
322
                      req->nchannels);
323
        goto err;
324
    }
325

    
326
    if (nchannels != 1 && nchannels != 2) {
327
        alsa_logerr2 (err, typ,
328
                      "Can not handle obtained number of channels %d\n",
329
                      nchannels);
330
        goto err;
331
    }
332

    
333
    if (!((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out))) {
334
        if (!buffer_size) {
335
            buffer_size = DEFAULT_BUFFER_SIZE;
336
            period_size= DEFAULT_PERIOD_SIZE;
337
        }
338
    }
339

    
340
    if (buffer_size) {
341
        if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) {
342
            if (period_size) {
343
                err = snd_pcm_hw_params_set_period_time_near (
344
                    handle,
345
                    hw_params,
346
                    &period_size,
347
                    0
348
                    );
349
                if (err < 0) {
350
                    alsa_logerr2 (err, typ,
351
                                  "Failed to set period time %d\n",
352
                                  req->period_size);
353
                    goto err;
354
                }
355
            }
356

    
357
            err = snd_pcm_hw_params_set_buffer_time_near (
358
                handle,
359
                hw_params,
360
                &buffer_size,
361
                0
362
                );
363

    
364
            if (err < 0) {
365
                alsa_logerr2 (err, typ,
366
                              "Failed to set buffer time %d\n",
367
                              req->buffer_size);
368
                goto err;
369
            }
370
        }
371
        else {
372
            int dir;
373
            snd_pcm_uframes_t minval;
374

    
375
            if (period_size) {
376
                minval = period_size;
377
                dir = 0;
378

    
379
                err = snd_pcm_hw_params_get_period_size_min (
380
                    hw_params,
381
                    &minval,
382
                    &dir
383
                    );
384
                if (err < 0) {
385
                    alsa_logerr (
386
                        err,
387
                        "Could not get minmal period size for %s\n",
388
                        typ
389
                        );
390
                }
391
                else {
392
                    if (period_size < minval) {
393
                        if ((in && conf.period_size_in_overriden)
394
                            || (!in && conf.period_size_out_overriden)) {
395
                            dolog ("%s period size(%d) is less "
396
                                   "than minmal period size(%ld)\n",
397
                                   typ,
398
                                   period_size,
399
                                   minval);
400
                        }
401
                        period_size = minval;
402
                    }
403
                }
404

    
405
                err = snd_pcm_hw_params_set_period_size (
406
                    handle,
407
                    hw_params,
408
                    period_size,
409
                    0
410
                    );
411
                if (err < 0) {
412
                    alsa_logerr2 (err, typ, "Failed to set period size %d\n",
413
                                  req->period_size);
414
                    goto err;
415
                }
416
            }
417

    
418
            minval = buffer_size;
419
            err = snd_pcm_hw_params_get_buffer_size_min (
420
                hw_params,
421
                &minval
422
                );
423
            if (err < 0) {
424
                alsa_logerr (err, "Could not get minmal buffer size for %s\n",
425
                             typ);
426
            }
427
            else {
428
                if (buffer_size < minval) {
429
                    if ((in && conf.buffer_size_in_overriden)
430
                        || (!in && conf.buffer_size_out_overriden)) {
431
                        dolog (
432
                            "%s buffer size(%d) is less "
433
                            "than minimal buffer size(%ld)\n",
434
                            typ,
435
                            buffer_size,
436
                            minval
437
                            );
438
                    }
439
                    buffer_size = minval;
440
                }
441
            }
442

    
443
            err = snd_pcm_hw_params_set_buffer_size (
444
                handle,
445
                hw_params,
446
                buffer_size
447
                );
448
            if (err < 0) {
449
                alsa_logerr2 (err, typ, "Failed to set buffer size %d\n",
450
                              req->buffer_size);
451
                goto err;
452
            }
453
        }
454
    }
455
    else {
456
        dolog ("warning: Buffer size is not set\n");
457
    }
458

    
459
    err = snd_pcm_hw_params (handle, hw_params);
460
    if (err < 0) {
461
        alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
462
        goto err;
463
    }
464

    
465
    err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
466
    if (err < 0) {
467
        alsa_logerr2 (err, typ, "Failed to get buffer size\n");
468
        goto err;
469
    }
470

    
471
    err = snd_pcm_prepare (handle);
472
    if (err < 0) {
473
        alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
474
        goto err;
475
    }
476

    
477
    obt->can_pause = snd_pcm_hw_params_can_pause (hw_params);
478
    if (obt->can_pause < 0) {
479
        alsa_logerr (err, "Could not get pause capability for %s\n", typ);
480
        obt->can_pause = 0;
481
    }
482

    
483
    if (!in && conf.threshold) {
484
        snd_pcm_uframes_t threshold;
485
        int bytes_per_sec;
486

    
487
        bytes_per_sec = freq
488
            << (nchannels == 2)
489
            << (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16);
490

    
491
        threshold = (conf.threshold * bytes_per_sec) / 1000;
492
        alsa_set_threshold (handle, threshold);
493
    }
494

    
495
    obt->fmt = req->fmt;
496
    obt->nchannels = nchannels;
497
    obt->freq = freq;
498
    obt->samples = obt_buffer_size;
499
    *handlep = handle;
500

    
501
#if defined DEBUG_MISMATCHES || defined DEBUG
502
    if (obt->fmt != req->fmt ||
503
        obt->nchannels != req->nchannels ||
504
        obt->freq != req->freq) {
505
        dolog ("Audio paramters mismatch for %s\n", typ);
506
        alsa_dump_info (req, obt);
507
    }
508
#endif
509

    
510
#ifdef DEBUG
511
    alsa_dump_info (req, obt);
512
#endif
513
    return 0;
514

    
515
 err:
516
    alsa_anal_close (&handle);
517
    return -1;
518
}
519

    
520
static int alsa_recover (snd_pcm_t *handle)
521
{
522
    int err = snd_pcm_prepare (handle);
523
    if (err < 0) {
524
        alsa_logerr (err, "Failed to prepare handle %p\n", handle);
525
        return -1;
526
    }
527
    return 0;
528
}
529

    
530
static int alsa_run_out (HWVoiceOut *hw)
531
{
532
    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
533
    int rpos, live, decr;
534
    int samples;
535
    uint8_t *dst;
536
    st_sample_t *src;
537
    snd_pcm_sframes_t avail;
538

    
539
    live = audio_pcm_hw_get_live_out (hw);
540
    if (!live) {
541
        return 0;
542
    }
543

    
544
    avail = snd_pcm_avail_update (alsa->handle);
545
    if (avail < 0) {
546
        if (avail == -EPIPE) {
547
            if (!alsa_recover (alsa->handle)) {
548
                avail = snd_pcm_avail_update (alsa->handle);
549
                if (avail >= 0) {
550
                    goto ok;
551
                }
552
            }
553
        }
554

    
555
        alsa_logerr (avail, "Could not get amount free space\n");
556
        return 0;
557
    }
558

    
559
 ok:
560
    decr = audio_MIN (live, avail);
561
    samples = decr;
562
    rpos = hw->rpos;
563
    while (samples) {
564
        int left_till_end_samples = hw->samples - rpos;
565
        int convert_samples = audio_MIN (samples, left_till_end_samples);
566
        snd_pcm_sframes_t written;
567

    
568
        src = hw->mix_buf + rpos;
569
        dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
570

    
571
        hw->clip (dst, src, convert_samples);
572

    
573
    again:
574
        written = snd_pcm_writei (alsa->handle, dst, convert_samples);
575

    
576
        if (written < 0) {
577
            switch (written) {
578
            case -EPIPE:
579
                if (!alsa_recover (alsa->handle)) {
580
                    goto again;
581
                }
582
                dolog (
583
                    "Failed to write %d frames to %p, handle %p not prepared\n",
584
                    convert_samples,
585
                    dst,
586
                    alsa->handle
587
                    );
588
                goto exit;
589

    
590
            case -EAGAIN:
591
                goto again;
592

    
593
            default:
594
                alsa_logerr (written, "Failed to write %d frames to %p\n",
595
                             convert_samples, dst);
596
                goto exit;
597
            }
598
        }
599

    
600
        mixeng_clear (src, written);
601
        rpos = (rpos + written) % hw->samples;
602
        samples -= written;
603
    }
604

    
605
 exit:
606
    hw->rpos = rpos;
607
    return decr;
608
}
609

    
610
static void alsa_fini_out (HWVoiceOut *hw)
611
{
612
    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
613

    
614
    ldebug ("alsa_fini\n");
615
    alsa_anal_close (&alsa->handle);
616

    
617
    if (alsa->pcm_buf) {
618
        qemu_free (alsa->pcm_buf);
619
        alsa->pcm_buf = NULL;
620
    }
621
}
622

    
623
static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
624
{
625
    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
626
    struct alsa_params_req req;
627
    struct alsa_params_obt obt;
628
    audfmt_e effective_fmt;
629
    int endianness;
630
    int err;
631
    snd_pcm_t *handle;
632
    audsettings_t obt_as;
633

    
634
    req.fmt = aud_to_alsafmt (as->fmt);
635
    req.freq = as->freq;
636
    req.nchannels = as->nchannels;
637
    req.period_size = conf.period_size_out;
638
    req.buffer_size = conf.buffer_size_out;
639

    
640
    if (alsa_open (0, &req, &obt, &handle)) {
641
        return -1;
642
    }
643

    
644
    err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
645
    if (err) {
646
        alsa_anal_close (&handle);
647
        return -1;
648
    }
649

    
650
    obt_as.freq = obt.freq;
651
    obt_as.nchannels = obt.nchannels;
652
    obt_as.fmt = effective_fmt;
653

    
654
    audio_pcm_init_info (
655
        &hw->info,
656
        &obt_as,
657
        audio_need_to_swap_endian (endianness)
658
        );
659
    alsa->can_pause = obt.can_pause;
660
    hw->samples = obt.samples;
661

    
662
    alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
663
    if (!alsa->pcm_buf) {
664
        dolog ("Could not allocate DAC buffer (%d bytes)\n",
665
               hw->samples << hw->info.shift);
666
        alsa_anal_close (&handle);
667
        return -1;
668
    }
669

    
670
    alsa->handle = handle;
671
    alsa->was_enabled = 0;
672
    return 0;
673
}
674

    
675
static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
676
{
677
    int err;
678
    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
679

    
680
    switch (cmd) {
681
    case VOICE_ENABLE:
682
        ldebug ("enabling voice\n");
683
        audio_pcm_info_clear_buf (&hw->info, alsa->pcm_buf, hw->samples);
684
        if (alsa->can_pause) {
685
            /* Why this was_enabled madness is needed at all?? */
686
            if (alsa->was_enabled) {
687
                err = snd_pcm_pause (alsa->handle, 0);
688
                if (err < 0) {
689
                    alsa_logerr (err, "Failed to resume playing\n");
690
                    /* not fatal really */
691
                }
692
            }
693
            else {
694
                alsa->was_enabled = 1;
695
            }
696
        }
697
        break;
698

    
699
    case VOICE_DISABLE:
700
        ldebug ("disabling voice\n");
701
        if (alsa->can_pause) {
702
            err = snd_pcm_pause (alsa->handle, 1);
703
            if (err < 0) {
704
                alsa_logerr (err, "Failed to stop playing\n");
705
                /* not fatal really */
706
            }
707
        }
708
        break;
709
    }
710
    return 0;
711
}
712

    
713
static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
714
{
715
    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
716
    struct alsa_params_req req;
717
    struct alsa_params_obt obt;
718
    int endianness;
719
    int err;
720
    audfmt_e effective_fmt;
721
    snd_pcm_t *handle;
722
    audsettings_t obt_as;
723

    
724
    req.fmt = aud_to_alsafmt (as->fmt);
725
    req.freq = as->freq;
726
    req.nchannels = as->nchannels;
727
    req.period_size = conf.period_size_in;
728
    req.buffer_size = conf.buffer_size_in;
729

    
730
    if (alsa_open (1, &req, &obt, &handle)) {
731
        return -1;
732
    }
733

    
734
    err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
735
    if (err) {
736
        alsa_anal_close (&handle);
737
        return -1;
738
    }
739

    
740
    obt_as.freq = obt.freq;
741
    obt_as.nchannels = obt.nchannels;
742
    obt_as.fmt = effective_fmt;
743

    
744
    audio_pcm_init_info (
745
        &hw->info,
746
        &obt_as,
747
        audio_need_to_swap_endian (endianness)
748
        );
749
    alsa->can_pause = obt.can_pause;
750
    hw->samples = obt.samples;
751

    
752
    alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
753
    if (!alsa->pcm_buf) {
754
        dolog ("Could not allocate ADC buffer (%d bytes)\n",
755
               hw->samples << hw->info.shift);
756
        alsa_anal_close (&handle);
757
        return -1;
758
    }
759

    
760
    alsa->handle = handle;
761
    return 0;
762
}
763

    
764
static void alsa_fini_in (HWVoiceIn *hw)
765
{
766
    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
767

    
768
    alsa_anal_close (&alsa->handle);
769

    
770
    if (alsa->pcm_buf) {
771
        qemu_free (alsa->pcm_buf);
772
        alsa->pcm_buf = NULL;
773
    }
774
}
775

    
776
static int alsa_run_in (HWVoiceIn *hw)
777
{
778
    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
779
    int hwshift = hw->info.shift;
780
    int i;
781
    int live = audio_pcm_hw_get_live_in (hw);
782
    int dead = hw->samples - live;
783
    struct {
784
        int add;
785
        int len;
786
    } bufs[2] = {
787
        { hw->wpos, 0 },
788
        { 0, 0 }
789
    };
790

    
791
    snd_pcm_uframes_t read_samples = 0;
792

    
793
    if (!dead) {
794
        return 0;
795
    }
796

    
797
    if (hw->wpos + dead > hw->samples) {
798
        bufs[0].len = (hw->samples - hw->wpos);
799
        bufs[1].len = (dead - (hw->samples - hw->wpos));
800
    }
801
    else {
802
        bufs[0].len = dead;
803
    }
804

    
805

    
806
    for (i = 0; i < 2; ++i) {
807
        void *src;
808
        st_sample_t *dst;
809
        snd_pcm_sframes_t nread;
810
        snd_pcm_uframes_t len;
811

    
812
        len = bufs[i].len;
813

    
814
        src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
815
        dst = hw->conv_buf + bufs[i].add;
816

    
817
        while (len) {
818
            nread = snd_pcm_readi (alsa->handle, src, len);
819

    
820
            if (nread < 0) {
821
                switch (nread) {
822
                case -EPIPE:
823
                    if (!alsa_recover (alsa->handle)) {
824
                        continue;
825
                    }
826
                    dolog (
827
                        "Failed to read %ld frames from %p, "
828
                        "handle %p not prepared\n",
829
                        len,
830
                        src,
831
                        alsa->handle
832
                        );
833
                    goto exit;
834

    
835
                case -EAGAIN:
836
                    continue;
837

    
838
                default:
839
                    alsa_logerr (
840
                        nread,
841
                        "Failed to read %ld frames from %p\n",
842
                        len,
843
                        src
844
                        );
845
                    goto exit;
846
                }
847
            }
848

    
849
            hw->conv (dst, src, nread, &nominal_volume);
850

    
851
            src = advance (src, nread << hwshift);
852
            dst += nread;
853

    
854
            read_samples += nread;
855
            len -= nread;
856
        }
857
    }
858

    
859
 exit:
860
    hw->wpos = (hw->wpos + read_samples) % hw->samples;
861
    return read_samples;
862
}
863

    
864
static int alsa_read (SWVoiceIn *sw, void *buf, int size)
865
{
866
    return audio_pcm_sw_read (sw, buf, size);
867
}
868

    
869
static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
870
{
871
    (void) hw;
872
    (void) cmd;
873
    return 0;
874
}
875

    
876
static void *alsa_audio_init (void)
877
{
878
    return &conf;
879
}
880

    
881
static void alsa_audio_fini (void *opaque)
882
{
883
    (void) opaque;
884
}
885

    
886
static struct audio_option alsa_options[] = {
887
    {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,
888
     "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
889
    {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
890
     "DAC period size", &conf.period_size_out_overriden, 0},
891
    {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
892
     "DAC buffer size", &conf.buffer_size_out_overriden, 0},
893

    
894
    {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,
895
     "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
896
    {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
897
     "ADC period size", &conf.period_size_in_overriden, 0},
898
    {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
899
     "ADC buffer size", &conf.buffer_size_in_overriden, 0},
900

    
901
    {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
902
     "(undocumented)", NULL, 0},
903

    
904
    {"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out,
905
     "DAC device name (for instance dmix)", NULL, 0},
906

    
907
    {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,
908
     "ADC device name", NULL, 0},
909
    {NULL, 0, NULL, NULL, NULL, 0}
910
};
911

    
912
static struct audio_pcm_ops alsa_pcm_ops = {
913
    alsa_init_out,
914
    alsa_fini_out,
915
    alsa_run_out,
916
    alsa_write,
917
    alsa_ctl_out,
918

    
919
    alsa_init_in,
920
    alsa_fini_in,
921
    alsa_run_in,
922
    alsa_read,
923
    alsa_ctl_in
924
};
925

    
926
struct audio_driver alsa_audio_driver = {
927
    INIT_FIELD (name           = ) "alsa",
928
    INIT_FIELD (descr          = ) "ALSA http://www.alsa-project.org",
929
    INIT_FIELD (options        = ) alsa_options,
930
    INIT_FIELD (init           = ) alsa_audio_init,
931
    INIT_FIELD (fini           = ) alsa_audio_fini,
932
    INIT_FIELD (pcm_ops        = ) &alsa_pcm_ops,
933
    INIT_FIELD (can_be_default = ) 1,
934
    INIT_FIELD (max_voices_out = ) INT_MAX,
935
    INIT_FIELD (max_voices_in  = ) INT_MAX,
936
    INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut),
937
    INIT_FIELD (voice_size_in  = ) sizeof (ALSAVoiceIn)
938
};