1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Sound Channel Process Functions - PulseAudio
4 Copyright (C) Krupen'ko Nikita <krnekit@gmail.com> 2010
5 Copyright (C) Henrik Andersson <hean01@cendio.com> 2017
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "rdesktop.h"
23 #include "rdpsnd.h"
24 #include "rdpsnd_dsp.h"
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <assert.h>
28 #include <errno.h>
29 #include <sys/time.h>
30
31 #include <pulse/version.h>
32
33 #ifndef PA_CHECK_VERSION
34 #define PA_CHECK_VERSION(major, minor, micro) (0)
35 #endif
36
37 #include <pulse/thread-mainloop.h>
38 #if PA_CHECK_VERSION(0,9,11)
39 #include <pulse/proplist.h>
40 #endif
41 #include <pulse/context.h>
42 #include <pulse/sample.h>
43 #include <pulse/stream.h>
44 #include <pulse/error.h>
45
46 #define DEFAULTDEVICE NULL
47
48 /* Messages that may be sent from the PulseAudio thread */
49 enum RDPSND_PULSE_MSG_TYPE
50 {
51 RDPSND_PULSE_OUT_AVAIL, // Output space available in output stream
52 RDPSND_PULSE_IN_AVAIL, // Input data available in input stream
53 RDPSND_PULSE_OUT_ERR, // An error occured in the output stream
54 RDPSND_PULSE_IN_ERR // An error occured in the input strem
55 };
56
57 static pa_threaded_mainloop *mainloop;
58 #if PA_CHECK_VERSION(0,9,11)
59 static pa_proplist *proplist;
60 #endif
61 static pa_context *context;
62 static pa_stream *playback_stream;
63 static pa_stream *capture_stream;
64 static int pulse_ctl[2] = { -1, -1 }; // Pipe for comminicating with main thread
65
66 /* Streams states for the possibility of the proper reinitialization */
67 static RD_BOOL playback_started = False;
68 static RD_BOOL capture_started = False;
69
70 /* Device's parameters */
71 static const char *device;
72 static int playback_channels;
73 static int playback_samplerate;
74 static int playback_samplewidth;
75 static int capture_channels;
76 static int capture_samplerate;
77 static int capture_samplewidth;
78
79 /* Internal audio buffer sizes (latency) */
80 static const int playback_latency_part = 10; // Playback latency (in part of second)
81 static const int capture_latency_part = 10; // Capture latency (in part of second)
82
83 /* Capture buffer */
84 static void *capture_buf = NULL;
85 static size_t capture_buf_size = 0;
86
87 static RD_BOOL pulse_init(void);
88 static void pulse_deinit(void);
89 static RD_BOOL pulse_context_init(void);
90 static void pulse_context_deinit(void);
91 static RD_BOOL pulse_stream_open(pa_stream ** stream, int channels, int samplerate, int samplewidth,
92 pa_stream_flags_t flags);
93 static void pulse_stream_close(pa_stream ** stream);
94
95 static void pulse_send_msg(int fd, char message);
96
97 static RD_BOOL pulse_playback_start(void);
98 static RD_BOOL pulse_playback_stop(void);
99 static RD_BOOL pulse_playback_set_audio(int channels, int samplerate, int samplewidth);
100 static RD_BOOL pulse_play(void);
101
102 static RD_BOOL pulse_capture_start(void);
103 static RD_BOOL pulse_capture_stop(void);
104 static RD_BOOL pulse_capture_set_audio(int channels, int samplerate, int samplewidth);
105 static RD_BOOL pulse_record(void);
106
107 static RD_BOOL pulse_recover(pa_stream ** stream);
108
109 /* Callbacks for the PulseAudio events */
110 static void pulse_context_state_cb(pa_context * c, void *userdata);
111 static void pulse_stream_state_cb(pa_stream * p, void *userdata);
112 static void pulse_write_cb(pa_stream *, size_t nbytes, void *userdata);
113 static void pulse_read_cb(pa_stream * p, size_t nbytes, void *userdata);
114
115 static void pulse_cork_cb(pa_stream * p, int success, void *userdata);
116 static void pulse_flush_cb(pa_stream * p, int success, void *userdata);
117 static void pulse_update_timing_cb(pa_stream * p, int success, void *userdata);
118
119 static RD_BOOL
pulse_init(void)120 pulse_init(void)
121 {
122 RD_BOOL ret = False;
123
124
125 do
126 {
127 /* PulsaAudio mainloop thread initialization */
128 mainloop = pa_threaded_mainloop_new();
129 if (mainloop == NULL)
130 {
131 logger(Sound, Error,
132 "pulse_init(), Error creating PulseAudio threaded mainloop");
133 break;
134 }
135 if (pa_threaded_mainloop_start(mainloop) != 0)
136 {
137 logger(Sound, Error,
138 "pulse_init(), Error starting PulseAudio threaded mainloop");
139 break;
140 }
141 #if PA_CHECK_VERSION(0,9,11)
142 /* PulseAudio proplist initialization */
143 proplist = pa_proplist_new();
144 if (proplist == NULL)
145 {
146 logger(Sound, Error, "pulse_init(), Error creating PulseAudio proplist");
147 break;
148 }
149 if (pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "rdesktop") != 0)
150 {
151 logger(Sound, Error,
152 "pulse_init(), Error setting option to PulseAudio proplist");
153 break;
154 }
155 #endif
156
157 if (pulse_context_init() != True)
158 break;
159
160 ret = True;
161 }
162 while (0);
163
164 if (ret != True)
165 pulse_deinit();
166
167 return ret;
168 }
169
170 static void
pulse_deinit(void)171 pulse_deinit(void)
172 {
173 pulse_stream_close(&capture_stream);
174 pulse_stream_close(&playback_stream);
175 pulse_context_deinit();
176 #if PA_CHECK_VERSION(0,9,11)
177 if (proplist != NULL)
178 {
179 pa_proplist_free(proplist);
180 proplist = NULL;
181 }
182 #endif
183 if (mainloop != NULL)
184 {
185 pa_threaded_mainloop_stop(mainloop);
186 pa_threaded_mainloop_free(mainloop);
187 mainloop = NULL;
188 }
189 }
190
191 static RD_BOOL
pulse_context_init(void)192 pulse_context_init(void)
193 {
194 pa_context_flags_t flags;
195 pa_context_state_t context_state;
196 int err;
197 RD_BOOL ret = False;
198
199
200 pa_threaded_mainloop_lock(mainloop);
201
202 do
203 {
204 /* Pipe for the control information from the audio thread */
205 if (pipe(pulse_ctl) != 0)
206 {
207 logger(Sound, Error, "pulse_context_init(), pipe: %s", strerror(errno));
208 pulse_ctl[0] = pulse_ctl[1] = -1;
209 break;
210 }
211 if (fcntl(pulse_ctl[0], F_SETFL, O_NONBLOCK) == -1)
212 {
213 logger(Sound, Error, "pulse_context_init(), fcntl: %s", strerror(errno));
214 break;
215 }
216 #if PA_CHECK_VERSION(0,9,11)
217 context =
218 pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mainloop), NULL,
219 proplist);
220 #else
221 context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "rdesktop");
222 #endif
223 if (context == NULL)
224 {
225 logger(Sound, Error,
226 "pulse_context_init(), error creating PulseAudio context");
227 break;
228 }
229 pa_context_set_state_callback(context, pulse_context_state_cb, mainloop);
230 /* PulseAudio context connection */
231 #if PA_CHECK_VERSION(0,9,15)
232 flags = PA_CONTEXT_NOFAIL;
233 #else
234 flags = 0;
235 #endif
236 if (pa_context_connect(context, NULL, flags, NULL) != 0)
237 {
238 err = pa_context_errno(context);
239 logger(Sound, Error, "pulse_context_init(), %s", pa_strerror(err));
240 break;
241 }
242 do
243 {
244 context_state = pa_context_get_state(context);
245 if (context_state == PA_CONTEXT_READY || context_state == PA_CONTEXT_FAILED)
246 break;
247 else
248 pa_threaded_mainloop_wait(mainloop);
249 }
250 while (1);
251 if (context_state != PA_CONTEXT_READY)
252 {
253 err = pa_context_errno(context);
254 logger(Sound, Error, "pulse_context_init(), %s", pa_strerror(err));
255 break;
256 }
257
258 ret = True;
259 }
260 while (0);
261
262 pa_threaded_mainloop_unlock(mainloop);
263
264 return ret;
265 }
266
267 static void
pulse_context_deinit(void)268 pulse_context_deinit(void)
269 {
270 int err;
271
272
273 if (context != NULL)
274 {
275 pa_threaded_mainloop_lock(mainloop);
276
277 pa_context_disconnect(context);
278 pa_context_unref(context);
279 context = NULL;
280
281 pa_threaded_mainloop_unlock(mainloop);
282 }
283
284 if (pulse_ctl[0] != -1)
285 {
286 do
287 err = close(pulse_ctl[0]);
288 while (err == -1 && errno == EINTR);
289 if (err == -1)
290 logger(Sound, Error, "pulse_context_deinit(), close: %s", strerror(errno));
291 pulse_ctl[0] = -1;
292 }
293 if (pulse_ctl[1] != -1)
294 {
295 do
296 err = close(pulse_ctl[1]);
297 while (err == -1 && errno == EINTR);
298 if (err == -1)
299 logger(Sound, Error, "pulse_context_deinit(), close: %s", strerror(errno));
300 pulse_ctl[1] = 0;
301 }
302 }
303
304 static RD_BOOL
pulse_stream_open(pa_stream ** stream,int channels,int samplerate,int samplewidth,pa_stream_flags_t flags)305 pulse_stream_open(pa_stream ** stream, int channels, int samplerate, int samplewidth,
306 pa_stream_flags_t flags)
307 {
308 pa_sample_spec samples;
309 pa_buffer_attr buffer_attr;
310 pa_stream_state_t state;
311 int err;
312 RD_BOOL ret = False;
313
314
315 assert(stream != NULL);
316 assert(stream == &playback_stream || stream == &capture_stream);
317
318 logger(Sound, Debug, "pulse_stream_open(), channels=%d, samplerate=%d, samplewidth=%d",
319 channels, samplerate, samplewidth);
320
321 pa_threaded_mainloop_lock(mainloop);
322
323 do
324 {
325 /* PulseAudio sample format initialization */
326 #if PA_CHECK_VERSION(0,9,13)
327 if (pa_sample_spec_init(&samples) == NULL)
328 {
329 logger(Sound, Error,
330 "pulse_stream_open(), error initializing PulseAudio sample format");
331 break;
332 }
333 #endif
334 if (samplewidth == 2)
335 samples.format = PA_SAMPLE_S16LE;
336 else if (samplewidth == 1)
337 samples.format = PA_SAMPLE_U8;
338 else
339 {
340 logger(Sound, Error,
341 "pulse_stream_open(), wrong samplewidth for the PulseAudio stream: %d",
342 samplewidth);
343 break;
344 }
345 samples.rate = samplerate;
346 samples.channels = channels;
347 if (!pa_sample_spec_valid(&samples))
348 {
349 logger(Sound, Error,
350 "pulse_stream_open(), Invalid PulseAudio sample format");
351 break;
352 }
353 /* PulseAudio stream creation */
354 #if PA_CHECK_VERSION(0,9,11)
355 if (stream == &playback_stream)
356 *stream =
357 pa_stream_new_with_proplist(context, "Playback Stream", &samples,
358 NULL, proplist);
359 else
360 *stream =
361 pa_stream_new_with_proplist(context, "Capture Stream", &samples,
362 NULL, proplist);
363 #else
364 if (stream == &playback_stream)
365 *stream = pa_stream_new(context, "Playback Stream", &samples, NULL);
366 else
367 *stream = pa_stream_new(context, "Capture Stream", &samples, NULL);
368 #endif
369 if (*stream == NULL)
370 {
371 err = pa_context_errno(context);
372 logger(Sound, Error, "pulse_stream_open(), pa_stream_new: %s",
373 pa_strerror(err));
374 break;
375 }
376 pa_stream_set_state_callback(*stream, pulse_stream_state_cb, mainloop);
377
378 buffer_attr.maxlength = (uint32_t) - 1;
379 buffer_attr.minreq = (uint32_t) - 1;
380 buffer_attr.prebuf = (uint32_t) - 1;
381 buffer_attr.tlength = (uint32_t) - 1;
382 buffer_attr.fragsize = (uint32_t) - 1;
383
384 /* PulseAudio stream connection */
385 if (stream == &playback_stream)
386 {
387 #if PA_CHECK_VERSION(0,9,0)
388 buffer_attr.tlength =
389 pa_usec_to_bytes(1000000 / playback_latency_part, &samples);
390 #else
391 buffer_attr.tlength =
392 (samples.rate / playback_latency_part) * samples.channels *
393 (samples.format == PA_SAMPLE_S16LE ? 2 : 1);
394 #endif
395 buffer_attr.prebuf = 0;
396 buffer_attr.maxlength = buffer_attr.tlength;
397 }
398 else
399 {
400 #if PA_CHECK_VERSION(0,9,0)
401 buffer_attr.fragsize =
402 pa_usec_to_bytes(1000000 / capture_latency_part, &samples);
403 #else
404 buffer_attr.fragsize =
405 (samples.rate / capture_latency_part) * samples.channels *
406 (samples.format == PA_SAMPLE_S16LE ? 2 : 1);
407 #endif
408 buffer_attr.maxlength = buffer_attr.fragsize;
409 }
410
411 #if !PA_CHECK_VERSION(0,9,16)
412 buffer_attr.minreq = (samples.rate / 50) * samples.channels * (samples.format == PA_SAMPLE_S16LE ? 2 : 1); // 20 ms
413 #endif
414
415 if (stream == &playback_stream)
416 err = pa_stream_connect_playback(*stream, device, &buffer_attr, flags, NULL,
417 NULL);
418 else
419 err = pa_stream_connect_record(*stream, device, &buffer_attr, flags);
420 if (err)
421 {
422 err = pa_context_errno(context);
423 logger(Sound, Error,
424 "pulse_stream_open(), error connecting PulseAudio stream: %s",
425 pa_strerror(err));
426 break;
427 }
428 do
429 {
430 state = pa_stream_get_state(*stream);
431 if (state == PA_STREAM_READY || state == PA_STREAM_FAILED)
432 break;
433 else
434 pa_threaded_mainloop_wait(mainloop);
435 }
436 while (1);
437 if (state != PA_STREAM_READY)
438 {
439 err = pa_context_errno(context);
440 logger(Sound, Error,
441 "pulse_stream_open(), error connecting PulseAudio stream: %s",
442 pa_strerror(err));
443 break;
444 }
445
446 #if PA_CHECK_VERSION(0,9,8)
447 logger(Sound, Debug, "pulse_stream_open(), opened PulseAudio stream on device %s",
448 pa_stream_get_device_name(*stream));
449 #endif
450 #if PA_CHECK_VERSION(0,9,0)
451 const pa_buffer_attr *res_ba;
452 res_ba = pa_stream_get_buffer_attr(*stream);
453 logger(Sound, Debug,
454 "pulse_stream_open(), PulseAudio stream buffer metrics: maxlength %u, minreq %u, prebuf %u, tlength %u, fragsize %u",
455 res_ba->maxlength, res_ba->minreq, res_ba->prebuf, res_ba->tlength,
456 res_ba->fragsize);
457 #endif
458
459 /* Set the data callbacks for the PulseAudio stream */
460 if (stream == &playback_stream)
461 pa_stream_set_write_callback(*stream, pulse_write_cb, mainloop);
462 else
463 pa_stream_set_read_callback(*stream, pulse_read_cb, mainloop);
464
465 ret = True;
466 }
467 while (0);
468
469 pa_threaded_mainloop_unlock(mainloop);
470
471 return ret;
472 }
473
474 static void
pulse_stream_close(pa_stream ** stream)475 pulse_stream_close(pa_stream ** stream)
476 {
477 pa_stream_state_t state;
478 int err;
479
480
481 assert(stream != NULL);
482
483 if (*stream != NULL)
484 {
485 pa_threaded_mainloop_lock(mainloop);
486
487 state = pa_stream_get_state(*stream);
488 if (state == PA_STREAM_READY)
489 {
490 if (pa_stream_disconnect(*stream) != 0)
491 {
492 err = pa_context_errno(context);
493 logger(Sound, Error,
494 "pulse_stream_close(), pa_stream_disconnect: %s\n",
495 pa_strerror(err));
496 }
497 }
498 pa_stream_unref(*stream);
499 *stream = NULL;
500
501 pa_threaded_mainloop_unlock(mainloop);
502 }
503 }
504
505 static void
pulse_send_msg(int fd,char message)506 pulse_send_msg(int fd, char message)
507 {
508 int ret;
509
510
511 do
512 ret = write(fd, &message, sizeof message);
513 while (ret == -1 && errno == EINTR);
514 if (ret == -1)
515 logger(Sound, Error, "pulse_send_msg(), error writing message to the pipe: %s\n",
516 strerror(errno));
517 }
518
519 static RD_BOOL
pulse_playback_start(void)520 pulse_playback_start(void)
521 {
522 RD_BOOL result = False;
523 int ret;
524 int err;
525 pa_operation *po;
526
527
528 if (playback_stream == NULL)
529 {
530 logger(Sound, Warning,
531 "pulse_playback_start(), trying to start PulseAudio stream while it's not exists");
532 return True;
533 }
534
535 pa_threaded_mainloop_lock(mainloop);
536
537 do
538 {
539 if (pa_stream_get_state(playback_stream) != PA_STREAM_READY)
540 {
541 logger(Sound, Warning,
542 "pulse_playback_start(), trying to start PulseAudio stream while it's not ready");
543 break;
544 }
545 #if PA_CHECK_VERSION(0,9,11)
546 ret = pa_stream_is_corked(playback_stream);
547 #else
548 ret = 1;
549 #endif
550 if (ret < 0)
551 {
552 err = pa_context_errno(context);
553 logger(Sound, Error, "pulse_playback_start(), pa_stream_is_corked: %s",
554 pa_strerror(err));
555 break;
556 }
557 else if (ret != 0)
558 {
559 po = pa_stream_cork(playback_stream, 0, pulse_cork_cb, mainloop);
560 if (po == NULL)
561 {
562 err = pa_context_errno(context);
563 logger(Sound, Error, "pulse_playback_start(), pa_stream_corked: %s",
564 pa_strerror(err));
565 break;
566 }
567 while (pa_operation_get_state(po) == PA_OPERATION_RUNNING)
568 pa_threaded_mainloop_wait(mainloop);
569 pa_operation_unref(po);
570 }
571
572 result = True;
573 }
574 while (0);
575
576 pa_threaded_mainloop_unlock(mainloop);
577
578 return result;
579 }
580
581 static RD_BOOL
pulse_playback_stop(void)582 pulse_playback_stop(void)
583 {
584 RD_BOOL result = False;
585 int ret;
586 int err;
587 pa_operation *po;
588
589
590 if (playback_stream == NULL)
591 {
592 logger(Sound, Debug,
593 "pulse_playback_stop(), trying to stop PulseAudio stream while it's not exists");
594 return True;
595 }
596
597 pa_threaded_mainloop_lock(mainloop);
598
599 do
600 {
601 if (pa_stream_get_state(playback_stream) != PA_STREAM_READY)
602 {
603 logger(Sound, Error,
604 "pulse_playback_stop(), trying to stop PulseAudio stream while it's not ready");
605 break;
606 }
607 #if PA_CHECK_VERSION(0,9,11)
608 ret = pa_stream_is_corked(playback_stream);
609 #else
610 ret = 0;
611 #endif
612 if (ret < 0)
613 {
614 err = pa_context_errno(context);
615 logger(Sound, Error, "pulse_playback_stop(), pa_stream_is_corked: %s",
616 pa_strerror(err));
617 break;
618 }
619 else if (ret == 0)
620 {
621 po = pa_stream_cork(playback_stream, 1, pulse_cork_cb, mainloop);
622 if (po == NULL)
623 {
624 err = pa_context_errno(context);
625 logger(Sound, Error, "pulse_playback_stop(), pa_stream_cork: %s",
626 pa_strerror(err));
627 break;
628 }
629 while (pa_operation_get_state(po) == PA_OPERATION_RUNNING)
630 pa_threaded_mainloop_wait(mainloop);
631 pa_operation_unref(po);
632 }
633 po = pa_stream_flush(playback_stream, pulse_flush_cb, mainloop);
634 if (po == NULL)
635 {
636 err = pa_context_errno(context);
637 logger(Sound, Error, "pulse_playback_stop(), pa_stream_flush: %s",
638 pa_strerror(err));
639 break;
640 }
641 while (pa_operation_get_state(po) == PA_OPERATION_RUNNING)
642 pa_threaded_mainloop_wait(mainloop);
643 pa_operation_unref(po);
644
645 result = True;
646 }
647 while (0);
648
649 pa_threaded_mainloop_unlock(mainloop);
650
651 return result;
652 }
653
654 static RD_BOOL
pulse_playback_set_audio(int channels,int samplerate,int samplewidth)655 pulse_playback_set_audio(int channels, int samplerate, int samplewidth)
656 {
657 pa_stream_flags_t flags;
658
659
660 pulse_stream_close(&playback_stream);
661
662 flags = PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING |
663 PA_STREAM_AUTO_TIMING_UPDATE;
664 #if PA_CHECK_VERSION(0,9,11)
665 flags |= PA_STREAM_ADJUST_LATENCY;
666 #endif
667 if (pulse_stream_open(&playback_stream, channels, samplerate, samplewidth, flags) != True)
668 return False;
669
670 return True;
671 }
672
673 static RD_BOOL
pulse_capture_start(void)674 pulse_capture_start(void)
675 {
676 RD_BOOL result = False;
677 int ret;
678 int err;
679 pa_operation *po;
680
681
682 if (capture_stream == NULL)
683 {
684 logger(Sound, Warning,
685 "pulse_capture_start(), trying to start PulseAudio stream while it's not exists");
686 return True;
687 }
688
689 pa_threaded_mainloop_lock(mainloop);
690
691 do
692 {
693 if (pa_stream_get_state(capture_stream) != PA_STREAM_READY)
694 {
695 logger(Sound, Error,
696 "pulse_capture_start(), trying to start PulseAudio stream while it's not exists");
697 break;
698 }
699 #if PA_CHECK_VERSION(0,9,11)
700 ret = pa_stream_is_corked(capture_stream);
701 #else
702 ret = 1;
703 #endif
704 if (ret < 0)
705 {
706 err = pa_context_errno(context);
707 logger(Sound, Error, "pulse_capture_start(), pa_stream_is_corked: %s",
708 pa_strerror(err));
709 break;
710 }
711 else if (ret != 0)
712 {
713 po = pa_stream_cork(capture_stream, 0, pulse_cork_cb, mainloop);
714 if (po == NULL)
715 {
716 err = pa_context_errno(context);
717 logger(Sound, Error, "pulse_capture_start(), pa_stream_cork: %s\n",
718 pa_strerror(err));
719 break;
720 }
721 while (pa_operation_get_state(po) == PA_OPERATION_RUNNING)
722 pa_threaded_mainloop_wait(mainloop);
723 pa_operation_unref(po);
724 }
725
726 result = True;
727 }
728 while (0);
729
730 pa_threaded_mainloop_unlock(mainloop);
731
732 return result;
733 }
734
735 static RD_BOOL
pulse_capture_stop(void)736 pulse_capture_stop(void)
737 {
738 RD_BOOL result = False;
739 int ret;
740 int err;
741 pa_operation *po;
742
743
744 if (capture_stream == NULL)
745 {
746 logger(Sound, Debug,
747 "pulse_capture_stop(), trying to stop PulseAudio stream while it's not exists");
748 return True;
749 }
750
751 pa_threaded_mainloop_lock(mainloop);
752
753 do
754 {
755 if (pa_stream_get_state(capture_stream) != PA_STREAM_READY)
756 {
757 logger(Sound, Error,
758 "pulse_capture_stop(), trying to stop PulseAudio stream while it's not exists");
759 break;
760 }
761 #if PA_CHECK_VERSION(0,9,11)
762 ret = pa_stream_is_corked(capture_stream);
763 #else
764 ret = 0;
765 #endif
766 if (ret < 0)
767 {
768 err = pa_context_errno(context);
769 logger(Sound, Error, "pulse_capture_stop(), pa_stream_is_corked: %s\n",
770 pa_strerror(err));
771 break;
772 }
773 else if (ret == 0)
774 {
775 po = pa_stream_cork(capture_stream, 1, pulse_cork_cb, mainloop);
776 if (po == NULL)
777 {
778 err = pa_context_errno(context);
779 logger(Sound, Error, "pulse_capture_stop(), pa_stream_cork: %s\n",
780 pa_strerror(err));
781 break;
782 }
783 while (pa_operation_get_state(po) == PA_OPERATION_RUNNING)
784 pa_threaded_mainloop_wait(mainloop);
785 pa_operation_unref(po);
786 }
787
788 result = True;
789 }
790 while (0);
791
792 pa_threaded_mainloop_unlock(mainloop);
793
794 return result;
795 }
796
797 static RD_BOOL
pulse_capture_set_audio(int channels,int samplerate,int samplewidth)798 pulse_capture_set_audio(int channels, int samplerate, int samplewidth)
799 {
800 pa_stream_flags_t flags;
801 pa_stream_state_t state;
802 int ret;
803 int err;
804
805
806 flags = PA_STREAM_START_CORKED;
807 #if PA_CHECK_VERSION(0,9,11)
808 flags |= PA_STREAM_ADJUST_LATENCY;
809 #endif
810
811 if (capture_stream != NULL)
812 {
813 pa_threaded_mainloop_lock(mainloop);
814 state = pa_stream_get_state(capture_stream);
815 if (state == PA_STREAM_READY)
816 {
817 #if PA_CHECK_VERSION(0,9,11)
818 ret = pa_stream_is_corked(capture_stream);
819 #else
820 ret = (capture_started == False);
821 #endif
822 if (ret == 0)
823 flags &= ~PA_STREAM_START_CORKED;
824 else if (ret < 0)
825 {
826 err = pa_context_errno(context);
827 pa_threaded_mainloop_unlock(mainloop);
828 logger(Sound, Error,
829 "pulse_capture_set_audio(), pa_stream_is_corked: %s\n",
830 pa_strerror(err));
831 return False;
832 }
833 }
834 pa_threaded_mainloop_unlock(mainloop);
835 }
836
837 pulse_stream_close(&capture_stream);
838
839 if (pulse_stream_open(&capture_stream, channels, samplerate, samplewidth, flags) != True)
840 return False;
841
842 return True;
843 }
844
845 static void
pulse_context_state_cb(pa_context * c,void * userdata)846 pulse_context_state_cb(pa_context * c, void *userdata)
847 {
848 pa_context_state_t state;
849
850
851 assert(userdata != NULL);
852
853 state = pa_context_get_state(c);
854 if (state == PA_CONTEXT_READY || state == PA_CONTEXT_FAILED)
855 pa_threaded_mainloop_signal((pa_threaded_mainloop *) userdata, 0);
856 }
857
858 static void
pulse_stream_state_cb(pa_stream * p,void * userdata)859 pulse_stream_state_cb(pa_stream * p, void *userdata)
860 {
861 pa_stream_state_t state;
862
863
864 assert(userdata != NULL);
865
866 state = pa_stream_get_state(p);
867 if (state == PA_STREAM_FAILED)
868 {
869 if (p == playback_stream)
870 {
871 logger(Sound, Debug,
872 "pulse_stream_state_cb(), PulseAudio playback stream is in a fail state");
873 pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_OUT_ERR);
874 }
875 else
876 {
877 logger(Sound, Debug,
878 "pulse_stream_state_cb(), PulseAudio capture stream is in a fail state");
879 pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_IN_ERR);
880 }
881 }
882 if (state == PA_STREAM_READY || state == PA_STREAM_FAILED)
883 pa_threaded_mainloop_signal((pa_threaded_mainloop *) userdata, 0);
884 }
885
886 static void
pulse_read_cb(pa_stream * p,size_t nbytes,void * userdata)887 pulse_read_cb(pa_stream * p, size_t nbytes, void *userdata)
888 {
889 assert(userdata != NULL);
890
891 pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_IN_AVAIL);
892 }
893
894 static void
pulse_write_cb(pa_stream * p,size_t nbytes,void * userdata)895 pulse_write_cb(pa_stream * p, size_t nbytes, void *userdata)
896 {
897 assert(userdata != NULL);
898
899 pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_OUT_AVAIL);
900 }
901
902 static void
pulse_cork_cb(pa_stream * p,int success,void * userdata)903 pulse_cork_cb(pa_stream * p, int success, void *userdata)
904 {
905 assert(userdata != NULL);
906
907 if (!success)
908 {
909 if (p == playback_stream)
910 {
911 logger(Sound, Warning,
912 "pulse_cork_cb(), fail to cork/uncork the PulseAudio playback stream: %s",
913 pa_strerror(pa_context_errno(context)));
914 pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_OUT_ERR);
915 }
916 else
917 {
918 logger(Sound, Warning,
919 "pulse_cork_cb(), fail to cork/uncork the PulseAudio capture stream: %s",
920 pa_strerror(pa_context_errno(context)));
921 pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_IN_ERR);
922 }
923 }
924
925 pa_threaded_mainloop_signal((pa_threaded_mainloop *) userdata, 0);
926 }
927
928 static void
pulse_flush_cb(pa_stream * p,int success,void * userdata)929 pulse_flush_cb(pa_stream * p, int success, void *userdata)
930 {
931 assert(userdata != NULL);
932
933 if (!success)
934 {
935 logger(Sound, Warning, "pulse_flush_cb(), Fail to flush the PulseAudio stream: %s",
936 pa_strerror(pa_context_errno(context)));
937 pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_OUT_ERR);
938 }
939
940 pa_threaded_mainloop_signal((pa_threaded_mainloop *) userdata, 0);
941 }
942
943 static void
pulse_update_timing_cb(pa_stream * p,int success,void * userdata)944 pulse_update_timing_cb(pa_stream * p, int success, void *userdata)
945 {
946 assert(userdata != NULL);
947
948 if (!success)
949 {
950 logger(Sound, Warning,
951 "pulse_update_timing_cb(), fail to update timing info of the PulseAudio stream: %s",
952 pa_strerror(pa_context_errno(context)));
953 pulse_send_msg(pulse_ctl[1], RDPSND_PULSE_OUT_ERR);
954 }
955
956 pa_threaded_mainloop_signal((pa_threaded_mainloop *) userdata, 0);
957 }
958
959 void
pulse_add_fds(int * n,fd_set * rfds,fd_set * wfds,struct timeval * tv)960 pulse_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
961 {
962 if (pulse_ctl[0] != -1)
963 {
964 if (pulse_ctl[0] > *n)
965 *n = pulse_ctl[0];
966
967 FD_SET(pulse_ctl[0], rfds);
968 }
969 }
970
971 void
pulse_check_fds(fd_set * rfds,fd_set * wfds)972 pulse_check_fds(fd_set * rfds, fd_set * wfds)
973 {
974 char audio_cmd;
975 int n;
976
977
978 if (pulse_ctl[0] == -1)
979 return;
980
981 if (FD_ISSET(pulse_ctl[0], rfds))
982 {
983 do
984 {
985 n = read(pulse_ctl[0], &audio_cmd, sizeof audio_cmd);
986 if (n == -1)
987 {
988 if (errno == EINTR)
989 continue;
990 else if (errno == EAGAIN || errno == EWOULDBLOCK)
991 break;
992 else
993 {
994 logger(Sound, Error, "pulse_check_fds(), read: %s\n",
995 strerror(errno));
996 return;
997 }
998 }
999 else if (n == 0)
1000 {
1001 logger(Sound, Warning,
1002 "pulse_check_fds(), audio control pipe was closed");
1003 break;
1004 }
1005 else
1006 switch (audio_cmd)
1007 {
1008 case RDPSND_PULSE_OUT_AVAIL:
1009 if (pulse_play() != True)
1010 if (pulse_recover(&playback_stream) != True)
1011 {
1012 logger(Sound, Error,
1013 "pulse_check_fds(), PulseAudio playback error");
1014 return;
1015 }
1016 break;
1017 case RDPSND_PULSE_IN_AVAIL:
1018 if (pulse_record() != True)
1019 if (pulse_recover(&capture_stream) != True)
1020 {
1021 logger(Sound, Error,
1022 "pulse_check_fds(), PulseAudio capture error");
1023 return;
1024 }
1025 break;
1026 case RDPSND_PULSE_OUT_ERR:
1027 if (pulse_recover(&playback_stream) != True)
1028 {
1029 logger(Sound, Error,
1030 "pulse_check_fds(), an error occured in audio thread with PulseAudio playback stream");
1031 return;
1032 }
1033 break;
1034 case RDPSND_PULSE_IN_ERR:
1035 if (pulse_recover(&capture_stream) != True)
1036 {
1037 logger(Sound, Error,
1038 "pulse_check_fds(), an error occured in audio thread with PulseAudio capture stream");
1039 return;
1040 }
1041 break;
1042 default:
1043 logger(Sound, Error,
1044 "pulse_check_fds(), wrong command from the audio thread: %d",
1045 audio_cmd);
1046 break;
1047 }
1048 }
1049 while (1);
1050 }
1051
1052 return;
1053 }
1054
1055 RD_BOOL
pulse_open_out(void)1056 pulse_open_out(void)
1057 {
1058 if (context == NULL || mainloop == NULL)
1059 if (pulse_init() != True)
1060 return False;
1061
1062 return True;
1063 }
1064
1065 void
pulse_close_out(void)1066 pulse_close_out(void)
1067 {
1068 /* Ack all remaining packets */
1069 while (!rdpsnd_queue_empty())
1070 rdpsnd_queue_next(0);
1071
1072 playback_started = False;
1073
1074 if (playback_stream && pulse_playback_stop() != True)
1075 if (pulse_recover(&playback_stream) != True)
1076 {
1077 logger(Sound, Error,
1078 "pulse_close_out(), fail to close the PulseAudio playback stream");
1079 return;
1080 }
1081 }
1082
1083 RD_BOOL
pulse_format_supported(RD_WAVEFORMATEX * pwfx)1084 pulse_format_supported(RD_WAVEFORMATEX * pwfx)
1085 {
1086 if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
1087 return False;
1088 if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
1089 return False;
1090 if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
1091 return False;
1092
1093 return True;
1094 }
1095
1096 RD_BOOL
pulse_set_format_out(RD_WAVEFORMATEX * pwfx)1097 pulse_set_format_out(RD_WAVEFORMATEX * pwfx)
1098 {
1099 if (playback_stream == NULL
1100 || playback_channels != pwfx->nChannels
1101 || playback_samplerate != pwfx->nSamplesPerSec
1102 || playback_samplewidth != pwfx->wBitsPerSample / 8)
1103 {
1104 playback_channels = pwfx->nChannels;
1105 playback_samplerate = pwfx->nSamplesPerSec;
1106 playback_samplewidth = pwfx->wBitsPerSample / 8;
1107
1108 if (pulse_playback_set_audio
1109 (pwfx->nChannels, pwfx->nSamplesPerSec, pwfx->wBitsPerSample / 8) != True)
1110 if (pulse_recover(&playback_stream) != True)
1111 {
1112 logger(Sound, Error,
1113 "pulse_set_format_out(), fail to open the PulseAudio playback stream");
1114 return False;
1115 }
1116 }
1117
1118 playback_started = True;
1119
1120 if (pulse_playback_start() != True)
1121 if (pulse_recover(&playback_stream) != True)
1122 {
1123 logger(Sound, Error,
1124 "pulse_set_format_out(), fail to start the PulseAudio playback stream");
1125 return False;
1126 }
1127
1128 return True;
1129 }
1130
1131 RD_BOOL
pulse_play(void)1132 pulse_play(void)
1133 {
1134 struct audio_packet *packet;
1135 STREAM out;
1136 const pa_timing_info *ti;
1137 pa_operation *po;
1138 pa_seek_mode_t playback_seek;
1139 size_t avail_space, audio_size;
1140 pa_usec_t delay = 0;
1141 int ret;
1142 int err;
1143 RD_BOOL result = False;
1144
1145
1146 if (rdpsnd_queue_empty())
1147 return True;
1148
1149 if (playback_stream == NULL)
1150 return False;
1151
1152 pa_threaded_mainloop_lock(mainloop);
1153
1154 do
1155 {
1156 packet = rdpsnd_queue_current_packet();
1157 out = packet->s;
1158
1159 ti = pa_stream_get_timing_info(playback_stream);
1160 if (ti == NULL)
1161 {
1162 err = pa_context_errno(context);
1163 logger(Sound, Error, "pulse_play(), pa_stream_get_timing_info: %s",
1164 pa_strerror(err));
1165 break;
1166 }
1167
1168 if (ti->read_index_corrupt || ti->write_index_corrupt)
1169 {
1170 po = pa_stream_update_timing_info(playback_stream, pulse_update_timing_cb,
1171 mainloop);
1172 if (po == NULL)
1173 {
1174 err = pa_context_errno(context);
1175 logger(Sound, Error,
1176 "pulse_play(), pa_stream_update_timing_info: %s",
1177 pa_strerror(err));
1178 break;
1179 }
1180 while (pa_operation_get_state(po) == PA_OPERATION_RUNNING)
1181 pa_threaded_mainloop_wait(mainloop);
1182 pa_operation_unref(po);
1183 }
1184
1185 if (ti->read_index > ti->write_index)
1186 {
1187 logger(Sound, Debug, "pulse_play(), PulseAudio stream underflow %ld bytes",
1188 (long) (ti->read_index - ti->write_index));
1189 playback_seek = PA_SEEK_RELATIVE_ON_READ;
1190 }
1191 else
1192 playback_seek = PA_SEEK_RELATIVE;
1193
1194 avail_space = pa_stream_writable_size(playback_stream);
1195 audio_size = MIN(s_remaining(out), avail_space);
1196 if (audio_size)
1197 {
1198 unsigned char *data;
1199
1200 in_uint8p(out, data, audio_size);
1201 if (pa_stream_write
1202 (playback_stream, data, audio_size, NULL, 0, playback_seek) != 0)
1203 {
1204 err = pa_context_errno(context);
1205 logger(Sound, Error, "pulse_play(), pa_stream_write: %s",
1206 pa_strerror(err));
1207 break;
1208 }
1209 else if (playback_seek == PA_SEEK_RELATIVE_ON_READ)
1210 playback_seek = PA_SEEK_RELATIVE;
1211 }
1212
1213 if (s_check_end(out))
1214 {
1215 ret = pa_stream_get_latency(playback_stream, &delay, NULL);
1216 if (ret != 0 && (err = pa_context_errno(context)) == PA_ERR_NODATA)
1217 {
1218 po = pa_stream_update_timing_info(playback_stream,
1219 pulse_update_timing_cb, mainloop);
1220 if (po == NULL)
1221 {
1222 delay = 0;
1223 err = pa_context_errno(context);
1224 logger(Sound, Error,
1225 "pulse_play(), pa_stream_update_timing_info: %s",
1226 pa_strerror(err));
1227 break;
1228 }
1229 while (pa_operation_get_state(po) == PA_OPERATION_RUNNING)
1230 pa_threaded_mainloop_wait(mainloop);
1231 pa_operation_unref(po);
1232
1233 ret = pa_stream_get_latency(playback_stream, &delay, NULL);
1234 }
1235 if (ret != 0)
1236 {
1237 delay = 0;
1238 err = pa_context_errno(context);
1239 logger(Sound, Error, "pulse_play(), pa_stream_get_latency: %s",
1240 pa_strerror(err));
1241 break;
1242 }
1243
1244 logger(Sound, Debug,
1245 "pulse_play(), PulseAudio playback stream latency %lu usec",
1246 (long) delay);
1247 }
1248
1249 result = True;
1250 }
1251 while (0);
1252
1253 pa_threaded_mainloop_unlock(mainloop);
1254
1255 if (s_check_end(out))
1256 rdpsnd_queue_next(delay);
1257
1258 return result;
1259 }
1260
1261 RD_BOOL
pulse_open_in(void)1262 pulse_open_in(void)
1263 {
1264 if (context == NULL || mainloop == NULL)
1265 if (pulse_init() != True)
1266 return False;
1267
1268 return True;
1269 }
1270
1271 void
pulse_close_in(void)1272 pulse_close_in(void)
1273 {
1274 capture_started = False;
1275
1276 if (capture_stream && pulse_capture_stop() != True)
1277 if (pulse_recover(&capture_stream) != True)
1278 {
1279 logger(Sound, Error,
1280 "pulse_close_in(), fail to close the PulseAudio capture stream");
1281 return;
1282 }
1283 }
1284
1285 RD_BOOL
pulse_set_format_in(RD_WAVEFORMATEX * pwfx)1286 pulse_set_format_in(RD_WAVEFORMATEX * pwfx)
1287 {
1288 if (capture_stream == NULL
1289 || capture_channels != pwfx->nChannels
1290 || capture_samplerate != pwfx->nSamplesPerSec
1291 || capture_samplewidth != pwfx->wBitsPerSample / 8)
1292 {
1293 capture_channels = pwfx->nChannels;
1294 capture_samplerate = pwfx->nSamplesPerSec;
1295 capture_samplewidth = pwfx->wBitsPerSample / 8;
1296
1297 if (pulse_capture_set_audio
1298 (pwfx->nChannels, pwfx->nSamplesPerSec, pwfx->wBitsPerSample / 8) != True)
1299 if (pulse_recover(&capture_stream) != True)
1300 {
1301 logger(Sound, Error,
1302 "pulse_set_format_in(), fail to open the PulseAudio capture stream");
1303 return False;
1304 }
1305 }
1306
1307 capture_started = True;
1308
1309 if (pulse_capture_start() != True)
1310 if (pulse_recover(&capture_stream) != True)
1311 {
1312 logger(Sound, Error,
1313 "pulse_set_format_in(), fail to start the PulseAudio capture stream");
1314 return False;
1315 }
1316
1317 return True;
1318 }
1319
1320 RD_BOOL
pulse_record(void)1321 pulse_record(void)
1322 {
1323 const void *pulse_buf;
1324 size_t audio_size;
1325 RD_BOOL result = False;
1326
1327
1328 if (capture_stream == NULL)
1329 return False;
1330
1331 pa_threaded_mainloop_lock(mainloop);
1332
1333 do
1334 {
1335 if (pa_stream_peek(capture_stream, &pulse_buf, &audio_size) != 0)
1336 {
1337 logger(Sound, Error, "pulse_record(), pa_stream_peek: %s",
1338 pa_strerror(pa_context_errno(context)));
1339 break;
1340 }
1341
1342 /* Stretch the buffer, if needed */
1343 if (capture_buf_size < audio_size)
1344 {
1345 capture_buf_size = audio_size;
1346 if (capture_buf != NULL)
1347 free(capture_buf);
1348 capture_buf = malloc(capture_buf_size);
1349 if (capture_buf == NULL)
1350 {
1351 logger(Sound, Error, "pulse_record(), malloc error");
1352 capture_buf_size = 0;
1353 break;
1354 }
1355 }
1356
1357 memcpy(capture_buf, pulse_buf, audio_size);
1358
1359 if (pa_stream_drop(capture_stream) != 0)
1360 {
1361 logger(Sound, Error, "pulse_record(), pa_stream_drop: %s",
1362 pa_strerror(pa_context_errno(context)));
1363 break;
1364 }
1365
1366 result = True;
1367 }
1368 while (0);
1369
1370 pa_threaded_mainloop_unlock(mainloop);
1371
1372 if (result == True)
1373 rdpsnd_record(capture_buf, audio_size);
1374
1375 return result;
1376 }
1377
1378 static RD_BOOL
pulse_recover(pa_stream ** stream)1379 pulse_recover(pa_stream ** stream)
1380 {
1381 RD_BOOL playback, capture;
1382
1383
1384 playback = capture = False;
1385
1386 if (playback_stream != NULL)
1387 playback = True;
1388 if (capture_stream != NULL)
1389 capture = True;
1390
1391 if (stream == &playback_stream)
1392 {
1393 if (pulse_playback_set_audio
1394 (playback_channels, playback_samplerate, playback_samplewidth) == True)
1395 if (playback_started != True || pulse_playback_start() == True)
1396 return True;
1397 }
1398 else if (stream == &capture_stream)
1399 {
1400 if (pulse_capture_set_audio
1401 (capture_channels, capture_samplerate, capture_samplewidth) == True)
1402 if (capture_started != True || pulse_capture_start() == True)
1403 return True;
1404 }
1405
1406 pulse_deinit();
1407
1408 if (pulse_init() != True)
1409 return False;
1410
1411 do
1412 {
1413 if (playback == True)
1414 {
1415 if (pulse_playback_set_audio
1416 (playback_channels, playback_samplerate, playback_samplewidth) != True
1417 || (playback_started == True && pulse_playback_start() != True))
1418 break;
1419 }
1420 if (capture == True)
1421 {
1422 if (pulse_capture_set_audio
1423 (capture_channels, capture_samplerate, capture_samplewidth) != True
1424 || (capture_started == True && pulse_capture_start() != True))
1425 break;
1426 }
1427
1428 return True;
1429 }
1430 while (0);
1431
1432 pulse_deinit();
1433
1434 return False;
1435 }
1436
1437 struct audio_driver *
pulse_register(char * options)1438 pulse_register(char *options)
1439 {
1440 static struct audio_driver pulse_driver;
1441
1442 memset(&pulse_driver, 0, sizeof(pulse_driver));
1443
1444 pulse_driver.name = "pulse";
1445 pulse_driver.description = "PulseAudio output driver, default device: system dependent";
1446
1447 pulse_driver.add_fds = pulse_add_fds;
1448 pulse_driver.check_fds = pulse_check_fds;
1449
1450 pulse_driver.wave_out_open = pulse_open_out;
1451 pulse_driver.wave_out_close = pulse_close_out;
1452 pulse_driver.wave_out_format_supported = pulse_format_supported;
1453 pulse_driver.wave_out_set_format = pulse_set_format_out;
1454 pulse_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
1455
1456 pulse_driver.wave_in_open = pulse_open_in;
1457 pulse_driver.wave_in_close = pulse_close_in;
1458 pulse_driver.wave_in_format_supported = pulse_format_supported;
1459 pulse_driver.wave_in_set_format = pulse_set_format_in;
1460 pulse_driver.wave_in_volume = NULL; /* FIXME */
1461
1462 pulse_driver.need_byteswap_on_be = 0;
1463 pulse_driver.need_resampling = 0;
1464
1465 if (options != NULL)
1466 {
1467 device = xstrdup(options);
1468 }
1469 else
1470 {
1471 device = DEFAULTDEVICE;
1472 }
1473
1474 return &pulse_driver;
1475 }
1476