[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master-tx, updated. v0.9.15-test5-129-g2a32de1

Lennart Poettering gitmailer-noreply at 0pointer.de
Tue Mar 31 11:29:44 PDT 2009


This is an automated email from the git hooks/post-receive script. It was
generated because of a push to the "PulseAudio Sound Server" repository.

The master-tx branch has been updated
      from  c29e9cf7c86fd9991d058566bc43986914d5db83 (commit)

- Log -----------------------------------------------------------------
2a32de1 Merge commit 'origin/master-tx'
5e11972 revive solaris module
92ae5f1 Specifying ALSA mixer control
facc46d fix some typos in doxygen comments
-----------------------------------------------------------------------

Summary of changes:
 src/modules/alsa/alsa-sink.c          |    2 +-
 src/modules/alsa/alsa-source.c        |    2 +-
 src/modules/alsa/alsa-util.c          |   13 +++-
 src/modules/alsa/alsa-util.h          |    2 +-
 src/modules/alsa/module-alsa-sink.c   |    4 +-
 src/modules/alsa/module-alsa-source.c |    4 +-
 src/modules/module-solaris.c          |  101 ++++++++++++++++++--------------
 src/pulse/introspect.h                |   14 ++--
 src/pulsecore/core-util.c             |   34 ++++++++---
 9 files changed, 107 insertions(+), 69 deletions(-)

-----------------------------------------------------------------------

commit facc46d5bfe8120424e9cb0679da91a35c9003ec
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Sun Mar 29 20:41:58 2009 +0200

    fix some typos in doxygen comments
    
    these bugged me for a while now.
    
    Maarten

diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index ec8a2c0..d7ef1c0 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -344,7 +344,7 @@ typedef struct pa_module_info {
     pa_proplist *proplist;              /**< Property list \since 0.9.15 */
 } pa_module_info;
 
-/** Callback prototype for pa_context_get_module_info() and firends*/
+/** Callback prototype for pa_context_get_module_info() and friends*/
 typedef void (*pa_module_info_cb_t) (pa_context *c, const pa_module_info*i, int eol, void *userdata);
 
 /** Get some information about a module by its index */
@@ -377,7 +377,7 @@ typedef struct pa_client_info {
     pa_proplist *proplist;               /**< Property list \since 0.9.11 */
 } pa_client_info;
 
-/** Callback prototype for pa_context_get_client_info() and firends*/
+/** Callback prototype for pa_context_get_client_info() and friends*/
 typedef void (*pa_client_info_cb_t) (pa_context *c, const pa_client_info*i, int eol, void *userdata);
 
 /** Get information about a client by its index */
@@ -418,7 +418,7 @@ typedef struct pa_card_info {
     pa_proplist *proplist;               /**< Property list */
 } pa_card_info;
 
-/** Callback prototype for pa_context_get_card_info() and firends \since 0.9.15 */
+/** Callback prototype for pa_context_get_card_info() and friends \since 0.9.15 */
 typedef void (*pa_card_info_cb_t) (pa_context *c, const pa_card_info*i, int eol, void *userdata);
 
 /** Get information about a card by its index \since 0.9.15 */
@@ -460,7 +460,7 @@ typedef struct pa_sink_input_info {
     pa_proplist *proplist;               /**< Property list \since 0.9.11 */
 } pa_sink_input_info;
 
-/** Callback prototype for pa_context_get_sink_input_info() and firends*/
+/** Callback prototype for pa_context_get_sink_input_info() and friends*/
 typedef void (*pa_sink_input_info_cb_t) (pa_context *c, const pa_sink_input_info *i, int eol, void *userdata);
 
 /** Get some information about a sink input by its index */
@@ -506,7 +506,7 @@ typedef struct pa_source_output_info {
     pa_proplist *proplist;               /**< Property list \since 0.9.11 */
 } pa_source_output_info;
 
-/** Callback prototype for pa_context_get_source_output_info() and firends*/
+/** Callback prototype for pa_context_get_source_output_info() and friends*/
 typedef void (*pa_source_output_info_cb_t) (pa_context *c, const pa_source_output_info *i, int eol, void *userdata);
 
 /** Get information about a source output by its index */
@@ -571,7 +571,7 @@ typedef struct pa_sample_info {
     pa_proplist *proplist;                /**< Property list for this sample. \since 0.9.11 */
 } pa_sample_info;
 
-/** Callback prototype for pa_context_get_sample_info_by_name() and firends */
+/** Callback prototype for pa_context_get_sample_info_by_name() and friends */
 typedef void (*pa_sample_info_cb_t)(pa_context *c, const pa_sample_info *i, int eol, void *userdata);
 
 /** Get information about a sample by its name */
@@ -606,7 +606,7 @@ typedef struct pa_autoload_info {
     const char *argument;         /**< Argument string for module */
 } pa_autoload_info;
 
-/** \deprecated Callback prototype for pa_context_get_autoload_info_by_name() and firends */
+/** \deprecated Callback prototype for pa_context_get_autoload_info_by_name() and friends */
 typedef void (*pa_autoload_info_cb_t)(pa_context *c, const pa_autoload_info *i, int eol, void *userdata);
 
 /** \deprecated Get info about a specific autoload entry. */

commit 92ae5f1a742d52a72562251a0b550bf39af28d8c
Author: Kyle Cronan <kyle at pbx.org>
Date:   Mon Mar 30 12:49:37 2009 -0500

    Specifying ALSA mixer control
    
    On Fri, Mar 27, 2009 at 7:21 AM, Lennart Poettering <lennart at poettering.net> wrote:
    
    >> I tried installing the latest git sources on my Ubuntu Jaunty box but
    >> it just broke sound in all my applications.  For my own purposes, I'm
    >> going to need to start with the Ubuntu-patched 0.9.14.  However, if
    >> you are willing to accept this patch I will forward port it so that it
    >> applies to the latest sources.  It's a completely harmless change, so
    >> why not apply it?
    >
    > Yes, I am happy to apply it. Could you please update it for current git?
    >
    
    Great.  An updated patch is attached.  For symmetry, I added this
    option to the alsa source module as well.
    
    The Ubuntu folks have customized pulse so much that it is difficult
    for me to get this version working on my system.  For this patch I
    have only made sure that it compiles.  But it does pretty much the
    same thing as the one for 0.9.14, which is working great for me.
    
    Thanks,
    Kyle

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 0296f64..0dc0e2b 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -1644,7 +1644,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
     /* ALSA might tweak the sample spec, so recalculate the frame size */
     frame_size = pa_frame_size(&ss);
 
-    pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem);
+    pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL));
 
     pa_sink_new_data_init(&data);
     data.driver = driver;
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index ef365a2..348cd08 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1496,7 +1496,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
     /* ALSA might tweak the sample spec, so recalculate the frame size */
     frame_size = pa_frame_size(&ss);
 
