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