Lumiera  0.pre.03
»edit your freedom«
alsa.c
Go to the documentation of this file.
1 /*
2  ALSA - sound output backend using the Advanced Linux Sound Architecture
3 
4  Copyright (C)
5  2011, Odin Omdal Hørthe <odin.omdal@gmail.com>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
14 
20 #include "alsa.h"
21 
22 #include <alsa/asoundlib.h>
23 
24 static snd_pcm_t* playback_handle = 0;
25 static snd_pcm_sw_params_t* sw_params = 0;
26 static snd_pcm_hw_params_t* hw_params = 0;
27 static snd_pcm_sframes_t buffer_size = 0;
28 
29 static snd_pcm_sframes_t written = 0;
30 static snd_pcm_sframes_t delay = 0;
31 
32 static unsigned int rate = 44100;
33 
34 static int audio_initialised = 0;
35 
36 size_t
37 audio_offset()
38 {
39  snd_pcm_delay(playback_handle, &delay);
40 
41  return written - delay;
42 }
43 
44 void
45 audio_init()
46 {
47  unsigned int buffer_time = 50000;
48  const char* device;
49  int err;
50 
51  if(audio_initialised)
52  return;
53 
54  audio_initialised = 1;
55 
56  device = getenv("ALSA_DEVICE");
57 
58  if(!device)
59  device = "default";
60 
61  if(0 > (err = snd_pcm_open(&playback_handle, device,
62  SND_PCM_STREAM_PLAYBACK, 0/*SND_PCM_NONBLOCK*/)))
63  errx(EXIT_FAILURE, "Audio: Cannot open device %s: %s", device, snd_strerror(err));
64 
65  if(0 > (err = snd_pcm_sw_params_malloc(&sw_params)))
66  errx(EXIT_FAILURE, "Audio: Could not allocate software parameter structure: %s",
67  snd_strerror(err));
68 
69  if(0 > (err = snd_pcm_hw_params_malloc(&hw_params)))
70  errx(EXIT_FAILURE, "Audio: Could not allocate hardware parameter structure: %s",
71  snd_strerror(err));
72 
73  if(0 > (err = snd_pcm_hw_params_any(playback_handle, hw_params)))
74  errx(EXIT_FAILURE, "Audio: Could not initializa hardware parameters: %s",
75  snd_strerror(err));
76 
77  if(0 > (err = snd_pcm_hw_params_set_access(playback_handle, hw_params,
78  SND_PCM_ACCESS_RW_INTERLEAVED)))
79  errx(EXIT_FAILURE, "Audio: Could not set access type: %s", snd_strerror(err));
80 
81  if(0 > (err = snd_pcm_hw_params_set_format(playback_handle, hw_params,
82  SND_PCM_FORMAT_S16)))
83  errx(EXIT_FAILURE, "Audio: Could not set sample format to signed 16 bit "
84  "native endian: %s", snd_strerror(err));
85 
86  if(0 > (err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params,
87  &rate, 0)))
88  errx(EXIT_FAILURE, "Audio: Could not set sample rate %uHz: %s", rate,
89  snd_strerror(err));
90 
91  if(0 > (err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, 2)))
92  errx(EXIT_FAILURE, "Audio: Could not set channel count to %u: %s",
93  2, snd_strerror(err));
94 
95  snd_pcm_hw_params_set_buffer_time_near(playback_handle, hw_params, &buffer_time, 0);
96 
97  if(0 > (err = snd_pcm_hw_params(playback_handle, hw_params)))
98  errx(EXIT_FAILURE, "Audio: Could not set hardware parameters: %s", snd_strerror(err));
99 
100  fprintf(stderr, "Buffer time is %.3f seconds\n", buffer_time / 1.0e6);
101 
102  if(0 > (err = snd_pcm_sw_params_current(playback_handle, sw_params)))
103  errx(EXIT_FAILURE, "Audio: Could not initialise software parameters: %s",
104  snd_strerror(err));
105 
106  snd_pcm_sw_params_set_start_threshold(playback_handle, sw_params, 0);
107  snd_pcm_sw_params_set_avail_min(playback_handle, sw_params, 1024);
108 
109  snd_pcm_uframes_t min;
110  snd_pcm_sw_params_get_avail_min(sw_params, &min);
111  fprintf(stderr, "Minimum %u\n", (unsigned) min);
112 
113  if(0 > (err = snd_pcm_sw_params(playback_handle, sw_params)))
114  errx(EXIT_FAILURE, "Audio: Could not set software parameters: %s",
115  snd_strerror(err));
116 
117  buffer_size = snd_pcm_avail_update(playback_handle);
118 }
119 
120 size_t
121 audio_write(const void* data, size_t amount)
122 {
123  int err;
124 
125  amount /= 4;
126 
127  for(;;)
128  {
129  err = snd_pcm_writei(playback_handle, data, amount);
130 
131  if(err == -EAGAIN)
132  return 0;
133 
134  if(err < 0)
135  {
136  err = snd_pcm_recover(playback_handle, err, 0);
137 
138  if(err < 0)
139  errx(EXIT_FAILURE, "Audio playback failed: %s", strerror(-err));
140  }
141 
142 
143  break;
144  }
145 
146  written += err;
147 
148  err *= 4;
149 
150  return err;
151 }
152 
153 void
154 audio_start(unsigned int rate, unsigned int channel_count)
155 {
156  audio_init();
157 
158  snd_pcm_prepare(playback_handle);
159 }
160 
161 void
162 audio_stop()
163 {
164  snd_pcm_drain(playback_handle);
165 }
Interfacing to ALSA sound output.