git stults online alsa-signals / master play.c
master

Tree @master (Download .tar.gz)

play.c @masterraw · history · blame

#include <alsa/asoundlib.h>

static inline void handle_snd_error (int err)
{
  if (err < 0)
    {
      fprintf (stderr, "error: %s\n", snd_strerror(err));
      exit (1);
    }
  return;
}

void main()
{
  long                 loops;
  int                  err;
  int                  dir;
  int                  playback_bfsize;
  unsigned int         i;
  unsigned int         val;
  unsigned int         playback_rate;
  char                *playback_bf;
  char                *device = "default";
  snd_pcm_t           *playback_handle;
  snd_pcm_stream_t     playback_stream = SND_PCM_STREAM_PLAYBACK;
  snd_pcm_uframes_t    playback_frames;
  snd_pcm_hw_params_t *playback_params;

  /* PLAYBACK */

  /* open playback device */
  handle_snd_error (snd_pcm_open (&playback_handle, device, playback_stream, 0));

  /* create param structure */
  handle_snd_error (snd_pcm_hw_params_malloc (&playback_params));

  /* set params to default values */
  handle_snd_error (snd_pcm_hw_params_any (playback_handle, playback_params));

  /* now set a few of the params */

  /* interleaved mode */
  handle_snd_error (snd_pcm_hw_params_set_access(playback_handle, playback_params, SND_PCM_ACCESS_RW_INTERLEAVED));

  /* signed 16-bit little-endian format */
  handle_snd_error (snd_pcm_hw_params_set_format(playback_handle, playback_params, SND_PCM_FORMAT_S16_LE));

  /* two channels (stereo) */
  handle_snd_error (snd_pcm_hw_params_set_channels(playback_handle, playback_params, 2));

  /* 44100 bits/second sampling rate (CD quality) */
  /* will try to set the rate as near to this as possible; if not
     equal dir is set accordingly; we don't check dir currently */
  playback_rate = 44100;
  handle_snd_error (snd_pcm_hw_params_set_rate_near (playback_handle, playback_params, &playback_rate, &dir));

  /* set period size to 32 frames */
  playback_frames = 32;
  handle_snd_error (snd_pcm_hw_params_set_period_size_near (playback_handle, playback_params, &playback_frames, &dir));

  /* Write the parameters to the driver */
  handle_snd_error (snd_pcm_hw_params (playback_handle, playback_params));

  /* free */
  snd_pcm_hw_params_free (playback_params);

  /* want a buffer large enough to hold one period */
  handle_snd_error (snd_pcm_hw_params_get_period_size(playback_params, &playback_frames, &dir));
  playback_bfsize = playback_frames * 4; /* 2 bytes/sample * 2 channels * numframes */
  playback_bf = calloc (playback_bfsize, sizeof(char));

  /* find out how long one period takes (usecs) */
  handle_snd_error (snd_pcm_hw_params_get_period_time(playback_params, &val, &dir));

  /* play for 5 seconds */
  loops = 5000000 / val;
  
  while (loops)
    {
      int rc;
      loops--;
      rc = read(0, playback_bf, playback_bfsize);
      if (rc == 0)
	{
	  fprintf(stderr, "end of file on input\n");
	  break;
	} 
      else if (rc != playback_bfsize) 
	fprintf(stderr, "short read: read %d bytes\n", rc);
      rc = snd_pcm_writei(playback_handle, playback_bf, playback_frames);
      if (rc == -EPIPE) 
	{
	  /* EPIPE means underrun */
	  fprintf(stderr, "underrun occurred\n");
	  snd_pcm_prepare (playback_handle);
	} 
      else if (rc < 0)
	fprintf(stderr, "error from writei: %s\n", snd_strerror(rc));
      else if (rc != (int)playback_frames)
	fprintf(stderr, "short write, write %d frames\n", rc);
    }

  free (playback_bf);

  snd_pcm_drain (playback_handle);
  snd_pcm_close (playback_handle);

  return;
}