1 /*
2  * Copyright (C) 2008 2009 2011 2012, Magnus Hjorth
3  *
4  * This file is part of mhWaveEdit.
5  *
6  * mhWaveEdit is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * mhWaveEdit is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with mhWaveEdit; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 
22 #include <poll.h>
23 #include <pulse/pulseaudio.h>
24 
25 #include "int_box.h"
26 
27 #ifndef PA_CHECK_VERSION
28 #define PA_CHECK_VERSION(a,b,c) (0)
29 #endif
30 
31 #undef MLDEBUG
32 
33 /* ----------------------- */
34 /* Mainloop API */
35 
36 struct pulse_api_io_event {
37      gpointer iosource;
38      int fd;
39      pa_io_event_flags_t events;
40      gpointer userdata;
41      pa_io_event_cb_t cb;
42      pa_io_event_destroy_cb_t destroy_cb;
43 };
44 
45 struct pulse_api_time_event {
46      gpointer timesource;
47      pa_time_event_cb_t cb;
48      pa_time_event_destroy_cb_t destroy_cb;
49      void *userdata;
50 };
51 
52 struct pulse_api_defer_event {
53      gpointer constsource;
54      pa_defer_event_cb_t cb;
55      pa_defer_event_destroy_cb_t destroy_cb;
56      void *userdata;
57 };
58 
59 struct pulse_api_userdata {
60      gpointer *sources;
61      int sources_cap;
62      int sources_len;
63 };
64 
65 static pa_mainloop_api *pulse_api(void);
66 
67 #ifdef MLDEBUG
pulse_api_list_sources(struct pulse_api_userdata * ud)68 static void pulse_api_list_sources(struct pulse_api_userdata *ud)
69 {
70      int i;
71      printf("sources: ");
72      for (i=0; i<ud->sources_len; i++)
73 	  printf("%p ",ud->sources[i]);
74      puts("");
75 }
76 #endif
77 
pulse_api_source_added(gpointer src,struct pa_mainloop_api * api)78 static void pulse_api_source_added(gpointer src, struct pa_mainloop_api *api)
79 {
80      struct pulse_api_userdata *ud = (struct pulse_api_userdata *)api->userdata;
81 
82 #ifdef MLDEBUG
83      printf("pulse_api_source_added: %p\n",src);
84 #endif
85      if (ud->sources_cap == ud->sources_len) {
86 	  if (ud->sources_cap == 0)
87 	       ud->sources_cap = 1;
88 	  else
89 	       ud->sources_cap *= 2;
90 	  ud->sources = g_realloc(ud->sources,
91 				  ud->sources_cap*sizeof(ud->sources[0]));
92      }
93      ud->sources[ud->sources_len++] = src;
94 #ifdef MLDEBUG
95      pulse_api_list_sources(ud);
96 #endif
97 }
98 
pulse_api_source_removed(gpointer src,struct pa_mainloop_api * api)99 static void pulse_api_source_removed(gpointer src, struct pa_mainloop_api *api)
100 {
101      struct pulse_api_userdata *ud = (struct pulse_api_userdata *)api->userdata;
102      int i;
103 #ifdef MLDEBUG
104      printf("pulse_api_source_removed: %p\n",src);
105 #endif
106      for (i=0; i<ud->sources_len; i++)
107 	  if (ud->sources[i] == src)
108 	       break;
109      for (; i+1<ud->sources_len; i++)
110 	  ud->sources[i] = ud->sources[i+1];
111      ud->sources_len--;
112 
113 #ifdef MLDEBUG
114      pulse_api_list_sources(ud);
115 #endif
116 }
117 
pa_to_poll(pa_io_event_flags_t events)118 static int pa_to_poll(pa_io_event_flags_t events)
119 {
120      int i = 0;
121      if (events & PA_IO_EVENT_INPUT) i |= POLLIN;
122      if (events & PA_IO_EVENT_OUTPUT) i |= POLLOUT;
123      if (events & PA_IO_EVENT_HANGUP) i |= POLLHUP;
124      if (events & PA_IO_EVENT_ERROR) i |= POLLERR;
125      return i;
126 }
127 
poll_to_pa(int events)128 static pa_io_event_flags_t poll_to_pa(int events)
129 {
130      pa_io_event_flags_t e = PA_IO_EVENT_NULL;
131      if (events & POLLIN) e |= PA_IO_EVENT_INPUT;
132      if (events & POLLOUT) e |= PA_IO_EVENT_OUTPUT;
133      if (events & POLLHUP) e |= PA_IO_EVENT_HANGUP;
134      if (events & PA_IO_EVENT_ERROR) e |= POLLERR;
135      return e;
136 }
137 
pulse_api_io_cb(gpointer iosource,int fd,gushort revents,gpointer user_data)138 static void pulse_api_io_cb(gpointer iosource, int fd, gushort revents,
139 			    gpointer user_data)
140 {
141      struct pulse_api_io_event *e = user_data;
142      /* puts("I/O event triggered"); */
143      e->cb(pulse_api(),(pa_io_event *)e,fd,poll_to_pa(revents),e->userdata);
144 }
145 
pulse_api_io_new(pa_mainloop_api * a,int fd,pa_io_event_flags_t events,pa_io_event_cb_t cb,void * userdata)146 static pa_io_event *pulse_api_io_new(pa_mainloop_api *a, int fd,
147 				     pa_io_event_flags_t events,
148 				     pa_io_event_cb_t cb,
149 				     void *userdata)
150 {
151      struct pulse_api_io_event *e;
152 
153 #ifdef MLDEBUG
154      printf("Adding I/O event, fd=%d, events=%d\n",fd,events);
155 #endif
156      e = g_malloc(sizeof(*e));
157      e->userdata = userdata;
158      e->fd = fd;
159      e->events = events;
160      e->cb = cb;
161      e->destroy_cb = NULL;
162      e->iosource = mainloop_io_source_add(fd, pa_to_poll(events),
163 					  pulse_api_io_cb, e);
164      pulse_api_source_added(e->iosource,a);
165      return (pa_io_event *)e;
166 }
167 
pulse_api_io_enable(pa_io_event * e,pa_io_event_flags_t events)168 static void pulse_api_io_enable(pa_io_event *e, pa_io_event_flags_t events)
169 {
170      struct pulse_api_io_event *es = (struct pulse_api_io_event *)e;
171 
172 #ifdef MLDEBUG
173      printf("IO event set enable, fd=%d ,events=%d, es->events=%d\n",
174 	    es->fd,events,es->events);
175 #endif
176      mainloop_io_source_set_events(es->iosource,pa_to_poll(events));
177 }
178 
pulse_api_io_free(pa_io_event * e)179 static void pulse_api_io_free(pa_io_event *e)
180 {
181      struct pulse_api_io_event *es = (struct pulse_api_io_event *)e;
182 #ifdef MLDEBUG
183      printf("Removing IO event (fd %d)\n",es->fd);
184 #endif
185      mainloop_io_source_free(es->iosource);
186      pulse_api_source_removed(es->iosource, pulse_api());
187      if (es->destroy_cb) es->destroy_cb(pulse_api(),e,es->userdata);
188 
189      g_free(es);
190 }
191 
pulse_api_io_set_destroy(pa_io_event * e,pa_io_event_destroy_cb_t cb)192 static void pulse_api_io_set_destroy(pa_io_event *e,
193 				     pa_io_event_destroy_cb_t cb)
194 {
195      struct pulse_api_io_event *es = (struct pulse_api_io_event *)e;
196      es->destroy_cb = cb;
197 }
198 
pa_api_time_new_cb(gpointer timesource,GTimeVal * current_time,gpointer user_data)199 static gint pa_api_time_new_cb(gpointer timesource, GTimeVal *current_time,
200 			       gpointer user_data)
201 {
202      struct pulse_api_time_event *es =
203 	  (struct pulse_api_time_event *)user_data;
204      struct timeval tv;
205      /* puts("Time event triggered"); */
206      tv.tv_sec = current_time->tv_sec;
207      tv.tv_usec = current_time->tv_usec;
208      es->cb(pulse_api(),(pa_time_event *)es,&tv,es->userdata);
209      return 0;
210 }
211 
pulse_api_time_new(pa_mainloop_api * a,const struct timeval * tv,pa_time_event_cb_t cb,void * userdata)212 static pa_time_event *pulse_api_time_new(pa_mainloop_api *a,
213 					 const struct timeval *tv,
214 					 pa_time_event_cb_t cb,
215 					 void *userdata)
216 {
217      struct pulse_api_time_event *es;
218      GTimeVal gtv;
219 
220 #ifdef MLDEBUG
221      GTimeVal temp_tv;
222 
223      g_get_current_time(&temp_tv);
224      printf("Adding time event, triggers in %d s %d us\n",
225 	    tv->tv_sec-temp_tv.tv_sec, tv->tv_usec-temp_tv.tv_usec);
226 #endif
227 
228      es = g_malloc(sizeof(*es));
229      es->cb = cb;
230      es->destroy_cb = NULL;
231      es->userdata = userdata;
232      gtv.tv_sec = tv->tv_sec;
233      gtv.tv_usec = tv->tv_usec;
234      es->timesource = mainloop_time_source_add(&gtv,pa_api_time_new_cb,es);
235      pulse_api_source_added(es->timesource, a);
236      return (pa_time_event *)es;
237 }
238 
pulse_api_time_restart(pa_time_event * e,const struct timeval * tv)239 static void pulse_api_time_restart(pa_time_event *e, const struct timeval *tv)
240 {
241      struct pulse_api_time_event *es = (struct pulse_api_time_event *)e;
242      GTimeVal gtv;
243 
244      /*
245      GTimeVal temp_tv;
246      g_get_current_time(&temp_tv);
247      printf("Restarting time event, triggers in %d s %d us\n",
248 	tv->tv_sec-temp_tv.tv_sec, tv->tv_usec-temp_tv.tv_usec); */
249 
250      gtv.tv_sec = tv->tv_sec;
251      gtv.tv_usec = tv->tv_usec;
252      mainloop_time_source_restart(es->timesource,&gtv);
253 }
254 
pulse_api_time_free(pa_time_event * e)255 static void pulse_api_time_free(pa_time_event *e)
256 {
257      struct pulse_api_time_event *es = (struct pulse_api_time_event *)e;
258 #ifdef MLDEBUG
259      puts("Removing time event");
260 #endif
261      mainloop_time_source_free(es->timesource);
262      if (es->destroy_cb) es->destroy_cb(pulse_api(),e,es->userdata);
263      pulse_api_source_removed(es->timesource, pulse_api());
264      g_free(es);
265 }
266 
pulse_api_time_set_destroy(pa_time_event * e,pa_time_event_destroy_cb_t cb)267 static void pulse_api_time_set_destroy(pa_time_event *e,
268 				       pa_time_event_destroy_cb_t cb)
269 {
270      struct pulse_api_time_event *es = (struct pulse_api_time_event *)e;
271      es->destroy_cb = cb;
272 }
273 
pulse_api_defer_new_cb(gpointer csource,gpointer user_data)274 static int pulse_api_defer_new_cb(gpointer csource, gpointer user_data)
275 {
276      struct pulse_api_defer_event *es = user_data;
277 #ifdef MLDEBUG
278      puts("Defer event triggered");
279 #endif
280      es->cb(pulse_api(),(pa_defer_event *)es,es->userdata);
281      return 0;
282 }
283 
pulse_api_defer_new(pa_mainloop_api * a,pa_defer_event_cb_t cb,void * userdata)284 static pa_defer_event *pulse_api_defer_new(pa_mainloop_api *a,
285 					   pa_defer_event_cb_t cb,
286 					   void *userdata)
287 {
288      struct pulse_api_defer_event *es;
289 
290 #ifdef MLDEBUG
291      puts("Adding defer event");
292 #endif
293      es = g_malloc(sizeof(*es));
294      es->cb = cb;
295      es->destroy_cb = NULL;
296      es->userdata = userdata;
297      es->constsource = mainloop_constant_source_add(pulse_api_defer_new_cb,
298 						    es, FALSE);
299      pulse_api_source_added(es->constsource,a);
300      return (pa_defer_event *)es;
301 }
302 
pulse_api_defer_enable(pa_defer_event * e,int b)303 static void pulse_api_defer_enable(pa_defer_event *e, int b)
304 {
305      struct pulse_api_defer_event *es = (struct pulse_api_defer_event *)e;
306 #ifdef MLDEBUG
307      printf("Defer event set enabled=%d\n",b);
308 #endif
309      mainloop_constant_source_enable(es->constsource, b);
310 }
311 
pulse_api_defer_free(pa_defer_event * e)312 static void pulse_api_defer_free(pa_defer_event *e)
313 {
314      struct pulse_api_defer_event *es = (struct pulse_api_defer_event *)e;
315 #ifdef MLDEBUG
316      puts("Removing defer event");
317 #endif
318      mainloop_constant_source_free(es->constsource);
319      if (es->destroy_cb) es->destroy_cb(pulse_api(),e,es->userdata);
320      pulse_api_source_removed(es->constsource,pulse_api());
321      g_free(es);
322 }
323 
pulse_api_defer_set_destroy(pa_defer_event * e,pa_defer_event_destroy_cb_t cb)324 static void pulse_api_defer_set_destroy(pa_defer_event *e,
325 					pa_defer_event_destroy_cb_t cb)
326 {
327      struct pulse_api_defer_event *es = (struct pulse_api_defer_event *)e;
328      es->destroy_cb = cb;
329 }
330 
pulse_api_quit(pa_mainloop_api * a,int retval)331 static void pulse_api_quit(pa_mainloop_api *a, int retval)
332 {
333 }
334 
pulse_api(void)335 static pa_mainloop_api *pulse_api(void)
336 {
337      static gboolean api_setup = FALSE;
338      static struct pa_mainloop_api api;
339      struct pulse_api_userdata *ud;
340 
341      if (!api_setup) {
342 	  api.io_new = pulse_api_io_new;
343 	  api.io_enable = pulse_api_io_enable;
344 	  api.io_free = pulse_api_io_free;
345 	  api.io_set_destroy = pulse_api_io_set_destroy;
346 	  api.time_new = pulse_api_time_new;
347 	  api.time_restart = pulse_api_time_restart;
348 	  api.time_free = pulse_api_time_free;
349 	  api.time_set_destroy = pulse_api_time_set_destroy;
350 	  api.defer_new = pulse_api_defer_new;
351 	  api.defer_enable = pulse_api_defer_enable;
352 	  api.defer_free = pulse_api_defer_free;
353 	  api.defer_set_destroy = pulse_api_defer_set_destroy;
354 	  api.quit = pulse_api_quit;
355 
356 	  ud = g_malloc0(sizeof(*ud));
357 	  api.userdata = ud;
358 
359 	  api_setup = TRUE;
360      }
361 
362      return &api;
363 }
364 
pulse_api_block(void)365 static void pulse_api_block(void)
366 {
367      gpointer *srcp;
368      struct pulse_api_userdata *ud =
369 	  (struct pulse_api_userdata *)(pulse_api()->userdata);
370 #ifdef MLDEBUG
371      puts("pulse_api_block");
372      pulse_api_list_sources(ud);
373 #endif
374 
375      srcp = g_malloc(ud->sources_len * sizeof(ud->sources[0]));
376      memcpy(srcp,ud->sources,ud->sources_len*sizeof(ud->sources[0]));
377      mainloop_recurse_on(srcp, ud->sources_len);
378      g_free(srcp);
379 }
380 
381 
382 /* --------------------------------
383  *  Driver core
384  */
385 
386 static struct {
387      pa_context *ctx;
388      pa_context_state_t ctx_state;
389      int ctx_errno;
390      pa_stream *stream;
391      pa_stream_state_t stream_state;
392      pa_sample_spec stream_sspec;
393      pa_buffer_attr stream_attr;
394      pa_stream_flags_t stream_flags;
395      gboolean record_flag;
396      const char *record_data;
397      size_t record_bytes,record_pos;
398      gint overflow_count,overflow_report_count;
399      gboolean flush_state; /* 0 = no flush requested yet, 1 = waiting, 2 = done */
400      gboolean recursing_mainloop;
401      gpointer ready_constsource;
402      GVoidFunc ready_func;
403      gboolean stopping;
404 } pulse_data = { 0 };
405 
pulse_context_state_cb(pa_context * c,void * userdata)406 static void pulse_context_state_cb(pa_context *c, void *userdata)
407 {
408      g_assert(pulse_data.ctx == c);
409 
410      pulse_data.ctx_state = pa_context_get_state(c);
411      /* printf("Context state change to: %d\n",pulse_data.ctx_state); */
412 
413      if (pulse_data.ctx_state == PA_CONTEXT_FAILED ||
414 	 pulse_data.ctx_state == PA_CONTEXT_TERMINATED) {
415 	  pulse_data.ctx_errno = pa_context_errno(pulse_data.ctx);
416 	  pa_context_unref(pulse_data.ctx);
417 	  pulse_data.ctx = NULL;
418      }
419 
420 }
421 
pulse_connect(gboolean autospawn,gboolean silent)422 static gboolean pulse_connect(gboolean autospawn, gboolean silent)
423 {
424      gchar *c;
425      int i;
426      if (pulse_data.ctx != NULL) return TRUE;
427      pulse_data.ctx = pa_context_new(pulse_api(),"mhwaveedit");
428      g_assert(pulse_data.ctx != NULL);
429      pulse_data.ctx_state = PA_CONTEXT_UNCONNECTED;
430      pa_context_set_state_callback(pulse_data.ctx,pulse_context_state_cb,
431 				   NULL);
432      i = pa_context_connect(pulse_data.ctx, NULL,
433 			    autospawn?0:PA_CONTEXT_NOAUTOSPAWN, NULL);
434      g_assert(i == 0 || pulse_data.ctx == NULL);
435 
436      while (pulse_data.ctx_state != PA_CONTEXT_READY &&
437 	    pulse_data.ctx_state != PA_CONTEXT_FAILED &&
438 	    pulse_data.ctx_state != PA_CONTEXT_TERMINATED)
439 	  pulse_api_block();
440 
441      if (!silent && pulse_data.ctx_state != PA_CONTEXT_READY) {
442 	  c = g_strdup_printf(_("Connection to PulseAudio server failed: %s"),
443 			      pa_strerror(pulse_data.ctx_errno));
444 	  user_error(c);
445 	  g_free(c);
446      }
447 
448      return (pulse_data.ctx != NULL);
449 }
450 
pulse_init(gboolean silent)451 static gboolean pulse_init(gboolean silent)
452 {
453      return pulse_connect(FALSE,silent);
454 }
455 
pulse_quit(void)456 static void pulse_quit(void)
457 {
458      if (pulse_data.ctx != NULL) {
459 	  pa_context_disconnect(pulse_data.ctx);
460 	  /* Should be unref:d and set to NULL by the state callback */
461 	  g_assert(pulse_data.ctx == NULL);
462      }
463 }
464 
465 #if PA_CHECK_VERSION(0,9,15)
466 #define HAS24
467 #endif
468 
format_to_pulse(Dataformat * format,pa_sample_spec * ss_out)469 static gboolean format_to_pulse(Dataformat *format, pa_sample_spec *ss_out)
470 {
471      pa_sample_format_t sf;
472 
473      if (format->type == DATAFORMAT_PCM) {
474 	  if (format->samplesize == 1 && !format->sign)
475 	       sf = PA_SAMPLE_U8;
476 	  else if (format->samplesize == 2 && format->sign)
477 	       sf = (format->bigendian)?PA_SAMPLE_S16BE:PA_SAMPLE_S16LE;
478 #ifdef HAS24
479 	  else if (format->samplesize == 3 && format->sign)
480 	       sf = (format->bigendian)?PA_SAMPLE_S24BE:PA_SAMPLE_S24LE;
481 #endif
482 	  else if (format->samplesize == 4 && format->sign) {
483 	       if (format->packing == 0 || format->packing == 1)
484 		    sf = (format->bigendian)?PA_SAMPLE_S32BE:PA_SAMPLE_S32LE;
485 #ifdef HAS24
486 	       else
487 		    sf = (format->bigendian)?PA_SAMPLE_S24_32LE:PA_SAMPLE_S24_32BE;
488 #endif
489 	  } else
490 	       return TRUE;
491      } else if (format->type == DATAFORMAT_FLOAT && format->samplesize == 4) {
492 	  if (!ieee_le_compatible && !ieee_be_compatible)
493 	       return TRUE;
494 	  else if (format->bigendian)
495 	       sf = PA_SAMPLE_FLOAT32BE;
496 	  else
497 	       sf = PA_SAMPLE_FLOAT32LE;
498      } else
499 	  return TRUE;
500 
501      ss_out->format = sf;
502      ss_out->rate = format->samplerate;
503      ss_out->channels = format->channels;
504      return FALSE;
505 }
506 
pa_format_from_pulse(pa_sample_spec * ss,Dataformat * format_out)507 static gboolean pa_format_from_pulse(pa_sample_spec *ss, Dataformat *format_out)
508 {
509      Dataformat f;
510      int i = ss->format;
511 
512      switch (i) {
513      case PA_SAMPLE_U8:
514      case PA_SAMPLE_S16LE:
515      case PA_SAMPLE_S16BE:
516 #ifdef HAS24
517      case PA_SAMPLE_S24LE:
518      case PA_SAMPLE_S24BE:
519      case PA_SAMPLE_S24_32LE:
520      case PA_SAMPLE_S24_32BE:
521 #endif
522      case PA_SAMPLE_S32LE:
523      case PA_SAMPLE_S32BE:
524 	  f.type = DATAFORMAT_PCM;
525 	  f.packing = 0;
526 	  if (i == PA_SAMPLE_U8)
527 	       f.samplesize = 1;
528 	  else if (i == PA_SAMPLE_S16LE || i == PA_SAMPLE_S16BE) {
529 	       f.samplesize = 2;
530 #ifdef HAS24
531 	  } else if (i == PA_SAMPLE_S24LE || i == PA_SAMPLE_S24BE)
532 	       f.samplesize = 3;
533 	  else if (i == PA_SAMPLE_S24_32LE || i == PA_SAMPLE_S24_32LE) {
534 	       f.samplesize = 4;
535 	       f.packing = 2;
536 #endif
537 	  } else
538 	       f.samplesize = 4;
539 	  f.sign = !(i == PA_SAMPLE_U8);
540 	  if (i == PA_SAMPLE_S16BE || i == PA_SAMPLE_S32BE
541 #ifdef HAS24
542 	      || i == PA_SAMPLE_S24BE || i == PA_SAMPLE_S24_32BE
543 #endif
544 	      )
545 	       f.bigendian = TRUE;
546 	  else
547 	       f.bigendian = FALSE;
548 	  break;
549      case PA_SAMPLE_FLOAT32LE:
550 	  if (!ieee_le_compatible && !ieee_be_compatible) return TRUE;
551 	  f.type = DATAFORMAT_FLOAT;
552 	  f.samplesize = 4;
553 	  f.bigendian = FALSE;
554 	  break;
555      case PA_SAMPLE_FLOAT32BE:
556 	  if (!ieee_le_compatible && !ieee_be_compatible) return TRUE;
557 	  f.type = DATAFORMAT_FLOAT;
558 	  f.samplesize = 4;
559 	  f.bigendian = TRUE;
560 	  break;
561      default:
562 	  return TRUE;
563      }
564      f.channels = ss->channels;
565      f.samplebytes = f.samplesize * f.channels;
566      f.samplerate = ss->rate;
567 
568      memcpy(format_out,&f,sizeof(Dataformat));
569      return FALSE;
570 }
571 
572 
pulse_stream_state_cb(pa_stream * p,void * userdata)573 static void pulse_stream_state_cb(pa_stream *p, void *userdata)
574 {
575      g_assert(pulse_data.stream == p);
576      pulse_data.stream_state = pa_stream_get_state(p);
577      /* printf("Stream state change to: %d\n",pulse_data.stream_state); */
578      if (pulse_data.stream_state == PA_STREAM_FAILED ||
579 	 pulse_data.stream_state == PA_STREAM_TERMINATED) {
580 	  pa_stream_unref(pulse_data.stream);
581 	  pulse_data.stream = NULL;
582      }
583 }
584 
pulse_overflow_func(pa_stream * p,void * userdata)585 static void pulse_overflow_func(pa_stream *p, void *userdata)
586 {
587      pulse_data.overflow_count ++;
588 }
589 
pulse_wait_connect(int silent)590 static int pulse_wait_connect(int silent)
591 {
592      gchar *c;
593 
594      pulse_data.recursing_mainloop = TRUE;
595      while (pulse_data.stream_state != PA_STREAM_READY &&
596 	    pulse_data.stream_state != PA_STREAM_FAILED &&
597 	    pulse_data.stream_state != PA_STREAM_TERMINATED)
598 	  pulse_api_block();
599      pulse_data.recursing_mainloop = FALSE;
600 
601      if (!silent && pulse_data.stream_state != PA_STREAM_READY) {
602 	  c = g_strdup_printf(_("Connection to PulseAudio server failed: %s"),
603 			      pa_strerror(pa_context_errno(pulse_data.ctx)));
604 	  user_error(c);
605 	  g_free(c);
606 	  return 1;
607      }
608 
609      return 0;
610 }
611 
pulse_select_format_main(Dataformat * format,gboolean record,gboolean silent,pa_stream_request_cb_t ready_func,gpointer rf_userdata)612 static gint pulse_select_format_main(Dataformat *format, gboolean record,
613 				     gboolean silent,
614 				     pa_stream_request_cb_t ready_func,
615 				     gpointer rf_userdata)
616 {
617      pa_sample_spec ss;
618      int i;
619      guint32 u;
620 
621      /* printf("pulse_output_select_format, silent==%d\n",silent); */
622      if (format_to_pulse(format,&ss)) return -1;
623 
624      if (!pulse_connect(TRUE,silent)) return silent?-1:+1;
625 
626      g_assert(pulse_data.stream == NULL);
627      pulse_data.record_flag = record;
628      pulse_data.record_data = NULL;
629      pulse_data.stream_state = PA_STREAM_UNCONNECTED;
630      pulse_data.stream = pa_stream_new(pulse_data.ctx, "p", &ss, NULL);
631      g_assert(pulse_data.stream != NULL);
632      memcpy(&pulse_data.stream_sspec, &ss, sizeof(pa_sample_spec));
633      pa_stream_set_state_callback(pulse_data.stream, pulse_stream_state_cb,
634 				  NULL);
635 
636      if (record) {
637 	  pa_stream_set_read_callback(pulse_data.stream,ready_func,rf_userdata);
638 	  pulse_data.overflow_count = pulse_data.overflow_report_count = 0;
639 	  pa_stream_set_overflow_callback(pulse_data.stream,
640 					  pulse_overflow_func,NULL);
641      } else
642 	  pa_stream_set_write_callback(pulse_data.stream,ready_func,
643 				       rf_userdata);
644 
645      memset(&pulse_data.stream_attr, 0xFF, sizeof(pulse_data.stream_attr));
646      pulse_data.stream_flags = 0;
647 
648      if (record) {
649 	  pulse_data.stream_flags |= PA_STREAM_ADJUST_LATENCY;
650 	  pulse_data.stream_attr.fragsize = (format->samplerate *
651 					     format->samplebytes) / 10;
652      } else {
653 	  u = inifile_get_guint32("pulseLatency", 0);
654 	  if (u != 0) {
655 	       pulse_data.stream_flags |= PA_STREAM_ADJUST_LATENCY;
656 	       pulse_data.stream_attr.tlength =
657 		    (u * format->samplerate * format->samplebytes) / 1000;
658 	  }
659      }
660 
661      if (record)
662 	  i = pa_stream_connect_record(pulse_data.stream,NULL,
663 				       &pulse_data.stream_attr,
664 				       pulse_data.stream_flags);
665      else
666 	  i = pa_stream_connect_playback(pulse_data.stream,NULL,
667 					 &pulse_data.stream_attr,
668 					 pulse_data.stream_flags,NULL,
669 					 NULL);
670 
671      g_assert(i == 0 || pulse_data.stream == NULL);
672 
673      if (pulse_wait_connect(silent)) return 1;
674 
675      if (pulse_data.stream_state != PA_STREAM_READY)
676 	  return -1;
677 
678      return 0;
679 }
680 
ready_constsource_cb(gpointer csource,gpointer user_data)681 static int ready_constsource_cb(gpointer csource, gpointer user_data)
682 {
683      g_assert(pulse_data.stream != NULL);
684      mainloop_constant_source_enable(csource, FALSE);
685      pulse_data.ready_func();
686      return 0;
687 }
688 
pulse_ready_func(pa_stream * p,size_t bytes,void * userdata)689 static void pulse_ready_func(pa_stream *p, size_t bytes, void *userdata)
690 {
691      if (!pulse_data.stopping)
692           mainloop_constant_source_enable(pulse_data.ready_constsource, TRUE);
693 }
694 
ready_constsource_setup(void)695 static void ready_constsource_setup(void)
696 {
697      if (pulse_data.ready_constsource == NULL)
698 	  pulse_data.ready_constsource =
699 	       mainloop_constant_source_add(ready_constsource_cb,NULL,FALSE);
700      mainloop_constant_source_enable(pulse_data.ready_constsource, FALSE);
701 }
702 
pulse_output_select_format(Dataformat * format,gboolean silent,GVoidFunc ready_func)703 static gint pulse_output_select_format(Dataformat *format, gboolean silent,
704 				       GVoidFunc ready_func)
705 {
706      ready_constsource_setup();
707      pulse_data.ready_func = ready_func;
708      return pulse_select_format_main(format,FALSE,silent,
709 				     pulse_ready_func,NULL);
710 }
711 
pulse_input_select_format(Dataformat * format,gboolean silent,GVoidFunc ready_func)712 static gint pulse_input_select_format(Dataformat *format, gboolean silent,
713 				      GVoidFunc ready_func)
714 {
715      ready_constsource_setup();
716      pulse_data.ready_func = ready_func;
717      return pulse_select_format_main(format,TRUE,silent,
718 				     pulse_ready_func,NULL);
719 }
720 
pulse_output_want_data(void)721 static gboolean pulse_output_want_data(void)
722 {
723      size_t s;
724      if (pulse_data.stream == NULL) return FALSE;
725      s = pa_stream_writable_size(pulse_data.stream);
726      return (s > 0);
727 }
728 
pulse_flush_success_cb(pa_stream * s,int success,void * userdata)729 static void pulse_flush_success_cb(pa_stream *s, int success, void *userdata)
730 {
731      gchar *c;
732      if (!success) {
733 	  c = g_strdup_printf(_("Failed to drain stream: %s"),
734 			      pa_strerror(pa_context_errno(pulse_data.ctx)));
735 	  user_error(c);
736 	  g_free(c);
737      }
738      /* puts("pulse_flush_success_cb"); */
739      pulse_data.flush_state = 2;
740 }
741 
pulse_flush_start(void)742 static void pulse_flush_start(void)
743 {
744      pa_operation *o;
745 
746      /* puts("pulse_flush_start"); */
747      if (pulse_data.flush_state != 0) return;
748      pulse_data.flush_state = 1;
749      o = pa_stream_drain(pulse_data.stream, pulse_flush_success_cb,
750 			 NULL);
751      g_assert(o != NULL);
752      pa_operation_unref(o);
753 }
754 
pulse_flush_done(void)755 static gboolean pulse_flush_done(void)
756 {
757      return (pulse_data.flush_state == 2);
758 }
759 
pulse_flush_in_progress(void)760 static gboolean pulse_flush_in_progress(void)
761 {
762      return (pulse_data.flush_state == 1);
763 }
764 
pulse_output_play(gchar * buffer,guint bufsize)765 static guint pulse_output_play(gchar *buffer, guint bufsize)
766 {
767      int i;
768      size_t s;
769      if (pulse_data.stream == NULL) return 0;
770      if (buffer == NULL) {
771 	  g_assert(bufsize == 0);
772 	  pulse_flush_start();
773 	  return pulse_flush_done()?0:1;
774      }
775      s = pa_stream_writable_size(pulse_data.stream);
776      if (bufsize > s) bufsize = s;
777      i = pa_stream_write(pulse_data.stream, buffer, bufsize, NULL, 0,
778 			 PA_SEEK_RELATIVE);
779      g_assert(i == 0);
780      if (pulse_data.flush_state == 2)
781 	  pulse_data.flush_state = 0;
782      if (bufsize < s)
783 	  mainloop_constant_source_enable(pulse_data.ready_constsource,TRUE);
784      return bufsize;
785 }
786 
pulse_output_clear_buffers(void)787 static void pulse_output_clear_buffers(void)
788 {
789      pa_operation *p;
790      int i;
791      if (pulse_data.stream == NULL) return;
792      if (inifile_get_gboolean("pulseReconnect",TRUE)) {
793 	  pa_stream_set_write_callback(pulse_data.stream, NULL, NULL);
794 	  pa_stream_set_state_callback(pulse_data.stream, NULL, NULL);
795 	  pa_stream_disconnect(pulse_data.stream);
796 	  pa_stream_unref(pulse_data.stream);
797 	  pulse_data.stream_state = PA_STREAM_UNCONNECTED;
798 	  pulse_data.stream = pa_stream_new(pulse_data.ctx, "p", &pulse_data.stream_sspec, NULL);
799 	  pa_stream_set_state_callback(pulse_data.stream, pulse_stream_state_cb, NULL);
800 	  pa_stream_set_write_callback(pulse_data.stream,pulse_ready_func, NULL);
801 	  i = pa_stream_connect_playback(pulse_data.stream,NULL,
802 					 &pulse_data.stream_attr,
803 					 pulse_data.stream_flags,NULL,
804 					 NULL);
805 	  g_assert(i==0 && pulse_data.stream!=NULL);
806 	  i = pulse_wait_connect(0);
807 	  g_assert(pulse_data.stream_state == PA_STREAM_READY ||
808 		   (i != 0 && pulse_data.stream==NULL) );
809      } else {
810 	  p = pa_stream_flush(pulse_data.stream, NULL, NULL);
811 	  pa_operation_unref(p);
812      }
813 }
814 
pulse_output_stop(gboolean must_flush)815 static gboolean pulse_output_stop(gboolean must_flush)
816 {
817      /* puts("pulse_output_stop"); */
818      if (pulse_data.ready_constsource != NULL)
819 	  mainloop_constant_source_enable(pulse_data.ready_constsource,FALSE);
820      pulse_data.stopping = 1;
821 
822      if (pulse_data.stream != NULL) {
823 	  if (must_flush || pulse_flush_in_progress()) {
824 
825 	       pulse_flush_start();
826 
827 	       pulse_data.recursing_mainloop = TRUE;
828 	       while (!pulse_flush_done())
829 		    pulse_api_block();
830 	       pulse_data.recursing_mainloop = FALSE;
831 	  }
832 	  pulse_data.flush_state = 0;
833 
834 	  pa_stream_disconnect(pulse_data.stream);
835 	  pulse_data.recursing_mainloop = TRUE;
836 	  while (pulse_data.stream != NULL)
837 	       pulse_api_block();
838 	  pulse_data.recursing_mainloop = FALSE;
839 
840      }
841      pulse_data.stopping = 0;
842      return FALSE;
843 }
844 
pulse_needs_polling(void)845 static gboolean pulse_needs_polling(void)
846 {
847      return FALSE;
848 }
849 
850 struct pulse_scb_data {
851      pa_sample_spec ss;
852      gboolean is_set;
853 };
854 
pulse_source_info_cb(pa_context * c,const pa_source_info * i,int eol,gpointer userdata)855 static void pulse_source_info_cb(pa_context *c, const pa_source_info *i,
856 				 int eol, gpointer userdata)
857 {
858      struct pulse_scb_data *dp = (struct pulse_scb_data *)userdata;
859      if (eol) return;
860      memcpy(&(dp->ss),&(i->sample_spec),sizeof(pa_sample_spec));
861      dp->is_set = TRUE;
862 }
863 
864 
865 /* PA 0.9.12-? has a bug where passing @DEFAULT_SOURCE@ doesn't work
866  * Perform a quite messy workaround, ifdef:d with the
867  * DEFUALT_SOURCE_BROKEN macro */
868 
869 /* Becuase PA didn't introduce PA_MAJOR/MINOR/MICRO macros until 0.9.15,
870  * this will have to be done for the older versions as well... */
871 #define DEFAULT_SOURCE_BROKEN
872 
873 
874 #ifdef DEFAULT_SOURCE_BROKEN
875 
pulse_output_info_cb(pa_context * c,const pa_source_output_info * i,int eol,void * userdata)876 static void pulse_output_info_cb(pa_context *c, const pa_source_output_info *i,
877 				 int eol, void *userdata)
878 {
879      int *idxp = (int *)userdata;
880      if (eol || *idxp >= 0) return;
881      *idxp = i->source;
882 }
883 
pulse_get_default_source_index(pa_context * c)884 static int pulse_get_default_source_index(pa_context *c)
885 {
886      pa_stream *str;
887      pa_sample_spec ss;
888      int i;
889      pa_stream_state_t state;
890      pa_operation *oper;
891      pa_operation_state_t oper_state;
892      int idx;
893      int srcidx;
894 
895      ss.format = PA_SAMPLE_S16LE;
896      ss.rate = 44100;
897      ss.channels = 2;
898      str = pa_stream_new(c,"in_fmt_probe",&ss,NULL);
899      g_assert(str != NULL);
900      i = pa_stream_connect_record(str,NULL,NULL,0);
901      g_assert(i == 0);
902      while (1) {
903 	  state = pa_stream_get_state(str);
904 	  if (state != PA_STREAM_CREATING) break;
905 	  pulse_api_block();
906      }
907      if (state != PA_STREAM_READY) {
908 	  printf("pa_stream_connect_record: %s\n",
909 		 pa_strerror(pa_context_errno(c)));
910 	  pa_stream_unref(str);
911 	  return -1;
912      }
913      idx = pa_stream_get_index(str);
914      /*printf("Calling get_source_output_info_by_index with index %d\n",idx);*/
915      srcidx = -1;
916      oper = pa_context_get_source_output_info(c,idx,
917 					      pulse_output_info_cb,
918 					      &srcidx);
919      while (1) {
920 	  oper_state = pa_operation_get_state(oper);
921 	  if (oper_state != PA_OPERATION_RUNNING) break;
922 	  pulse_api_block();
923      }
924      if (srcidx < 0)
925 	  printf("pa_context_get_output_info_by_name: %s\n",
926 		 pa_strerror(pa_context_errno(c)));
927      pa_operation_unref(oper);
928      pa_stream_disconnect(str);
929      pa_stream_unref(str);
930      return srcidx;
931 }
932 
933 #endif
934 
pulse_get_default_source_info(pa_context * c,pa_source_info_cb_t cb,void * userdata)935 static pa_operation *pulse_get_default_source_info(pa_context *c,
936 						   pa_source_info_cb_t cb,
937 						   void *userdata)
938 {
939 #ifdef DEFAULT_SOURCE_BROKEN
940      int i;
941      i = pulse_get_default_source_index(c);
942      if (i < 0) return NULL;
943      return pa_context_get_source_info_by_index(c,i,cb,userdata);
944 #else
945      return pa_context_get_source_info_by_name(c,"@DEFAULT_SOURCE@",cb,
946 					       userdata);
947 #endif
948 }
949 
pulse_input_supported_formats(gboolean * complete)950 static GList *pulse_input_supported_formats(gboolean *complete)
951 {
952      pa_operation *p;
953      struct pulse_scb_data d;
954      Dataformat f,*pf;
955 
956      if (!pulse_connect(TRUE,TRUE)) {
957 	  *complete = TRUE;
958 	  return NULL;
959      }
960      d.is_set = FALSE;
961      p = pulse_get_default_source_info(pulse_data.ctx,
962 				       pulse_source_info_cb,&d);
963      while (p != NULL && pa_operation_get_state(p) == PA_OPERATION_RUNNING)
964 	  pulse_api_block();
965      if (p != NULL) pa_operation_unref(p);
966 
967      if (!d.is_set) {
968 	  /* if (p != NULL) puts("Unexpected p!=NULL"); */
969 
970 	  printf("get_default_source_info: %s\n",
971 		 pa_strerror(pa_context_errno(pulse_data.ctx)));
972 	  *complete = TRUE;
973 	  return NULL;
974      }
975 
976      if (pa_format_from_pulse(&d.ss,&f)) {
977 	  printf("Unsupported input format: %s\n",
978 		 pa_sample_format_to_string(d.ss.format));
979 	  *complete = TRUE;
980 	  return NULL;
981      }
982 
983      pf = g_malloc(sizeof(*pf));
984      memcpy(pf,&f,sizeof(Dataformat));
985      *complete = TRUE;
986      return g_list_append(NULL,pf);
987 }
988 
pulse_input_store(Ringbuf * buf)989 static void pulse_input_store(Ringbuf *buf)
990 {
991      int i;
992      size_t b;
993 
994      if (pulse_data.overflow_report_count < pulse_data.overflow_count) {
995 	  console_message("Overrun occured!");
996 	  pulse_data.overflow_report_count = pulse_data.overflow_count;
997      }
998 
999      if (pulse_data.record_data == NULL) {
1000 	  i = pa_stream_peek(pulse_data.stream,
1001 			     (const void **)&pulse_data.record_data,
1002 			     &pulse_data.record_bytes);
1003 	  if (i != 0) {
1004 	       fprintf(stderr,"mhWaveEdit: pa_stream_peek: %s\n",
1005 		       pa_strerror(pa_context_errno(pulse_data.ctx)));
1006 	       return;
1007 	  }
1008 	  /*
1009 	  printf("pa_stream_peek: i=%d,data=%p,bytes=%d\n",i,
1010 		 pulse_data.record_data,pulse_data.record_bytes);
1011 	  */
1012 	  pulse_data.record_pos = 0;
1013      }
1014 
1015      if (pulse_data.record_data == NULL) return;
1016 
1017      b = ringbuf_enqueue(buf,
1018 			 (gpointer)pulse_data.record_data+pulse_data.record_pos,
1019 			 pulse_data.record_bytes-pulse_data.record_pos);
1020      pulse_data.record_pos += b;
1021 
1022      if (pulse_data.record_pos >= pulse_data.record_bytes) {
1023 	  g_assert(pulse_data.record_pos == pulse_data.record_bytes);
1024 	  pa_stream_drop(pulse_data.stream);
1025 	  pulse_data.record_data = NULL;
1026      } else {
1027 	  mainloop_constant_source_enable(pulse_data.ready_constsource,TRUE);
1028      }
1029 
1030 }
1031 
pulse_input_stop(void)1032 static void pulse_input_stop(void)
1033 {
1034      pulse_data.stopping = TRUE;
1035      if (pulse_data.ready_constsource != NULL)
1036 	  mainloop_constant_source_enable(pulse_data.ready_constsource,FALSE);
1037 
1038      if (pulse_data.stream != NULL) {
1039 
1040 	  g_assert(pulse_data.record_flag);
1041 
1042 	  pa_stream_disconnect(pulse_data.stream);
1043 	  pulse_data.recursing_mainloop = TRUE;
1044 	  while (pulse_data.stream != NULL)
1045 	       pulse_api_block();
1046 	  pulse_data.recursing_mainloop = FALSE;
1047      }
1048      pulse_data.stopping = FALSE;
1049 }
1050 
pulse_input_overrun_count(void)1051 static int pulse_input_overrun_count(void)
1052 {
1053      /* Pulse does not report internal overruns in the source,
1054       * therefore just using the overflow_count could give a false
1055       * impression */
1056      return -1;
1057 }
1058 
1059 
1060 
1061 /* --------------------------------
1062  *  Preferences UI
1063  */
1064 
1065 struct pulse_prefs_ui {
1066      GtkWidget *wnd;
1067      GtkToggleButton *reconn;
1068      Intbox *pblat;
1069 };
1070 
pulse_prefs_ok(GtkButton * button,gpointer user_data)1071 static void pulse_prefs_ok(GtkButton *button, gpointer user_data)
1072 {
1073      struct pulse_prefs_ui *up = (struct pulse_prefs_ui *)user_data;
1074      if (intbox_check_limit(up->pblat,0,10000,_("playback latency")))
1075 	  return;
1076      inifile_set_guint32("pulseLatency",up->pblat->val);
1077      inifile_set_gboolean("pulseReconnect",
1078 			  gtk_toggle_button_get_active(up->reconn));
1079      gtk_widget_destroy(up->wnd);
1080 }
1081 
pulse_preferences(void)1082 static void pulse_preferences(void)
1083 {
1084      GtkWidget *a,*b,*c,*d;
1085      struct pulse_prefs_ui *up;
1086      up = g_malloc(sizeof(*up));
1087      a = gtk_window_new(GTK_WINDOW_DIALOG);
1088      up->wnd = a;
1089      gtk_window_set_title(GTK_WINDOW(a),_("PulseAudio Preferences"));
1090      gtk_window_set_modal(GTK_WINDOW(a),TRUE);
1091      gtk_window_set_position(GTK_WINDOW(a),GTK_WIN_POS_MOUSE);
1092      gtk_container_set_border_width(GTK_CONTAINER(a),5);
1093      gtk_signal_connect_object(GTK_OBJECT(a),"destroy",
1094 			       GTK_SIGNAL_FUNC(g_free),(GtkObject *)up);
1095      b = gtk_vbox_new(FALSE,5);
1096      gtk_container_add(GTK_CONTAINER(a),b);
1097      c = gtk_hbox_new(FALSE,3);
1098      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1099      d = gtk_label_new(_("Playback latency: "));
1100      gtk_box_pack_start(GTK_BOX(c),d,FALSE,FALSE,0);
1101      d = intbox_new(inifile_get_guint32("pulseLatency",0));
1102      up->pblat = INTBOX(d);
1103      gtk_box_pack_start(GTK_BOX(c),d,TRUE,TRUE,0);
1104      d = gtk_label_new(_("ms (0 for maximum)"));
1105      gtk_box_pack_start(GTK_BOX(c),d,FALSE,FALSE,0);
1106      c = gtk_check_button_new_with_label(_("Reconnect when moving playback"));
1107      up->reconn = GTK_TOGGLE_BUTTON(c);
1108      gtk_toggle_button_set_active(up->reconn,inifile_get_gboolean("pulseReconnect",TRUE));
1109      gtk_box_pack_start(GTK_BOX(b),c,FALSE,FALSE,0);
1110      c = gtk_hseparator_new();
1111      gtk_box_pack_end(GTK_BOX(b),c,FALSE,FALSE,0);
1112      c = gtk_hbutton_box_new();
1113      gtk_box_pack_end(GTK_BOX(b),c,FALSE,FALSE,0);
1114      d = gtk_button_new_with_label(_("OK"));
1115      gtk_signal_connect(GTK_OBJECT(d),"clicked",GTK_SIGNAL_FUNC(pulse_prefs_ok),
1116 			up);
1117      gtk_container_add(GTK_CONTAINER(c),d);
1118      d = gtk_button_new_with_label(_("Cancel"));
1119      gtk_signal_connect_object(GTK_OBJECT(d),"clicked",
1120 			       GTK_SIGNAL_FUNC(gtk_widget_destroy),
1121 			       GTK_OBJECT(a));
1122      gtk_container_add(GTK_CONTAINER(c),d);
1123      gtk_widget_show_all(a);
1124 }
1125