-    pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem);
+    pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL));
 
     pa_source_new_data_init(&data);
     data.driver = driver;
diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index 2d0ca10..5b5270b 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -1094,7 +1094,8 @@ success:
 int pa_alsa_find_mixer_and_elem(
         snd_pcm_t *pcm,
         snd_mixer_t **_m,
-        snd_mixer_elem_t **_e) {
+        snd_mixer_elem_t **_e,
+        const char *control_name) {
 
     int err;
     snd_mixer_t *m;
@@ -1146,11 +1147,17 @@ int pa_alsa_find_mixer_and_elem(
     switch (snd_pcm_stream(pcm)) {
 
         case SND_PCM_STREAM_PLAYBACK:
-            e = pa_alsa_find_elem(m, "Master", "PCM", TRUE);
+            if (control_name)
+                e = pa_alsa_find_elem(m, control_name, NULL, TRUE);
+            else
+                e = pa_alsa_find_elem(m, "Master", "PCM", TRUE);
             break;
 
         case SND_PCM_STREAM_CAPTURE:
-            e = pa_alsa_find_elem(m, "Capture", "Mic", FALSE);
+            if (control_name)
+                e = pa_alsa_find_elem(m, control_name, NULL, FALSE);
+            else
+                e = pa_alsa_find_elem(m, "Capture", "Mic", FALSE);
             break;
 
         default:
diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h
index 68496d5..5cad295 100644
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -54,7 +54,7 @@ int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min);
 
 int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev);
 snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback, pa_bool_t playback);
