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