• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* public domain */
2 #include "qemu-common.h"
3 #include "audio.h"
4 
5 #include <pulse/simple.h>
6 #include <pulse/error.h>
7 #include <dlfcn.h>
8 
9 #define AUDIO_CAP "pulseaudio"
10 #include "audio_int.h"
11 #include "audio_pt_int.h"
12 
13 #define DEBUG 1
14 
15 #if DEBUG
16 #  include "qemu_debug.h"
17 #  include <stdio.h>
18 #  define D(...)  VERBOSE_PRINT(audio,__VA_ARGS__)
19 #  define D_ACTIVE  VERBOSE_CHECK(audio)
20 #  define O(...)  VERBOSE_PRINT(audioout,__VA_ARGS__)
21 #  define I(...)  VERBOSE_PRINT(audioin,__VA_ARGS__)
22 #else
23 #  define D(...)  ((void)0)
24 #  define D_ACTIVE 0
25 #  define O(...)  ((void)0)
26 #  define I(...)  ((void)0)
27 #endif
28 
29 #define  DYNLINK_FUNCTIONS   \
30     DYNLINK_FUNC(pa_simple*,pa_simple_new,(const char* server,const char* name, pa_stream_direction_t dir, const char* dev, const char* stream_name, const pa_sample_spec* ss, const pa_channel_map* map, const pa_buffer_attr *attr, int *error)) \
31     DYNLINK_FUNC(void,pa_simple_free,(pa_simple* s))\
32     DYNLINK_FUNC(int,pa_simple_write,(pa_simple* s, const void* data, size_t bytes, int* error))\
33     DYNLINK_FUNC(int,pa_simple_read,(pa_simple* s,void* data, size_t bytes, int* error))\
34     DYNLINK_FUNC(const char*,pa_strerror,(int error))\
35 
36 #define DYNLINK_FUNCTIONS_INIT \
37     pa_dynlink_init
38 
39 static void* pa_lib;
40 
41 #include "dynlink.h"
42 
43 typedef struct {
44     HWVoiceOut hw;
45     int done;
46     int live;
47     int decr;
48     int rpos;
49     pa_simple *s;
50     void *pcm_buf;
51     struct audio_pt pt;
52 } PAVoiceOut;
53 
54 typedef struct {
55     HWVoiceIn hw;
56     int done;
57     int dead;
58     int incr;
59     int wpos;
60     pa_simple *s;
61     void *pcm_buf;
62     struct audio_pt pt;
63 } PAVoiceIn;
64 
65 static struct {
66     int samples;
67     int divisor;
68     char *server;
69     char *sink;
70     char *source;
71 } conf = {
72     .samples = 1024,
73     .divisor = 2,
74 };
75 
qpa_logerr(int err,const char * fmt,...)76 static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
77 {
78     va_list ap;
79 
80     va_start (ap, fmt);
81     AUD_vlog (AUDIO_CAP, fmt, ap);
82     va_end (ap);
83 
84     AUD_log (AUDIO_CAP, "Reason: %s\n", FF(pa_strerror) (err));
85 }
86 
qpa_thread_out(void * arg)87 static void *qpa_thread_out (void *arg)
88 {
89     PAVoiceOut *pa = arg;
90     HWVoiceOut *hw = &pa->hw;
91     int threshold;
92 
93     threshold = conf.divisor ? hw->samples / conf.divisor : 0;
94 
95     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
96         return NULL;
97     }
98 
99     for (;;) {
100         int decr, to_mix, rpos;
101 
102         for (;;) {
103             if (pa->done) {
104                 goto exit;
105             }
106 
107             if (pa->live > threshold) {
108                 break;
109             }
110 
111             if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
112                 goto exit;
113             }
114         }
115 
116         decr = to_mix = pa->live;
117         rpos = hw->rpos;
118 
119         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
120             return NULL;
121         }
122 
123         while (to_mix) {
124             int error;
125             int chunk = audio_MIN (to_mix, hw->samples - rpos);
126             struct st_sample *src = hw->mix_buf + rpos;
127 
128             hw->clip (pa->pcm_buf, src, chunk);
129 
130             if (FF(pa_simple_write) (pa->s, pa->pcm_buf,
131                                  chunk << hw->info.shift, &error) < 0) {
132                 qpa_logerr (error, "pa_simple_write failed\n");
133                 return NULL;
134             }
135 
136             rpos = (rpos + chunk) % hw->samples;
137             to_mix -= chunk;
138         }
139 
140         if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
141             return NULL;
142         }
143 
144         pa->rpos = rpos;
145         pa->live -= decr;
146         pa->decr += decr;
147     }
148 
149  exit:
150     audio_pt_unlock (&pa->pt, AUDIO_FUNC);
151     return NULL;
152 }
153 
qpa_run_out(HWVoiceOut * hw,int live)154 static int qpa_run_out (HWVoiceOut *hw, int live)
155 {
156     int decr;
157     PAVoiceOut *pa = (PAVoiceOut *) hw;
158 
159     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
160         return 0;
161     }
162 
163     decr = audio_MIN (live, pa->decr);
164     pa->decr -= decr;
165     pa->live = live - decr;
166     hw->rpos = pa->rpos;
167     if (pa->live > 0) {
168         audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
169     }
170     else {
171         audio_pt_unlock (&pa->pt, AUDIO_FUNC);
172     }
173     return decr;
174 }
175 
qpa_write(SWVoiceOut * sw,void * buf,int len)176 static int qpa_write (SWVoiceOut *sw, void *buf, int len)
177 {
178     return audio_pcm_sw_write (sw, buf, len);
179 }
180 
181 /* capture */
qpa_thread_in(void * arg)182 static void *qpa_thread_in (void *arg)
183 {
184     PAVoiceIn *pa = arg;
185     HWVoiceIn *hw = &pa->hw;
186     int threshold;
187 
188     threshold = conf.divisor ? hw->samples / conf.divisor : 0;
189 
190     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
191         return NULL;
192     }
193 
194     for (;;) {
195         int incr, to_grab, wpos;
196 
197         for (;;) {
198             if (pa->done) {
199                 goto exit;
200             }
201 
202             if (pa->dead > threshold) {
203                 break;
204             }
205 
206             if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
207                 goto exit;
208             }
209         }
210 
211         incr = to_grab = pa->dead;
212         wpos = hw->wpos;
213 
214         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
215             return NULL;
216         }
217 
218         while (to_grab) {
219             int error;
220             int chunk = audio_MIN (to_grab, hw->samples - wpos);
221             void *buf = advance (pa->pcm_buf, wpos);
222 
223             if (FF(pa_simple_read) (pa->s, buf,
224                                 chunk << hw->info.shift, &error) < 0) {
225                 qpa_logerr (error, "pa_simple_read failed\n");
226                 return NULL;
227             }
228 
229             hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume);
230             wpos = (wpos + chunk) % hw->samples;
231             to_grab -= chunk;
232         }
233 
234         if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
235             return NULL;
236         }
237 
238         pa->wpos = wpos;
239         pa->dead -= incr;
240         pa->incr += incr;
241     }
242 
243  exit:
244     audio_pt_unlock (&pa->pt, AUDIO_FUNC);
245     return NULL;
246 }
247 
qpa_run_in(HWVoiceIn * hw)248 static int qpa_run_in (HWVoiceIn *hw)
249 {
250     int live, incr, dead;
251     PAVoiceIn *pa = (PAVoiceIn *) hw;
252 
253     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
254         return 0;
255     }
256 
257     live = audio_pcm_hw_get_live_in (hw);
258     dead = hw->samples - live;
259     incr = audio_MIN (dead, pa->incr);
260     pa->incr -= incr;
261     pa->dead = dead - incr;
262     hw->wpos = pa->wpos;
263     if (pa->dead > 0) {
264         audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
265     }
266     else {
267         audio_pt_unlock (&pa->pt, AUDIO_FUNC);
268     }
269     return incr;
270 }
271 
qpa_read(SWVoiceIn * sw,void * buf,int len)272 static int qpa_read (SWVoiceIn *sw, void *buf, int len)
273 {
274     return audio_pcm_sw_read (sw, buf, len);
275 }
276 
audfmt_to_pa(audfmt_e afmt,int endianness)277 static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
278 {
279     int format;
280 
281     switch (afmt) {
282     case AUD_FMT_S8:
283     case AUD_FMT_U8:
284         format = PA_SAMPLE_U8;
285         break;
286     case AUD_FMT_S16:
287     case AUD_FMT_U16:
288         format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
289         break;
290     case AUD_FMT_S32:
291     case AUD_FMT_U32:
292         format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
293         break;
294     default:
295         dolog ("Internal logic error: Bad audio format %d\n", afmt);
296         format = PA_SAMPLE_U8;
297         break;
298     }
299     return format;
300 }
301 
pa_to_audfmt(pa_sample_format_t fmt,int * endianness)302 static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
303 {
304     switch (fmt) {
305     case PA_SAMPLE_U8:
306         return AUD_FMT_U8;
307     case PA_SAMPLE_S16BE:
308         *endianness = 1;
309         return AUD_FMT_S16;
310     case PA_SAMPLE_S16LE:
311         *endianness = 0;
312         return AUD_FMT_S16;
313     case PA_SAMPLE_S32BE:
314         *endianness = 1;
315         return AUD_FMT_S32;
316     case PA_SAMPLE_S32LE:
317         *endianness = 0;
318         return AUD_FMT_S32;
319     default:
320         dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
321         return AUD_FMT_U8;
322     }
323 }
324 
qpa_init_out(HWVoiceOut * hw,struct audsettings * as)325 static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
326 {
327     int error;
328     static pa_sample_spec ss;
329     struct audsettings obt_as = *as;
330     PAVoiceOut *pa = (PAVoiceOut *) hw;
331 
332     ss.format = audfmt_to_pa (as->fmt, as->endianness);
333     ss.channels = as->nchannels;
334     ss.rate = as->freq;
335 
336     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
337 
338     pa->s = FF(pa_simple_new) (
339         conf.server,
340         "qemu",
341         PA_STREAM_PLAYBACK,
342         conf.sink,
343         "pcm.playback",
344         &ss,
345         NULL,                   /* channel map */
346         NULL,                   /* buffering attributes */
347         &error
348         );
349     if (!pa->s) {
350         qpa_logerr (error, "pa_simple_new for playback failed\n");
351         goto fail1;
352     }
353 
354     audio_pcm_init_info (&hw->info, &obt_as);
355     hw->samples = conf.samples;
356     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
357     if (!pa->pcm_buf) {
358         dolog ("Could not allocate buffer (%d bytes)\n",
359                hw->samples << hw->info.shift);
360         goto fail2;
361     }
362 
363     if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
364         goto fail3;
365     }
366 
367     return 0;
368 
369  fail3:
370     qemu_free (pa->pcm_buf);
371     pa->pcm_buf = NULL;
372  fail2:
373     FF(pa_simple_free) (pa->s);
374     pa->s = NULL;
375  fail1:
376     return -1;
377 }
378 
qpa_init_in(HWVoiceIn * hw,struct audsettings * as)379 static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
380 {
381     int error;
382     static pa_sample_spec ss;
383     struct audsettings obt_as = *as;
384     PAVoiceIn *pa = (PAVoiceIn *) hw;
385 
386     ss.format = audfmt_to_pa (as->fmt, as->endianness);
387     ss.channels = as->nchannels;
388     ss.rate = as->freq;
389 
390     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
391 
392     pa->s = FF(pa_simple_new) (
393         conf.server,
394         "qemu",
395         PA_STREAM_RECORD,
396         conf.source,
397         "pcm.capture",
398         &ss,
399         NULL,                   /* channel map */
400         NULL,                   /* buffering attributes */
401         &error
402         );
403     if (!pa->s) {
404         qpa_logerr (error, "pa_simple_new for capture failed\n");
405         goto fail1;
406     }
407 
408     audio_pcm_init_info (&hw->info, &obt_as);
409     hw->samples = conf.samples;
410     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
411     if (!pa->pcm_buf) {
412         dolog ("Could not allocate buffer (%d bytes)\n",
413                hw->samples << hw->info.shift);
414         goto fail2;
415     }
416 
417     if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
418         goto fail3;
419     }
420 
421     return 0;
422 
423  fail3:
424     qemu_free (pa->pcm_buf);
425     pa->pcm_buf = NULL;
426  fail2:
427     FF(pa_simple_free) (pa->s);
428     pa->s = NULL;
429  fail1:
430     return -1;
431 }
432 
qpa_fini_out(HWVoiceOut * hw)433 static void qpa_fini_out (HWVoiceOut *hw)
434 {
435     void *ret;
436     PAVoiceOut *pa = (PAVoiceOut *) hw;
437 
438     audio_pt_lock (&pa->pt, AUDIO_FUNC);
439     pa->done = 1;
440     audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
441     audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
442 
443     if (pa->s) {
444         FF(pa_simple_free) (pa->s);
445         pa->s = NULL;
446     }
447 
448     audio_pt_fini (&pa->pt, AUDIO_FUNC);
449     qemu_free (pa->pcm_buf);
450     pa->pcm_buf = NULL;
451 }
452 
qpa_fini_in(HWVoiceIn * hw)453 static void qpa_fini_in (HWVoiceIn *hw)
454 {
455     void *ret;
456     PAVoiceIn *pa = (PAVoiceIn *) hw;
457 
458     audio_pt_lock (&pa->pt, AUDIO_FUNC);
459     pa->done = 1;
460     audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
461     audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
462 
463     if (pa->s) {
464         FF(pa_simple_free) (pa->s);
465         pa->s = NULL;
466     }
467 
468     audio_pt_fini (&pa->pt, AUDIO_FUNC);
469     qemu_free (pa->pcm_buf);
470     pa->pcm_buf = NULL;
471 }
472 
qpa_ctl_out(HWVoiceOut * hw,int cmd,...)473 static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
474 {
475     (void) hw;
476     (void) cmd;
477     return 0;
478 }
479 
qpa_ctl_in(HWVoiceIn * hw,int cmd,...)480 static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
481 {
482     (void) hw;
483     (void) cmd;
484     return 0;
485 }
486 
487 /* common */
qpa_audio_init(void)488 static void *qpa_audio_init (void)
489 {
490     void*  result = NULL;
491 
492     D("%s: entering", __FUNCTION__);
493     pa_lib = dlopen( "libpulse-simple.so", RTLD_NOW );
494     if (pa_lib == NULL)
495         pa_lib = dlopen( "libpulse-simple.so.0", RTLD_NOW );
496 
497     if (pa_lib == NULL) {
498         D("could not find libpulse on this system\n");
499         goto Exit;
500     }
501 
502     if (pa_dynlink_init(pa_lib) < 0)
503         goto Fail;
504 
505     {
506         pa_sample_spec  ss;
507         int             error;
508         pa_simple*      simple;
509 
510         ss.format   = PA_SAMPLE_U8;
511         ss.rate     = 44100;
512         ss.channels = 1;
513 
514         /* try to open it for playback */
515         simple = FF(pa_simple_new) (
516             conf.server,
517             "qemu",
518             PA_STREAM_PLAYBACK,
519             conf.sink,
520             "pcm.playback",
521             &ss,
522             NULL,                   /* channel map */
523             NULL,                   /* buffering attributes */
524             &error
525             );
526 
527         if (simple == NULL) {
528             D("%s: error opening open pulse audio library: %s",
529               __FUNCTION__, FF(pa_strerror)(error));
530             goto Fail;
531         }
532         FF(pa_simple_free)(simple);
533     }
534 
535     result = &conf;
536     goto Exit;
537 
538 Fail:
539     D("%s: failed to open library\n", __FUNCTION__);
540     dlclose(pa_lib);
541 
542 Exit:
543     D("%s: exiting", __FUNCTION__);
544     return result;
545 }
546 
qpa_audio_fini(void * opaque)547 static void qpa_audio_fini (void *opaque)
548 {
549     if (pa_lib != NULL) {
550         dlclose(pa_lib);
551         pa_lib = NULL;
552     }
553     (void) opaque;
554     (void) opaque;
555 }
556 
557 struct audio_option qpa_options[] = {
558     {
559         .name  = "SAMPLES",
560         .tag   = AUD_OPT_INT,
561         .valp  = &conf.samples,
562         .descr = "buffer size in samples"
563     },
564     {
565         .name  = "DIVISOR",
566         .tag   = AUD_OPT_INT,
567         .valp  = &conf.divisor,
568         .descr = "threshold divisor"
569     },
570     {
571         .name  = "SERVER",
572         .tag   = AUD_OPT_STR,
573         .valp  = &conf.server,
574         .descr = "server address"
575     },
576     {
577         .name  = "SINK",
578         .tag   = AUD_OPT_STR,
579         .valp  = &conf.sink,
580         .descr = "sink device name"
581     },
582     {
583         .name  = "SOURCE",
584         .tag   = AUD_OPT_STR,
585         .valp  = &conf.source,
586         .descr = "source device name"
587     },
588     { /* End of list */ }
589 };
590 
591 static struct audio_pcm_ops qpa_pcm_ops = {
592     .init_out = qpa_init_out,
593     .fini_out = qpa_fini_out,
594     .run_out  = qpa_run_out,
595     .write    = qpa_write,
596     .ctl_out  = qpa_ctl_out,
597 
598     .init_in  = qpa_init_in,
599     .fini_in  = qpa_fini_in,
600     .run_in   = qpa_run_in,
601     .read     = qpa_read,
602     .ctl_in   = qpa_ctl_in
603 };
604 
605 struct audio_driver pa_audio_driver = {
606     .name           = "pa",
607     .descr          = "http://www.pulseaudio.org/",
608     .options        = qpa_options,
609     .init           = qpa_audio_init,
610     .fini           = qpa_audio_fini,
611     .pcm_ops        = &qpa_pcm_ops,
612     .can_be_default = 1,
613     .max_voices_out = INT_MAX,
614     .max_voices_in  = INT_MAX,
615     .voice_size_out = sizeof (PAVoiceOut),
616     .voice_size_in  = sizeof (PAVoiceIn)
617 };
618