-int pa_alsa_find_mixer_and_elem(snd_pcm_t *pcm, snd_mixer_t **_m, snd_mixer_elem_t **_e);
+int pa_alsa_find_mixer_and_elem(snd_pcm_t *pcm, snd_mixer_t **_m, snd_mixer_elem_t **_e, const char *control_name);
 
 typedef struct pa_alsa_profile_info {
     pa_channel_map map;
diff --git a/src/modules/alsa/module-alsa-sink.c b/src/modules/alsa/module-alsa-sink.c
index c728a44..8e600ab 100644
--- a/src/modules/alsa/module-alsa-sink.c
+++ b/src/modules/alsa/module-alsa-sink.c
@@ -52,7 +52,8 @@ PA_MODULE_USAGE(
         "tsched=<enable system timer based scheduling mode?> "
         "tsched_buffer_size=<buffer size when using timer based scheduling> "
         "tsched_buffer_watermark=<lower fill watermark> "
-        "ignore_dB=<ignore dB information from the device?>");
+        "ignore_dB=<ignore dB information from the device?> "
+        "control=<name of mixer control>");
 
 static const char* const valid_modargs[] = {
     "name",
@@ -70,6 +71,7 @@ static const char* const valid_modargs[] = {
     "tsched_buffer_size",
     "tsched_buffer_watermark",
     "ignore_dB",
+    "control",
     NULL
 };
 
diff --git a/src/modules/alsa/module-alsa-source.c b/src/modules/alsa/module-alsa-source.c
index 6188019..e6b27b3 100644
--- a/src/modules/alsa/module-alsa-source.c
+++ b/src/modules/alsa/module-alsa-source.c
@@ -76,7 +76,8 @@ PA_MODULE_USAGE(
         "tsched=<enable system timer based scheduling mode?> "
         "tsched_buffer_size=<buffer size when using timer based scheduling> "
         "tsched_buffer_watermark=<upper fill watermark> "
-        "ignore_dB=<ignore dB information from the device?>");
+        "ignore_dB=<ignore dB information from the device?> "
+        "control=<name of mixer control>");
 
 static const char* const valid_modargs[] = {
     "name",
@@ -94,6 +95,7 @@ static const char* const valid_modargs[] = {
     "tsched_buffer_size",
     "tsched_buffer_watermark",
     "ignore_dB",
+    "control",
     NULL
 };
 

commit 5e1197207637bd459b09af8d7e374a44174d1403
Author: Finn Thain <fthain at telegraphics.com.au>
Date:   Sat Mar 7 16:48:10 2009 +1100

    revive solaris module
    
    On Wed, 4 Mar 2009, Lennart Poettering wrote:
    
    [snip]
    > > This patch disables link map/library versioning unless ld is GNU ld.
    > > Another approach for solaris would be to use that linker's -M option,
    > > but I couldn't make that work (due to undefined mainloop, browse and
    > > simple symbols when linking pacat. I can post the errors if anyone is
    > > intested.)
    >
    > The linking in PA is a bit weird since we have a cyclic dependency
    > between libpulse and libpulsecommon which however is not explicit.
    
    Could that affect the pacat link somehow?
    
    What are the implications for client apps that link with the non-versioned
    libraries I've been building on solaris?
    
    [snip]
    > >  struct userdata {
    > >      pa_core *core;
    > > @@ -87,15 +92,24 @@ struct userdata {
    > >
    > >      pa_memchunk memchunk;
    > >
    > > -    unsigned int page_size;
    > > -
    > >      uint32_t frame_size;
    > > -    uint32_t buffer_size;
    > > -    unsigned int written_bytes, read_bytes;
    > > +    int32_t buffer_size;
    > > +    volatile uint64_t written_bytes, read_bytes;
    > > +    pa_mutex *written_bytes_lock;
    >
    > Hmm, we generally try do do things without locking in PA. This smells as
    > if it was solvable using atomic ints as well.
    >
    > Actually, looking at this again I get the impression these mutex are
    > completely unnecessary here. All functions that lock these mutexes are
    > called from the IO thread so no locking should be nessary.
    >
    > Please don't use volatile here. I am pretty sure it is a misuse. Also
    > see http://kernel.org/doc/Documentation/volatile-considered-harmful.txt
    > which applies here too I think.
    
    OK, I've removed the locks. For some reason I thought that the get_latency
    function was called from two different threads.
    
    > > +static void sink_set_volume(pa_sink *s) {
    > > +    struct userdata *u;
    > > +    audio_info_t info;
    > > +
    > > +    pa_assert_se(u = s->userdata);
    > > +
    > > +    if (u->fd >= 0) {
    > > +        AUDIO_INITINFO(&info);
    > > +
    > > +        info.play.gain = pa_cvolume_avg(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
    > > +        assert(info.play.gain <= AUDIO_MAX_GAIN);
    >
    > I'd prefer if you'd use pa_cvolume_max here instead of pa_cvolume_avg()
    > because this makes the volume independant of the balance.
    >
    > > -    info.play.error = 0;
    > > +        info.play.gain = pa_cvolume_avg(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
    > > +        assert(info.play.gain <= AUDIO_MAX_GAIN);
    >
    > Same here. (i.e. for the source)
    
    Done and done.
    
    > > +            if (u->sink->thread_info.rewind_requested)
    > > +                pa_sink_process_rewind(u->sink, 0);
    >
    > This is correct.
    >
    > >
    > >              err = ioctl(u->fd, AUDIO_GETINFO, &info);
    > >              pa_assert(err >= 0);
    >
    > Hmm, if at all this should be pa_assert_se(), not pa_assert() (so that
    > it is not defined away by -DNDEBUG). However I'd prefer if the error
    > would be could correctly. (I see that this code is not yours, but
    > still...)
    
    Done.
    
    > > +                        case EINTR:
    > > +                            break;
    >
    > I think you should simply try again in this case...
    
    Done.
    
    > > +                        case EAGAIN:
    > > +                            u->buffer_size = u->buffer_size * 18 / 25;
    > > +                            u->buffer_size -= u->buffer_size % u->frame_size;
    > > +                            u->buffer_size = PA_MAX(u->buffer_size, (int32_t)MIN_BUFFER_SIZE);
    > > +                            pa_sink_set_max_request(u->sink, u->buffer_size);
    > > +                            pa_log("EAGAIN. Buffer size is now %u bytes (%llu buffered)", u->buffer_size, buffered_bytes);
    > > +                            break;
    >
    > Hmm, care to explain this?
    
    EAGAIN happens when the user requests a buffer size that is too large for
    the STREAMS layer to accept. We end up looping with EAGAIN every time we
    try to write out the rest of the buffer, which burns enough CPU time to
    trip the CPU limit.
    
    So, I reduce the buffer size with each EAGAIN. This gets us reasonably
    close to the largest usable buffer size. (Perhaps there's a better way to
    determine what that limit is, but I don't know how.)
    
    > > +
    > > +            pa_rtpoll_set_timer_absolute(u->rtpoll, xtime0 + pa_bytes_to_usec(buffered_bytes / 2, &u->sink->sample_spec));
    > > +        } else {
    > > +            pa_rtpoll_set_timer_disabled(u->rtpoll);
    > >          }
    >
    > Hmm, you schedule audio via timers? Is that a good idea?
    
    Perhaps not. I won't know until I test on more hardware.
    
    But, given that we have rt priority and high resolution timers on solaris,
    I think it is OK in theory...
    
    The reason I used a timer was to minimise CPU usage and avoid the CPU
    limit. Recall that getting woken up by poll is not an option for playback
    unfortunately. We can arrange for a signal when the FD becomes writable,
    but that throws out the whole buffer size concept, which acts to reduce
    latency.
    
    > That really only makes sense if you have to deal with large buffers and
    > support rewinding.
    
    I've implemented rewind support, but I'm still not sure that I have
    understood the concept; I take it that we "rewind" (from the point-of-view
    of the renderer, not the sink) so that some rendered but as yet unplayed
    portion of the memblock/buffers can then be rendered again?
    
    > Please keep in mind that the system clock and the sound card clock
    > deviate. If you use the system timers to do PCM scheduling ou might need
    > a pa_smoother object that is able to estimate the deviation for you.
    
    Actually, in an earlier version I did use a smoother (after reading about
    that in the wiki). But because of the non-monotonic sample counter (bug?)
    I decided that it probably wasn't worth the added complexity so I removed
    it. I'll put the smoother back if I can figure out the problem with the
    sample counter.
    
    >
    > > +    u->frame_size = pa_frame_size(&ss);
    > >
    > > -    if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0)
    > > +    u->buffer_size = 16384;
    >
    > It would appear more appropriate to me if the buffer size is adjusted by
    > the sample spec used.
    
    Done.
    
    > One last thing: it would probably be a good idea to allocate a pa_card
    > object and attach the sink and the source to it.
    
    It is possible to open /dev/audio twice by loading the solaris module
    twice -- once for the sink (passing record=0) and once for source (passing
    playback=0), thus giving seperate threads/LWPs for source and sink. It
    might be misleading to allocate two cards in that situation?
    
    > Right now pa_cards are mostly useful for switching profiles but even if
    > you do not allow switching profiles on-the-fly it is of some value to
    > find out via the cards object which source belongs to which sink.
    >
    > Otherwise I am happy!
    >
    > Thanks for your patch! I'd be thankful if you could fix the issues
    > pointed out and prepare another patch on top of current git!
    
    No problem. Patch follows. It also includes a portability fix for
    pa_realpath and a fix for a bug in the pa_signal_new() error path that
    causes signal data be freed if you attempt to register the same signal
    twice.
    
    > I hope I answered all your questions,
    
    Your answers were very helpful, thanks.
    
    Finn
    
    >
    > Lennart
    >
    >

diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c
index e7dfc05..ecd3ba3 100644
--- a/src/modules/module-solaris.c
+++ b/src/modules/module-solaris.c
@@ -75,7 +75,7 @@ PA_MODULE_USAGE(
     "format=<sample format> "
     "channels=<number of channels> "
     "rate=<sample rate> "
-    "buffer_size=<record buffer size> "
+    "buffer_length=<milliseconds> "
     "channel_map=<channel map>");
 PA_MODULE_LOAD_ONCE(FALSE);
 
@@ -94,8 +94,7 @@ struct userdata {
 
     uint32_t frame_size;
     int32_t buffer_size;
-    volatile uint64_t written_bytes, read_bytes;
-    pa_mutex *written_bytes_lock;
+    uint64_t written_bytes, read_bytes;
 
     char *device_name;
     int mode;
@@ -107,9 +106,8 @@ struct userdata {
 
     uint32_t play_samples_msw, record_samples_msw;
     uint32_t prev_playback_samples, prev_record_samples;
-    pa_mutex *sample_counter_lock;
 
-    size_t min_request;
+    int32_t minimum_request;
 };
 
 static const char* const valid_modargs[] = {
@@ -118,7 +116,7 @@ static const char* const valid_modargs[] = {
     "device",
     "record",
     "playback",
-    "buffer_size",
+    "buffer_length",
     "format",
     "rate",
     "channels",
@@ -127,13 +125,9 @@ static const char* const valid_modargs[] = {
 };
 
 #define DEFAULT_DEVICE "/dev/audio"
-#define MIN_BUFFER_SIZE (640)
-#define MAX_RENDER_HZ   (300)
 
-/* This render rate limit implies a minimum latency,  but without it we waste too much CPU time in the
- * IO thread. The maximum render rate and minimum latency (or minimum buffer size) are unachievable on
- * common hardware anyway. Note that MIN_BUFFER_SIZE * MAX_RENDER_HZ >= 4 * 48000 Bps.
- */
+#define MAX_RENDER_HZ   (300)
+/* This render rate limit imposes a minimum latency, but without it we waste too much CPU time. */
 
 static uint64_t get_playback_buffered_bytes(struct userdata *u) {
     audio_info_t info;
@@ -142,8 +136,6 @@ static uint64_t get_playback_buffered_bytes(struct userdata *u) {
 
     pa_assert(u->sink);
 
-    pa_mutex_lock(u->sample_counter_lock);
-
     err = ioctl(u->fd, AUDIO_GETINFO, &info);
     pa_assert(err >= 0);
 
@@ -159,8 +151,6 @@ static uint64_t get_playback_buffered_bytes(struct userdata *u) {
     u->prev_playback_samples = info.play.samples;
     played_bytes = (((uint64_t)u->play_samples_msw << 32) + info.play.samples) * u->frame_size;
 
-    pa_mutex_unlock(u->sample_counter_lock);
-
     return u->written_bytes - played_bytes;
 }
 
@@ -171,11 +161,9 @@ static pa_usec_t sink_get_latency(struct userdata *u, pa_sample_spec *ss) {
     pa_assert(ss);
 
     if (u->fd >= 0) {
-        pa_mutex_lock(u->written_bytes_lock);
         r = pa_bytes_to_usec(get_playback_buffered_bytes(u), ss);
         if (u->memchunk.memblock)
             r += pa_bytes_to_usec(u->memchunk.length, ss);
-        pa_mutex_unlock(u->written_bytes_lock);
     }
     return r;
 }
@@ -487,7 +475,7 @@ static void sink_set_volume(pa_sink *s) {
     if (u->fd >= 0) {
         AUDIO_INITINFO(&info);
 
-        info.play.gain = pa_cvolume_avg(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
+        info.play.gain = pa_cvolume_max(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
         assert(info.play.gain <= AUDIO_MAX_GAIN);
 
         if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
@@ -523,7 +511,7 @@ static void source_set_volume(pa_source *s) {
     if (u->fd >= 0) {
         AUDIO_INITINFO(&info);
 
-        info.play.gain = pa_cvolume_avg(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
+        info.play.gain = pa_cvolume_max(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
         assert(info.play.gain <= AUDIO_MAX_GAIN);
 
         if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
@@ -580,6 +568,25 @@ static void sink_get_mute(pa_sink *s) {
     }
 }
 
+static void process_rewind(struct userdata *u) {
+    size_t rewind_nbytes;
+
+    pa_assert(u);
+
+    /* Figure out how much we shall rewind and reset the counter */
+    rewind_nbytes = u->sink->thread_info.rewind_nbytes;
+    u->sink->thread_info.rewind_nbytes = 0;
+
+    if (rewind_nbytes > 0) {
+        pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes);
+        rewind_nbytes = PA_MIN(u->memchunk.length, rewind_nbytes);
+        u->memchunk.length -= rewind_nbytes;
+        pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes);
+    }
+
+    pa_sink_process_rewind(u->sink, rewind_nbytes);
+}
+
 static void thread_func(void *userdata) {
     struct userdata *u = userdata;
     unsigned short revents = 0;
@@ -604,10 +611,13 @@ static void thread_func(void *userdata) {
             uint64_t buffered_bytes;
 
             if (u->sink->thread_info.rewind_requested)
-                pa_sink_process_rewind(u->sink, 0);
+                process_rewind(u);
 
             err = ioctl(u->fd, AUDIO_GETINFO, &info);
-            pa_assert(err >= 0);
+            if (err < 0) {
+                pa_log("AUDIO_GETINFO ioctl failed: %s", pa_cstrerror(errno));
+                goto fail;
+            }
 
             if (info.play.error) {
                 pa_log_debug("buffer under-run!");
@@ -635,7 +645,7 @@ static void thread_func(void *userdata) {
                 len = u->buffer_size - buffered_bytes;
                 len -= len % u->frame_size;
 
-                if (len < u->min_request)
+                if (len < (size_t) u->minimum_request)
                     break;
 
                 if (u->memchunk.length < len)
@@ -648,12 +658,16 @@ static void thread_func(void *userdata) {
                 if (w <= 0) {
                     switch (errno) {
                         case EINTR:
-                            break;
+                            continue;
                         case EAGAIN:
+                            /* If the buffer_size is too big, we get EAGAIN. Avoiding that limit by trial and error
+                             * is not ideal, but I don't know how to get the system to tell me what the limit is.
+                             */
                             u->buffer_size = u->buffer_size * 18 / 25;
                             u->buffer_size -= u->buffer_size % u->frame_size;
-                            u->buffer_size = PA_MAX(u->buffer_size, (int32_t)MIN_BUFFER_SIZE);
+                            u->buffer_size = PA_MAX(u->buffer_size, 2 * u->minimum_request);
                             pa_sink_set_max_request_within_thread(u->sink, u->buffer_size);
+                            pa_sink_set_max_rewind_within_thread(u->sink, u->buffer_size);
                             pa_log("EAGAIN. Buffer size is now %u bytes (%llu buffered)", u->buffer_size, buffered_bytes);
                             break;
                         default:
@@ -663,10 +677,8 @@ static void thread_func(void *userdata) {
                 } else {
                     pa_assert(w % u->frame_size == 0);
 
-                    pa_mutex_lock(u->written_bytes_lock);
                     u->written_bytes += w;
                     u->memchunk.length -= w;
-                    pa_mutex_unlock(u->written_bytes_lock);
 
                     u->memchunk.index += w;
                     if (u->memchunk.length <= 0) {
@@ -677,9 +689,8 @@ static void thread_func(void *userdata) {
             }
 
             pa_rtpoll_set_timer_absolute(u->rtpoll, xtime0 + pa_bytes_to_usec(buffered_bytes / 2, &u->sink->sample_spec));
-        } else {
+        } else
             pa_rtpoll_set_timer_disabled(u->rtpoll);
-        }
 
         /* Try to read some data and pass it on to the source driver */
 
@@ -797,6 +808,7 @@ int pa__init(pa_module *m) {
     pa_sample_spec ss;
     pa_channel_map map;
     pa_modargs *ma = NULL;
+    uint32_t buffer_length_msec;
     int fd;
     pa_sink_new_data sink_new_data;
     pa_source_new_data source_new_data;
@@ -822,8 +834,6 @@ int pa__init(pa_module *m) {
     }
 
     u = pa_xnew0(struct userdata, 1);
-    u->sample_counter_lock = pa_mutex_new(FALSE, FALSE);
-    u->written_bytes_lock = pa_mutex_new(FALSE, FALSE);
 
     /*
      * For a process (or several processes) to use the same audio device for both
@@ -839,13 +849,15 @@ int pa__init(pa_module *m) {
     }
     u->frame_size = pa_frame_size(&ss);
 
-    u->buffer_size = 16384;
-    if (pa_modargs_get_value_s32(ma, "buffer_size", &u->buffer_size) < 0) {
-        pa_log("failed to parse buffer size argument");
+    u->minimum_request = pa_usec_to_bytes(PA_USEC_PER_SEC / MAX_RENDER_HZ, &ss);
+
+    buffer_length_msec = 100;
+    if (pa_modargs_get_value_u32(ma, "buffer_length", &buffer_length_msec) < 0) {
+        pa_log("failed to parse buffer_length argument");
         goto fail;
     }
-    u->buffer_size -= u->buffer_size % u->frame_size;
-    if (u->buffer_size < (int32_t)MIN_BUFFER_SIZE) {
+    u->buffer_size = pa_usec_to_bytes(1000 * buffer_length_msec, &ss);
+    if (u->buffer_size < 2 * u->minimum_request) {
         pa_log("supplied buffer size argument is too small");
         goto fail;
     }
@@ -947,15 +959,17 @@ int pa__init(pa_module *m) {
         u->sink->refresh_volume = u->sink->refresh_muted = TRUE;
 
         pa_sink_set_max_request(u->sink, u->buffer_size);
-        u->min_request = pa_usec_to_bytes(PA_USEC_PER_SEC / MAX_RENDER_HZ, &ss);
+        pa_sink_set_max_rewind(u->sink, u->buffer_size);
     } else
         u->sink = NULL;
 
     pa_assert(u->source || u->sink);
 
     u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
-    pa_assert(u->sig);
-    ioctl(u->fd, I_SETSIG, S_MSG);
+    if (u->sig)
+        ioctl(u->fd, I_SETSIG, S_MSG);
+    else
+        pa_log_warn("Could not register SIGPOLL handler");
 
     if (!(u->thread = pa_thread_new(thread_func, u))) {
         pa_log("Failed to create thread.");
@@ -1010,8 +1024,10 @@ void pa__done(pa_module *m) {
     if (!(u = m->userdata))
         return;
 
-    ioctl(u->fd, I_SETSIG, 0);
-    pa_signal_free(u->sig);
+    if (u->sig) {
+        ioctl(u->fd, I_SETSIG, 0);
+        pa_signal_free(u->sig);
+    }
 
     if (u->sink)
         pa_sink_unlink(u->sink);
@@ -1044,9 +1060,6 @@ void pa__done(pa_module *m) {
     if (u->fd >= 0)
         close(u->fd);
 
-    pa_mutex_free(u->written_bytes_lock);
-    pa_mutex_free(u->sample_counter_lock);
-
     pa_xfree(u->device_name);
 
     pa_xfree(u);
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index e5d8a2f..4b093c0 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -2608,7 +2608,7 @@ char *pa_unescape(char *p) {
 }
 
 char *pa_realpath(const char *path) {
-    char *r, *t;
+    char *t;
     pa_assert(path);
 
     /* We want only abolsute paths */
@@ -2617,17 +2617,31 @@ char *pa_realpath(const char *path) {
         return NULL;
     }
 
-#if !defined(__GLIBC__) && !defined(__APPLE__)
-#error "It's not clear whether this system supports realpath(..., NULL) like GNU libc does. If it doesn't we need a private version of realpath() here."
-#endif
+#if defined(__GLIBC__) || defined(__APPLE__)
+    {
+        char *r;
 
-    if (!(r = realpath(path, NULL)))
-        return NULL;
+        if (!(r = realpath(path, NULL)))
+            return NULL;
+
+        /* We copy this here in case our pa_xmalloc() is not
+         * implemented on top of libc malloc() */
+        t = pa_xstrdup(r);
+        pa_xfree(r);
+    }
+#elif defined(PATH_MAX)
+    {
+        char *path_buf;
+        path_buf = pa_xmalloc(PATH_MAX);
 
-    /* We copy this here in case our pa_xmalloc() is not implemented
-     * on top of libc malloc() */
-    t = pa_xstrdup(r);
-    pa_xfree(r);
+        if (!(t = realpath(path, path_buf))) {
+            pa_xfree(path_buf);
+            return NULL;
+        }
+    }
+#else
+#error "It's not clear whether this system supports realpath(..., NULL) like GNU libc does. If it doesn't we need a private version of realpath() here."
+#endif
 
     return t;
 }

commit 2a32de1eaa15624b3d773115d849dba863ca5a44
Merge: 5e11972 c29e9cf
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Mar 31 20:28:58 2009 +0200

    Merge commit 'origin/master-tx'


-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list