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