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