r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / audioalsa.C
blobb8c977e57958c54d74ee547d3d70ebe146a2d8b1
1 #include "audiodevice.h"
2 #include "audioalsa.h"
3 #include "playbackconfig.h"
4 #include "preferences.h"
5 #include "recordconfig.h"
7 #include <errno.h>
9 #ifdef HAVE_ALSA
11 AudioALSA::AudioALSA(AudioDevice *device) : AudioLowLevel(device)
15 AudioALSA::~AudioALSA()
19 void AudioALSA::list_devices(ArrayList<char*> *devices, int pcm_title)
21         snd_ctl_t *handle;
22         int card, err, dev, idx;
23         snd_ctl_card_info_t *info;
24         snd_pcm_info_t *pcminfo;
25         char string[BCTEXTLEN];
26         snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
27         int error;
29         snd_ctl_card_info_alloca(&info);
30         snd_pcm_info_alloca(&pcminfo);
32         card = -1;
34         if((error = snd_card_next(&card)) < 0)
35         {
36                 printf("AudioALSA::list_devices: %s\n", snd_strerror(error));
37                 return;
38         }
40         while(card >= 0) 
41         {
42                 char name[BCTEXTLEN];
43                 sprintf(name, "hw:%d", card);
45                 if((err = snd_ctl_open(&handle, name, 0)) < 0) 
46                 {
47                         printf("AudioALSA::list_devices (%i): %s", card, snd_strerror(err));
48                         continue;
49                 }
51                 if((err = snd_ctl_card_info(handle, info)) < 0)
52                 {
53                         printf("AudioALSA::list_devices (%i): %s", card, snd_strerror(err));
54                         snd_ctl_close(handle);
55                         continue;
56                 }
58                 dev = -1;
60                 while(1)
61                 {
62                         unsigned int count;
63                         if(snd_ctl_pcm_next_device(handle, &dev) < 0)
64                                 printf("AudioALSA::list_devices: snd_ctl_pcm_next_device");
66                         if (dev < 0)
67                                 break;
69                         snd_pcm_info_set_device(pcminfo, dev);
70                         snd_pcm_info_set_subdevice(pcminfo, 0);
71                         snd_pcm_info_set_stream(pcminfo, stream);
73                         if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) 
74                         {
75                                 if(err != -ENOENT)
76                                         printf("AudioALSA::list_devices (%i): %s", card, snd_strerror(err));
77                                 continue;
78                         }
80                         if(pcm_title)
81                         {
82 //                              sprintf(string, "plug:%d,%d", card, dev);
83 printf("AudioALSA::list_devices: %s\n", snd_ctl_card_info_get_name(info));
84                                 strcpy(string, "cards.pcm.front");
85                         }
86                         else
87                         {
88                                 sprintf(string, "%s #%d", 
89                                         snd_ctl_card_info_get_name(info), 
90                                         dev);
91                         }
93                         char *result = devices->append(new char[strlen(string) + 1]);
94                         strcpy(result, string);
95                 }
97                 snd_ctl_close(handle);
99                 if(snd_card_next(&card) < 0) 
100                 {
101                         printf("AudioALSA::list_devices: snd_card_next");
102                         break;
103                 }
104         }
106 //      snd_ctl_card_info_free(info);
107 //      snd_pcm_info_free(pcminfo);
110 void AudioALSA::translate_name(char *output, char *input)
112         ArrayList<char*> titles;
113         ArrayList<char*> pcm_titles;
114         
115         list_devices(&titles, 0);
116         list_devices(&pcm_titles, 1);
118         sprintf(output, "default");     
119         for(int i = 0; i < titles.total; i++)
120         {
121 //printf("AudioALSA::translate_name %s %s\n", titles.values[i], pcm_titles.values[i]);
122                 if(!strcasecmp(titles.values[i], input))
123                 {
124                         strcpy(output, pcm_titles.values[i]);
125                         break;
126                 }
127         }
128         
129         titles.remove_all_objects();
130         pcm_titles.remove_all_objects();
133 snd_pcm_format_t AudioALSA::translate_format(int format)
135         switch(format)
136         {
137                 case 8:
138                         return SND_PCM_FORMAT_S8;
139                         break;
140                 case 16:
141                         return SND_PCM_FORMAT_S16_LE;
142                         break;
143                 case 24:
144                         return SND_PCM_FORMAT_S24_LE;
145                         break;
146                 case 32:
147                         return SND_PCM_FORMAT_S32_LE;
148                         break;
149         }
152 void AudioALSA::set_params(snd_pcm_t *dsp, 
153         int channels, 
154         int bits,
155         int samplerate,
156         int samples)
158         snd_pcm_hw_params_t *params;
159         snd_pcm_sw_params_t *swparams;
160         int err;
162 printf("AudioALSA::set_params 1\n");
163         snd_pcm_hw_params_alloca(&params);
164 printf("AudioALSA::set_params 1\n");
165         snd_pcm_sw_params_alloca(&swparams);
166 printf("AudioALSA::set_params 1 %p %p\n", dsp, params);
167         err = snd_pcm_hw_params_any(dsp, params);
169 printf("AudioALSA::set_params 1\n");
170         if (err < 0) 
171         {
172                 printf("AudioALSA::set_params: no PCM configurations available\n");
173                 return;
174         }
176 printf("AudioALSA::set_params 1\n");
177         snd_pcm_hw_params_set_access(dsp, 
178                 params,
179                 SND_PCM_ACCESS_RW_INTERLEAVED);
180         snd_pcm_hw_params_set_format(dsp, 
181                 params, 
182                 translate_format(bits));
183         snd_pcm_hw_params_set_channels(dsp, 
184                 params, 
185                 channels);
186         snd_pcm_hw_params_set_rate_near(dsp, 
187                 params, 
188                 samplerate, 
189                 0);
191 printf("AudioALSA::set_params 1\n");
192 // Buffers written must be equal to period_time
193         int buffer_time = (int)((double)samples / samplerate * 1000000 * 2 + 0.5);
194         int period_time = buffer_time / 2;
195         buffer_time = snd_pcm_hw_params_set_buffer_time_near(dsp, 
196                 params,
197                 buffer_time, 
198                 0);
199         period_time = snd_pcm_hw_params_set_period_time_near(dsp, 
200                 params,
201                 period_time, 
202                 0);
203         err = snd_pcm_hw_params(dsp, params);
204         if(err < 0) 
205         {
206                 printf("AudioALSA::set_params: hw_params failed\n");
207                 return;
208         }
210 printf("AudioALSA::set_params 1\n");
211         int chunk_size = snd_pcm_hw_params_get_period_size(params, 0);
212         int buffer_size = snd_pcm_hw_params_get_buffer_size(params);
214 printf("AudioALSA::set_params 1\n");
215         snd_pcm_sw_params_current(dsp, swparams);
216         size_t xfer_align = 1 /* snd_pcm_sw_params_get_xfer_align(swparams) */;
217         unsigned int sleep_min = 0;
218         err = snd_pcm_sw_params_set_sleep_min(dsp, swparams, sleep_min);
219         int n = chunk_size;
220         err = snd_pcm_sw_params_set_avail_min(dsp, swparams, n);
221         err = snd_pcm_sw_params_set_xfer_align(dsp, swparams, xfer_align);
222         if(snd_pcm_sw_params(dsp, swparams) < 0)
223         {
224                 printf("AudioALSA::set_params: snd_pcm_sw_params failed\n");
225         }
227 printf("AudioALSA::set_params 1\n");
228         device->device_buffer = buffer_size / 
229                 (bits / 8) / 
230                 channels;
232 printf("AudioALSA::set_params 2 %d %d\n", samples,  device->device_buffer);
234 //      snd_pcm_hw_params_free(params);
235 //      snd_pcm_sw_params_free(swparams);
238 int AudioALSA::open_input()
240         char pcm_name[BCTEXTLEN];
241         snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
242         int open_mode = 0;
243         int err;
245 //printf("AudioALSA::open_input 1\n");
246         device->in_channels = device->in_config->alsa_in_channels;
247         device->in_bits = device->in_config->alsa_in_bits;
248 //printf("AudioALSA::open_input 1\n");
250         translate_name(pcm_name, device->in_config->alsa_in_device);
251 //printf("AudioALSA::open_input 1\n");
253         err = snd_pcm_open(&dsp_in, pcm_name, stream, open_mode);
254 //printf("AudioALSA::open_input 1\n");
256         if(err < 0)
257         {
258                 printf("AudioALSA::open_input: %s\n", snd_strerror(err));
259                 return 1;
260         }
261 //printf("AudioALSA::open_input 1\n");
263         set_params(dsp_in, 
264                 device->in_config->alsa_in_channels, 
265                 device->in_config->alsa_in_bits,
266                 device->in_samplerate,
267                 device->in_samples);
268 //printf("AudioALSA::open_input 2\n");
269         return 0;
272 int AudioALSA::open_output()
274         char pcm_name[BCTEXTLEN];
275         snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
276         int open_mode = 0;
277         int err;
279         device->out_channels = device->out_config->alsa_out_channels;
280         device->out_bits = device->out_config->alsa_out_bits;
282         translate_name(pcm_name, device->out_config->alsa_out_device);
284         err = snd_pcm_open(&dsp_out, pcm_name, stream, open_mode);
286         if(err < 0)
287         {
288                 printf("AudioALSA::open_output %s: %s\n", pcm_name, snd_strerror(err));
289                 return 1;
290         }
292         set_params(dsp_out, 
293                 device->out_config->alsa_out_channels, 
294                 device->out_config->alsa_out_bits,
295                 device->out_samplerate,
296                 device->out_samples);
297         return 0;
300 int AudioALSA::open_duplex()
302 // ALSA always opens 2 devices
303         return 0;
307 int AudioALSA::close_all()
309         if(device->r)
310         {
311                 snd_pcm_reset(dsp_in);
312                 snd_pcm_drop(dsp_in);
313                 snd_pcm_drain(dsp_in);
314                 snd_pcm_close(dsp_in);
315         }
316         if(device->w)
317         {
318                 snd_pcm_close(dsp_out);
319         }
320         if(device->d)
321         {
322                 snd_pcm_close(dsp_duplex);
323         }
326 // Undocumented
327 int64_t AudioALSA::device_position()
329         return -1;
332 int AudioALSA::read_buffer(char *buffer, int size)
334 //printf("AudioALSA::read_buffer 1\n");
335         snd_pcm_readi(get_input(), 
336                 buffer, 
337                 size / (device->in_bits / 8) / device->in_channels);
338 //printf("AudioALSA::read_buffer 2\n");
339         return 0;
342 int AudioALSA::write_buffer(char *buffer, int size)
344 // Buffers written must be equal to period_time
345         if(snd_pcm_writei(get_output(), 
346                 buffer, 
347                 size / (device->out_bits / 8) / device->out_channels) < 0)
348         {
349                 printf("AudioALSA::write_buffer: failed\n");
350         }
351         return 0;
354 int AudioALSA::flush_device()
356         snd_pcm_drain(get_output());
357         return 0;
360 int AudioALSA::interrupt_playback()
362         
363         return 0;
367 snd_pcm_t* AudioALSA::get_output()
369         if(device->w) return dsp_out;
370         else
371         if(device->d) return dsp_duplex;
372         return 0;
375 snd_pcm_t* AudioALSA::get_input()
377         if(device->r) return dsp_in;
378         else
379         if(device->d) return dsp_duplex;
380         return 0;
383 #endif