Re: [pulseaudio-discuss] My attempt to reduce latency with pacat and tvtime

2012-05-21 Thread Steven Elliott
On Mon, 2012-05-21 at 21:09 +0600, Alexander E. Patrakov wrote:
 2012/5/21 Pierre-Louis Bossart pierre-louis.boss...@linux.intel.com:
  I am not sure if there's really a problem. Increasing the audio latency
  doesn't necessarily result in A/V sync issues. As long as the A/V sync is
  done by querying how many samples are queued instead of using the number of
  samples pushed into PulseAudio, you should be able to use pretty much
  whatever buffer size you want. It's the same issue with ALSA, if you use
  large buffers and base the A/V on the number of samples written to the ring
  buffer, A/V sync will be off. Use snd_pcm_delay() and you'll be fine.
 
 Dear Pierre-Louis,
 
 this thread is based on a misunderstanding. The original poster,
 instead of asking someone to fix the original problem (see below),
 asks you about workarounds, and you don't see the big picture.

Thanks for that explanation.  Yes, the issue is that tvtime does not
handle A/V sync and yes, admittedly I'm trying to fix the problem
somewhere other than where it should be fixed ideally.  But I thought
this might be a case where it would be easiest to fix the problem in
PulseAudio.

-- 

|  Steven Elliott  |  http://selliott.org  |  sellio...@austin.rr.com  |


___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] My attempt to reduce latency with pacat and tvtime

2012-05-21 Thread Steven Elliott
On Mon, 2012-05-21 at 18:15 -0500, Pierre-Louis Bossart wrote:
  1) TVtime (that's what the original poster uses): doesn't handle audio
  at all (but I was told that there is a fork that does), assumes that
  there is a zero-latency analog wire coming from the TV tuner audio
  output to the sound card's TV input. That's why the OP asks about
  module-loopback and/or parec|pacat solution, as a replacement of the
  said wire. Due to the now-invalid assumption about the wire, zero
  latency is needed. Because the audio chain is external to tvtime,
  there is no possibility for any A/V sync queries.
 
 Isn't the simplest solution to add a fixed delay for the video in 
 TVtime, and apply the same fixed delay in module-loopback? 

That's an interesting idea.  I suppose the audio frames would have to be
queued up and then rendered after the appropriate delay.  I'm not sure
if that would be simpler than my patch or not.  I'd have to know more
about how tvtime handles audio.

One concern is that tvtime has not had a release since 2005.  Also, are
there other programs that don't maintain A/V sync?  Perhaps it would
benefit them as well.

 Any attempts 
 to emulate the behavior of an zero-latency analog wire with PulseAudio 
 aren't very likely to succeed :-)

Fair enough.  My hope was just to keep it low enough.

-- 

|  Steven Elliott  |  http://selliott.org  |  sellio...@austin.rr.com  |


___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] My attempt to reduce latency with pacat and tvtime

2012-05-19 Thread Steven Elliott
On Mon, 2012-03-26 at 23:54 -0500, Steven Elliott wrote:
 I use tvtime (an open source TV application) to watch TV on my Fedora 16
 system.  As some of you may know forwarding audio from the sound card
 built into the TV tuner card to the primary sound card is not done by
 tvtime.  There are various ways of forwarding the audio including SoX,
 module-loopback, etc. but I've had the best luck (least latency) using
 pacat in a manner similar to what this webpage describes:
 
 http://thelinuxexperiment.com/guinea-pigs/tyler-b/fix-pulseaudio-loopback-delay/
 
 But with a change that I've made to pacat that I'd like to share in case
 it's helpful.

Since I've posted the above I've refined my patch a bit, which I've
attached, but I've also explored an additional cause of latency in the
PulseAudio server.  I've found that, if for some reason, there
is an underrun the watermark or latency is increased via
increase_watermark() in alsa-source.c and alsa-sink.c.  That probably
makes sense in a lot of cases, but in the case of watching TV via tvtime
I'd rather suffer a fleeting glitch due to underrun than a longer
lasting A/V sync issue.

I don't think the attached
pulseaudio-limited-watermark-experimental.diff patch is ideal which
why I marked it experimental.  Consequently I'm curious if there is
potential for it to evolve into a submitable patch.  Should the 50 msec
limit that I've imposed in fix_tsched_watermark() be configurable?
Would it be preferable to decrease the watermark more aggressively in
decrease_watermark()?

-- 

|  Steven Elliott  |  http://selliott.org  |  sellio...@austin.rr.com  |

This experimental patch adds a --drain option to pacat that causes pacat
to drain extra data from stdin.  This is helpful when pacat is used to forward
audio from one audio card to another with minimal latency.

--- man/pacat.1.xml.in.orig	2011-03-20 08:28:04.299902459 -0500
+++ man/pacat.1.xml.in	2012-04-06 15:12:55.642080385 -0500
@@ -212,6 +212,14 @@
 /option
 
 option
