root/rat/trunk/auddev_alsa.c @ 3687

Revision 3687, 27.9 KB (checked in by piers, 8 years ago)

Changes: auddev.c, configure.in, auddev_alsa.[ch]

auddev: Changed DEF's to match standard RAT style Audio device configuration
alsa: Fixed ALSA for UCL-RAT

Modified Sample selection to be more lenient
Added ALSA "default" device for use by ALSA plugins
Added preliminary support for

 http://alsa.opensrc.org/index.php?action=find&find=emu10k1

(e.g. Audigy) style cards (with no "Capture" dev).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * FILE:    auddev_alsa.c
3 * PROGRAM: RAT ALSA 0.9+/final audio driver.
4 * AUTHOR:  Steve Smith  (ALSA 0.9+/final)
5 *          Robert Olson (ALSA 0.5)
6 *
7 * Copyright (c) 2003 University of Sydney
8 * Copyright (c) 2000 Argonne National Laboratory
9 * All rights reserved.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 *
14 * $Revision$
15 * $Date$
16 *
17 */
18
19#define ALSA_PCM_NEW_HW_PARAMS_API
20#define ALSA_PCM_NEW_SW_PARAMS_API
21#include <alsa/asoundlib.h>
22#include <stdio.h>
23#include <stdarg.h>
24
25#include "config_unix.h"
26#include "audio_types.h"
27#include "auddev_alsa.h"
28#include "debug.h"
29
30
31/*
32 * Structure that keeps track of the cards we know about. Rat wants a linear
33 * list of cards, so we'll give it that.
34 *
35 * This is filled in during the init step.
36 */
37
38typedef struct RatCardInfo_t
39{
40    char *name;
41    int card_number;
42    char *pcm_device;
43    char *pcm_mixer;
44} RatCardInfo;
45
46#define MAX_RAT_CARDS 128
47
48static RatCardInfo ratCards[MAX_RAT_CARDS];
49static int nRatCards = 0;
50
51/* Define ALSA mixer identifiers.  We use these to lookup the volume
52 * controls on the mixer.  This feels like a bit of a hack, but
53 * appears to be what everybody else uses. */
54#define RAT_ALSA_MIXER_PCM_NAME "PCM"
55#define RAT_ALSA_MIXER_CAPTURE_NAME "Capture"
56#define RAT_ALSA_MIXER_LINE_NAME "Line"
57#define RAT_ALSA_MIXER_MIC_NAME "Mic"
58#define RAT_ALSA_MIXER_CD_NAME "CD"
59
60/*
61 * The list of input ports to choose between.  These are scanned from the
62 * mixer device.
63 */
64#define MAX_RAT_DEVICES 32
65
66typedef struct _port_t {
67    audio_port_details_t details;
68    snd_mixer_elem_t* mixer;
69    int priority;
70} port_t;
71
72static port_t iports[MAX_RAT_DEVICES];
73static unsigned num_iports;
74
75/*
76 * All output passes through the pcm device, so we only have a single port
77 * here.
78 * FIXME: There are some cards that don't have a PCM control, only a master.
79 * It is assumed that these are unlikely to occur in real RAT usage.
80 */
81static audio_port_details_t out_port = {
82    0, RAT_ALSA_MIXER_PCM_NAME
83};
84
85/*
86 * Current open audio device
87 */
88
89typedef struct _pcm_stream_t {
90    snd_pcm_t *handle;
91    snd_pcm_uframes_t buffer_size;
92    snd_pcm_uframes_t period_size;
93    int channels;
94} pcm_stream_t;
95
96static struct current_t {
97    int index;
98    RatCardInfo *info;
99    unsigned bytes_per_block;
100    pcm_stream_t tx;
101    pcm_stream_t rx;
102    audio_port_t iport;
103    snd_mixer_t *mixer;
104    snd_mixer_elem_t *txgain;
105    snd_mixer_elem_t *rxgain;
106    audio_port_t txport;
107} current;
108
109static void clear_current()
110{
111    current.tx.handle = NULL;
112    current.rx.handle = NULL;
113    current.mixer =  NULL;
114    current.index = -1;
115    current.info = NULL;
116}
117
118
119/*
120 * Utility funcs
121 */
122static char *encodingToString[] = {
123    "PCMU",
124    "PCMA",
125    "S8",
126    "U8",
127    "S16"
128};
129
130// Ah, exceptions, I hardly new thee ...
131#define CHECKERR(msg) \
132{ \
133  if (err < 0) \
134  { \
135    fprintf(stderr, msg ": %s\n", snd_strerror(err)); \
136    return FALSE; \
137  } \
138    }
139#define CHECKERRCONT(msg) \
140{ \
141  if (err < 0) \
142    fprintf(stderr, msg ": %s\n", snd_strerror(err)); \
143    }
144#define VCHECKERR(msg) \
145{ \
146  if (err < 0) \
147  { \
148    fprintf(stderr, msg ": %s\n", snd_strerror(err)); \
149    return; \
150  } \
151}
152
153
154static int mapformat(deve_e encoding)
155{
156    int format = -1;
157    switch (encoding)
158    {
159    case DEV_PCMU:
160        format = SND_PCM_FORMAT_MU_LAW;
161        break;
162      case DEV_PCMA:
163        format = SND_PCM_FORMAT_A_LAW;
164        break;
165    case DEV_S8:
166        format = SND_PCM_FORMAT_S8;
167        break;
168    case DEV_U8:
169        format = SND_PCM_FORMAT_U8;
170        break;
171    case DEV_S16:
172        format = SND_PCM_FORMAT_S16;
173        break;
174    }
175    return format;
176}
177
178__attribute__((unused)) static char* mapstate(snd_pcm_state_t s)
179{
180    switch (s) {
181      case SND_PCM_STATE_OPEN:
182        return "SND_PCM_STATE_OPEN";
183      case SND_PCM_STATE_SETUP:
184        return "SND_PCM_STATE_SETUP";
185      case SND_PCM_STATE_PREPARED:
186        return "SND_PCM_STATE_PREPARED";
187      case SND_PCM_STATE_RUNNING:
188        return "SND_PCM_STATE_RUNNING";
189      case SND_PCM_STATE_XRUN:
190        return "SND_PCM_STATE_XRUN";
191      case SND_PCM_STATE_DRAINING:
192        return "SND_PCM_STATE_DRAINING";
193      case SND_PCM_STATE_PAUSED:
194        return "SND_PCM_STATE_PAUSED";
195      case SND_PCM_STATE_SUSPENDED:
196        return "SND_PCM_STATE_SUSPENDED";
197      default:
198        return "UNKNOWN!!!";
199    }
200}
201
202static void dump_audio_format(audio_format *f)
203{
204    if (f == 0)
205        debug_msg("    <null>\n");
206    else
207        debug_msg("encoding=%s sample_rate=%d bits_per_sample=%d "
208                  "channels=%d bytes_per_block=%d\n",
209                  encodingToString[f->encoding],
210                  f->sample_rate, f->bits_per_sample,
211                  f->channels, f->bytes_per_block);
212}
213
214
215static void  __attribute__((unused)) dump_alsa_current(snd_pcm_t *handle)
216{
217    int err;
218    snd_output_t *out;
219
220    err = snd_output_stdio_attach(&out, stderr, 0);
221    snd_output_printf(out, "--- MY IO\n");
222
223    err = snd_pcm_dump_setup(handle, out);
224
225    snd_output_printf(out, "--- SW\n");
226    err = snd_pcm_dump_sw_setup(handle, out);
227
228    snd_output_printf(out, "--- HW\n");
229    err = snd_pcm_dump_hw_setup(handle, out);
230
231    snd_output_printf(out, "--- DONE\n");
232    snd_output_close(out);
233    }
234
235
236/* *** Alsa driver implementation. *** */
237
238#undef CHECKOPENERR
239#define CHECKOPENERR(msg) \
240{ \
241  if (err < 0) \
242  { \
243    fprintf(stderr, msg ": %s\n", snd_strerror(err)); \
244    snd_pcm_close(stream->handle); \
245    stream->handle=NULL; \
246    return FALSE; \
247  } \
248}
249
250static int open_stream(RatCardInfo *info, pcm_stream_t *stream,
251                       snd_pcm_stream_t type, audio_format *fmt)
252    {
253    int err;
254    int dir=0;
255    size_t bsize;
256    snd_pcm_uframes_t frames;
257    unsigned int rrate;
258    snd_pcm_hw_params_t *hw_params;
259    snd_pcm_sw_params_t *sw_params;
260    /* Set avail min inside a software configuration container */
261    /* Can we tweak this up/down?*/
262    snd_pcm_uframes_t    avail_min=4;   
263    snd_pcm_uframes_t    xfer_align=1; 
264
265    err = snd_pcm_open(&stream->handle, info->pcm_device,
266                       type, SND_PCM_NONBLOCK);
267    CHECKERR("Card open failed");
268
269    snd_pcm_hw_params_alloca (&hw_params);
270
271    err = snd_pcm_hw_params_any (stream->handle, hw_params);
272    CHECKOPENERR("Failed to initialise HW parameters");
273
274    err = snd_pcm_hw_params_set_access(stream->handle, hw_params,
275                                       SND_PCM_ACCESS_RW_INTERLEAVED);
276    CHECKOPENERR("Failed to set interleaved access");
277
278    err = snd_pcm_hw_params_set_format (stream->handle, hw_params,
279                                        mapformat(fmt->encoding));
280    CHECKOPENERR("Failed to set encoding");
281
282    err = snd_pcm_hw_params_set_channels (stream->handle, hw_params,
283                                          fmt->channels);
284    CHECKOPENERR("Failed to set channels");
285    stream->channels = fmt->channels;
286
287    rrate = fmt->sample_rate;
288    err = snd_pcm_hw_params_set_rate_near (stream->handle, hw_params,
289                                           &rrate, &dir);
290    CHECKOPENERR("Failed to set sample rate");
291    if (rrate != fmt->sample_rate) {
292        fprintf(stderr, "ALSA rate set to %d when we wanted %d\n",
293                rrate, fmt->sample_rate);
294        return FALSE;
295    }
296
297    // Setup the buffer size. This stuff's all in frames, BTW.  We can't
298    // convert with the helper functions at this point as they require
299    // a working handle, and ours isn't setup yet. We don't actually do
300    // anything with these values anyway.
301    bsize = snd_pcm_format_size (mapformat(fmt->encoding),
302                                 fmt->sample_rate / RAT_ALSA_BUFFER_DIVISOR);
303    bsize = (fmt->sample_rate * (fmt->bits_per_sample/8) * fmt->channels* RAT_ALSA_BUFFER_DIVISOR)/ (1000);
304            //* fmt->bytes_per_block
305
306    frames = bsize;
307    debug_msg("Bsize == %d\n", bsize);
308    err = snd_pcm_hw_params_set_buffer_size_near(stream->handle, hw_params,
309                                                 &frames);
310    CHECKOPENERR("Failed to set buffer size");
311
312    stream->buffer_size = frames;
313    debug_msg("Buffer == %d\n", stream->buffer_size);
314
315    frames = stream->buffer_size / 2;
316    err = snd_pcm_hw_params_set_period_size_near(stream->handle, hw_params,
317                                                 &frames, &dir);
318    stream->buffer_size = frames;
319    CHECKOPENERR("Failed to set period size");
320
321    stream->period_size = frames;
322    debug_msg("Period == %d\n", stream->period_size);
323
324    err = snd_pcm_hw_params (stream->handle, hw_params);
325    CHECKOPENERR("Failed to install HW parameters");
326
327
328    // ALSA software settings
329    snd_pcm_sw_params_alloca(&sw_params);
330    err = snd_pcm_sw_params_current(stream->handle, sw_params);
331    CHECKOPENERR("Failed to initialise SW params");
332
333    err = snd_pcm_sw_params_set_start_threshold(stream->handle, sw_params,
334                                                stream->buffer_size);
335    CHECKOPENERR("Failed to set threshold value");
336
337    err = snd_pcm_sw_params_set_avail_min(stream->handle, sw_params, avail_min);
338    CHECKOPENERR("Failed to set min available value");
339
340    err = snd_pcm_sw_params_set_xfer_align(stream->handle,sw_params,xfer_align);
341    CHECKOPENERR("Failed to set xfer align value");
342
343    err = snd_pcm_sw_params(stream->handle, sw_params);
344    CHECKOPENERR("Failed to set SW params");
345   
346    return TRUE;
347}
348
349
350// Get the mixer
351
352#undef CHECKOPENERR
353#define CHECKOPENERR(msg) \
354{ \
355  if (err < 0) \
356  { \
357    fprintf(stderr, msg ": %s\n", snd_strerror(err)); \
358    snd_mixer_close(current.mixer); \
359    current.mixer=NULL; \
360    return FALSE; \
361  } \
362}
363
364
365// Open a named mixer
366static int open_volume_ctl(char *name, snd_mixer_elem_t **ctl)
367{
368  snd_mixer_selem_id_t *sid;
369  int err=NULL;
370
371  snd_mixer_selem_id_alloca(&sid);
372
373  // FIXME? Find the appropriate mixer element.  This feels really wrong,
374  // there has to be another way to do this.
375  snd_mixer_selem_id_set_index (sid, 0);
376  snd_mixer_selem_id_set_name (sid, name);
377
378  *ctl = snd_mixer_find_selem(current.mixer, sid);
379  //err = (int)*ctl;
380  //CHECKOPENERR("Couldn't find mixer control element");
381  if (*ctl == NULL ) {
382   fprintf(stderr,"ALSA:Couldn't find mixer control element (name:%s)\n",name);
383   return FALSE;
384  }
385
386  printf("open_volume_ctl err2:%d\n",err);
387  if (snd_mixer_selem_has_playback_volume(*ctl)) {
388    debug_msg("Got volume control %s of type PLAY\n", name);
389    // FIXME: Does this always work?
390    snd_mixer_selem_set_playback_volume_range (*ctl, 0, 100);
391
392    if ( snd_mixer_selem_has_playback_switch( *ctl ) ) {
393      err = snd_mixer_selem_set_playback_switch_all(*ctl, 1);
394      CHECKOPENERR("Failed to switch on playback volume");
395    }
396
397  } else if (snd_mixer_selem_has_capture_volume(*ctl)) {
398    debug_msg("Got volume control %s of type CAPTURE\n", name);
399    snd_mixer_selem_set_capture_volume_range (*ctl, 0, 100);
400
401    err = snd_mixer_selem_set_capture_switch_all(*ctl, 1);
402    CHECKOPENERR("Failed to switch on capture volume");
403
404  } else {
405    debug_msg("Unknown mixer type %s set\n", name);
406    return FALSE;
407  }
408
409  return TRUE;
410}
411
412
413// Open and initialise the system mixer
414
415static int porder(const void *a, const void *b)
416{
417    return (((port_t*)a)->priority - ((port_t*)b)->priority);
418}
419
420static int setup_mixers()
421{
422    snd_mixer_elem_t *elem;
423    int err;
424    unsigned i;
425   
426    err = snd_mixer_open (&current.mixer, 0);
427    CHECKERR("Failed to open the mixer");
428
429    // FIXME: Attach the mixer to the default card.  Is this enough?
430    //err = snd_mixer_attach(current.mixer, "default");
431    err = snd_mixer_attach(current.mixer, current.info->pcm_mixer);
432//  err = snd_mixer_attach(current.mixer, "hw:0,0");
433    CHECKOPENERR("Failed to attach mixer");
434
435    err = snd_mixer_selem_register(current.mixer, NULL, NULL);
436    CHECKOPENERR("Failed to register mixer");
437   
438    err = snd_mixer_load(current.mixer);
439    CHECKOPENERR("Failed to load mixer");
440
441
442    // Get the playback and capture volume controls
443    if ((!open_volume_ctl(RAT_ALSA_MIXER_PCM_NAME, &current.txgain)) ||
444        (!open_volume_ctl(RAT_ALSA_MIXER_CAPTURE_NAME, &current.rxgain)))
445            return FALSE;       
446
447    num_iports = 0;
448
449    // We now scan the mixer for recording controls.  We're interested in
450    // the controls that are part of a group (i.e. radio-button types) that
451    // can be flipped between.
452    for (elem = snd_mixer_first_elem (current.mixer);
453        elem && (num_iports < MAX_RAT_DEVICES);
454        elem = snd_mixer_elem_next (elem))
455    {
456      if (snd_mixer_selem_is_active (elem) &&
457          snd_mixer_selem_has_capture_switch(elem) &&
458          snd_mixer_selem_has_capture_switch_exclusive(elem))
459      {
460        // FIXME: It's theoretically possible that there would be more
461        // than one capture group, but RAT isn't really equipped to handle
462        // the case so we'll just ignore it for now.
463        int gid = snd_mixer_selem_get_capture_group(elem);
464
465        const char *name = snd_mixer_selem_get_name(elem);
466
467        debug_msg("Got CAPTURE element '%s' of group %d\n", name, gid);
468
469        snprintf(iports[num_iports].details.name, AUDIO_PORT_NAME_LENGTH,
470            "%s", name);
471        iports[num_iports].mixer = elem;
472
473        // The principle of least-surprise means that we should present
474        // the ports in the same order as the other drivers.  As we're
475        // more flexible about retrieving the mixer ports we need to
476        // attempt to reorder the list, so we assign a priority and
477        // sort the list at the end.
478        if (strstr(name, RAT_ALSA_MIXER_MIC_NAME) == name) {
479          iports[num_iports].priority = 100;
480        } else if (strstr(name, RAT_ALSA_MIXER_LINE_NAME) == name) {
481          iports[num_iports].priority = 50;
482        } else if (strstr(name, RAT_ALSA_MIXER_CD_NAME) == name) {
483          iports[num_iports].priority = 30;
484        } else {
485          iports[num_iports].priority = 10;
486        }
487        num_iports++;
488      }
489    }
490
491    qsort(iports, num_iports, sizeof(port_t), porder);
492
493    // Now it's sorted we need to set the port ID to the index, allowing us
494    // a fast lookup for port-IDs
495    for (i=0; i<num_iports; i++) {
496        iports[i].details.port = i;
497    }
498
499    return TRUE;
500}
501
502
503int alsa_audio_open(audio_desc_t ad, audio_format *infmt, audio_format *outfmt)
504{
505    int err;
506
507    debug_msg("Audio open ad == %d\n", ad);
508    debug_msg("Input format:\n");
509    dump_audio_format(infmt);
510    debug_msg("Output format:\n");
511    dump_audio_format(outfmt);
512   
513    //clear_current();
514    if (current.tx.handle != NULL) {
515        fprintf(stderr, "Attempt to open a device while another is open\n");
516        return FALSE;
517    }
518    current.index = ad;
519    current.info = ratCards + ad;
520    current.bytes_per_block = infmt->bytes_per_block;
521
522        fprintf(stderr, "to open device for playback\n");
523    if (!open_stream(current.info, &current.tx,
524                     SND_PCM_STREAM_PLAYBACK, outfmt)) {
525        alsa_audio_close(ad);
526        fprintf(stderr, "Failed to open device for playback\n");
527        return FALSE;
528    }
529        fprintf(stderr, "to open device for capture\n");
530    if (!open_stream(current.info, &current.rx,
531                     SND_PCM_STREAM_CAPTURE, infmt)) {
532        alsa_audio_close(ad);
533        fprintf(stderr, "Failed to open device for capture\n");
534        return FALSE;
535    }
536
537    if (setup_mixers() == FALSE) {
538      alsa_audio_close(ad);
539        fprintf(stderr, "Failed to set mixer levels \n");
540      return FALSE;
541    }
542
543    err = snd_pcm_prepare(current.tx.handle);
544    CHECKERR("Failed to prepare playback");
545
546    err = snd_pcm_start(current.rx.handle);
547    CHECKERR("Failed to start PCM capture");
548
549    return TRUE;
550}
551
552/*
553 * Shutdown.
554 */
555void alsa_audio_close(audio_desc_t ad)
556{
557    int err;
558   
559    if (current.index != ad) {
560        fprintf(stderr, "Index to close (%d) doesn't match current(%d)\n",
561                ad, current.index);
562        return;
563    }
564
565    debug_msg("Closing device \"%s\"\n", current.info->name);
566
567    if (current.tx.handle != NULL ) {
568            err = snd_pcm_close(current.tx.handle);
569            CHECKERRCONT("Error closing playback PCM");
570    }
571
572    if (current.rx.handle != NULL ) {
573            err = snd_pcm_close(current.rx.handle);
574            CHECKERRCONT("Error closing capture PCM");
575    }
576
577    // Close mixer
578    if (current.mixer !=  NULL ) {
579        err = snd_mixer_close(current.mixer);
580        CHECKERRCONT("Error closing mixer");
581    }
582
583    clear_current();
584}
585
586/*
587 * Flush input buffer.
588 */
589void alsa_audio_drain(audio_desc_t ad __attribute__((unused)))
590{
591    int err;
592
593    debug_msg("audio_drain\n");
594    err = snd_pcm_drain(current.rx.handle);
595    VCHECKERR("Problem draining input");
596    }
597   
598
599
600/*
601 * Set record gain.
602 */
603void alsa_audio_set_igain(audio_desc_t ad, int gain)
604{
605    int err;
606    debug_msg("Set igain %d %d\n", ad, gain);
607
608    err = snd_mixer_selem_set_capture_volume_all(current.rxgain, gain);
609    VCHECKERR("Couldn't set capture volume");
610}
611
612
613/*
614 * Get capture gain.
615 */
616int alsa_audio_get_igain(audio_desc_t ad)
617{
618    long igain;
619    int err;
620    debug_msg("Get igain %d\n", ad);
621
622    err = snd_mixer_selem_get_capture_volume(current.rxgain,
623                                             SND_MIXER_SCHN_MONO, &igain);
624    CHECKERR("Failed to get capture volume");
625
626    return (int)igain;
627}
628
629int alsa_audio_duplex(audio_desc_t ad __attribute__((unused)))
630{
631    return TRUE; // FIXME: ALSA always duplex?
632}
633
634/*
635 * Set play gain.
636 */
637void alsa_audio_set_ogain(audio_desc_t ad, int vol)
638{
639    int err;
640
641    debug_msg("Set igain %d %d\n", ad, vol);
642
643    err = snd_mixer_selem_set_playback_switch_all(current.txgain, 1);
644    VCHECKERR("Failed to switch on playback volume");
645
646    err = snd_mixer_selem_set_playback_volume_all(current.txgain, vol);
647    VCHECKERR("Couldn't set mixer playback volume");
648
649}
650
651/*
652 * Get play gain.
653 */
654int
655alsa_audio_get_ogain(audio_desc_t ad)
656{
657    long ogain;
658    int err;
659
660    debug_msg("Get igain %d\n", ad);
661    err = snd_mixer_selem_get_playback_volume(current.txgain,
662                                             SND_MIXER_SCHN_MONO, &ogain);
663    CHECKERR("Failed to get capture volume");
664
665    return (int)ogain;
666}
667
668/*
669 * Record audio data.
670 */
671
672int alsa_audio_read(audio_desc_t ad __attribute__((unused)),
673                u_char *buf, int bytes)
674        {
675    snd_pcm_sframes_t frames = snd_pcm_bytes_to_frames(current.rx.handle, bytes);
676    snd_pcm_sframes_t fread;
677    int err;
678
679    fread = snd_pcm_readi(current.rx.handle, buf, frames);
680
681    if (fread >= 0) {
682        // Normal case
683        fread = snd_pcm_frames_to_bytes(current.rx.handle, fread);
684        debug_msg("Read %d bytes\n", fread);
685        return fread;
686    }
687
688    // Something happened
689    switch (fread)
690        {
691        case -EAGAIN:
692        // Normal when non-blocking
693            return 0;
694
695        case -EPIPE:
696        debug_msg("Got capture XRUN\n");
697        err = snd_pcm_prepare(current.rx.handle);
698        CHECKERR("Can't recover from capture overrun");
699    err = snd_pcm_start(current.rx.handle);
700    CHECKERR("Failed to start PCM capture");
701        return FALSE;
702
703      case -ESTRPIPE:
704        debug_msg("Got capture ESTRPIPE\n");
705        while ((err = snd_pcm_resume(current.rx.handle)) == -EAGAIN)
706            sleep(1);       /* wait until the suspend flag is released */
707        if (err < 0) {
708            err = snd_pcm_prepare(current.rx.handle);
709            CHECKERR("Can't recovery from capture suspend");
710                }
711        return FALSE;
712
713        default:
714        debug_msg("Write failed status=%d: %s\n", snd_strerror(fread));
715        return 0;
716    }
717}
718
719/*
720 * Playback audio data.
721 */
722
723
724int alsa_audio_write(audio_desc_t ad __attribute__((unused)),
725                     u_char *buf, int bytes)
726{
727    int fwritten, err;
728    snd_pcm_sframes_t frames =
729        snd_pcm_bytes_to_frames(current.tx.handle,bytes);
730
731    debug_msg("Audio write %d\n", bytes);
732
733    fwritten = snd_pcm_writei(current.tx.handle, buf, frames);
734    if (fwritten >= 0) {
735        // Normal case
736        fwritten = snd_pcm_frames_to_bytes(current.tx.handle, fwritten);
737        debug_msg("Wrote %d bytes\n", fwritten);
738        return fwritten;
739    }
740
741    // Something happened
742    switch (fwritten)
743    {
744      case -EAGAIN:
745        // Normal when non-blocking
746        return FALSE;
747
748      case -EPIPE:
749        debug_msg("Got transmit XRUN\n");
750        err = snd_pcm_prepare(current.tx.handle);
751        err = snd_pcm_writei(current.tx.handle, buf, frames);
752        CHECKERR("Can't recover from transmit overrun");
753        return TRUE;
754
755      case -ESTRPIPE:
756        debug_msg("Got transmit ESTRPIPE\n");
757        while ((err = snd_pcm_resume(current.tx.handle)) == -EAGAIN)
758            sleep(1);       /* wait until the suspend flag is released */
759        if (err < 0) {
760            err = snd_pcm_prepare(current.tx.handle);
761            CHECKERR("Can't recovery from transmit suspend");
762    }
763        return FALSE;
764
765      default:
766        debug_msg("Write failed status=%d: %s\n", snd_strerror(fwritten));
767        return FALSE;
768    }
769
770
771    fwritten = snd_pcm_frames_to_bytes(current.tx.handle, fwritten);
772    debug_msg("Audio wrote %d\n", fwritten);
773    return fwritten;
774}
775
776
777/*
778 * Set options on audio device to be non-blocking.
779 */
780void alsa_audio_non_block(audio_desc_t ad __attribute__((unused)))
781    {
782    int err;
783    debug_msg("Set nonblocking\n");
784
785    err = snd_pcm_nonblock(current.tx.handle, TRUE);
786    VCHECKERR("Error setting TX non-blocking");
787
788    err = snd_pcm_nonblock(current.rx.handle, TRUE);
789    VCHECKERR("Error setting RX non-blocking");
790    }
791
792    /*
793 * Set options on audio device to be blocking.
794    */
795void alsa_audio_block(audio_desc_t ad)
796    {
797    int err;
798    debug_msg("[%d] set blocking\n", ad);
799    if ((err = snd_pcm_nonblock(current.tx.handle, FALSE)) < 0) {
800        fprintf (stderr, "Cannot set blocking: %s\n",
801                 snd_strerror (err));
802    }
803}
804
805
806
807/*
808 * Output port controls.  In our case there is only one output port, the
809 * PCM control, so this is a dummy.
810 */
811void
812alsa_audio_oport_set(audio_desc_t ad, audio_port_t port)
813{
814    debug_msg("oport_set %d %d\n", ad, port);
815}
816audio_port_t
817alsa_audio_oport_get(audio_desc_t ad)
818{
819    debug_msg("oport_get %d\n", ad);
820    return 0;
821}
822
823int
824alsa_audio_oport_count(audio_desc_t ad)
825{
826    debug_msg("Get oport count for %d\n", ad);
827    return 1;
828}
829
830const audio_port_details_t* alsa_audio_oport_details(audio_desc_t ad, int idx)
831{
832        debug_msg("oport details ad=%d idx=%d\n", ad, idx);
833    return &out_port;
834}
835
836/*
837 * Set input port.
838 */
839void
840alsa_audio_iport_set(audio_desc_t ad, audio_port_t port)
841{
842    int err = 0;
843    audio_port_t i;
844    debug_msg("iport_set %d %d\n", ad, port);
845    current.iport = port;
846
847    for (i=0; i < num_iports; i++) {
848        err = snd_mixer_selem_set_capture_switch_all(
849            iports[i].mixer, (i==port));
850    }
851    VCHECKERR("Failed to set record switch");
852}
853
854
855/*
856 * Get input port.
857 */
858audio_port_t
859alsa_audio_iport_get(audio_desc_t ad)
860{
861    debug_msg("iport_get %d\n", ad);
862    return current.iport;
863}
864
865int
866alsa_audio_iport_count(audio_desc_t ad)
867{
868    debug_msg("Get iport count for %d (=%d)\n", ad, num_iports);
869    return num_iports;
870}
871
872const audio_port_details_t* alsa_audio_iport_details(audio_desc_t ad, int idx)
873{
874        debug_msg("iport details ad=%d idx=%d\n", ad, idx);
875    return &iports[idx].details;
876}
877
878
879/*
880 * For external purposes this function returns non-zero
881 * if audio is ready.
882 */
883int alsa_audio_is_ready(audio_desc_t ad __attribute__((unused)))
884{
885    snd_pcm_status_t *status;
886    snd_pcm_uframes_t avail;
887    int err;
888
889    snd_pcm_status_alloca(&status);
890    err = snd_pcm_status(current.rx.handle, status);
891    CHECKERR("Can't get status of rx");
892
893    avail = snd_pcm_frames_to_bytes(current.rx.handle,
894                                    snd_pcm_status_get_avail(status));
895    debug_msg("Audio ready == %d\n", avail);
896    return (avail >= current.bytes_per_block);
897
898}
899
900
901void alsa_audio_wait_for(audio_desc_t ad __attribute__((unused)), int delay_ms)
902        {
903    debug_msg("Audio wait %d\n", delay_ms);
904    snd_pcm_wait(current.rx.handle, delay_ms);
905        }
906
907
908char* alsa_get_device_name(audio_desc_t idx)
909        {
910    debug_msg("Get name for card %d: \"%s\"\n", idx, ratCards[idx].name);
911    return ratCards[idx].name;
912}
913
914
915int alsa_audio_init()
916    {
917    int fd;
918    char buf[4096];
919    char *version;
920    size_t count;
921    int result =  FALSE;
922
923    // Based on xmms-alsa
924
925    fd = open("/proc/asound/version", O_RDONLY, 0);
926    if (fd < 0) {
927        result = FALSE;
928        } 
929
930    count = read(fd, buf, sizeof(buf) - 1);
931    buf[count] = 0;
932    close(fd);
933
934    debug_msg("ALSA version identifier == %s\n", buf);
935
936    version = strstr(buf, " Version ");
937
938    if (version == NULL) {
939        result = FALSE;
940    }
941           
942    version += 9; /* strlen(" Version ") */
943
944    /* The successor to 0.9 might be 0.10, not 1.0.... */
945    if (strcmp(version, "0.9") > 0  ||  isdigit(version[3])) {
946        result = TRUE;
947    } else {
948        result = FALSE;
949            }
950
951    debug_msg("ALSA init result == %d\n", result);
952
953    clear_current();
954    return result;
955            }
956
957int alsa_get_device_count()
958            {
959    snd_ctl_t *ctl_handle;
960    snd_ctl_card_info_t *ctl_info;
961    int err, cindex = 0;
962    char card[128];
963    // Ptr to ratCards array
964    RatCardInfo *ratCard;
965
966    debug_msg("ALSA get device count\n");
967
968    snd_ctl_card_info_alloca(&ctl_info);
969    do {
970        sprintf (card , "hw:%d", cindex);
971    debug_msg("ALSA for dev:%s\n",card);
972        err = snd_ctl_open (&ctl_handle, card, SND_CTL_NONBLOCK);
973
974        if (err == 0) {
975            // Grab the card info
976            ratCard = ratCards + cindex;
977            ratCard->card_number = cindex;
978            ratCard->pcm_mixer = strdup(card);
979            sprintf (card , "plughw:%d", cindex);
980            ratCard->pcm_device = strdup(card);
981
982            if ((err = snd_ctl_card_info (ctl_handle, ctl_info) < 0)) {
983                fprintf(stderr, "Card query failed: %s\n", snd_strerror(err));
984                snprintf(card, sizeof(card), "ALSA %d: Not Available", cindex);
985                ratCard->name = strdup (card);
986                debug_msg("Got failed ALSA card %s\n", ratCard->name);
987                snd_ctl_close(ctl_handle);
988                cindex++;
989                err=0;
990                continue;
991            }
992            snprintf(card, sizeof(card), "ALSA %d: %s", cindex,
993                     snd_ctl_card_info_get_name (ctl_info));
994            ratCard->name = strdup (card);
995            debug_msg("Got ALSA card %s\n", ratCard->name);
996   
997            snd_ctl_close(ctl_handle);
998        }
999        cindex++;
1000
1001    } while (err == 0);
1002        cindex--;
1003
1004    // Get ALSA "default" card - so things like dsnoop etc can work
1005    if (!snd_ctl_open(&ctl_handle, "default", SND_CTL_NONBLOCK)) {
1006      ratCard = ratCards + cindex;
1007      ratCard->card_number = cindex;
1008      ratCard->pcm_device = strdup("default");
1009      ratCard->pcm_mixer = "default";
1010      if ((err = snd_ctl_card_info (ctl_handle, ctl_info) < 0)) {
1011        fprintf(stderr, "ALSA default Card query failed: %s\n", snd_strerror(err));
1012        snd_ctl_close(ctl_handle);
1013      } else {
1014        snprintf(card, sizeof(card), "ALSA default: %s",
1015                                  snd_ctl_card_info_get_name (ctl_info));
1016        ratCard->name = strdup (card);
1017        debug_msg("Got \"default\" card %s\n", ratCard->name);
1018        snd_ctl_close(ctl_handle);
1019        cindex++;
1020        cindex++;
1021      }
1022    }
1023
1024    nRatCards = cindex - 1;
1025    debug_msg("Got %d devices\n", nRatCards);
1026
1027    return nRatCards;
1028}
1029
1030int alsa_audio_supports(audio_desc_t ad, audio_format *fmt)
1031{
1032    snd_pcm_hw_params_t *hw_params;
1033    unsigned rmin, rmax, cmin, cmax;
1034    int err, dir;
1035
1036    debug_msg("Got \"ALSA supports\" for %d\n", ad);
1037    dump_audio_format(fmt);
1038
1039
1040    snd_pcm_hw_params_alloca (&hw_params);
1041    err = snd_pcm_hw_params_any (current.tx.handle, hw_params);
1042
1043    err = snd_pcm_hw_params_get_rate_min (hw_params, &rmin, &dir);
1044    CHECKERR("Failed to get min rate");
1045    err = snd_pcm_hw_params_get_rate_max (hw_params, &rmax, &dir);
1046    CHECKERR("Failed to get max rate");
1047
1048    err = snd_pcm_hw_params_get_channels_min (hw_params, &cmin);
1049    CHECKERR("Failed to get min channels");
1050    err = snd_pcm_hw_params_get_channels_max (hw_params, &cmax);
1051    CHECKERR("Failed to get max channels");
1052
1053    if ((fmt->sample_rate >= rmin) && (fmt->sample_rate <= rmax) &&
1054        (fmt->channels >= (int)cmin) && (fmt->channels <= (int)cmax))
1055{
1056        debug_msg("Config is supported\n");
1057        return TRUE;
1058    }
1059    return FALSE;
1060}
Note: See TracBrowser for help on using the browser.