Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / audioalsa.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "audiodevice.h"
23 #include "audioalsa.h"
24 #include "bcsignals.h"
25 #include "mutex.h"
26 #include "playbackconfig.h"
27 #include "preferences.h"
28 #include "recordconfig.h"
29
30 #include <errno.h>
31
32 #ifdef HAVE_ALSA
33
34 AudioALSA::AudioALSA(AudioDevice *device)
35  : AudioLowLevel(device)
36 {
37         buffer_position = 0;
38         samples_written = 0;
39         timer = new Timer;
40         delay = 0;
41         period_size = 0;
42         timer_lock = new Mutex("AudioALSA::timer_lock");
43         interrupted = 0;
44         dsp_in = 0;
45         dsp_out = 0;
46 }
47
48 AudioALSA::~AudioALSA()
49 {
50         delete timer_lock;
51         delete timer;
52 }
53
54 // leak checking
55 static class alsa_leaks
56 {
57 public:
58 // This is required in the top thread for Alsa to work
59         alsa_leaks() {
60                 ArrayList<char*> *alsa_titles = new ArrayList<char*>;
61                 AudioALSA::list_devices(alsa_titles, 0, MODEPLAY);
62                 alsa_titles->remove_all_objects();
63                 delete alsa_titles;
64         }
65         ~alsa_leaks() { snd_config_update_free_global(); }
66 } alsa_leak;
67
68 void AudioALSA::list_devices(ArrayList<char*> *devices, int pcm_title, int mode)
69 {
70         snd_ctl_t *handle;
71         int card, err, dev;
72         snd_ctl_card_info_t *info;
73         snd_pcm_info_t *pcminfo;
74         char string[BCTEXTLEN];
75         snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
76
77         devices->set_array_delete();
78
79
80         switch(mode)
81         {
82                 case MODERECORD:
83                         stream = SND_PCM_STREAM_CAPTURE;
84                         break;
85                 case MODEPLAY:
86                         stream = SND_PCM_STREAM_PLAYBACK;
87                         break;
88         }
89
90
91         snd_ctl_card_info_alloca(&info);
92         snd_pcm_info_alloca(&pcminfo);
93
94         card = -1;
95 #define DEFAULT_DEVICE "default"
96         char *result = new char[strlen(DEFAULT_DEVICE) + 1];
97         devices->append(result);
98         devices->set_array_delete();     // since we are allocating by new[]
99         strcpy(result, DEFAULT_DEVICE);
100
101         while(snd_card_next(&card) >= 0)
102         {
103                 char name[BCTEXTLEN];
104                 if(card < 0) break;
105                 sprintf(name, "hw:%i", card);
106
107                 if((err = snd_ctl_open(&handle, name, 0)) < 0)
108                 {
109                         printf("AudioALSA::list_devices card=%i: %s\n", card, snd_strerror(err));
110                         continue;
111                 }
112
113                 if((err = snd_ctl_card_info(handle, info)) < 0)
114                 {
115                         printf("AudioALSA::list_devices card=%i: %s\n", card, snd_strerror(err));
116                         snd_ctl_close(handle);
117                         continue;
118                 }
119
120                 dev = -1;
121
122                 while(1)
123                 {
124                         if(snd_ctl_pcm_next_device(handle, &dev) < 0)
125                                 printf("AudioALSA::list_devices: snd_ctl_pcm_next_device\n");
126
127                         if (dev < 0)
128                                 break;
129
130                         snd_pcm_info_set_device(pcminfo, dev);
131                         snd_pcm_info_set_subdevice(pcminfo, 0);
132                         snd_pcm_info_set_stream(pcminfo, stream);
133
134                         if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0)
135                         {
136                                 if(err != -ENOENT)
137                                         printf("AudioALSA::list_devices card=%i: %s\n", card, snd_strerror(err));
138                                 continue;
139                         }
140
141                         if(pcm_title)
142                         {
143                                 sprintf(string, "plughw:%d,%d", card, dev);
144 //                              strcpy(string, "cards.pcm.front");
145                         }
146                         else
147                         {
148                                 sprintf(string, "%s #%d",
149                                         snd_ctl_card_info_get_name(info),
150                                         dev);
151                         }
152
153                         char *result = devices->append(new char[strlen(string) + 1]);
154                         strcpy(result, string);
155                 }
156
157
158
159                 snd_ctl_close(handle);
160         }
161
162 // attempt to add pulseaudio "monitor" devices
163 //  run: pactl list <sources>|<sinks>
164 //   scan output for <Source/Sink> #n,  Name: <device>
165 //   build alsa device config and add to alsa snd_config
166
167         const char *arg = 0;
168         switch( mode ) {
169                 case MODERECORD:
170                         arg = "source";
171                         break;
172                 case MODEPLAY:
173                         arg = "sink";
174                         break;
175         }
176         FILE *pactl = 0;
177         char line[BCTEXTLEN];
178         if( arg ) {
179                 sprintf(line, "pactl list %ss", arg);
180                 pactl = popen(line,"r");
181         }
182         if( pactl ) {
183                 if( pcm_title ) snd_config_update();
184                 char name[BCTEXTLEN], pa_name[BCTEXTLEN], device[BCTEXTLEN];
185                 name[0] = pa_name[0] = device[0] = 0;
186                 int arg_len = strlen(arg);
187                 while( fgets(line, sizeof(line), pactl) ) {
188                         if( !strncasecmp(line, arg, arg_len) ) {
189                                 char *sp = name, *id = pa_name;
190                                 for( char *cp=line; *cp && *cp!='\n'; *sp++=*cp++ )
191                                         *id++ = (*cp>='A' && *cp<='Z') ||
192                                                 (*cp>='a' && *cp<='z') ||
193                                                 (*cp>='0' && *cp<='9') ? *cp : '_';
194                                 *sp++ = 0;  *id = 0;
195                                 if( !pcm_title )
196                                         devices->append(strcpy(new char[sp-name], name));
197                                 continue;
198                         }
199                         if( !pcm_title ) continue;
200                         if( sscanf(line, " Name: %s", device) != 1 ) continue;
201                         int len = strlen(pa_name);
202                         devices->append(strcpy(new char[len+1], pa_name));
203                         char alsa_config[BCTEXTLEN];
204                         len = snprintf(alsa_config, sizeof(alsa_config),
205                                 "pcm.!%s {\n type pulse\n device %s\n}\n"
206                                 "ctl.!%s {\n type pulse\n device %s\n}\n",
207                                 pa_name, device, pa_name, device);
208                         FILE *fp = fmemopen(alsa_config,len,"r");
209                         snd_input_t *inp;
210                         snd_input_stdio_attach(&inp, fp, 1);
211                         snd_config_load(snd_config, inp);
212                         name[0] = pa_name[0] = device[0] = 0;
213                         snd_input_close(inp);
214                 }
215                 pclose(pactl);
216         }
217 }
218
219 void AudioALSA::translate_name(char *output, char *input, int mode)
220 {
221         ArrayList<char*> titles;
222         ArrayList<char*> pcm_titles;
223
224         list_devices(&titles, 0, mode);
225         list_devices(&pcm_titles, 1, mode);
226
227         sprintf(output, "default");
228         for(int i = 0; i < titles.total; i++)
229         {
230 //printf("AudioALSA::translate_name %s %s\n", titles.values[i], pcm_titles.values[i]);
231                 if(!strcasecmp(titles.values[i], input))
232                 {
233                         strcpy(output, pcm_titles.values[i]);
234                         break;
235                 }
236         }
237
238         titles.remove_all_objects();
239         pcm_titles.remove_all_objects();
240 }
241
242 snd_pcm_format_t AudioALSA::translate_format(int format)
243 {
244         switch(format)
245         {
246         case 8:
247                 return SND_PCM_FORMAT_S8;
248                 break;
249         case 16:
250                 return SND_PCM_FORMAT_S16_LE;
251                 break;
252         case 24:
253                 return SND_PCM_FORMAT_S24_LE;
254                 break;
255         case 32:
256                 return SND_PCM_FORMAT_S32_LE;
257                 break;
258         }
259         return SND_PCM_FORMAT_UNKNOWN;
260 }
261
262 int AudioALSA::set_params(snd_pcm_t *dsp, int mode,
263         int channels, int bits, int samplerate, int samples)
264 {
265         snd_pcm_hw_params_t *params;
266         snd_pcm_sw_params_t *swparams;
267         int err;
268
269         snd_pcm_hw_params_alloca(&params);
270         snd_pcm_sw_params_alloca(&swparams);
271         err = snd_pcm_hw_params_any(dsp, params);
272
273         if (err < 0) {
274                 fprintf(stderr, "AudioALSA::set_params: no PCM configurations available\n");
275                 return 1;
276         }
277
278         err=snd_pcm_hw_params_set_access(dsp,
279                 params,
280                 SND_PCM_ACCESS_RW_INTERLEAVED);
281         if(err) {
282                 fprintf(stderr, "AudioALSA::set_params: failed to set up "
283                                 "interleaved device access.\n");
284                 return 1;
285         }
286
287         err=snd_pcm_hw_params_set_format(dsp,
288                 params,
289                 translate_format(bits));
290         if(err) {
291                 fprintf(stderr, "AudioALSA::set_params: failed to set output format.\n");
292                 return 1;
293         }
294
295         err=snd_pcm_hw_params_set_channels(dsp,
296                 params,
297                 channels);
298         if(err) {
299                 fprintf(stderr, "AudioALSA::set_params: Configured ALSA device "
300                                 "does not support %d channel operation.\n",
301                         channels);
302                 return 1;
303         }
304
305         err=snd_pcm_hw_params_set_rate_near(dsp,
306                 params,
307                 (unsigned int*)&samplerate,
308                 (int*)0);
309         if(err) {
310                 fprintf(stderr, "AudioALSA::set_params: Configured ALSA device "
311                                 "does not support %u Hz playback.\n",
312                         (unsigned int)samplerate);
313                 return 1;
314         }
315
316 // Buffers written must be equal to period_time
317         int buffer_time = 0;
318         int period_time = (int)(1000000 * (double)samples / samplerate);
319         switch( mode ) {
320         case MODERECORD:
321                 buffer_time = 10000000;
322                 break;
323         case MODEPLAY:
324                 buffer_time = 2 * period_time;
325                 break;
326         }
327
328 //printf("AudioALSA::set_params 1 %d %d %d\n", samples, buffer_time, period_time);
329         snd_pcm_hw_params_set_buffer_time_near(dsp,
330                 params,
331                 (unsigned int*)&buffer_time,
332                 (int*)0);
333         snd_pcm_hw_params_set_period_time_near(dsp,
334                 params,
335                 (unsigned int*)&period_time,
336                 (int*)0);
337 //printf("AudioALSA::set_params 5 %d %d\n", buffer_time, period_time);
338         err = snd_pcm_hw_params(dsp, params);
339         if(err < 0) {
340                 fprintf(stderr, "AudioALSA::set_params: hw_params failed\n");
341                 return 1;
342         }
343
344         snd_pcm_uframes_t chunk_size = 1024;
345         snd_pcm_uframes_t buffer_size = 262144;
346         snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
347         snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
348 //printf("AudioALSA::set_params 10 %d %d\n", chunk_size, buffer_size);
349
350         snd_pcm_sw_params_current(dsp, swparams);
351         //snd_pcm_uframes_t xfer_align = 1;
352         //snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);
353         //unsigned int sleep_min = 0;
354         //err = snd_pcm_sw_params_set_sleep_min(dsp, swparams, sleep_min);
355         period_size = chunk_size;
356         err = snd_pcm_sw_params_set_avail_min(dsp, swparams, period_size);
357         //err = snd_pcm_sw_params_set_xfer_align(dsp, swparams, xfer_align);
358         if(snd_pcm_sw_params(dsp, swparams) < 0) {
359                 /* we can continue staggering along even if this fails */
360                 fprintf(stderr, "AudioALSA::set_params: snd_pcm_sw_params failed\n");
361         }
362
363         device->device_buffer = samples * bits / 8 * channels;
364         period_size /= 2;
365 //printf("AudioALSA::set_params 100 %d %d\n", samples,  device->device_buffer);
366
367 //      snd_pcm_hw_params_free(params);
368 //      snd_pcm_sw_params_free(swparams);
369         return 0;
370 }
371
372 int AudioALSA::open_input()
373 {
374         char pcm_name[BCTEXTLEN];
375         snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
376         int open_mode = 0;
377         int err;
378
379         device->in_channels = device->get_ichannels();
380         device->in_bits = device->in_config->alsa_in_bits;
381
382         translate_name(pcm_name, device->in_config->alsa_in_device,MODERECORD);
383 //printf("AudioALSA::open_input %s\n", pcm_name);
384
385         err = snd_pcm_open(&dsp_in, device->in_config->alsa_in_device, stream, open_mode);
386
387         if(err < 0) {
388                 dsp_in = 0;
389                 printf("AudioALSA::open_input: %s\n", snd_strerror(err));
390                 return 1;
391         }
392
393         err = set_params(dsp_in, MODERECORD,
394                 device->get_ichannels(),
395                 device->in_config->alsa_in_bits,
396                 device->in_samplerate,
397                 device->in_samples);
398         if(err) {
399                 fprintf(stderr, "AudioALSA::open_input: set_params failed.  Aborting sampling.\n");
400                 close_input();
401                 return 1;
402         }
403
404         return 0;
405 }
406
407 int AudioALSA::open_output()
408 {
409         char pcm_name[BCTEXTLEN];
410         snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
411         int open_mode = SND_PCM_NONBLOCK;
412         int err;
413
414         device->out_channels = device->get_ochannels();
415         device->out_bits = device->out_config->alsa_out_bits;
416
417 //printf("AudioALSA::open_output out_device %s\n", device->out_config->alsa_out_device);
418         translate_name(pcm_name, device->out_config->alsa_out_device,MODEPLAY);
419 //printf("AudioALSA::open_output pcm_name %s\n", pcm_name);
420
421         err = snd_pcm_open(&dsp_out, pcm_name, stream, open_mode);
422
423         if(err < 0)
424         {
425                 dsp_out = 0;
426                 printf("AudioALSA::open_output %s: %s\n", pcm_name, snd_strerror(err));
427                 return 1;
428         }
429
430         set_params(dsp_out, MODEPLAY,
431                 device->get_ochannels(),
432                 device->out_config->alsa_out_bits,
433                 device->out_samplerate,
434                 device->out_samples);
435         if(err) {
436                 fprintf(stderr, "AudioALSA::open_output: set_params failed.  Aborting playback.\n");
437                 close_output();
438                 return 1;
439         }
440
441         timer->update();
442         return 0;
443 }
444
445 int AudioALSA::stop_output()
446 {
447 //printf("AudioALSA::stop_output\n");
448         if(!device->out_config->interrupt_workaround)
449         {
450                 if( get_output() )
451                         snd_pcm_drop(get_output());
452         }
453         else
454                 flush_device();
455         return 0;
456 }
457
458 int AudioALSA::close_output()
459 {
460 //printf("AudioALSA::close_output\n");
461         if(device->w && dsp_out) {
462                 stop_output();
463                 snd_pcm_close(dsp_out);
464                 dsp_out = 0;
465         }
466         return 0;
467 }
468
469 int AudioALSA::close_input()
470 {
471 //printf("AudioALSA::close_input\n");
472         if(device->r && dsp_in) {
473 //              snd_pcm_reset(dsp_in);
474                 snd_pcm_drop(dsp_in);
475                 snd_pcm_drain(dsp_in);
476                 snd_pcm_close(dsp_in);
477                 dsp_in = 0;
478         }
479         return 0;
480 }
481
482 int AudioALSA::close_all()
483 {
484 //printf("AudioALSA::close_all\n");
485         close_input();
486         close_output();
487         buffer_position = 0;
488         samples_written = 0;
489         delay = 0;
490         interrupted = 0;
491         return 0;
492 }
493
494 // Undocumented
495 int64_t AudioALSA::device_position()
496 {
497         timer_lock->lock("AudioALSA::device_position");
498         int64_t delta = timer->get_scaled_difference(device->out_samplerate);
499         int64_t result = buffer_position - delay + delta;
500 //printf("AudioALSA::device_position 1 w=%jd dt=%jd dly=%d pos=%jd\n",
501 // buffer_position, delta, delay, result);
502         timer_lock->unlock();
503         return result;
504 }
505
506 int AudioALSA::read_buffer(char *buffer, int size)
507 {
508 //printf("AudioALSA::read_buffer 1\n");
509         int attempts = 0;
510         int done = 0;
511         int frame_size = (device->in_bits / 8) * device->get_ichannels();
512         int result = 0;
513
514         if(!get_input())
515         {
516                 sleep(1);
517                 return 0;
518         }
519
520         while(attempts < 1 && !done)
521         {
522                 snd_pcm_uframes_t frames = size / frame_size;
523                 result = snd_pcm_readi(get_input(), buffer, frames);
524                 if( result < 0)
525                 {
526                         printf("AudioALSA::read_buffer overrun at sample %jd\n",
527                                 device->total_samples_read);
528 //                      snd_pcm_resume(get_input());
529                         close_input();  open_input();
530                         attempts++;
531                 }
532                 else
533                         done = 1;
534 //printf("AudioALSA::read_buffer %d result=%d done=%d\n", __LINE__, result, done);
535         }
536         return 0;
537 }
538
539 int AudioALSA::write_buffer(char *buffer, int size)
540 {
541 //printf("AudioALSA::write_buffer %d\n",size);
542 // Don't give up and drop the buffer on the first error.
543         int attempts = 0;
544         int done = 0;
545         int sample_size = (device->out_bits / 8) * device->get_ochannels();
546         int samples = size / sample_size;
547 //printf("AudioALSA::write_buffer %d\n",samples);
548         int count = samples;
549         snd_pcm_sframes_t delay = 0;
550
551 // static FILE *debug_fd = 0;
552 // if(!debug_fd)
553 // {
554 //      debug_fd = fopen("/tmp/debug.pcm", "w");
555 // }
556 // fwrite(buffer, size, 1, debug_fd);
557 // fflush(debug_fd);
558
559
560         if(!get_output()) return 0;
561         if( buffer_position == 0 )
562                 timer->update();
563
564         AudioThread *audio_out = device->audio_out;
565         while(attempts < 2 && !done && !device->playback_interrupted)
566         {
567 // Buffers written must be equal to period_time
568                 audio_out->Thread::enable_cancel();
569                 int ret = snd_pcm_avail_update(get_output());
570                 if( ret >= period_size ) {
571                         if( ret > count ) ret = count;
572 //FILE *alsa_fp = 0;
573 //if( !alsa_fp ) alsa_fp = fopen("/tmp/alsa.raw","w");
574 //if( alsa_fp ) fwrite(buffer, sample_size, ret, alsa_fp);
575 //printf("AudioALSA::snd_pcm_writei start %d\n",count);
576                         ret = snd_pcm_writei(get_output(),buffer,ret);
577 //printf("AudioALSA::snd_pcm_writei done %d\n", ret);
578                 }
579                 else if( ret >= 0 || ret == -EAGAIN ) {
580                         ret = snd_pcm_wait(get_output(),15);
581                         if( ret > 0 ) ret = 0;
582                 }
583                 audio_out->Thread::disable_cancel();
584                 if( ret == 0 ) continue;
585
586                 if( ret > 0 ) {
587                         samples_written += ret;
588                         if( (count-=ret) > 0 ) {
589                                 buffer += ret * sample_size;
590                                 attempts = 0;
591                         }
592                         else
593                                 done = 1;
594                 }
595                 else {
596                         printf("AudioALSA::write_buffer err %d(%s) at sample %jd\n",
597                                 ret, snd_strerror(ret), device->current_position());
598                         Timer::delay(50);
599 //                      snd_pcm_resume(get_output());
600                         snd_pcm_recover(get_output(), ret, 1);
601 //                      close_output();  open_output();
602                         attempts++;
603                 }
604         }
605
606         if( !interrupted && device->playback_interrupted )
607         {
608                 interrupted = 1;
609 //printf("AudioALSA::write_buffer interrupted\n");
610                 stop_output();
611         }
612
613         if(done)
614         {
615                 timer_lock->lock("AudioALSA::write_buffer");
616                 snd_pcm_delay(get_output(), &delay);
617                 this->delay = delay;
618                 timer->update();
619                 buffer_position += samples;
620 //printf("AudioALSA::write_buffer ** wrote %d, delay %d\n",samples,(int)delay);
621                 timer_lock->unlock();
622         }
623         return 0;
624 }
625
626 //this delay seems to prevent a problem where the sound system outputs
627 //a lot of silence while waiting for the device drain to happen.
628 int AudioALSA::output_wait()
629 {
630         snd_pcm_sframes_t delay = 0;
631         snd_pcm_delay(get_output(), &delay);
632         if( delay <= 0 ) return 0;
633         int64_t udelay = 1e6 * delay / device->out_samplerate;
634         // don't allow more than 10 seconds
635         if( udelay > 10000000 ) udelay = 10000000;
636         while( udelay > 0 && !device->playback_interrupted ) {
637                 int64_t usecs = udelay;
638                 if( usecs > 100000 ) usecs = 100000;
639                 usleep(usecs);
640                 udelay -= usecs;
641         }
642         if( device->playback_interrupted &&
643             !device->out_config->interrupt_workaround )
644                 snd_pcm_drop(get_output());
645         return 0;
646 }
647
648 int AudioALSA::flush_device()
649 {
650 //printf("AudioALSA::flush_device\n");
651         if(get_output())
652         {
653                 output_wait();
654                 //this causes the output to stutter.
655                 //snd_pcm_nonblock(get_output(), 0);
656                 snd_pcm_drain(get_output());
657                 //snd_pcm_nonblock(get_output(), 1);
658         }
659         return 0;
660 }
661
662 int AudioALSA::interrupt_playback()
663 {
664 //printf("AudioALSA::interrupt_playback *********\n");
665 //      if(get_output())
666 //      {
667 // Interrupts the playback but may not have caused snd_pcm_writei to exit.
668 // With some soundcards it causes snd_pcm_writei to freeze for a few seconds.
669 //              if(!device->out_config->interrupt_workaround)
670 //                      snd_pcm_drop(get_output());
671
672 // Makes sure the current buffer finishes before stopping.
673 //              snd_pcm_drain(get_output());
674
675 // The only way to ensure snd_pcm_writei exits, but
676 // got a lot of crashes when doing this.
677 //              device->Thread::cancel();
678 //      }
679         return 0;
680 }
681
682
683 snd_pcm_t* AudioALSA::get_output()
684 {
685         return dsp_out;
686 }
687
688 snd_pcm_t* AudioALSA::get_input()
689 {
690         return dsp_in;
691 }
692
693 #endif