···11+Index: decoder_plugins/ffmpeg/ffmpeg.c
22+===================================================================
33+--- /decoder_plugins/ffmpeg/ffmpeg.c (revisión: 2963)
44++++ /decoder_plugins/ffmpeg/ffmpeg.c (copia de trabajo)
55+@@ -697,7 +697,7 @@
66+ * FFmpeg/LibAV in use. For some versions this will be caught in
77+ * *_find_stream_info() above and misreported as an unfound codec
88+ * parameters error. */
99+- if (data->codec->capabilities & CODEC_CAP_EXPERIMENTAL) {
1010++ if (data->codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL) {
1111+ decoder_error (&data->error, ERROR_FATAL, 0,
1212+ "The codec is experimental and may damage MOC: %s",
1313+ data->codec->name);
1414+@@ -705,8 +705,8 @@
1515+ }
1616+1717+ set_downmixing (data);
1818+- if (data->codec->capabilities & CODEC_CAP_TRUNCATED)
1919+- data->enc->flags |= CODEC_FLAG_TRUNCATED;
2020++ if (data->codec->capabilities & AV_CODEC_CAP_TRUNCATED)
2121++ data->enc->flags |= AV_CODEC_FLAG_TRUNCATED;
2222+2323+ if (avcodec_open2 (data->enc, data->codec, NULL) < 0)
2424+ {
2525+@@ -725,7 +725,7 @@
2626+2727+ data->sample_width = sfmt_Bps (data->fmt);
2828+2929+- if (data->codec->capabilities & CODEC_CAP_DELAY)
3030++ if (data->codec->capabilities & AV_CODEC_CAP_DELAY)
3131+ data->delay = true;
3232+ data->seek_broken = is_seek_broken (data);
3333+ data->timing_broken = is_timing_broken (data->ic);
+800
pkgs/applications/audio/moc/pulseaudio.patch
···11+diff --git a/audio.c b/audio.c
22+--- a/audio.c
33++++ b/audio.c
44+@@ -32,6 +32,9 @@
55+ #include "log.h"
66+ #include "lists.h"
77+88++#ifdef HAVE_PULSE
99++# include "pulse.h"
1010++#endif
1111+ #ifdef HAVE_OSS
1212+ # include "oss.h"
1313+ #endif
1414+@@ -893,6 +896,15 @@
1515+ }
1616+ #endif
1717+1818++#ifdef HAVE_PULSE
1919++ if (!strcasecmp(name, "pulseaudio")) {
2020++ pulse_funcs (funcs);
2121++ printf ("Trying PulseAudio...\n");
2222++ if (funcs->init(&hw_caps))
2323++ return;
2424++ }
2525++#endif
2626++
2727+ #ifdef HAVE_OSS
2828+ if (!strcasecmp(name, "oss")) {
2929+ oss_funcs (funcs);
3030+diff --git a/configure.in b/configure.in
3131+--- a/configure.in
3232++++ b/configure.in
3333+@@ -162,6 +162,21 @@
3434+ AC_MSG_ERROR([BerkeleyDB (libdb) not found.]))
3535+ fi
3636+3737++AC_ARG_WITH(pulse, AS_HELP_STRING(--without-pulse,
3838++ Compile without PulseAudio support.))
3939++
4040++if test "x$with_pulse" != "xno"
4141++then
4242++ PKG_CHECK_MODULES(PULSE, [libpulse],
4343++ [SOUND_DRIVERS="$SOUND_DRIVERS PULSE"
4444++ EXTRA_OBJS="$EXTRA_OBJS pulse.o"
4545++ AC_DEFINE([HAVE_PULSE], 1, [Define if you have PulseAudio.])
4646++ EXTRA_LIBS="$EXTRA_LIBS $PULSE_LIBS"
4747++ CFLAGS="$CFLAGS $PULSE_CFLAGS"],
4848++ [true])
4949++fi
5050++
5151++
5252+ AC_ARG_WITH(oss, AS_HELP_STRING([--without-oss],
5353+ [Compile without OSS support]))
5454+5555+diff --git a/options.c b/options.c
5656+--- a/options.c
5757++++ b/options.c
5858+@@ -572,10 +572,11 @@
5959+6060+ #ifdef OPENBSD
6161+ add_list ("SoundDriver", "SNDIO:JACK:OSS",
6262+- CHECK_DISCRETE(5), "SNDIO", "Jack", "ALSA", "OSS", "null");
6363++ CHECK_DISCRETE(5), "SNDIO", "PulseAudio", "Jack", "ALSA", "OSS", "null");
6464++
6565+ #else
6666+ add_list ("SoundDriver", "Jack:ALSA:OSS",
6767+- CHECK_DISCRETE(5), "SNDIO", "Jack", "ALSA", "OSS", "null");
6868++ CHECK_DISCRETE(5), "SNDIO", "PulseAudio", "Jack", "ALSA", "OSS", "null");
6969+ #endif
7070+7171+ add_str ("JackClientName", "moc", CHECK_NONE);
7272+diff --git a/pulse.c b/pulse.c
7373+new file mode 100644
7474+--- /dev/null
7575++++ b/pulse.c
7676+@@ -0,0 +1,705 @@
7777++/*
7878++ * MOC - music on console
7979++ * Copyright (C) 2011 Marien Zwart <marienz@marienz.net>
8080++ *
8181++ * This program is free software; you can redistribute it and/or modify
8282++ * it under the terms of the GNU General Public License as published by
8383++ * the Free Software Foundation; either version 2 of the License, or
8484++ * (at your option) any later version.
8585++ *
8686++ */
8787++
8888++/* PulseAudio backend.
8989++ *
9090++ * FEATURES:
9191++ *
9292++ * Does not autostart a PulseAudio server, but uses an already-started
9393++ * one, which should be better than alsa-through-pulse.
9494++ *
9595++ * Supports control of either our stream's or our entire sink's volume
9696++ * while we are actually playing. Volume control while paused is
9797++ * intentionally unsupported: the PulseAudio documentation strongly
9898++ * suggests not passing in an initial volume when creating a stream
9999++ * (allowing the server to track this instead), and we do not know
100100++ * which sink to control if we do not have a stream open.
101101++ *
102102++ * IMPLEMENTATION:
103103++ *
104104++ * Most client-side (resource allocation) errors are fatal. Failure to
105105++ * create a server context or stream is not fatal (and MOC should cope
106106++ * with these failures too), but server communication failures later
107107++ * on are currently not handled (MOC has no great way for us to tell
108108++ * it we no longer work, and I am not sure if attempting to reconnect
109109++ * is worth it or even a good idea).
110110++ *
111111++ * The pulse "simple" API is too simple: it combines connecting to the
112112++ * server and opening a stream into one operation, while I want to
113113++ * connect to the server when MOC starts (and fall back to a different
114114++ * backend if there is no server), and I cannot open a stream at that
115115++ * time since I do not know the audio format yet.
116116++ *
117117++ * PulseAudio strongly recommends we use a high-latency connection,
118118++ * which the MOC frontend code might not expect from its audio
119119++ * backend. We'll see.
120120++ *
121121++ * We map MOC's percentage volumes linearly to pulse's PA_VOLUME_MUTED
122122++ * (0) .. PA_VOLUME_NORM range. This is what the PulseAudio docs recommend
123123++ * ( http://pulseaudio.org/wiki/WritingVolumeControlUIs ). It does mean
124124++ * PulseAudio volumes above PA_VOLUME_NORM do not work well with MOC.
125125++ *
126126++ * Comments in audio.h claim "All functions are executed only by one
127127++ * thread" (referring to the function in the hw_funcs struct). This is
128128++ * a blatant lie. Most of them are invoked off the "output buffer"
129129++ * thread (out_buf.c) but at least the "playing" thread (audio.c)
130130++ * calls audio_close which calls our close function. We can mostly
131131++ * ignore this problem because we serialize on the pulseaudio threaded
132132++ * mainloop lock. But it does mean that functions that are normally
133133++ * only called between open and close (like reset) are sometimes
134134++ * called without us having a stream. Bulletproof, therefore:
135135++ * serialize setting/unsetting our global stream using the threaded
136136++ * mainloop lock, and check for that stream being non-null before
137137++ * using it.
138138++ *
139139++ * I am not convinced there are no further dragons lurking here: can
140140++ * the "playing" thread(s) close and reopen our output stream while
141141++ * the "output buffer" thread is sending output there? We can bail if
142142++ * our stream is simply closed, but we do not currently detect it
143143++ * being reopened and no longer using the same sample format, which
144144++ * might have interesting results...
145145++ *
146146++ * Also, read_mixer is called from the main server thread (handling
147147++ * commands). This crashed me once when it got at a stream that was in
148148++ * the "creating" state and therefore did not have a valid stream
149149++ * index yet. Fixed by only assigning to the stream global when the
150150++ * stream is valid.
151151++ */
152152++
153153++#ifdef HAVE_CONFIG_H
154154++# include "config.h"
155155++#endif
156156++
157157++#define DEBUG
158158++
159159++#include <pulse/pulseaudio.h>
160160++#include "common.h"
161161++#include "log.h"
162162++#include "audio.h"
163163++
164164++
165165++/* The pulse mainloop and context are initialized in pulse_init and
166166++ * destroyed in pulse_shutdown.
167167++ */
168168++static pa_threaded_mainloop *mainloop = NULL;
169169++static pa_context *context = NULL;
170170++
171171++/* The stream is initialized in pulse_open and destroyed in pulse_close. */
172172++static pa_stream *stream = NULL;
173173++
174174++static int showing_sink_volume = 0;
175175++
176176++/* Callbacks that do nothing but wake up the mainloop. */
177177++
178178++static void context_state_callback (pa_context *context ATTR_UNUSED,
179179++ void *userdata)
180180++{
181181++ pa_threaded_mainloop *m = userdata;
182182++
183183++ pa_threaded_mainloop_signal (m, 0);
184184++}
185185++
186186++static void stream_state_callback (pa_stream *stream ATTR_UNUSED,
187187++ void *userdata)
188188++{
189189++ pa_threaded_mainloop *m = userdata;
190190++
191191++ pa_threaded_mainloop_signal (m, 0);
192192++}
193193++
194194++static void stream_write_callback (pa_stream *stream ATTR_UNUSED,
195195++ size_t nbytes ATTR_UNUSED, void *userdata)
196196++{
197197++ pa_threaded_mainloop *m = userdata;
198198++
199199++ pa_threaded_mainloop_signal (m, 0);
200200++}
201201++
202202++/* Initialize pulse mainloop and context. Failure to connect to the
203203++ * pulse daemon is nonfatal, everything else is fatal (as it
204204++ * presumably means we ran out of resources).
205205++ */
206206++static int pulse_init (struct output_driver_caps *caps)
207207++{
208208++ pa_context *c;
209209++ pa_proplist *proplist;
210210++
211211++ assert (!mainloop);
212212++ assert (!context);
213213++
214214++ mainloop = pa_threaded_mainloop_new ();
215215++ if (!mainloop)
216216++ fatal ("Cannot create PulseAudio mainloop");
217217++
218218++ if (pa_threaded_mainloop_start (mainloop) < 0)
219219++ fatal ("Cannot start PulseAudio mainloop");
220220++
221221++ /* TODO: possibly add more props.
222222++ *
223223++ * There are a few we could set in proplist.h but nothing I
224224++ * expect to be very useful.
225225++ *
226226++ * http://pulseaudio.org/wiki/ApplicationProperties recommends
227227++ * setting at least application.name, icon.name and media.role.
228228++ *
229229++ * No need to set application.name here, the name passed to
230230++ * pa_context_new_with_proplist overrides it.
231231++ */
232232++ proplist = pa_proplist_new ();
233233++ if (!proplist)
234234++ fatal ("Cannot allocate PulseAudio proplist");
235235++
236236++ pa_proplist_sets (proplist,
237237++ PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION);
238238++ pa_proplist_sets (proplist, PA_PROP_MEDIA_ROLE, "music");
239239++ pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "net.daper.moc");
240240++
241241++ pa_threaded_mainloop_lock (mainloop);
242242++
243243++ c = pa_context_new_with_proplist (
244244++ pa_threaded_mainloop_get_api (mainloop),
245245++ PACKAGE_NAME, proplist);
246246++ pa_proplist_free (proplist);
247247++
248248++ if (!c)
249249++ fatal ("Cannot allocate PulseAudio context");
250250++
251251++ pa_context_set_state_callback (c, context_state_callback, mainloop);
252252++
253253++ /* Ignore return value, rely on state being set properly */
254254++ pa_context_connect (c, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
255255++
256256++ while (1) {
257257++ pa_context_state_t state = pa_context_get_state (c);
258258++
259259++ if (state == PA_CONTEXT_READY)
260260++ break;
261261++
262262++ if (!PA_CONTEXT_IS_GOOD (state)) {
263263++ error ("PulseAudio connection failed: %s",
264264++ pa_strerror (pa_context_errno (c)));
265265++
266266++ goto unlock_and_fail;
267267++ }
268268++
269269++ debug ("waiting for context to become ready...");
270270++ pa_threaded_mainloop_wait (mainloop);
271271++ }
272272++
273273++ /* Only set the global now that the context is actually ready */
274274++ context = c;
275275++
276276++ pa_threaded_mainloop_unlock (mainloop);
277277++
278278++ /* We just make up the hardware capabilities, since pulse is
279279++ * supposed to be abstracting these out. Assume pulse will
280280++ * deal with anything we want to throw at it, and that we will
281281++ * only want mono or stereo audio.
282282++ */
283283++ caps->min_channels = 1;
284284++ caps->max_channels = 2;
285285++ caps->formats = (SFMT_S8 | SFMT_S16 | SFMT_S32 |
286286++ SFMT_FLOAT | SFMT_BE | SFMT_LE);
287287++
288288++ return 1;
289289++
290290++unlock_and_fail:
291291++
292292++ pa_context_unref (c);
293293++
294294++ pa_threaded_mainloop_unlock (mainloop);
295295++
296296++ pa_threaded_mainloop_stop (mainloop);
297297++ pa_threaded_mainloop_free (mainloop);
298298++ mainloop = NULL;
299299++
300300++ return 0;
301301++}
302302++
303303++static void pulse_shutdown (void)
304304++{
305305++ pa_threaded_mainloop_lock (mainloop);
306306++
307307++ pa_context_disconnect (context);
308308++ pa_context_unref (context);
309309++ context = NULL;
310310++
311311++ pa_threaded_mainloop_unlock (mainloop);
312312++
313313++ pa_threaded_mainloop_stop (mainloop);
314314++ pa_threaded_mainloop_free (mainloop);
315315++ mainloop = NULL;
316316++}
317317++
318318++static int pulse_open (struct sound_params *sound_params)
319319++{
320320++ pa_sample_spec ss;
321321++ pa_buffer_attr ba;
322322++ pa_stream *s;
323323++
324324++ assert (!stream);
325325++ /* Initialize everything to -1, which in practice gets us
326326++ * about 2 seconds of latency (which is fine). This is not the
327327++ * same as passing NULL for this struct, which gets us an
328328++ * unnecessarily short alsa-like latency.
329329++ */
330330++ ba.fragsize = (uint32_t) -1;
331331++ ba.tlength = (uint32_t) -1;
332332++ ba.prebuf = (uint32_t) -1;
333333++ ba.minreq = (uint32_t) -1;
334334++ ba.maxlength = (uint32_t) -1;
335335++
336336++ ss.channels = sound_params->channels;
337337++ ss.rate = sound_params->rate;
338338++ switch (sound_params->fmt) {
339339++ case SFMT_U8:
340340++ ss.format = PA_SAMPLE_U8;
341341++ break;
342342++ case SFMT_S16 | SFMT_LE:
343343++ ss.format = PA_SAMPLE_S16LE;
344344++ break;
345345++ case SFMT_S16 | SFMT_BE:
346346++ ss.format = PA_SAMPLE_S16BE;
347347++ break;
348348++ case SFMT_FLOAT | SFMT_LE:
349349++ ss.format = PA_SAMPLE_FLOAT32LE;
350350++ break;
351351++ case SFMT_FLOAT | SFMT_BE:
352352++ ss.format = PA_SAMPLE_FLOAT32BE;
353353++ break;
354354++ case SFMT_S32 | SFMT_LE:
355355++ ss.format = PA_SAMPLE_S32LE;
356356++ break;
357357++ case SFMT_S32 | SFMT_BE:
358358++ ss.format = PA_SAMPLE_S32BE;
359359++ break;
360360++
361361++ default:
362362++ fatal ("pulse: got unrequested format");
363363++ }
364364++
365365++ debug ("opening stream");
366366++
367367++ pa_threaded_mainloop_lock (mainloop);
368368++
369369++ /* TODO: figure out if there are useful stream properties to set.
370370++ *
371371++ * I do not really see any in proplist.h that we can set from
372372++ * here (there are media title/artist/etc props but we do not
373373++ * have that data available here).
374374++ */
375375++ s = pa_stream_new (context, "music", &ss, NULL);
376376++ if (!s)
377377++ fatal ("pulse: stream allocation failed");
378378++
379379++ pa_stream_set_state_callback (s, stream_state_callback, mainloop);
380380++ pa_stream_set_write_callback (s, stream_write_callback, mainloop);
381381++
382382++ /* Ignore return value, rely on failed stream state instead. */
383383++ pa_stream_connect_playback (
384384++ s, NULL, &ba,
385385++ PA_STREAM_INTERPOLATE_TIMING |
386386++ PA_STREAM_AUTO_TIMING_UPDATE |
387387++ PA_STREAM_ADJUST_LATENCY,
388388++ NULL, NULL);
389389++
390390++ while (1) {
391391++ pa_stream_state_t state = pa_stream_get_state (s);
392392++
393393++ if (state == PA_STREAM_READY)
394394++ break;
395395++
396396++ if (!PA_STREAM_IS_GOOD (state)) {
397397++ error ("PulseAudio stream connection failed");
398398++
399399++ goto fail;
400400++ }
401401++
402402++ debug ("waiting for stream to become ready...");
403403++ pa_threaded_mainloop_wait (mainloop);
404404++ }
405405++
406406++ /* Only set the global stream now that it is actually ready */
407407++ stream = s;
408408++
409409++ pa_threaded_mainloop_unlock (mainloop);
410410++
411411++ return 1;
412412++
413413++fail:
414414++ pa_stream_unref (s);
415415++
416416++ pa_threaded_mainloop_unlock (mainloop);
417417++ return 0;
418418++}
419419++
420420++static void pulse_close (void)
421421++{
422422++ debug ("closing stream");
423423++
424424++ pa_threaded_mainloop_lock (mainloop);
425425++
426426++ pa_stream_disconnect (stream);
427427++ pa_stream_unref (stream);
428428++ stream = NULL;
429429++
430430++ pa_threaded_mainloop_unlock (mainloop);
431431++}
432432++
433433++static int pulse_play (const char *buff, const size_t size)
434434++{
435435++ size_t offset = 0;
436436++
437437++ debug ("Got %d bytes to play", (int)size);
438438++
439439++ pa_threaded_mainloop_lock (mainloop);
440440++
441441++ /* The buffer is usually writable when we get here, and there
442442++ * are usually few (if any) writes after the first one. So
443443++ * there is no point in doing further writes directly from the
444444++ * callback: we can just do all writes from this thread.
445445++ */
446446++
447447++ /* Break out of the loop if some other thread manages to close
448448++ * our stream underneath us.
449449++ */
450450++ while (stream) {
451451++ size_t towrite = MIN(pa_stream_writable_size (stream),
452452++ size - offset);
453453++ debug ("writing %d bytes", (int)towrite);
454454++
455455++ /* We have no working way of dealing with errors
456456++ * (see below). */
457457++ if (pa_stream_write(stream, buff + offset, towrite,
458458++ NULL, 0, PA_SEEK_RELATIVE))
459459++ error ("pa_stream_write failed");
460460++
461461++ offset += towrite;
462462++
463463++ if (offset >= size)
464464++ break;
465465++
466466++ pa_threaded_mainloop_wait (mainloop);
467467++ }
468468++
469469++ pa_threaded_mainloop_unlock (mainloop);
470470++
471471++ debug ("Done playing!");
472472++
473473++ /* We should always return size, calling code does not deal
474474++ * well with anything else. Only read the rest if you want to
475475++ * know why.
476476++ *
477477++ * The output buffer reader thread (out_buf.c:read_thread)
478478++ * repeatedly loads some 64k/0.1s of audio into a buffer on
479479++ * the stack, then calls audio_send_pcm repeatedly until this
480480++ * entire buffer has been processed (similar to the loop in
481481++ * this function). audio_send_pcm applies the softmixer and
482482++ * equalizer, then feeds the result to this function, passing
483483++ * through our return value.
484484++ *
485485++ * So if we return less than size the equalizer/softmixer is
486486++ * re-applied to the remaining data, which is silly. Also,
487487++ * audio_send_pcm checks for our return value being zero and
488488++ * calls fatal() if it is, so try to always process *some*
489489++ * data. Also, out_buf.c uses the return value of this
490490++ * function from the last run through its inner loop to update
491491++ * its time attribute, which means it will be interestingly
492492++ * off if that loop ran more than once.
493493++ *
494494++ * Oh, and alsa.c seems to think it can return -1 to indicate
495495++ * failure, which will cause out_buf.c to rewind its buffer
496496++ * (to before its start, usually).
497497++ */
498498++ return size;
499499++}
500500++
501501++static void volume_cb (const pa_cvolume *v, void *userdata)
502502++{
503503++ int *result = userdata;
504504++
505505++ if (v)
506506++ *result = 100 * pa_cvolume_avg (v) / PA_VOLUME_NORM;
507507++
508508++ pa_threaded_mainloop_signal (mainloop, 0);
509509++}
510510++
511511++static void sink_volume_cb (pa_context *c ATTR_UNUSED,
512512++ const pa_sink_info *i, int eol ATTR_UNUSED,
513513++ void *userdata)
514514++{
515515++ volume_cb (i ? &i->volume : NULL, userdata);
516516++}
517517++
518518++static void sink_input_volume_cb (pa_context *c ATTR_UNUSED,
519519++ const pa_sink_input_info *i,
520520++ int eol ATTR_UNUSED,
521521++ void *userdata ATTR_UNUSED)
522522++{
523523++ volume_cb (i ? &i->volume : NULL, userdata);
524524++}
525525++
526526++static int pulse_read_mixer (void)
527527++{
528528++ pa_operation *op;
529529++ int result = 0;
530530++
531531++ debug ("read mixer");
532532++
533533++ pa_threaded_mainloop_lock (mainloop);
534534++
535535++ if (stream) {
536536++ if (showing_sink_volume)
537537++ op = pa_context_get_sink_info_by_index (
538538++ context, pa_stream_get_device_index (stream),
539539++ sink_volume_cb, &result);
540540++ else
541541++ op = pa_context_get_sink_input_info (
542542++ context, pa_stream_get_index (stream),
543543++ sink_input_volume_cb, &result);
544544++
545545++ while (pa_operation_get_state (op) == PA_OPERATION_RUNNING)
546546++ pa_threaded_mainloop_wait (mainloop);
547547++
548548++ pa_operation_unref (op);
549549++ }
550550++
551551++ pa_threaded_mainloop_unlock (mainloop);
552552++
553553++ return result;
554554++}
555555++
556556++static void pulse_set_mixer (int vol)
557557++{
558558++ pa_cvolume v;
559559++ pa_operation *op;
560560++
561561++ /* Setting volume for one channel does the right thing. */
562562++ pa_cvolume_set(&v, 1, vol * PA_VOLUME_NORM / 100);
563563++
564564++ pa_threaded_mainloop_lock (mainloop);
565565++
566566++ if (stream) {
567567++ if (showing_sink_volume)
568568++ op = pa_context_set_sink_volume_by_index (
569569++ context, pa_stream_get_device_index (stream),
570570++ &v, NULL, NULL);
571571++ else
572572++ op = pa_context_set_sink_input_volume (
573573++ context, pa_stream_get_index (stream),
574574++ &v, NULL, NULL);
575575++
576576++ pa_operation_unref (op);
577577++ }
578578++
579579++ pa_threaded_mainloop_unlock (mainloop);
580580++}
581581++
582582++static int pulse_get_buff_fill (void)
583583++{
584584++ /* This function is problematic. MOC uses it to for the "time
585585++ * remaining" in the UI, but calls it more than once per
586586++ * second (after each chunk of audio played, not for each
587587++ * playback time update). We have to be fairly accurate here
588588++ * for that time remaining to not jump weirdly. But PulseAudio
589589++ * cannot give us a 100% accurate value here, as it involves a
590590++ * server roundtrip. And if we call this a lot it suggests
591591++ * switching to a mode where the value is interpolated, making
592592++ * it presumably more inaccurate (see the flags we pass to
593593++ * pa_stream_connect_playback).
594594++ *
595595++ * MOC also contains what I believe to be a race: it calls
596596++ * audio_get_buff_fill "soon" (after playing the first chunk)
597597++ * after starting playback of the next song, at which point we
598598++ * still have part of the previous song buffered. This means
599599++ * our position into the new song is negative, which fails an
600600++ * assert (in out_buf.c:out_buf_time_get). There is no sane
601601++ * way for us to detect this condition. I believe no other
602602++ * backend triggers this because the assert sits after an
603603++ * implicit float -> int seconds conversion, which means we
604604++ * have to be off by at least an entire second to get a
605605++ * negative value, and none of the other backends have buffers
606606++ * that large (alsa buffers are supposedly a few 100 ms).
607607++ */
608608++ pa_usec_t buffered_usecs = 0;
609609++ int buffered_bytes = 0;
610610++
611611++ pa_threaded_mainloop_lock (mainloop);
612612++
613613++ /* Using pa_stream_get_timing_info and returning the distance
614614++ * between write_index and read_index would be more obvious,
615615++ * but because of how the result is actually used I believe
616616++ * using the latency value is slightly more correct, and it
617617++ * makes the following crash-avoidance hack more obvious.
618618++ */
619619++
620620++ /* This function will frequently fail the first time we call
621621++ * it (pulse does not have the requested data yet). We ignore
622622++ * that and just return 0.
623623++ *
624624++ * Deal with stream being NULL too, just in case this is
625625++ * called in a racy fashion similar to how reset() is.
626626++ */
627627++ if (stream &&
628628++ pa_stream_get_latency (stream, &buffered_usecs, NULL) >= 0) {
629629++ /* Crash-avoidance HACK: floor our latency to at most
630630++ * 1 second. It is usually more, but reporting that at
631631++ * the start of playback crashes MOC, and we cannot
632632++ * sanely detect when reporting it is safe.
633633++ */
634634++ if (buffered_usecs > 1000000)
635635++ buffered_usecs = 1000000;
636636++
637637++ buffered_bytes = pa_usec_to_bytes (
638638++ buffered_usecs,
639639++ pa_stream_get_sample_spec (stream));
640640++ }
641641++
642642++ pa_threaded_mainloop_unlock (mainloop);
643643++
644644++ debug ("buffer fill: %d usec / %d bytes",
645645++ (int) buffered_usecs, (int) buffered_bytes);
646646++
647647++ return buffered_bytes;
648648++}
649649++
650650++static void flush_callback (pa_stream *s ATTR_UNUSED, int success,
651651++ void *userdata)
652652++{
653653++ int *result = userdata;
654654++
655655++ *result = success;
656656++
657657++ pa_threaded_mainloop_signal (mainloop, 0);
658658++}
659659++
660660++static int pulse_reset (void)
661661++{
662662++ pa_operation *op;
663663++ int result = 0;
664664++
665665++ debug ("reset requested");
666666++
667667++ pa_threaded_mainloop_lock (mainloop);
668668++
669669++ /* We *should* have a stream here, but MOC is racy, so bulletproof */
670670++ if (stream) {
671671++ op = pa_stream_flush (stream, flush_callback, &result);
672672++
673673++ while (pa_operation_get_state (op) == PA_OPERATION_RUNNING)
674674++ pa_threaded_mainloop_wait (mainloop);
675675++
676676++ pa_operation_unref (op);
677677++ } else
678678++ logit ("pulse_reset() called without a stream");
679679++
680680++ pa_threaded_mainloop_unlock (mainloop);
681681++
682682++ return result;
683683++}
684684++
685685++static int pulse_get_rate (void)
686686++{
687687++ /* This is called once right after open. Do not bother making
688688++ * this fast. */
689689++
690690++ int result;
691691++
692692++ pa_threaded_mainloop_lock (mainloop);
693693++
694694++ if (stream)
695695++ result = pa_stream_get_sample_spec (stream)->rate;
696696++ else {
697697++ error ("get_rate called without a stream");
698698++ result = 0;
699699++ }
700700++
701701++ pa_threaded_mainloop_unlock (mainloop);
702702++
703703++ return result;
704704++}
705705++
706706++static void pulse_toggle_mixer_channel (void)
707707++{
708708++ showing_sink_volume = !showing_sink_volume;
709709++}
710710++
711711++static void sink_name_cb (pa_context *c ATTR_UNUSED,
712712++ const pa_sink_info *i, int eol ATTR_UNUSED,
713713++ void *userdata)
714714++{
715715++ char **result = userdata;
716716++
717717++ if (i && !*result)
718718++ *result = xstrdup (i->name);
719719++
720720++ pa_threaded_mainloop_signal (mainloop, 0);
721721++}
722722++
723723++static void sink_input_name_cb (pa_context *c ATTR_UNUSED,
724724++ const pa_sink_input_info *i,
725725++ int eol ATTR_UNUSED,
726726++ void *userdata)
727727++{
728728++ char **result = userdata;
729729++
730730++ if (i && !*result)
731731++ *result = xstrdup (i->name);
732732++
733733++ pa_threaded_mainloop_signal (mainloop, 0);
734734++}
735735++
736736++static char *pulse_get_mixer_channel_name (void)
737737++{
738738++ char *result = NULL;
739739++ pa_operation *op;
740740++
741741++ pa_threaded_mainloop_lock (mainloop);
742742++
743743++ if (stream) {
744744++ if (showing_sink_volume)
745745++ op = pa_context_get_sink_info_by_index (
746746++ context, pa_stream_get_device_index (stream),
747747++ sink_name_cb, &result);
748748++ else
749749++ op = pa_context_get_sink_input_info (
750750++ context, pa_stream_get_index (stream),
751751++ sink_input_name_cb, &result);
752752++
753753++ while (pa_operation_get_state (op) == PA_OPERATION_RUNNING)
754754++ pa_threaded_mainloop_wait (mainloop);
755755++
756756++ pa_operation_unref (op);
757757++ }
758758++
759759++ pa_threaded_mainloop_unlock (mainloop);
760760++
761761++ if (!result)
762762++ result = xstrdup ("disconnected");
763763++
764764++ return result;
765765++}
766766++
767767++void pulse_funcs (struct hw_funcs *funcs)
768768++{
769769++ funcs->init = pulse_init;
770770++ funcs->shutdown = pulse_shutdown;
771771++ funcs->open = pulse_open;
772772++ funcs->close = pulse_close;
773773++ funcs->play = pulse_play;
774774++ funcs->read_mixer = pulse_read_mixer;
775775++ funcs->set_mixer = pulse_set_mixer;
776776++ funcs->get_buff_fill = pulse_get_buff_fill;
777777++ funcs->reset = pulse_reset;
778778++ funcs->get_rate = pulse_get_rate;
779779++ funcs->toggle_mixer_channel = pulse_toggle_mixer_channel;
780780++ funcs->get_mixer_channel_name = pulse_get_mixer_channel_name;
781781++}
782782+diff --git a/pulse.h b/pulse.h
783783+new file mode 100644
784784+--- /dev/null
785785++++ b/pulse.h
786786+@@ -0,0 +1,14 @@
787787++#ifndef PULSE_H
788788++#define PULSE_H
789789++
790790++#ifdef __cplusplus
791791++extern "C" {
792792++#endif
793793++
794794++void pulse_funcs (struct hw_funcs *funcs);
795795++
796796++#ifdef __cplusplus
797797++}
798798++#endif
799799++
800800++#endif