4
* ALSA <-> PulseAudio PCM I/O plugin
6
* Copyright (c) 2006 by Pierre Ossman <ossman@cendio.se>
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
#include <alsa/asoundlib.h>
27
#include <alsa/pcm_external.h>
31
typedef struct snd_pcm_pulse {
38
/* Since ALSA expects a ring buffer we must do some voodoo. */
50
pa_buffer_attr buffer_attr;
53
static int check_stream(snd_pcm_pulse_t *pcm)
56
pa_stream_state_t state;
63
err = pulse_check_connection(pcm->p);
70
state = pa_stream_get_state(pcm->stream);
71
if (!PA_STREAM_IS_GOOD(state))
79
static int update_ptr(snd_pcm_pulse_t *pcm)
83
if (pcm->io.stream == SND_PCM_STREAM_PLAYBACK)
84
size = pa_stream_writable_size(pcm->stream);
86
size = pa_stream_readable_size(pcm->stream);
88
if (size == (size_t) -1)
91
if (pcm->io.stream == SND_PCM_STREAM_CAPTURE)
94
/* Prevent accidental overrun of the fake ringbuffer */
95
if (size > pcm->buffer_attr.tlength - pcm->frame_size)
96
size = pcm->buffer_attr.tlength - pcm->frame_size;
98
if (size > pcm->last_size) {
99
pcm->ptr += size - pcm->last_size;
100
pcm->ptr %= pcm->buffer_attr.tlength;
103
pcm->last_size = size;
107
static int check_active(snd_pcm_pulse_t *pcm) {
111
* ALSA thinks in periods, not bytes, samples or frames.
114
if (pcm->io.stream == SND_PCM_STREAM_PLAYBACK) {
117
wsize = pa_stream_writable_size(pcm->stream);
119
if (wsize == (size_t) -1)
122
return wsize >= pcm->buffer_attr.minreq;
126
rsize = pa_stream_readable_size(pcm->stream);
128
if (rsize == (size_t) -1)
131
return rsize >= pcm->buffer_attr.fragsize;
135
static int update_active(snd_pcm_pulse_t *pcm) {
143
ret = check_stream(pcm);
147
ret = check_active(pcm);
151
if (ret != 0) /* On error signal the caller, too */
152
pulse_poll_activate(pcm->p);
154
pulse_poll_deactivate(pcm->p);
159
static int wait_stream_state(snd_pcm_pulse_t *pcm, pa_stream_state_t target)
161
pa_stream_state_t state;
171
err = pulse_check_connection(pcm->p);
178
state = pa_stream_get_state(pcm->stream);
182
if (!PA_STREAM_IS_GOOD(state))
185
pa_threaded_mainloop_wait(pcm->p->mainloop);
191
static void stream_success_cb(pa_stream * p, int success, void *userdata)
193
snd_pcm_pulse_t *pcm = userdata;
200
pa_threaded_mainloop_signal(pcm->p->mainloop, 0);
203
static int pulse_start(snd_pcm_ioplug_t * io)
205
snd_pcm_pulse_t *pcm = io->private_data;
207
int err = 0, err_o = 0, err_u = 0;
211
if (!pcm->p || !pcm->p->mainloop)
214
pa_threaded_mainloop_lock(pcm->p->mainloop);
216
err = check_stream(pcm);
220
o = pa_stream_cork(pcm->stream, 0, stream_success_cb, pcm);
226
u = pa_stream_trigger(pcm->stream, stream_success_cb, pcm);
229
err_o = pulse_wait_operation(pcm->p, o);
231
err_u = pulse_wait_operation(pcm->p, u);
233
pa_operation_unref(o);
235
pa_operation_unref(u);
237
if (err_o < 0 || err_u < 0) {
243
pa_threaded_mainloop_unlock(pcm->p->mainloop);
248
static int pulse_stop(snd_pcm_ioplug_t * io)
250
snd_pcm_pulse_t *pcm = io->private_data;
252
int err = 0, err_o = 0, err_u = 0;
256
if (!pcm->p || !pcm->p->mainloop)
259
pa_threaded_mainloop_lock(pcm->p->mainloop);
261
err = check_stream(pcm);
265
o = pa_stream_cork(pcm->stream, 1, stream_success_cb, pcm);
271
u = pa_stream_flush(pcm->stream, stream_success_cb, pcm);
273
pa_operation_unref(o);
278
err_o = pulse_wait_operation(pcm->p, o);
279
err_u = pulse_wait_operation(pcm->p, u);
281
pa_operation_unref(o);
282
pa_operation_unref(u);
284
if (err_o < 0 || err_u < 0) {
290
pa_threaded_mainloop_unlock(pcm->p->mainloop);
295
static int pulse_drain(snd_pcm_ioplug_t * io)
297
snd_pcm_pulse_t *pcm = io->private_data;
303
if (!pcm->p || !pcm->p->mainloop)
306
pa_threaded_mainloop_lock(pcm->p->mainloop);
308
err = check_stream(pcm);
312
o = pa_stream_drain(pcm->stream, stream_success_cb, pcm);
318
err = pulse_wait_operation(pcm->p, o);
320
pa_operation_unref(o);
328
pa_threaded_mainloop_unlock(pcm->p->mainloop);
333
static snd_pcm_sframes_t pulse_pointer(snd_pcm_ioplug_t * io)
335
snd_pcm_pulse_t *pcm = io->private_data;
336
snd_pcm_sframes_t ret = 0;
340
if (!pcm->p || !pcm->p->mainloop)
343
if (io->state == SND_PCM_STATE_XRUN)
346
if (io->state != SND_PCM_STATE_RUNNING)
349
pa_threaded_mainloop_lock(pcm->p->mainloop);
351
ret = check_stream(pcm);
360
ret = update_ptr(pcm);
369
ret = snd_pcm_bytes_to_frames(io->pcm, pcm->ptr);
373
pa_threaded_mainloop_unlock(pcm->p->mainloop);
378
static int pulse_delay(snd_pcm_ioplug_t * io, snd_pcm_sframes_t * delayp)
380
snd_pcm_pulse_t *pcm = io->private_data;
386
if (!pcm->p || !pcm->p->mainloop)
389
pa_threaded_mainloop_lock(pcm->p->mainloop);
392
err = check_stream(pcm);
396
err = pa_stream_get_latency(pcm->stream, &lat, NULL);
398
if (err != PA_ERR_NODATA) {
405
pa_threaded_mainloop_wait(pcm->p->mainloop);
409
snd_pcm_bytes_to_frames(io->pcm,
410
pa_usec_to_bytes(lat, &pcm->ss));
416
if (pcm->underrun && pcm->io.state == SND_PCM_STATE_RUNNING)
417
snd_pcm_ioplug_set_state(io, SND_PCM_STATE_XRUN);
419
pa_threaded_mainloop_unlock(pcm->p->mainloop);
424
static snd_pcm_sframes_t pulse_write(snd_pcm_ioplug_t * io,
425
const snd_pcm_channel_area_t * areas,
426
snd_pcm_uframes_t offset,
427
snd_pcm_uframes_t size)
429
snd_pcm_pulse_t *pcm = io->private_data;
431
snd_pcm_sframes_t ret = 0;
436
if (!pcm->p || !pcm->p->mainloop)
439
pa_threaded_mainloop_lock(pcm->p->mainloop);
441
ret = check_stream(pcm);
445
/* Make sure the buffer pointer is in sync */
446
ret = update_ptr(pcm);
451
(char *) areas->addr + (areas->first +
452
areas->step * offset) / 8;
454
writebytes = size * pcm->frame_size;
455
ret = pa_stream_write(pcm->stream, buf, writebytes, NULL, 0, 0);
461
/* Make sure the buffer pointer is in sync */
462
pcm->last_size -= writebytes;
463
ret = update_ptr(pcm);
468
ret = update_active(pcm);
476
pa_threaded_mainloop_unlock(pcm->p->mainloop);
481
static snd_pcm_sframes_t pulse_read(snd_pcm_ioplug_t * io,
482
const snd_pcm_channel_area_t * areas,
483
snd_pcm_uframes_t offset,
484
snd_pcm_uframes_t size)
486
snd_pcm_pulse_t *pcm = io->private_data;
488
size_t remain_size, frag_length;
489
snd_pcm_sframes_t ret = 0;
493
if (!pcm->p || !pcm->p->mainloop)
496
pa_threaded_mainloop_lock(pcm->p->mainloop);
498
ret = check_stream(pcm);
502
/* Make sure the buffer pointer is in sync */
503
ret = update_ptr(pcm);
507
remain_size = size * pcm->frame_size;
510
(char *) areas->addr + (areas->first +
511
areas->step * offset) / 8;
512
while (remain_size > 0) {
515
if (pa_stream_peek(pcm->stream, &src_buf, &frag_length) < 0) {
520
if (frag_length == 0)
523
src_buf = (char *) src_buf + pcm->offset;
524
frag_length -= pcm->offset;
526
if (frag_length > remain_size) {
527
pcm->offset += remain_size;
528
frag_length = remain_size;
532
memcpy(dst_buf, src_buf, frag_length);
534
if (pcm->offset == 0)
535
pa_stream_drop(pcm->stream);
537
dst_buf = (char *) dst_buf + frag_length;
538
remain_size -= frag_length;
539
pcm->last_size -= frag_length;
542
/* Make sure the buffer pointer is in sync */
543
ret = update_ptr(pcm);
547
ret = update_active(pcm);
551
ret = size - (remain_size / pcm->frame_size);
554
pa_threaded_mainloop_unlock(pcm->p->mainloop);
559
static void stream_state_cb(pa_stream * p, void *userdata)
561
snd_pcm_pulse_t *pcm = userdata;
562
pa_stream_state_t state;
569
state = pa_stream_get_state(p);
570
if (!PA_STREAM_IS_GOOD(state))
571
pulse_poll_activate(pcm->p);
573
pa_threaded_mainloop_signal(pcm->p->mainloop, 0);
576
static void stream_request_cb(pa_stream * p, size_t length, void *userdata)
578
snd_pcm_pulse_t *pcm = userdata;
588
static void stream_underrun_cb(pa_stream * p, void *userdata)
590
snd_pcm_pulse_t *pcm = userdata;
600
static void stream_latency_cb(pa_stream *p, void *userdata) {
601
snd_pcm_pulse_t *pcm = userdata;
608
pa_threaded_mainloop_signal(pcm->p->mainloop, 0);
611
static int pulse_pcm_poll_revents(snd_pcm_ioplug_t * io,
612
struct pollfd *pfd, unsigned int nfds,
613
unsigned short *revents)
616
snd_pcm_pulse_t *pcm = io->private_data;
620
if (!pcm->p || !pcm->p->mainloop)
623
pa_threaded_mainloop_lock(pcm->p->mainloop);
625
err = check_stream(pcm);
629
err = check_active(pcm);
634
*revents = io->stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
640
pa_threaded_mainloop_unlock(pcm->p->mainloop);
645
static int pulse_prepare(snd_pcm_ioplug_t * io)
648
snd_pcm_pulse_t *pcm = io->private_data;
654
if (!pcm->p || !pcm->p->mainloop)
657
pa_threaded_mainloop_lock(pcm->p->mainloop);
660
pa_stream_disconnect(pcm->stream);
661
wait_stream_state(pcm, PA_STREAM_TERMINATED);
662
pa_stream_unref(pcm->stream);
666
err = pulse_check_connection(pcm->p);
670
assert(pcm->stream == NULL);
672
for (c = pcm->ss.channels; c > 0; c--)
673
if (pa_channel_map_init_auto(&map, c, PA_CHANNEL_MAP_ALSA))
676
/* Extend if nessary */
677
for (d = c; d < pcm->ss.channels; d++)
678
map.map[d] = PA_CHANNEL_POSITION_AUX0+(d-c);
680
map.channels = pcm->ss.channels;
682
if (io->stream == SND_PCM_STREAM_PLAYBACK)
684
pa_stream_new(pcm->p->context, "ALSA Playback", &pcm->ss, &map);
687
pa_stream_new(pcm->p->context, "ALSA Capture", &pcm->ss, &map);
694
pa_stream_set_state_callback(pcm->stream, stream_state_cb, pcm);
695
pa_stream_set_latency_update_callback(pcm->stream, stream_latency_cb, pcm);
697
if (io->stream == SND_PCM_STREAM_PLAYBACK) {
698
pa_stream_set_write_callback(pcm->stream,
699
stream_request_cb, pcm);
700
if (pcm->handle_underrun)
701
pa_stream_set_underflow_callback(pcm->stream,
702
stream_underrun_cb, pcm);
703
r = pa_stream_connect_playback(pcm->stream, pcm->device,
705
PA_STREAM_AUTO_TIMING_UPDATE |
706
PA_STREAM_INTERPOLATE_TIMING
707
#ifdef PA_STREAM_EARLY_REQUESTS
708
| PA_STREAM_EARLY_REQUESTS
712
pa_stream_set_read_callback(pcm->stream, stream_request_cb,
714
r = pa_stream_connect_record(pcm->stream, pcm->device,
716
PA_STREAM_AUTO_TIMING_UPDATE |
717
PA_STREAM_INTERPOLATE_TIMING
718
#ifdef PA_STREAM_EARLY_REQUESTS
719
| PA_STREAM_EARLY_REQUESTS
725
SNDERR("PulseAudio: Unable to create stream: %s\n", pa_strerror(pa_context_errno(pcm->p->context)));
726
pa_stream_unref(pcm->stream);
732
err = wait_stream_state(pcm, PA_STREAM_READY);
734
SNDERR("PulseAudio: Unable to create stream: %s\n", pa_strerror(pa_context_errno(pcm->p->context)));
735
pa_stream_unref(pcm->stream);
743
/* Reset fake ringbuffer */
749
pa_threaded_mainloop_unlock(pcm->p->mainloop);
754
static int pulse_hw_params(snd_pcm_ioplug_t * io,
755
snd_pcm_hw_params_t * params)
757
snd_pcm_pulse_t *pcm = io->private_data;
762
if (!pcm->p || !pcm->p->mainloop)
765
pa_threaded_mainloop_lock(pcm->p->mainloop);
768
(snd_pcm_format_physical_width(io->format) * io->channels) / 8;
770
switch (io->format) {
771
case SND_PCM_FORMAT_U8:
772
pcm->ss.format = PA_SAMPLE_U8;
774
case SND_PCM_FORMAT_A_LAW:
775
pcm->ss.format = PA_SAMPLE_ALAW;
777
case SND_PCM_FORMAT_MU_LAW:
778
pcm->ss.format = PA_SAMPLE_ULAW;
780
case SND_PCM_FORMAT_S16_LE:
781
pcm->ss.format = PA_SAMPLE_S16LE;
783
case SND_PCM_FORMAT_S16_BE:
784
pcm->ss.format = PA_SAMPLE_S16BE;
786
#ifdef PA_SAMPLE_FLOAT32LE
787
case SND_PCM_FORMAT_FLOAT_LE:
788
pcm->ss.format = PA_SAMPLE_FLOAT32LE;
791
#ifdef PA_SAMPLE_FLOAT32BE
792
case SND_PCM_FORMAT_FLOAT_BE:
793
pcm->ss.format = PA_SAMPLE_FLOAT32BE;
796
#ifdef PA_SAMPLE_S32LE
797
case SND_PCM_FORMAT_S32_LE:
798
pcm->ss.format = PA_SAMPLE_S32LE;
801
#ifdef PA_SAMPLE_S32BE
802
case SND_PCM_FORMAT_S32_BE:
803
pcm->ss.format = PA_SAMPLE_S32BE;
807
SNDERR("PulseAudio: Unsupported format %s\n",
808
snd_pcm_format_name(io->format));
813
pcm->ss.rate = io->rate;
814
pcm->ss.channels = io->channels;
816
pcm->buffer_attr.maxlength =
818
pcm->buffer_attr.tlength =
819
io->buffer_size * pcm->frame_size;
820
pcm->buffer_attr.prebuf =
821
(io->buffer_size - io->period_size) * pcm->frame_size;
822
pcm->buffer_attr.minreq = io->period_size * pcm->frame_size;
823
pcm->buffer_attr.fragsize = io->period_size * pcm->frame_size;
826
pa_threaded_mainloop_unlock(pcm->p->mainloop);
831
static int pulse_close(snd_pcm_ioplug_t * io)
833
snd_pcm_pulse_t *pcm = io->private_data;
837
if (pcm->p && pcm->p->mainloop) {
839
pa_threaded_mainloop_lock(pcm->p->mainloop);
842
pa_stream_disconnect(pcm->stream);
843
pa_stream_unref(pcm->stream);
846
pa_threaded_mainloop_unlock(pcm->p->mainloop);
858
static int pulse_pause(snd_pcm_ioplug_t * io, int enable)
860
snd_pcm_pulse_t *pcm = io->private_data;
866
if (!pcm->p || !pcm->p->mainloop)
869
pa_threaded_mainloop_lock(pcm->p->mainloop);
871
err = check_stream(pcm);
875
o = pa_stream_cork(pcm->stream, enable, NULL, NULL);
877
pa_operation_unref(o);
882
pa_threaded_mainloop_unlock(pcm->p->mainloop);
887
static const snd_pcm_ioplug_callback_t pulse_playback_callback = {
888
.start = pulse_start,
890
.drain = pulse_drain,
891
.pointer = pulse_pointer,
892
.transfer = pulse_write,
893
.delay = pulse_delay,
894
.poll_revents = pulse_pcm_poll_revents,
895
.prepare = pulse_prepare,
896
.hw_params = pulse_hw_params,
897
.close = pulse_close,
902
static const snd_pcm_ioplug_callback_t pulse_capture_callback = {
903
.start = pulse_start,
905
.pointer = pulse_pointer,
906
.transfer = pulse_read,
907
.delay = pulse_delay,
908
.poll_revents = pulse_pcm_poll_revents,
909
.prepare = pulse_prepare,
910
.hw_params = pulse_hw_params,
911
.close = pulse_close,
915
static int pulse_hw_constraint(snd_pcm_pulse_t * pcm)
917
snd_pcm_ioplug_t *io = &pcm->io;
919
static const snd_pcm_access_t access_list[] = {
920
SND_PCM_ACCESS_RW_INTERLEAVED
922
static const unsigned int formats[] = {
924
SND_PCM_FORMAT_A_LAW,
925
SND_PCM_FORMAT_MU_LAW,
926
SND_PCM_FORMAT_S16_LE,
927
SND_PCM_FORMAT_S16_BE,
928
SND_PCM_FORMAT_FLOAT_LE,
929
SND_PCM_FORMAT_FLOAT_BE,
930
SND_PCM_FORMAT_S32_LE,
931
SND_PCM_FORMAT_S32_BE
936
err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
937
ARRAY_SIZE(access_list),
942
err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
943
ARRAY_SIZE(formats), formats);
948
snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
953
err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,
959
snd_pcm_ioplug_set_param_minmax(io,
960
SND_PCM_IOPLUG_HW_BUFFER_BYTES,
966
snd_pcm_ioplug_set_param_minmax(io,
967
SND_PCM_IOPLUG_HW_PERIOD_BYTES,
968
128, 2 * 1024 * 1024);
973
snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS,
980
SND_PCM_PLUGIN_DEFINE_FUNC(pulse)
982
snd_config_iterator_t i, next;
983
const char *server = NULL;
984
const char *device = NULL;
985
int handle_underrun = 0;
987
snd_pcm_pulse_t *pcm;
989
snd_config_for_each(i, next, conf) {
990
snd_config_t *n = snd_config_iterator_entry(i);
992
if (snd_config_get_id(n, &id) < 0)
994
if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0
995
|| strcmp(id, "hint") == 0)
997
if (strcmp(id, "server") == 0) {
998
if (snd_config_get_string(n, &server) < 0) {
999
SNDERR("Invalid type for %s", id);
1004
if (strcmp(id, "device") == 0) {
1005
if (snd_config_get_string(n, &device) < 0) {
1006
SNDERR("Invalid type for %s", id);
1011
if (strcmp(id, "handle_underrun") == 0) {
1012
if ((err = snd_config_get_bool(n)) < 0) {
1013
SNDERR("Invalid value for %s", id);
1016
handle_underrun = err;
1019
SNDERR("Unknown field %s", id);
1023
pcm = calloc(1, sizeof(*pcm));
1028
pcm->device = strdup(device);
1036
pcm->p = pulse_new();
1042
pcm->handle_underrun = handle_underrun;
1044
err = pulse_connect(pcm->p, server);
1048
pcm->io.version = SND_PCM_IOPLUG_VERSION;
1049
pcm->io.name = "ALSA <-> PulseAudio PCM I/O Plugin";
1050
pcm->io.poll_fd = pcm->p->main_fd;
1051
pcm->io.poll_events = POLLIN;
1052
pcm->io.mmap_rw = 0;
1053
pcm->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
1054
&pulse_playback_callback : &pulse_capture_callback;
1055
pcm->io.private_data = pcm;
1057
err = snd_pcm_ioplug_create(&pcm->io, name, stream, mode);
1061
err = pulse_hw_constraint(pcm);
1063
snd_pcm_ioplug_delete(&pcm->io);
1067
*pcmp = pcm->io.pcm;
1080
SND_PCM_PLUGIN_SYMBOL(pulse);