+  popt--drain/opt/p
+  optdescpContinually drain stdin.  This is used for forwarding
+  audio from one device to another where latency is to be minimized
+  by discarding extra audio from stdin when this program is invoked
+  as cmdpacat/cmd./p/optdesc
+/option
+
+option
   popt--property/optarg=PROPERTY=VALUE/arg/p
   optdescpAttach a property to the client and stream. May be
   used multiple times/p/optdesc
--- src/utils/pacat.c.orig	2011-06-23 15:18:54.497124797 -0500
+++ src/utils/pacat.c	2012-04-06 15:25:53.478846580 -0500
@@ -51,6 +51,12 @@
 
 #define CLEAR_LINE \x1B[K
 
+/* It's not obvious what to set this to.  Setting it has high as 100 causes
+   bit of a delay before draining, but makes the adjustments less frequent. */
+#define DRAIN_THRESHOLD 5
+
+#define DRAIN_BYTES 65536
+
 static enum { RECORD, PLAYBACK } mode = PLAYBACK;
 
 static pa_context *context = NULL;
@@ -70,6 +76,7 @@
 static pa_bool_t verbose = FALSE;
 static pa_volume_t volume = PA_VOLUME_NORM;
 static pa_bool_t volume_is_set = FALSE;
+static pa_bool_t drain = FALSE;
 
 static pa_sample_spec sample_spec = {
 .format = PA_SAMPLE_S16LE,
@@ -501,8 +508,9 @@
 
 /* New data on STDIN **/
 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
-size_t l, w = 0;
+size_t l, l_extra, w = 0;
 ssize_t r;
+static int full_reads; /* Consecutive full reads (all bytes read). */
 
 pa_assert(a == mainloop_api);
 pa_assert(e);
@@ -516,9 +524,14 @@
 if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
 l = 4096;
 
-buffer = pa_xmalloc(l);
+if (drain) {
+l_extra = (full_reads  DRAIN_THRESHOLD) ? (l + DRAIN_BYTES) : l;
+} else {
+l_extra = l;
+}
+buffer = pa_xmalloc(l_extra);
 
-if ((r = read(fd, buffer, l)) = 0) {
+if ((r = read(fd, buffer, l_extra)) = 0) {
 if (r == 0) {
 if (verbose)
 pa_log(_(Got EOF.));
@@ -535,8 +548,31 @@
 return;
 }
 
-buffer_length = (uint32_t) r;
-buffer_index = 0;
+if (drain) {
+if ((size_t) r == l_extra) {
+full_reads++;
+}
+else {
+full_reads = 0;
+}
+}
+
+if ((size_t) r  l) {
+/* The read exceeds the writeable size.  Find the end of the buffer
+   that is aligned on a 4 byte boundary.
+   TODO: This probably fails if frame_size is not a power of 2. */
+const pa_sample_spec *spec = pa_stream_get_sample_spec(stream);
+size_t frame_size = pa_frame_size(spec);
+buffer_index = (~frame_size)  (r - l);
+buffer_length = (size_t) r - buffer_index;
+if (buffer_length  l)
+{
+buffer_length 

Re: [pulseaudio-discuss] My attempt to reduce latency with pacat and tvtime

2012-03-27 Thread Pierre-Louis Bossart

On 3/26/2012 11:54 PM, Steven Elliott wrote:

I use tvtime (an open source TV application) to watch TV on my Fedora 16
system.  As some of you may know forwarding audio from the sound card
built into the TV tuner card to the primary sound card is not done by
tvtime.  There are various ways of forwarding the audio including SoX,
module-loopback, etc. but I've had the best luck (least latency) using
pacat in a manner similar to what this webpage describes:

http://thelinuxexperiment.com/guinea-pigs/tyler-b/fix-pulseaudio-loopback-delay/

But with a change that I've made to pacat that I'd like to share in case
it's helpful.


Why not use module-loopback with latency set to a low value? Worked well 
when I last used it.

-Pierre
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


Re: [pulseaudio-discuss] My attempt to reduce latency with pacat and tvtime

2012-03-27 Thread Steven Elliott
On Tue, 2012-03-27 at 12:16 -0500, Pierre-Louis Bossart wrote:
 On 3/26/2012 11:54 PM, Steven Elliott wrote:
  I use tvtime (an open source TV application) to watch TV on my Fedora 16
  system.  As some of you may know forwarding audio from the sound card
  built into the TV tuner card to the primary sound card is not done by
  tvtime.  There are various ways of forwarding the audio including SoX,
  module-loopback, etc. but I've had the best luck (least latency) using
  pacat in a manner similar to what this webpage describes:
 
  http://thelinuxexperiment.com/guinea-pigs/tyler-b/fix-pulseaudio-loopback-delay/
 
  But with a change that I've made to pacat that I'd like to share in case
  it's helpful.
 
 Why not use module-loopback with latency set to a low value? Worked well 
 when I last used it.

I have tried it, but I've had better luck with the pacat solution I
outlined.  I've tried various latency times for each.

I just noticed that pa_stream_writable_size() typically returns values
that make sense for 23 msec instead of the 1 msec that I have latency
set to (I know it's not realistic to have latency be that low, but I
thought I'd try to get as close as possible).  Anyway, maybe that's
something I should investigate further since that 23 msec is only part
of the total latency.

-- 

|  Steven Elliott  |  http://selliott.org  |  sellio...@austin.rr.com  |


___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss


[pulseaudio-discuss] My attempt to reduce latency with pacat and tvtime

2012-03-26 Thread Steven Elliott
I use tvtime (an open source TV application) to watch TV on my Fedora 16
system.  As some of you may know forwarding audio from the sound card
built into the TV tuner card to the primary sound card is not done by
tvtime.  There are various ways of forwarding the audio including SoX,
module-loopback, etc. but I've had the best luck (least latency) using
pacat in a manner similar to what this webpage describes:

http://thelinuxexperiment.com/guinea-pigs/tyler-b/fix-pulseaudio-loopback-delay/

But with a change that I've made to pacat that I'd like to share in case
it's helpful.

The web page above describes using two instances of pacat with a pipe:
  pacat -r ... | pacat -p ...
to forward the audio.  I've found that this works quite well for a
while, but gradually the latency increases.  If for some reason the
pacat processes are temporarily suspended and then resumed (ctrl-Z
followed by bg, for example) the latency increases drastically.

I've found that the increased latency is due to audio queuing up on the
input to the play instance of pacat (the pacat on the right side of the
| shown above).  The extra queued up audio never gets consumed because
audio is being produced by the record instance of pacat (the pacat on
the left side of the | shown above) at the same rate it is consumed by
the play instance of pacat.  So I experimented with ways of discarding
the queued up audio that did not interfere with the sound quality too
much.

Each time stdin_callback() is called by the play instance of pacat to
get audio from the input pa_stream_writable_size() is called to see how
many bytes the sink can take.  This limits the amount of data that can
be read from stdin.

Each read of stdin is either full (precisely the number of bytes
requested is returned) or partial (less than the number of bytes
requested is returned).  I've found the if a large number of full reads
occur in a row that it's likely there latency due to extra audio queued
up in the input.  When this happens I've modified pacat to read as much
as 64 KiB more than what pa_stream_writable_size() requested, but then
discard the extra data read.

I suspect that there may be a more elegant solution at a different layer
in the code.  At the very least the change should be made optional so
that it does not break pacat when playing a file instead of reading from
a pipe:
  pacapt -p ...  audio.raw
But if there is interest I can add a command line option so that the
change is not always in effect.

-- 

|  Steven Elliott  |  http://selliott.org  |  sellio...@austin.rr.com  |

--- src/utils/pacat.c.orig	2012-03-24 10:13:10.382540053 -0500
+++ src/utils/pacat.c	2012-03-24 22:51:41.350164538 -0500
@@ -51,6 +51,10 @@
 
 #define CLEAR_LINE \x1B[K
 
+#define DRAIN_THRESHOLD 100
+
+#define DRAIN_BYTES 65536
+
 static enum { RECORD, PLAYBACK } mode = PLAYBACK;
 
 static pa_context *context = NULL;
@@ -501,8 +505,9 @@
 
 /* New data on STDIN **/
 static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
-size_t l, w = 0;
+size_t l, l_extra, w = 0;
 ssize_t r;
+static int full_reads; // Consecutive full reads (all bytes read).
 
 pa_assert(a == mainloop_api);
 pa_assert(e);
@@ -516,9 +521,10 @@
 if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
 l = 4096;
 
-buffer = pa_xmalloc(l);
+l_extra = (full_reads  DRAIN_THRESHOLD) ? (l + DRAIN_BYTES) : l;
+buffer = pa_xmalloc(l_extra);
 
-if ((r = read(fd, buffer, l)) = 0) {
+if ((r = read(fd, buffer, l_extra)) = 0) {
 if (r == 0) {
 if (verbose)
 pa_log(_(Got EOF.));
@@ -535,8 +541,27 @@
 return;
 }
 
-buffer_length = (uint32_t) r;
-buffer_index = 0;
+if ((size_t) r == l_extra) {
+full_reads++;
+}
+else {
+full_reads = 0;
+}
+
+if ((size_t) r  l) {
+// The read exceeds the writeable size.  Find the end of the buffer
+// that is aligned on a 4 byte boundary.
+// TODO: Determine the alignment bytes rather than assuming 4.
+buffer_index = (~3)  (r - l);
+buffer_length = (size_t) r - buffer_index;
+if (buffer_length  l)
+{
+buffer_length = l;
+}
+} else {
+buffer_length = (uint32_t) r;
+buffer_index = 0;
+}
 
 if (w)
 do_stream_write(w);
___
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss