]> git.alsa-project.org Git - alsa-plugins.git/blob - pulse/pcm_pulse.c
a201bf95aa28fa79567d8b4bafd6f79fab17bd8c
[alsa-plugins.git] / pulse / pcm_pulse.c
1 /*-*- linux-c -*-*/
2
3 /*
4  * ALSA <-> PulseAudio PCM I/O plugin
5  *
6  * Copyright (c) 2006 by Pierre Ossman <ossman@cendio.se>
7  *
8  * This library is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as
10  * published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #include <stdio.h>
24 #include <sys/poll.h>
25
26 #include <alsa/asoundlib.h>
27 #include <alsa/pcm_external.h>
28
29 #include "pulse.h"
30
31 typedef struct snd_pcm_pulse {
32         snd_pcm_ioplug_t io;
33
34         snd_pulse_t *p;
35
36         char *device;
37
38         /* Since ALSA expects a ring buffer we must do some voodoo. */
39         size_t last_size;
40         size_t ptr;
41         int underrun;
42         int handle_underrun;
43
44         size_t offset;
45         int64_t written;
46
47         pa_stream *stream;
48
49         pa_sample_spec ss;
50         size_t frame_size;
51         pa_buffer_attr buffer_attr;
52 } snd_pcm_pulse_t;
53
54 static int check_stream(snd_pcm_pulse_t *pcm)
55 {
56         int err;
57         pa_stream_state_t state;
58
59         assert(pcm);
60
61         if (!pcm->p)
62                 return -EBADFD;
63
64         err = pulse_check_connection(pcm->p);
65         if (err < 0)
66                 return err;
67
68         if (!pcm->stream)
69                 return -EBADFD;
70
71         state = pa_stream_get_state(pcm->stream);
72         if (!PA_STREAM_IS_GOOD(state))
73                 return -EIO;
74
75         err = 0;
76
77         return err;
78 }
79
80 static int update_ptr(snd_pcm_pulse_t *pcm)
81 {
82         size_t size;
83
84         if (pcm->io.stream == SND_PCM_STREAM_PLAYBACK)
85                 size = pa_stream_writable_size(pcm->stream);
86         else
87                 size = pa_stream_readable_size(pcm->stream);
88
89         if (size == (size_t) -1)
90                 return -EIO;
91
92         if (pcm->io.stream == SND_PCM_STREAM_CAPTURE)
93                 size -= pcm->offset;
94
95         /* Prevent accidental overrun of the fake ringbuffer */
96         if (size > pcm->buffer_attr.tlength - pcm->frame_size)
97                 size = pcm->buffer_attr.tlength - pcm->frame_size;
98
99         if (size > pcm->last_size) {
100                 pcm->ptr += size - pcm->last_size;
101                 pcm->ptr %= pcm->buffer_attr.tlength;
102         }
103
104         pcm->last_size = size;
105         return 0;
106   }
107
108 static int check_active(snd_pcm_pulse_t *pcm) {
109         assert(pcm);
110
111         /*
112          * ALSA thinks in periods, not bytes, samples or frames.
113          */
114
115         if (pcm->io.stream == SND_PCM_STREAM_PLAYBACK) {
116                 size_t wsize;
117
118                 wsize = pa_stream_writable_size(pcm->stream);
119
120                 if (wsize == (size_t) -1)
121                         return -EIO;
122
123                 return wsize >= pcm->buffer_attr.minreq;
124         } else {
125                 size_t rsize;
126
127                 rsize = pa_stream_readable_size(pcm->stream);
128
129                 if (rsize == (size_t) -1)
130                         return -EIO;
131
132                 return rsize >= pcm->buffer_attr.fragsize;
133         }
134 }
135
136 static int update_active(snd_pcm_pulse_t *pcm) {
137         int ret;
138
139         assert(pcm);
140
141         if (!pcm->p)
142                 return -EBADFD;
143
144         ret = check_stream(pcm);
145         if (ret < 0)
146                 goto finish;
147
148         ret = check_active(pcm);
149
150 finish:
151
152         if (ret != 0) /* On error signal the caller, too */
153                 pulse_poll_activate(pcm->p);
154         else
155                 pulse_poll_deactivate(pcm->p);
156
157         return ret;
158 }
159
160 static int wait_stream_state(snd_pcm_pulse_t *pcm, pa_stream_state_t target)
161 {
162         pa_stream_state_t state;
163
164         assert(pcm);
165
166         if (!pcm->p)
167                 return -EBADFD;
168
169         for (;;) {
170                 int err;
171
172                 err = pulse_check_connection(pcm->p);
173                 if (err < 0)
174                         return err;
175
176                 if (!pcm->stream)
177                         return -EBADFD;
178
179                 state = pa_stream_get_state(pcm->stream);
180                 if (state == target)
181                         break;
182
183                 if (!PA_STREAM_IS_GOOD(state))
184                         return -EIO;
185
186                 pa_threaded_mainloop_wait(pcm->p->mainloop);
187         }
188
189         return 0;
190 }
191
192 static void stream_success_cb(pa_stream * p, int success, void *userdata)
193 {
194         snd_pcm_pulse_t *pcm = userdata;
195
196         assert(pcm);
197
198         if (!pcm->p)
199                 return;
200
201         pa_threaded_mainloop_signal(pcm->p->mainloop, 0);
202 }
203
204 static int pulse_start(snd_pcm_ioplug_t * io)
205 {
206         snd_pcm_pulse_t *pcm = io->private_data;
207         pa_operation *o, *u;
208         int err = 0, err_o = 0, err_u = 0;
209
210         assert(pcm);
211
212         if (!pcm->p || !pcm->p->mainloop)
213                 return -EBADFD;
214
215         pa_threaded_mainloop_lock(pcm->p->mainloop);
216
217         err = check_stream(pcm);
218         if (err < 0)
219                 goto finish;
220
221         o = pa_stream_cork(pcm->stream, 0, stream_success_cb, pcm);
222         if (!o) {
223                 err = -EIO;
224                 goto finish;
225         }
226
227         u = pa_stream_trigger(pcm->stream, stream_success_cb, pcm);
228
229         pcm->underrun = 0;
230         err_o = pulse_wait_operation(pcm->p, o);
231         if (u)
232                 err_u = pulse_wait_operation(pcm->p, u);
233
234         pa_operation_unref(o);
235         if (u)
236                 pa_operation_unref(u);
237
238         if (err_o < 0 || err_u < 0) {
239                 err = -EIO;
240                 goto finish;
241         }
242
243 finish:
244         pa_threaded_mainloop_unlock(pcm->p->mainloop);
245
246         return err;
247 }
248
249 static int pulse_stop(snd_pcm_ioplug_t * io)
250 {
251         snd_pcm_pulse_t *pcm = io->private_data;
252         pa_operation *o, *u;
253         int err = 0, err_o = 0, err_u = 0;
254
255         assert(pcm);
256
257         if (!pcm->p || !pcm->p->mainloop)
258                 return -EBADFD;
259
260         pa_threaded_mainloop_lock(pcm->p->mainloop);
261
262         err = check_stream(pcm);
263         if (err < 0)
264                 goto finish;
265
266         o = pa_stream_cork(pcm->stream, 1, stream_success_cb, pcm);
267         if (!o) {
268                 err = -EIO;
269                 goto finish;
270         }
271
272         u = pa_stream_flush(pcm->stream, stream_success_cb, pcm);
273         if (!u) {
274                 pa_operation_unref(o);
275                 err = -EIO;
276                 goto finish;
277         }
278
279         err_o = pulse_wait_operation(pcm->p, o);
280         err_u = pulse_wait_operation(pcm->p, u);
281
282         pa_operation_unref(o);
283         pa_operation_unref(u);
284
285         if (err_o < 0 || err_u < 0) {
286                 err = -EIO;
287                 goto finish;
288         }
289
290 finish:
291         pa_threaded_mainloop_unlock(pcm->p->mainloop);
292
293         return err;
294 }
295
296 static int pulse_drain(snd_pcm_ioplug_t * io)
297 {
298         snd_pcm_pulse_t *pcm = io->private_data;
299         pa_operation *o;
300         int err = 0;
301
302         assert(pcm);
303
304         if (!pcm->p || !pcm->p->mainloop)
305                 return -EBADFD;
306
307         pa_threaded_mainloop_lock(pcm->p->mainloop);
308
309         err = check_stream(pcm);
310         if (err < 0)
311                 goto finish;
312
313         o = pa_stream_drain(pcm->stream, stream_success_cb, pcm);
314         if (!o) {
315                 err = -EIO;
316                 goto finish;
317         }
318
319         err = pulse_wait_operation(pcm->p, o);
320
321         pa_operation_unref(o);
322
323         if (err < 0) {
324                 err = -EIO;
325                 goto finish;
326         }
327
328 finish:
329         pa_threaded_mainloop_unlock(pcm->p->mainloop);
330
331         return err;
332 }
333
334 static snd_pcm_sframes_t pulse_pointer(snd_pcm_ioplug_t * io)
335 {
336         snd_pcm_pulse_t *pcm = io->private_data;
337         snd_pcm_sframes_t ret = 0;
338
339         assert(pcm);
340
341         if (!pcm->p || !pcm->p->mainloop)
342                 return -EBADFD;
343
344         if (io->state == SND_PCM_STATE_XRUN)
345                 return -EPIPE;
346
347         if (io->state != SND_PCM_STATE_RUNNING)
348                 return 0;
349
350         pa_threaded_mainloop_lock(pcm->p->mainloop);
351
352         ret = check_stream(pcm);
353         if (ret < 0)
354                 goto finish;
355
356         if (pcm->underrun) {
357                 ret = -EPIPE;
358                 goto finish;
359         }
360
361         ret = update_ptr(pcm);
362         if (ret < 0) {
363                 ret = -EPIPE;
364                 goto finish;
365         }
366
367         if (pcm->underrun)
368                 ret = -EPIPE;
369         else
370                 ret = snd_pcm_bytes_to_frames(io->pcm, pcm->ptr);
371
372 finish:
373
374         pa_threaded_mainloop_unlock(pcm->p->mainloop);
375
376         return ret;
377 }
378
379 static int pulse_delay(snd_pcm_ioplug_t * io, snd_pcm_sframes_t * delayp)
380 {
381         snd_pcm_pulse_t *pcm = io->private_data;
382         int err = 0;
383         pa_usec_t lat = 0;
384
385         assert(pcm);
386
387         if (!pcm->p || !pcm->p->mainloop)
388                 return -EBADFD;
389
390         pa_threaded_mainloop_lock(pcm->p->mainloop);
391
392         for (;;) {
393                 err = check_stream(pcm);
394                 if (err < 0)
395                         goto finish;
396
397                 err = pa_stream_get_latency(pcm->stream, &lat, NULL);
398                 if (err) {
399                         if (err != PA_ERR_NODATA) {
400                                 err = -EIO;
401                                 goto finish;
402                         }
403                 } else
404                         break;
405
406                 pa_threaded_mainloop_wait(pcm->p->mainloop);
407         }
408
409         *delayp =
410             snd_pcm_bytes_to_frames(io->pcm,
411                                     pa_usec_to_bytes(lat, &pcm->ss));
412
413         err = 0;
414
415 finish:
416
417         if (pcm->underrun && pcm->io.state == SND_PCM_STATE_RUNNING)
418                 snd_pcm_ioplug_set_state(io, SND_PCM_STATE_XRUN);
419
420         pa_threaded_mainloop_unlock(pcm->p->mainloop);
421
422         return err;
423 }
424
425 static snd_pcm_sframes_t pulse_write(snd_pcm_ioplug_t * io,
426                                      const snd_pcm_channel_area_t * areas,
427                                      snd_pcm_uframes_t offset,
428                                      snd_pcm_uframes_t size)
429 {
430         snd_pcm_pulse_t *pcm = io->private_data;
431         const char *buf;
432         snd_pcm_sframes_t ret = 0;
433         size_t writebytes;
434
435         assert(pcm);
436
437         if (!pcm->p || !pcm->p->mainloop)
438                 return -EBADFD;
439
440         pa_threaded_mainloop_lock(pcm->p->mainloop);
441
442         ret = check_stream(pcm);
443         if (ret < 0)
444                 goto finish;
445
446         /* Make sure the buffer pointer is in sync */
447         ret = update_ptr(pcm);
448         if (ret < 0)
449                 goto finish;
450
451         buf =
452             (char *) areas->addr + (areas->first +
453                                     areas->step * offset) / 8;
454
455         writebytes = size * pcm->frame_size;
456         ret = pa_stream_write(pcm->stream, buf, writebytes, NULL, 0, 0);
457         if (ret < 0) {
458                 ret = -EIO;
459                 goto finish;
460         }
461
462         /* Make sure the buffer pointer is in sync */
463         pcm->last_size -= writebytes;
464         pcm->written += writebytes;
465         ret = update_ptr(pcm);
466         if (ret < 0)
467                 goto finish;
468
469
470         ret = update_active(pcm);
471         if (ret < 0)
472                 goto finish;
473
474         ret = size;
475         pcm->underrun = 0;
476
477 finish:
478         pa_threaded_mainloop_unlock(pcm->p->mainloop);
479
480         return ret;
481 }
482
483 static snd_pcm_sframes_t pulse_read(snd_pcm_ioplug_t * io,
484                                     const snd_pcm_channel_area_t * areas,
485                                     snd_pcm_uframes_t offset,
486                                     snd_pcm_uframes_t size)
487 {
488         snd_pcm_pulse_t *pcm = io->private_data;
489         void *dst_buf;
490         size_t remain_size, frag_length;
491         snd_pcm_sframes_t ret = 0;
492
493         assert(pcm);
494
495         if (!pcm->p || !pcm->p->mainloop)
496                 return -EBADFD;
497
498         pa_threaded_mainloop_lock(pcm->p->mainloop);
499
500         ret = check_stream(pcm);
501         if (ret < 0)
502                 goto finish;
503
504         /* Make sure the buffer pointer is in sync */
505         ret = update_ptr(pcm);
506         if (ret < 0)
507                 goto finish;
508
509         remain_size = size * pcm->frame_size;
510
511         dst_buf =
512             (char *) areas->addr + (areas->first +
513                                     areas->step * offset) / 8;
514         while (remain_size > 0) {
515                 const void *src_buf;
516
517                 if (pa_stream_peek(pcm->stream, &src_buf, &frag_length) < 0) {
518                         ret = -EIO;
519                         goto finish;
520                 }
521
522                 if (frag_length == 0)
523                         break;
524
525                 if (src_buf) {
526                         src_buf = (char *) src_buf + pcm->offset;
527                         frag_length -= pcm->offset;
528
529                         if (frag_length > remain_size) {
530                                 pcm->offset += remain_size;
531                                 frag_length = remain_size;
532                         } else
533                                 pcm->offset = 0;
534
535                         memcpy(dst_buf, src_buf, frag_length);
536                 } else {
537                         /* If there is a hole in the stream, generate silence. */
538                         int sample_size = snd_pcm_format_physical_width(io->format) / 8;
539                         snd_pcm_format_set_silence(io->format, dst_buf, frag_length / sample_size);
540                 }
541
542                 if (pcm->offset == 0)
543                         pa_stream_drop(pcm->stream);
544
545                 dst_buf = (char *) dst_buf + frag_length;
546                 remain_size -= frag_length;
547                 pcm->last_size -= frag_length;
548         }
549
550         /* Make sure the buffer pointer is in sync */
551         ret = update_ptr(pcm);
552         if (ret < 0)
553                 goto finish;
554
555         ret = update_active(pcm);
556         if (ret < 0)
557                 goto finish;
558
559         ret = size - (remain_size / pcm->frame_size);
560
561 finish:
562         pa_threaded_mainloop_unlock(pcm->p->mainloop);
563
564         return ret;
565 }
566
567 static void stream_state_cb(pa_stream * p, void *userdata)
568 {
569         snd_pcm_pulse_t *pcm = userdata;
570         pa_stream_state_t state;
571
572         assert(pcm);
573
574         if (!pcm->p)
575                 return;
576
577         state = pa_stream_get_state(p);
578         if (!PA_STREAM_IS_GOOD(state))
579                 pulse_poll_activate(pcm->p);
580
581         pa_threaded_mainloop_signal(pcm->p->mainloop, 0);
582 }
583
584 static void stream_request_cb(pa_stream * p, size_t length, void *userdata)
585 {
586         snd_pcm_pulse_t *pcm = userdata;
587
588         assert(pcm);
589
590         if (!pcm->p)
591                 return;
592
593         update_active(pcm);
594 }
595
596 #ifndef PA_CHECK_VERSION
597 #define PA_CHECK_VERSION(x, y, z)       0
598 #endif
599
600 #if PA_CHECK_VERSION(0,99,0)
601 #define DEFAULT_HANDLE_UNDERRUN         1
602 #define do_underrun_detect(pcm, p) \
603         ((pcm)->written <= pa_stream_get_underflow_index(p))
604 #else
605 #define DEFAULT_HANDLE_UNDERRUN         0
606 #define do_underrun_detect(pcm, p)      1       /* always true */
607 #endif
608
609 static void stream_underrun_cb(pa_stream * p, void *userdata)
610 {
611         snd_pcm_pulse_t *pcm = userdata;
612
613         assert(pcm);
614
615         if (!pcm->p)
616                 return;
617
618         if (do_underrun_detect(pcm, p))
619                 pcm->underrun = 1;
620 }
621
622 static void stream_latency_cb(pa_stream *p, void *userdata) {
623         snd_pcm_pulse_t *pcm = userdata;
624
625         assert(pcm);
626
627         if (!pcm->p)
628                 return;
629
630         pa_threaded_mainloop_signal(pcm->p->mainloop, 0);
631 }
632
633 static int pulse_pcm_poll_revents(snd_pcm_ioplug_t * io,
634                                   struct pollfd *pfd, unsigned int nfds,
635                                   unsigned short *revents)
636 {
637         int err = 0;
638         snd_pcm_pulse_t *pcm = io->private_data;
639
640         assert(pcm);
641
642         if (!pcm->p || !pcm->p->mainloop)
643                 return -EBADFD;
644
645         pa_threaded_mainloop_lock(pcm->p->mainloop);
646
647         err = check_stream(pcm);
648         if (err < 0)
649                 goto finish;
650
651         err = check_active(pcm);
652         if (err < 0)
653                 goto finish;
654
655         if (err > 0)
656                 *revents = io->stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
657         else
658                 *revents = 0;
659
660         err = 0;
661
662 finish:
663
664         pa_threaded_mainloop_unlock(pcm->p->mainloop);
665
666         return err;
667 }
668
669 static int pulse_prepare(snd_pcm_ioplug_t * io)
670 {
671         pa_channel_map map;
672         snd_pcm_pulse_t *pcm = io->private_data;
673         int err = 0, r;
674         unsigned c, d;
675
676         assert(pcm);
677
678         if (!pcm->p || !pcm->p->mainloop)
679                 return -EBADFD;
680
681         pa_threaded_mainloop_lock(pcm->p->mainloop);
682
683         if (pcm->stream) {
684                 pa_stream_disconnect(pcm->stream);
685                 wait_stream_state(pcm, PA_STREAM_TERMINATED);
686                 pa_stream_unref(pcm->stream);
687                 pcm->stream = NULL;
688         }
689
690         err = pulse_check_connection(pcm->p);
691         if (err < 0)
692                 goto finish;
693
694         assert(pcm->stream == NULL);
695
696         for (c = pcm->ss.channels; c > 0; c--)
697                 if (pa_channel_map_init_auto(&map, c, PA_CHANNEL_MAP_ALSA))
698                         break;
699
700         /* Extend if nessary */
701         for (d = c; d < pcm->ss.channels; d++)
702                 map.map[d] = PA_CHANNEL_POSITION_AUX0+(d-c);
703
704         map.channels = pcm->ss.channels;
705
706         if (io->stream == SND_PCM_STREAM_PLAYBACK)
707                 pcm->stream =
708                     pa_stream_new(pcm->p->context, "ALSA Playback", &pcm->ss, &map);
709         else
710                 pcm->stream =
711                     pa_stream_new(pcm->p->context, "ALSA Capture", &pcm->ss, &map);
712
713         if (!pcm->stream) {
714                 err = -ENOMEM;
715                 goto finish;
716         }
717
718         pa_stream_set_state_callback(pcm->stream, stream_state_cb, pcm);
719         pa_stream_set_latency_update_callback(pcm->stream, stream_latency_cb, pcm);
720
721         if (io->stream == SND_PCM_STREAM_PLAYBACK) {
722                 pa_stream_set_write_callback(pcm->stream,
723                                              stream_request_cb, pcm);
724                 if (pcm->handle_underrun)
725                         pa_stream_set_underflow_callback(pcm->stream,
726                                                          stream_underrun_cb, pcm);
727                 r = pa_stream_connect_playback(pcm->stream, pcm->device,
728                                                &pcm->buffer_attr,
729                                                PA_STREAM_AUTO_TIMING_UPDATE |
730                                                PA_STREAM_INTERPOLATE_TIMING
731 #ifdef PA_STREAM_EARLY_REQUESTS
732                                              | PA_STREAM_EARLY_REQUESTS
733 #endif
734                                                , NULL, NULL);
735         } else {
736                 pa_stream_set_read_callback(pcm->stream, stream_request_cb,
737                                             pcm);
738                 r = pa_stream_connect_record(pcm->stream, pcm->device,
739                                              &pcm->buffer_attr,
740                                              PA_STREAM_AUTO_TIMING_UPDATE |
741                                              PA_STREAM_INTERPOLATE_TIMING
742 #ifdef PA_STREAM_EARLY_REQUESTS
743                                              | PA_STREAM_EARLY_REQUESTS
744 #endif
745                         );
746         }
747
748         if (r < 0) {
749                 SNDERR("PulseAudio: Unable to create stream: %s\n", pa_strerror(pa_context_errno(pcm->p->context)));
750                 pa_stream_unref(pcm->stream);
751                 pcm->stream = NULL;
752                 r = -EIO;
753                 goto finish;
754         }
755
756         err = wait_stream_state(pcm, PA_STREAM_READY);
757         if (err < 0) {
758                 SNDERR("PulseAudio: Unable to create stream: %s\n", pa_strerror(pa_context_errno(pcm->p->context)));
759                 pa_stream_unref(pcm->stream);
760                 pcm->stream = NULL;
761                 goto finish;
762         }
763
764         pcm->offset = 0;
765         pcm->underrun = 0;
766         pcm->written = 0;
767
768         /* Reset fake ringbuffer */
769         pcm->last_size = 0;
770         pcm->ptr = 0;
771         update_ptr(pcm);
772
773       finish:
774         pa_threaded_mainloop_unlock(pcm->p->mainloop);
775
776         return err;
777 }
778
779 static int pulse_hw_params(snd_pcm_ioplug_t * io,
780                            snd_pcm_hw_params_t * params)
781 {
782         snd_pcm_pulse_t *pcm = io->private_data;
783         int err = 0;
784
785         assert(pcm);
786
787         if (!pcm->p || !pcm->p->mainloop)
788                 return -EBADFD;
789
790         pa_threaded_mainloop_lock(pcm->p->mainloop);
791
792         pcm->frame_size =
793             (snd_pcm_format_physical_width(io->format) * io->channels) / 8;
794
795         switch (io->format) {
796         case SND_PCM_FORMAT_U8:
797                 pcm->ss.format = PA_SAMPLE_U8;
798                 break;
799         case SND_PCM_FORMAT_A_LAW:
800                 pcm->ss.format = PA_SAMPLE_ALAW;
801                 break;
802         case SND_PCM_FORMAT_MU_LAW:
803                 pcm->ss.format = PA_SAMPLE_ULAW;
804                 break;
805         case SND_PCM_FORMAT_S16_LE:
806                 pcm->ss.format = PA_SAMPLE_S16LE;
807                 break;
808         case SND_PCM_FORMAT_S16_BE:
809                 pcm->ss.format = PA_SAMPLE_S16BE;
810                 break;
811 #ifdef PA_SAMPLE_FLOAT32LE
812         case SND_PCM_FORMAT_FLOAT_LE:
813                 pcm->ss.format = PA_SAMPLE_FLOAT32LE;
814                 break;
815 #endif
816 #ifdef PA_SAMPLE_FLOAT32BE
817         case SND_PCM_FORMAT_FLOAT_BE:
818                 pcm->ss.format = PA_SAMPLE_FLOAT32BE;
819                 break;
820 #endif
821 #ifdef PA_SAMPLE_S32LE
822         case SND_PCM_FORMAT_S32_LE:
823                 pcm->ss.format = PA_SAMPLE_S32LE;
824                 break;
825 #endif
826 #ifdef PA_SAMPLE_S32BE
827         case SND_PCM_FORMAT_S32_BE:
828                 pcm->ss.format = PA_SAMPLE_S32BE;
829                 break;
830 #endif
831 #ifdef PA_SAMPLE_S24LE
832         case SND_PCM_FORMAT_S24_3LE:
833                 pcm->ss.format = PA_SAMPLE_S24LE;
834                 break;
835 #endif
836 #ifdef PA_SAMPLE_S24BE
837         case SND_PCM_FORMAT_S24_3BE:
838                 pcm->ss.format = PA_SAMPLE_S24BE;
839                 break;
840 #endif
841 #ifdef PA_SAMPLE_S24_32LE
842         case SND_PCM_FORMAT_S24_LE:
843                 pcm->ss.format = PA_SAMPLE_S24_32LE;
844                 break;
845 #endif
846 #ifdef PA_SAMPLE_S24_32BE
847         case SND_PCM_FORMAT_S24_BE:
848                 pcm->ss.format = PA_SAMPLE_S24_32BE;
849                 break;
850 #endif
851         default:
852                 SNDERR("PulseAudio: Unsupported format %s\n",
853                         snd_pcm_format_name(io->format));
854                 err = -EINVAL;
855                 goto finish;
856         }
857
858         pcm->ss.rate = io->rate;
859         pcm->ss.channels = io->channels;
860
861         pcm->buffer_attr.maxlength =
862                 4 * 1024 * 1024;
863         pcm->buffer_attr.tlength =
864                 io->buffer_size * pcm->frame_size;
865         if (pcm->buffer_attr.prebuf == (uint32_t)-1)
866                 pcm->buffer_attr.prebuf =
867                         (io->buffer_size - io->period_size) * pcm->frame_size;
868         pcm->buffer_attr.minreq = io->period_size * pcm->frame_size;
869         pcm->buffer_attr.fragsize = io->period_size * pcm->frame_size;
870
871       finish:
872         pa_threaded_mainloop_unlock(pcm->p->mainloop);
873
874         return err;
875 }
876
877 static int pulse_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params)
878 {
879         snd_pcm_pulse_t *pcm = io->private_data;
880         snd_pcm_uframes_t start_threshold;
881
882         assert(pcm);
883
884         if (!pcm->p || !pcm->p->mainloop)
885                 return -EBADFD;
886
887         pa_threaded_mainloop_lock(pcm->p->mainloop);
888
889         snd_pcm_sw_params_get_start_threshold(params, &start_threshold);
890
891         /* At least one period to keep PulseAudio happy */
892         if (start_threshold < io->period_size)
893                 start_threshold = io->period_size;
894
895         pcm->buffer_attr.prebuf = start_threshold * pcm->frame_size;
896
897         pa_threaded_mainloop_unlock(pcm->p->mainloop);
898
899         return 0;
900 }
901
902 static int pulse_close(snd_pcm_ioplug_t * io)
903 {
904         snd_pcm_pulse_t *pcm = io->private_data;
905
906         assert(pcm);
907
908         if (pcm->p && pcm->p->mainloop) {
909
910                 pa_threaded_mainloop_lock(pcm->p->mainloop);
911
912                 if (pcm->stream) {
913                         pa_stream_disconnect(pcm->stream);
914                         pa_stream_unref(pcm->stream);
915                 }
916
917                 pa_threaded_mainloop_unlock(pcm->p->mainloop);
918         }
919
920         if (pcm->p)
921                 pulse_free(pcm->p);
922
923         free(pcm->device);
924         free(pcm);
925
926         return 0;
927 }
928
929 static int pulse_pause(snd_pcm_ioplug_t * io, int enable)
930 {
931         snd_pcm_pulse_t *pcm = io->private_data;
932         int err = 0;
933         pa_operation *o;
934
935         assert (pcm);
936
937         if (!pcm->p || !pcm->p->mainloop)
938                 return -EBADFD;
939
940         pa_threaded_mainloop_lock(pcm->p->mainloop);
941
942         err = check_stream(pcm);
943         if (err < 0)
944                 goto finish;
945
946         o = pa_stream_cork(pcm->stream, enable, NULL, NULL);
947         if (o)
948                 pa_operation_unref(o);
949         else
950                 err = -EIO;
951
952 finish:
953         pa_threaded_mainloop_unlock(pcm->p->mainloop);
954
955         return err;
956 }
957
958 static const snd_pcm_ioplug_callback_t pulse_playback_callback = {
959         .start = pulse_start,
960         .stop = pulse_stop,
961         .drain = pulse_drain,
962         .pointer = pulse_pointer,
963         .transfer = pulse_write,
964         .delay = pulse_delay,
965         .poll_revents = pulse_pcm_poll_revents,
966         .prepare = pulse_prepare,
967         .hw_params = pulse_hw_params,
968         .sw_params = pulse_sw_params,
969         .close = pulse_close,
970         .pause = pulse_pause
971 };
972
973
974 static const snd_pcm_ioplug_callback_t pulse_capture_callback = {
975         .start = pulse_start,
976         .stop = pulse_stop,
977         .pointer = pulse_pointer,
978         .transfer = pulse_read,
979         .delay = pulse_delay,
980         .poll_revents = pulse_pcm_poll_revents,
981         .prepare = pulse_prepare,
982         .hw_params = pulse_hw_params,
983         .close = pulse_close,
984 };
985
986
987 static int pulse_hw_constraint(snd_pcm_pulse_t * pcm)
988 {
989         snd_pcm_ioplug_t *io = &pcm->io;
990
991         static const snd_pcm_access_t access_list[] = {
992                 SND_PCM_ACCESS_RW_INTERLEAVED
993         };
994         static const unsigned int formats[] = {
995                 SND_PCM_FORMAT_U8,
996                 SND_PCM_FORMAT_A_LAW,
997                 SND_PCM_FORMAT_MU_LAW,
998                 SND_PCM_FORMAT_S16_LE,
999                 SND_PCM_FORMAT_S16_BE,
1000                 SND_PCM_FORMAT_FLOAT_LE,
1001                 SND_PCM_FORMAT_FLOAT_BE,
1002                 SND_PCM_FORMAT_S32_LE,
1003                 SND_PCM_FORMAT_S32_BE,
1004                 SND_PCM_FORMAT_S24_3LE,
1005                 SND_PCM_FORMAT_S24_3BE,
1006                 SND_PCM_FORMAT_S24_LE,
1007                 SND_PCM_FORMAT_S24_BE
1008         };
1009
1010         int err;
1011
1012         err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
1013                                             ARRAY_SIZE(access_list),
1014                                             access_list);
1015         if (err < 0)
1016                 return err;
1017
1018         err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
1019                                             ARRAY_SIZE(formats), formats);
1020         if (err < 0)
1021                 return err;
1022
1023         err =
1024             snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
1025                                             1, PA_CHANNELS_MAX);
1026         if (err < 0)
1027                 return err;
1028
1029         err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,
1030                                               1, PA_RATE_MAX);
1031         if (err < 0)
1032                 return err;
1033
1034         err =
1035             snd_pcm_ioplug_set_param_minmax(io,
1036                                             SND_PCM_IOPLUG_HW_BUFFER_BYTES,
1037                                             1, 4 * 1024 * 1024);
1038         if (err < 0)
1039                 return err;
1040
1041         err =
1042             snd_pcm_ioplug_set_param_minmax(io,
1043                                             SND_PCM_IOPLUG_HW_PERIOD_BYTES,
1044                                             128, 2 * 1024 * 1024);
1045         if (err < 0)
1046                 return err;
1047
1048         err =
1049             snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS,
1050                                             3, 1024);
1051         if (err < 0)
1052                 return err;
1053         return 0;
1054 }
1055
1056 SND_PCM_PLUGIN_DEFINE_FUNC(pulse)
1057 {
1058         snd_config_iterator_t i, next;
1059         const char *server = NULL;
1060         const char *device = NULL;
1061         const char *fallback_name = NULL;
1062         int handle_underrun = DEFAULT_HANDLE_UNDERRUN;
1063         int err;
1064         snd_pcm_pulse_t *pcm;
1065
1066         snd_config_for_each(i, next, conf) {
1067                 snd_config_t *n = snd_config_iterator_entry(i);
1068                 const char *id;
1069                 if (snd_config_get_id(n, &id) < 0)
1070                         continue;
1071                 if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0
1072                     || strcmp(id, "hint") == 0)
1073                         continue;
1074                 if (strcmp(id, "server") == 0) {
1075                         if (snd_config_get_string(n, &server) < 0) {
1076                                 SNDERR("Invalid type for %s", id);
1077                                 return -EINVAL;
1078                         } else if (!*server) {
1079                                 server = NULL;
1080                         }
1081                         continue;
1082                 }
1083                 if (strcmp(id, "device") == 0) {
1084                         if (snd_config_get_string(n, &device) < 0) {
1085                                 SNDERR("Invalid type for %s", id);
1086                                 return -EINVAL;
1087                         } else if (!*device) {
1088                                 device = NULL;
1089                         }
1090                         continue;
1091                 }
1092                 if (strcmp(id, "handle_underrun") == 0) {
1093                         if ((err = snd_config_get_bool(n)) < 0) {
1094                                 SNDERR("Invalid value for %s", id);
1095                                 return -EINVAL;
1096                         }
1097                         handle_underrun = err;
1098                         continue;
1099                 }
1100                 if (strcmp(id, "fallback") == 0) {
1101                         if (snd_config_get_string(n, &fallback_name) < 0) {
1102                                 SNDERR("Invalid value for %s", id);
1103                                 return -EINVAL;
1104                         } else if (!*fallback_name) {
1105                                 fallback_name = NULL;
1106                         }
1107                         continue;
1108                 }
1109                 SNDERR("Unknown field %s", id);
1110                 return -EINVAL;
1111         }
1112
1113         if (fallback_name && name && !strcmp(name, fallback_name))
1114                 fallback_name = NULL; /* no fallback for the same name */
1115
1116         pcm = calloc(1, sizeof(*pcm));
1117         if (!pcm)
1118                 return -ENOMEM;
1119
1120         if (device) {
1121                 pcm->device = strdup(device);
1122
1123                 if (!pcm->device) {
1124                         err = -ENOMEM;
1125                         goto error;
1126                 }
1127         }
1128
1129         pcm->p = pulse_new();
1130         if (!pcm->p) {
1131                 err = -EIO;
1132                 goto error;
1133         }
1134
1135         pcm->handle_underrun = handle_underrun;
1136         pcm->buffer_attr.prebuf = -1;
1137
1138         err = pulse_connect(pcm->p, server, fallback_name != NULL);
1139         if (err < 0)
1140                 goto error;
1141
1142         pcm->io.version = SND_PCM_IOPLUG_VERSION;
1143         pcm->io.name = "ALSA <-> PulseAudio PCM I/O Plugin";
1144         pcm->io.poll_fd = pcm->p->main_fd;
1145         pcm->io.poll_events = POLLIN;
1146         pcm->io.mmap_rw = 0;
1147         pcm->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
1148             &pulse_playback_callback : &pulse_capture_callback;
1149         pcm->io.private_data = pcm;
1150
1151         err = snd_pcm_ioplug_create(&pcm->io, name, stream, mode);
1152         if (err < 0)
1153                 goto error;
1154
1155         err = pulse_hw_constraint(pcm);
1156         if (err < 0) {
1157                 snd_pcm_ioplug_delete(&pcm->io);
1158                 goto error2;
1159         }
1160
1161         *pcmp = pcm->io.pcm;
1162         return 0;
1163
1164 error:
1165         if (pcm->p)
1166                 pulse_free(pcm->p);
1167
1168         free(pcm->device);
1169         free(pcm);
1170
1171 error2:
1172         if (fallback_name)
1173                 return snd_pcm_open_fallback(pcmp, root, fallback_name, name,
1174                                              stream, mode);
1175
1176         return err;
1177 }
1178
1179 SND_PCM_PLUGIN_SYMBOL(pulse);