LinuxDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


An Introduction to Linux Audio
Pages: 1, 2, 3, 4

ALSA

ALSA was started to fill a perceived gap for free, open source sound drivers. In 1998, for example, the OSS free drivers would not allow you to use full duplex on your sound card (being able to monitor a prerecorded track as well as what you're recording). Also, the OSS drivers at the time would not address the more sophisticated parts of the higher-end cards like the RME Hammerfall which were becoming available. A thought at the time was that OSS was fine for users who just wanted to play CDs or MP3s, and ALSA was what you needed if you were going to do serious studio work.



The ALSA API could thus be said to be lower-level than OSS although in both APIs there are both generic and specific ways to talk to hardware; and the specific way (mmap in OSS, hw in ALSA) is more verbose and requires detailed knowledge of the card--which makes sense if you're trying, for example, to use specific features of a high-end audio card (to see if a specific card is supported see the sound card matrix mentioned earlier). Bear in mind also that these APIs enable the machine to talk to the sound card via the drivers; the generic way of talking to them isn't magic, it's just addressing information already contained in the drivers.

Below is an example of a minimal, interrupt-driven program from the Paul Davis Tutorial on the ALSA API.'This program opens an audio interface for playback, configures it for stereo, 16 bit, 44. 1kHz, interleaved conventional read/write access. It then waits till the interface is ready for playback data, and delivers random data to it at that time. This design allows your program to be easily ported to systems that rely on a callback-driven mechanism, such as JACK, LADSPA, CoreAudio, VST, and many others.


#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <poll.h>
#include &ltalsa/asoundlib.h>
              
snd_pcm_t *playback_handle;
short buf[4096];
        
int
playback_callback (snd_pcm_sframes_t nframes)
{
    int err;
        
    printf ("playback callback called with %u frames\n", nframes);
       
    /* ... fill buf with data ... */
        
    if ((err = snd_pcm_writei (playback_handle, buf, nframes)) < 0) {
          fprintf (stderr, "write failed (%s)\n", snd_strerror (err));
    }
        
    return err;
}
              
main (int argc, char *argv[])
{
       
    snd_pcm_hw_params_t *hw_params;
    snd_pcm_sw_params_t *sw_params;
    snd_pcm_sframes_t frames_to_deliver;
    int nfds;
    int err;
    struct pollfd *pfds;
        
    if ((err = snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
          fprintf (stderr, "cannot open audio device %s (%s)\n", 
                   argv[1],
                   snd_strerror (err));
          exit (1);
    }
                   
    if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
          fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
                                 
    if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) {
          fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
        
    if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
          fprintf (stderr, "cannot set access type (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
        
    if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
          fprintf (stderr, "cannot set sample format (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
        
    if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, 44100, 0)) < 0) {
          fprintf (stderr, "cannot set sample rate (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
        
    if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0) {
          fprintf (stderr, "cannot set channel count (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
        
    if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) {
          fprintf (stderr, "cannot set parameters (%s)\n",
                   snd_strerror (err));
    exit (1);
    }
        
    snd_pcm_hw_params_free (hw_params);
        
    /* tell ALSA to wake us up whenever 4096 or more frames
       of playback data can be delivered. Also, tell
       ALSA that we'll start the device ourselves.
    */
        
    if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) {
          fprintf (stderr, "cannot allocate software parameters structure (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
    if ((err = snd_pcm_sw_params_current (playback_handle, sw_params)) < 0) {
          fprintf (stderr, "cannot initialize software parameters structure (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
    if ((err = snd_pcm_sw_params_set_avail_min (playback_handle, sw_params, 4096)) < 0) {
          fprintf (stderr, "cannot set minimum available count (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
    if ((err = snd_pcm_sw_params_set_start_threshold (playback_handle, sw_params, 0U)) < 0) {
          fprintf (stderr, "cannot set start mode (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
    if ((err = snd_pcm_sw_params (playback_handle, sw_params)) < 0) {
          fprintf (stderr, "cannot set software parameters (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
        
    /* the interface will interrupt the kernel every 4096 frames,
       and ALSA will wake up this program very soon after that.
    */
        
    if ((err = snd_pcm_prepare (playback_handle)) < 0) {
          fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
                   snd_strerror (err));
          exit (1);
    }
       
    while (1) {
        
          /* wait till the interface is ready for data, or 1 
             second has elapsed.
          */
        
          if ((err = snd_pcm_wait (playback_handle, 1000)) < 0) {
                  fprintf (stderr, "poll failed (%s)\n", strerror (errno));
                  break;
          }                  
        
          /* find out how much space is available for playback 
             data 
          */
        
          if ((frames_to_deliver = snd_pcm_avail_update (playback_handle)) < 0) {
                  if (frames_to_deliver == -EPIPE) {
                          fprintf (stderr, "an xrun occured\n");
                          break;
                  } else {
                          fprintf (stderr, "unknown ALSA avail update return value (%d)\n", 
                                   frames_to_deliver);
                          break;
                  }
          }
        
          frames_to_deliver = frames_to_deliver > 4096 ? 4096 : frames_to_deliver;
      
          /* deliver the data */
        
          if (playback_callback (frames_to_deliver) != frames_to_deliver) {
                  fprintf (stderr, "playback callback failed\n");
                  break;
          }
    }
        
    snd_pcm_close (playback_handle);
    exit (0);
}

In the example after this one, Paul goes on to talk about full-duplex, or combining both capture and playback to achieve what we talked about a little earlier. Achieving this by combining ordinary capture and playback is, in his opinion, deeply flawed, and interupts are the way to go with this. However, doing it this way is complex and he recommends JACK.

Pages: 1, 2, 3, 4

Next Pagearrow




Linux Online Certification

Linux/Unix System Administration Certificate Series
Linux/Unix System Administration Certificate Series — This course series targets both beginning and intermediate Linux/Unix users who want to acquire advanced system administration skills, and to back those skills up with a Certificate from the University of Illinois Office of Continuing Education.

Enroll today!


Linux Resources
  • Linux Online
  • The Linux FAQ
  • linux.java.net
  • Linux Kernel Archives
  • Kernel Traffic
  • DistroWatch.com


  • Sponsored by: