[pulseaudio-commits] Branch 'next' - 5 commits - src/modules src/pulsecore

Tanu Kaskinen tanuk at kemper.freedesktop.org
Thu Jan 30 01:13:38 PST 2014


 src/modules/module-card-restore.c |    1 
 src/pulsecore/resampler.c         |  139 +++++++++++++++++++++++---------------
 src/pulsecore/thread-win32.c      |    7 +
 3 files changed, 93 insertions(+), 54 deletions(-)

New commits:
commit c07b6b509b6671f7a77775ccefd311c18f7cb832
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Sun Jan 26 19:11:07 2014 +0200

    thread-win32: Implement pa_thread_free_nojoin()
    
    This fixes a build error with mingw32:
    
    pulsecore/.libs/libpulsecommon_4.99_la-lock-autospawn.o: In function `unref':
    /home/abuild/rpmbuild/BUILD/pulseaudio-4.99.2/src/pulsecore/lock-autospawn.c:123: undefined reference to `pa_thread_free_nojoin'
    collect2: error: ld returned 1 exit status
    
    pa_thread_free_nojoin() was initially only implemented for the pthread
    based pa_thread backend, because it was incorrectly assumed that
    autospawning (the only user of pa_thread_free_nojoin()) is not used on
    Windows.
    
    Reported-By: Michael DePaulo <mikedep333 at gmail.com>

diff --git a/src/pulsecore/thread-win32.c b/src/pulsecore/thread-win32.c
index 89c8c46..0fa3b91 100644
--- a/src/pulsecore/thread-win32.c
+++ b/src/pulsecore/thread-win32.c
@@ -109,6 +109,13 @@ void pa_thread_free(pa_thread *t) {
     pa_xfree(t);
 }
 
+void pa_thread_free_nojoin(pa_thread *t) {
+    pa_assert(t);
+
+    CloseHandle(t->thread);
+    pa_xfree(t);
+}
+
 int pa_thread_join(pa_thread *t) {
     assert(t);
 

commit 4447c8301d2678492453ffa65fbe6e78818b7b25
Author: Tanu Kaskinen <tanu.kaskinen at linux.intel.com>
Date:   Wed Jan 29 20:54:39 2014 +0200

    card-restore: Fix a memory leak
    
    entry_read() may set entry->profile, so we need to free that string
    before we can replace it with a new string.

diff --git a/src/modules/module-card-restore.c b/src/modules/module-card-restore.c
index 252dcce..5b02602 100644
--- a/src/modules/module-card-restore.c
+++ b/src/modules/module-card-restore.c
@@ -390,6 +390,7 @@ static pa_hook_result_t card_profile_changed_callback(pa_core *c, pa_card *card,
         return PA_HOOK_OK;
 
     if ((entry = entry_read(u, card->name))) {
+        pa_xfree(entry->profile);
         entry->profile = pa_xstrdup(card->active_profile->name);
         pa_log_info("Storing card profile for card %s.", card->name);
     } else {

commit 67ced197b3ef1332f35e1e3063bfa8c8283e64ea
Author: Peter Meerwald <p.meerwald at bct-electronic.com>
Date:   Mon Dec 2 17:27:01 2013 +0100

    resampler: Resample first followed by remapping if have more out channels than in channels
    
    Reintroduces a cleaned-up version of commit 30ce3a14e5ae1cd316a18bec95b831c07ac57a1a which
    was reverted by 1ce71cbd8206d1be59ac62274ad83cdbe693a96a; for more information see
    http://thread.gmane.org/gmane.comp.audio.pulseaudio.general/17479/focus=17487
    
    The patch intends to reduce computational load when resampling AND remapping. The PA
    resampler performs the following steps:
    
    sample format conversion -> remapping -> resampling -> sample format conversion
    
    In case the number of output channels is higher than the number of input channels, the
    resampler has to be run more often than necessary. E.g. in case of mono to 4-channel remapping,
    the resampler runs on 4 channels separately.
    
    To ímprove this, the PA resampler pipeline is made adaptive:
    
    if out-channels <= in-channels:
      sample format conversion -> remapping -> resampling -> sample format conversion
    if out-channels > in-channels:
      sample format conversion -> resampling -> remapping -> sample format conversion
    
    Signed-off-by: Peter Meerwald <p.meerwald at bct-electronic.com>

diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index db65cea..38389f3 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -398,12 +398,7 @@ pa_resampler* pa_resampler_new(
 
     calc_map_table(r);
 
-    pa_log_info("Using resampler '%s'", pa_resample_method_to_string(method));
-
     r->work_format = pa_resampler_choose_work_format(method, a->format, b->format, r->map_required);
-
-    pa_log_info("Using %s as working format.", pa_sample_format_to_string(r->work_format));
-
     r->w_sz = pa_sample_size_of_format(r->work_format);
 
     if (r->i_ss.format != r->work_format) {
@@ -428,14 +423,31 @@ pa_resampler* pa_resampler_new(
         }
     }
 
-    /* leftover buffer is the buffer before the resampling stage */
-    r->leftover_buf = &r->remap_buf;
-    r->leftover_buf_size = &r->remap_buf_size;
-    r->have_leftover = &r->leftover_in_remap;
+    if (r->o_ss.channels <= r->i_ss.channels) {
+        /* pipeline is: format conv. -> remap -> resample -> format conv. */
+        r->work_channels = r->o_ss.channels;
+
+        /* leftover buffer is remap output buffer (before resampling) */
+        r->leftover_buf = &r->remap_buf;
+        r->leftover_buf_size = &r->remap_buf_size;
+        r->have_leftover = &r->leftover_in_remap;
+    } else {
+        /* pipeline is: format conv. -> resample -> remap -> format conv. */
+        r->work_channels = r->i_ss.channels;
 
-    r->work_channels = r->o_ss.channels;
+        /* leftover buffer is to_work output buffer (before resampling) */
+        r->leftover_buf = &r->to_work_format_buf;
+        r->leftover_buf_size = &r->to_work_format_buf_size;
+        r->have_leftover = &r->leftover_in_to_work;
+    }
     r->w_fz = pa_sample_size_of_format(r->work_format) * r->work_channels;
 
+    pa_log_debug("Resampler:");
+    pa_log_debug("  rate %d -> %d (method %s)", a->rate, b->rate, pa_resample_method_to_string(r->method));
+    pa_log_debug("  format %s -> %s (intermediate %s)", pa_sample_format_to_string(a->format),
+                 pa_sample_format_to_string(b->format), pa_sample_format_to_string(r->work_format));
+    pa_log_debug("  channels %d -> %d (resampling %d)", a->channels, b->channels, r->work_channels);
+
     /* initialize implementation */
     if (init_table[method](r) < 0)
         goto fail;
@@ -1348,8 +1360,16 @@ void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out)
 
     buf = (pa_memchunk*) in;
     buf = convert_to_work_format(r, buf);
-    buf = remap_channels(r, buf);
-    buf = resample(r, buf);
+
+    /* Try to save resampling effort: if we have more output channels than
+     * input channels, do resampling first, then remapping. */
+    if (r->o_ss.channels <= r->i_ss.channels) {
+        buf = remap_channels(r, buf);
+        buf = resample(r, buf);
+    } else {
+        buf = resample(r, buf);
+        buf = remap_channels(r, buf);
+    }
 
     if (buf->length) {
         buf = convert_from_work_format(r, buf);

commit 6134fde35c83d6739bd15466e34e91dc1635b8b6
Author: Peter Meerwald <p.meerwald at bct-electronic.com>
Date:   Mon Dec 2 17:27:00 2013 +0100

    resampler: Implement leftover handling in convert_to_work_format()
    
    Signed-off-by: Peter Meerwald <pmeerw at pmeerw.net>

diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index 4c788dc..db65cea 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -65,13 +65,14 @@ struct pa_resampler {
     size_t resample_buf_size;
     size_t from_work_format_buf_size;
 
-    /* points to buffer before resampling stage, remap */
+    /* points to buffer before resampling stage, remap or to_work */
     pa_memchunk *leftover_buf;
     size_t *leftover_buf_size;
 
-    /* have_leftover points to leftover_in_remap */
+    /* have_leftover points to leftover_in_remap or leftover_in_to_work */
     bool *have_leftover;
     bool leftover_in_remap;
+    bool leftover_in_to_work;
 
     pa_sample_format_t work_format;
     uint8_t work_channels;
@@ -1169,26 +1170,43 @@ static void fit_buf(pa_resampler *r, pa_memchunk *buf, size_t len, size_t *size,
 }
 
 static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) {
-    unsigned n_samples;
+    unsigned in_n_samples, out_n_samples;
     void *src, *dst;
+    bool have_leftover;
+    size_t leftover_length = 0;
 
     pa_assert(r);
     pa_assert(input);
     pa_assert(input->memblock);
 
     /* Convert the incoming sample into the work sample format and place them
-     * in to_work_format_buf. */
+     * in to_work_format_buf. The leftover data is already converted, so it's
+     * part of the output buffer. */
+
+    have_leftover = r->leftover_in_to_work;
+    r->leftover_in_to_work = false;
 
-    if (!r->to_work_format_func || !input->length)
+    if (!have_leftover && (!r->to_work_format_func || !input->length))
         return input;
+    else if (input->length <= 0)
+        return &r->to_work_format_buf;
+
+    in_n_samples = out_n_samples = (unsigned) ((input->length / r->i_fz) * r->i_ss.channels);
 
-    n_samples = (unsigned) ((input->length / r->i_fz) * r->i_ss.channels);
-    fit_buf(r, &r->to_work_format_buf, r->w_sz * n_samples, &r->to_work_format_buf_size, 0);
+    if (have_leftover) {
+        leftover_length = r->to_work_format_buf.length;
+        out_n_samples += (unsigned) (leftover_length / r->w_sz);
+    }
+
+    fit_buf(r, &r->to_work_format_buf, r->w_sz * out_n_samples, &r->to_work_format_buf_size, leftover_length);
 
     src = pa_memblock_acquire_chunk(input);
-    dst = pa_memblock_acquire(r->to_work_format_buf.memblock);
+    dst = (uint8_t *) pa_memblock_acquire(r->to_work_format_buf.memblock) + leftover_length;
 
-    r->to_work_format_func(n_samples, src, dst);
+    if (r->to_work_format_func)
+        r->to_work_format_func(in_n_samples, src, dst);
+    else
+        memcpy(dst, src, input->length);
 
     pa_memblock_release(input->memblock);
     pa_memblock_release(r->to_work_format_buf.memblock);

commit 71cf16656ba1d932c3ffd0778b47f097094c6030
Author: Peter Meerwald <p.meerwald at bct-electronic.com>
Date:   Mon Dec 2 17:26:59 2013 +0100

    resampler: Extend fit_buf() helper to copy leftover data to new buffer
    
    the patch changes the interface of the (internal) fit_buf() function:
    fit_buf() manages the memblock of the buf chunk, it reallocates the memblock
    if the requested number of bytes ('len') if larger than the memblock's size ('size')
    and optionally preserves 'copy' bytes
    
    the code should be in line with the comment now
    
    Signed-off-by: Peter Meerwald <pmeerw at pmeerw.net>

diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index f0c663f..4c788dc 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -1140,15 +1140,32 @@ static void calc_map_table(pa_resampler *r) {
     pa_init_remap(m);
 }
 
-static size_t fit_buf(pa_resampler *r, pa_memchunk *buf, size_t size) {
-    if (!buf->memblock || size < buf->length) {
-        size = buf->length;
-        if (buf->memblock)
+/* check if buf's memblock is large enough to hold 'len' bytes; create a
+ * new memblock if necessary and optionally preserve 'copy' data bytes */
+static void fit_buf(pa_resampler *r, pa_memchunk *buf, size_t len, size_t *size, size_t copy) {
+    pa_assert(size);
+
+    if (!buf->memblock || len > *size) {
+        pa_memblock *new_block = pa_memblock_new(r->mempool, len);
+
+        if (buf->memblock) {
+            if (copy > 0) {
+                void *src = pa_memblock_acquire(buf->memblock);
+                void *dst = pa_memblock_acquire(new_block);
+                pa_assert(copy <= len);
+                memcpy(dst, src, copy);
+                pa_memblock_release(new_block);
+                pa_memblock_release(buf->memblock);
+            }
+
             pa_memblock_unref(buf->memblock);
+        }
 
-        buf->memblock = pa_memblock_new(r->mempool, size);
+        buf->memblock = new_block;
+        *size = len;
     }
-    return size;
+
+    buf->length = len;
 }
 
 static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) {
@@ -1166,9 +1183,7 @@ static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input)
         return input;
 
     n_samples = (unsigned) ((input->length / r->i_fz) * r->i_ss.channels);
-
-    r->to_work_format_buf.length = r->w_sz * n_samples;
-    r->to_work_format_buf_size = fit_buf(r, &r->to_work_format_buf, r->to_work_format_buf_size);
+    fit_buf(r, &r->to_work_format_buf, r->w_sz * n_samples, &r->to_work_format_buf_size, 0);
 
     src = pa_memblock_acquire_chunk(input);
     dst = pa_memblock_acquire(r->to_work_format_buf.memblock);
@@ -1212,24 +1227,7 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
     }
 
     out_n_samples = out_n_frames * r->o_ss.channels;
-    r->remap_buf.length = out_n_samples * r->w_sz;
-
-    if (have_leftover) {
-        if (r->remap_buf_size < r->remap_buf.length) {
-            pa_memblock *new_block = pa_memblock_new(r->mempool, r->remap_buf.length);
-
-            src = pa_memblock_acquire(r->remap_buf.memblock);
-            dst = pa_memblock_acquire(new_block);
-            memcpy(dst, src, leftover_length);
-            pa_memblock_release(r->remap_buf.memblock);
-            pa_memblock_release(new_block);
-
-            pa_memblock_unref(r->remap_buf.memblock);
-            r->remap_buf.memblock = new_block;
-            r->remap_buf_size = r->remap_buf.length;
-        }
-    } else
-        r->remap_buf_size = fit_buf(r, &r->remap_buf, r->remap_buf_size);
+    fit_buf(r, &r->remap_buf, out_n_samples * r->w_sz, &r->remap_buf_size, leftover_length);
 
     src = pa_memblock_acquire_chunk(input);
     dst = (uint8_t *) pa_memblock_acquire(r->remap_buf.memblock) + leftover_length;
@@ -1257,8 +1255,7 @@ static void save_leftover(pa_resampler *r, void *buf, size_t len) {
     pa_assert(len > 0);
 
     /* Store the leftover data. */
-    r->leftover_buf->length = len;
-    *r->leftover_buf_size = fit_buf(r, r->leftover_buf, *r->leftover_buf_size);
+    fit_buf(r, r->leftover_buf, len, r->leftover_buf_size, 0);
     *r->have_leftover = true;
 
     dst = pa_memblock_acquire(r->leftover_buf->memblock);
@@ -1280,9 +1277,7 @@ static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) {
     in_n_frames = (unsigned) (input->length / r->w_fz);
 
     out_n_frames = ((in_n_frames*r->o_ss.rate)/r->i_ss.rate)+EXTRA_FRAMES;
-
-    r->resample_buf.length = r->w_fz * out_n_frames;
-    r->resample_buf_size = fit_buf(r, &r->resample_buf, r->resample_buf_size);
+    fit_buf(r, &r->resample_buf, r->w_fz * out_n_frames, &r->resample_buf_size, 0);
 
     leftover_n_frames = r->impl.resample(r, input, in_n_frames, &r->resample_buf, &out_n_frames);
 
@@ -1312,9 +1307,7 @@ static pa_memchunk *convert_from_work_format(pa_resampler *r, pa_memchunk *input
 
     n_samples = (unsigned) (input->length / r->w_sz);
     n_frames = n_samples / r->o_ss.channels;
-
-    r->from_work_format_buf.length = r->o_fz * n_frames;
-    r->from_work_format_buf_size = fit_buf(r, &r->from_work_format_buf, r->from_work_format_buf_size);
+    fit_buf(r, &r->from_work_format_buf, r->o_fz * n_frames, &r->from_work_format_buf_size, 0);
 
     src = pa_memblock_acquire_chunk(input);
     dst = pa_memblock_acquire(r->from_work_format_buf.memblock);



More information about the pulseaudio-commits mailing list