mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-02 09:01:46 -05:00
rework memory block management to be thread-safe and mostly lock-free.
pa_memblock is now an opaque structure. Access to its fields is now done through various accessor functions in a thread-safe manner. pa_memblock_acquire() and pa_memblock_release() are now used to access the attached audio data. Why? To allow safe manipulation of the memory pointer maintained by the memory block. Internally _acquire() and _release() maintain a reference counter. Please do not confuse this reference counter whith the one maintained by pa_memblock_ref()/_unref()! As a side effect this patch removes all direct usages of AO_t and replaces it with pa_atomic_xxx based code. This stuff needs some serious testing love. Especially if threads are actively used. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1404 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
5ad143b3ab
commit
d210ebbb09
36 changed files with 991 additions and 500 deletions
|
|
@ -51,8 +51,7 @@ struct pa_resampler {
|
|||
};
|
||||
|
||||
struct impl_libsamplerate {
|
||||
pa_memblock *buf1_block, *buf2_block, *buf3_block, *buf4_block;
|
||||
float* buf1, *buf2, *buf3, *buf4;
|
||||
pa_memchunk buf1, buf2, buf3, buf4;
|
||||
unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples;
|
||||
|
||||
pa_convert_to_float32ne_func_t to_float32ne_func;
|
||||
|
|
@ -224,14 +223,14 @@ static void libsamplerate_free(pa_resampler *r) {
|
|||
if (u->src_state)
|
||||
src_delete(u->src_state);
|
||||
|
||||
if (u->buf1_block)
|
||||
pa_memblock_unref(u->buf1_block);
|
||||
if (u->buf2_block)
|
||||
pa_memblock_unref(u->buf2_block);
|
||||
if (u->buf3_block)
|
||||
pa_memblock_unref(u->buf3_block);
|
||||
if (u->buf4_block)
|
||||
pa_memblock_unref(u->buf4_block);
|
||||
if (u->buf1.memblock)
|
||||
pa_memblock_unref(u->buf1.memblock);
|
||||
if (u->buf2.memblock)
|
||||
pa_memblock_unref(u->buf2.memblock);
|
||||
if (u->buf3.memblock)
|
||||
pa_memblock_unref(u->buf3.memblock);
|
||||
if (u->buf4.memblock)
|
||||
pa_memblock_unref(u->buf4.memblock);
|
||||
pa_xfree(u);
|
||||
}
|
||||
|
||||
|
|
@ -270,64 +269,80 @@ static void calc_map_table(pa_resampler *r) {
|
|||
}
|
||||
}
|
||||
|
||||
static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) {
|
||||
static pa_memchunk* convert_to_float(pa_resampler *r, pa_memchunk *input) {
|
||||
struct impl_libsamplerate *u;
|
||||
unsigned n_samples;
|
||||
void *src, *dst;
|
||||
|
||||
assert(r);
|
||||
assert(input);
|
||||
assert(input->memblock);
|
||||
|
||||
assert(r->impl_data);
|
||||
u = r->impl_data;
|
||||
|
||||
/* Convert the incoming sample into floats and place them in buf1 */
|
||||
|
||||
if (!u->to_float32ne_func)
|
||||
if (!u->to_float32ne_func || !input->length)
|
||||
return input;
|
||||
|
||||
n_samples = n_frames * r->i_ss.channels;
|
||||
n_samples = (input->length / r->i_fz) * r->i_ss.channels;
|
||||
|
||||
if (u->buf1_samples < n_samples) {
|
||||
if (u->buf1_block)
|
||||
pa_memblock_unref(u->buf1_block);
|
||||
if (!u->buf1.memblock || u->buf1_samples < n_samples) {
|
||||
if (u->buf1.memblock)
|
||||
pa_memblock_unref(u->buf1.memblock);
|
||||
|
||||
u->buf1_samples = n_samples;
|
||||
u->buf1_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
|
||||
u->buf1 = u->buf1_block->data;
|
||||
u->buf1.memblock = pa_memblock_new(r->mempool, u->buf1.length = sizeof(float) * n_samples);
|
||||
u->buf1.index = 0;
|
||||
}
|
||||
|
||||
u->to_float32ne_func(n_samples, input, u->buf1);
|
||||
|
||||
return u->buf1;
|
||||
src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
|
||||
dst = (uint8_t*) pa_memblock_acquire(u->buf1.memblock);
|
||||
u->to_float32ne_func(n_samples, src, dst);
|
||||
pa_memblock_release(input->memblock);
|
||||
pa_memblock_release(u->buf1.memblock);
|
||||
|
||||
u->buf1.length = sizeof(float) * n_samples;
|
||||
|
||||
return &u->buf1;
|
||||
}
|
||||
|
||||
static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) {
|
||||
static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
|
||||
struct impl_libsamplerate *u;
|
||||
unsigned n_samples;
|
||||
unsigned n_samples, n_frames;
|
||||
int i_skip, o_skip;
|
||||
unsigned oc;
|
||||
float *src, *dst;
|
||||
|
||||
assert(r);
|
||||
assert(input);
|
||||
assert(input->memblock);
|
||||
|
||||
assert(r->impl_data);
|
||||
u = r->impl_data;
|
||||
|
||||
/* Remap channels and place the result int buf2 */
|
||||
|
||||
if (!u->map_required)
|
||||
if (!u->map_required || !input->length)
|
||||
return input;
|
||||
|
||||
n_samples = n_frames * r->o_ss.channels;
|
||||
n_samples = input->length / sizeof(float);
|
||||
n_frames = n_samples / r->o_ss.channels;
|
||||
|
||||
if (u->buf2_samples < n_samples) {
|
||||
if (u->buf2_block)
|
||||
pa_memblock_unref(u->buf2_block);
|
||||
if (!u->buf2.memblock || u->buf2_samples < n_samples) {
|
||||
if (u->buf2.memblock)
|
||||
pa_memblock_unref(u->buf2.memblock);
|
||||
|
||||
u->buf2_samples = n_samples;
|
||||
u->buf2_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
|
||||
u->buf2 = u->buf2_block->data;
|
||||
u->buf2.memblock = pa_memblock_new(r->mempool, u->buf2.length = sizeof(float) * n_samples);
|
||||
u->buf2.index = 0;
|
||||
}
|
||||
|
||||
memset(u->buf2, 0, n_samples * sizeof(float));
|
||||
src = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
|
||||
dst = (float*) pa_memblock_acquire(u->buf2.memblock);
|
||||
|
||||
memset(dst, 0, n_samples * sizeof(float));
|
||||
|
||||
o_skip = sizeof(float) * r->o_ss.channels;
|
||||
i_skip = sizeof(float) * r->i_ss.channels;
|
||||
|
|
@ -338,49 +353,57 @@ static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) {
|
|||
|
||||
for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++)
|
||||
oil_vectoradd_f32(
|
||||
u->buf2 + oc, o_skip,
|
||||
u->buf2 + oc, o_skip,
|
||||
input + u->map_table[oc][i], i_skip,
|
||||
dst + oc, o_skip,
|
||||
dst + oc, o_skip,
|
||||
src + u->map_table[oc][i], i_skip,
|
||||
n_frames,
|
||||
&one, &one);
|
||||
}
|
||||
|
||||
return u->buf2;
|
||||
pa_memblock_release(input->memblock);
|
||||
pa_memblock_release(u->buf2.memblock);
|
||||
|
||||
u->buf2.length = n_frames * sizeof(float) * r->o_ss.channels;
|
||||
|
||||
return &u->buf2;
|
||||
}
|
||||
|
||||
static float *resample(pa_resampler *r, float *input, unsigned *n_frames) {
|
||||
static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) {
|
||||
struct impl_libsamplerate *u;
|
||||
SRC_DATA data;
|
||||
unsigned in_n_frames, in_n_samples;
|
||||
unsigned out_n_frames, out_n_samples;
|
||||
int ret;
|
||||
|
||||
assert(r);
|
||||
assert(input);
|
||||
assert(n_frames);
|
||||
assert(r->impl_data);
|
||||
u = r->impl_data;
|
||||
|
||||
/* Resample the data and place the result in buf3 */
|
||||
|
||||
if (!u->src_state)
|
||||
if (!u->src_state || !input->length)
|
||||
return input;
|
||||
|
||||
out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024;
|
||||
in_n_samples = input->length / sizeof(float);
|
||||
in_n_frames = in_n_samples * r->o_ss.channels;
|
||||
|
||||
out_n_frames = (in_n_frames*r->o_ss.rate/r->i_ss.rate)+1024;
|
||||
out_n_samples = out_n_frames * r->o_ss.channels;
|
||||
|
||||
if (u->buf3_samples < out_n_samples) {
|
||||
if (u->buf3_block)
|
||||
pa_memblock_unref(u->buf3_block);
|
||||
if (!u->buf3.memblock || u->buf3_samples < out_n_samples) {
|
||||
if (u->buf3.memblock)
|
||||
pa_memblock_unref(u->buf3.memblock);
|
||||
|
||||
u->buf3_samples = out_n_samples;
|
||||
u->buf3_block = pa_memblock_new(r->mempool, sizeof(float) * out_n_samples);
|
||||
u->buf3 = u->buf3_block->data;
|
||||
u->buf3.memblock = pa_memblock_new(r->mempool, u->buf3.length = sizeof(float) * out_n_samples);
|
||||
u->buf3.index = 0;
|
||||
}
|
||||
|
||||
data.data_in = input;
|
||||
data.input_frames = *n_frames;
|
||||
data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
|
||||
data.input_frames = in_n_frames;
|
||||
|
||||
data.data_out = u->buf3;
|
||||
data.data_out = (float*) pa_memblock_acquire(u->buf3.memblock);
|
||||
data.output_frames = out_n_frames;
|
||||
|
||||
data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate;
|
||||
|
|
@ -388,16 +411,20 @@ static float *resample(pa_resampler *r, float *input, unsigned *n_frames) {
|
|||
|
||||
ret = src_process(u->src_state, &data);
|
||||
assert(ret == 0);
|
||||
assert((unsigned) data.input_frames_used == *n_frames);
|
||||
assert((unsigned) data.input_frames_used == in_n_frames);
|
||||
|
||||
*n_frames = data.output_frames_gen;
|
||||
pa_memblock_release(input->memblock);
|
||||
pa_memblock_release(u->buf3.memblock);
|
||||
|
||||
u->buf3.length = data.output_frames_gen * sizeof(float) * r->o_ss.channels;
|
||||
|
||||
return u->buf3;
|
||||
return &u->buf3;
|
||||
}
|
||||
|
||||
static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) {
|
||||
static pa_memchunk *convert_from_float(pa_resampler *r, pa_memchunk *input) {
|
||||
struct impl_libsamplerate *u;
|
||||
unsigned n_samples;
|
||||
unsigned n_samples, n_frames;
|
||||
void *src, *dst;
|
||||
|
||||
assert(r);
|
||||
assert(input);
|
||||
|
|
@ -406,30 +433,35 @@ static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames
|
|||
|
||||
/* Convert the data into the correct sample type and place the result in buf4 */
|
||||
|
||||
if (!u->from_float32ne_func)
|
||||
if (!u->from_float32ne_func || !input->length)
|
||||
return input;
|
||||
|
||||
|
||||
n_frames = input->length / sizeof(float) / r->o_ss.channels;
|
||||
n_samples = n_frames * r->o_ss.channels;
|
||||
|
||||
if (u->buf4_samples < n_samples) {
|
||||
if (u->buf4_block)
|
||||
pa_memblock_unref(u->buf4_block);
|
||||
if (u->buf4.memblock)
|
||||
pa_memblock_unref(u->buf4.memblock);
|
||||
|
||||
u->buf4_samples = n_samples;
|
||||
u->buf4_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
|
||||
u->buf4 = u->buf4_block->data;
|
||||
u->buf4.memblock = pa_memblock_new(r->mempool, u->buf4.length = r->o_fz * n_frames);
|
||||
u->buf4.index = 0;
|
||||
}
|
||||
|
||||
u->from_float32ne_func(n_samples, input, u->buf4);
|
||||
|
||||
return u->buf4;
|
||||
src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->length;
|
||||
dst = pa_memblock_acquire(u->buf4.memblock);
|
||||
u->from_float32ne_func(n_samples, src, dst);
|
||||
pa_memblock_release(input->memblock);
|
||||
pa_memblock_release(u->buf4.memblock);
|
||||
|
||||
u->buf4.length = r->o_fz * n_frames;
|
||||
|
||||
return &u->buf4;
|
||||
}
|
||||
|
||||
static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
|
||||
struct impl_libsamplerate *u;
|
||||
float *buf;
|
||||
void *input, *output;
|
||||
unsigned n_frames;
|
||||
pa_memchunk *buf;
|
||||
|
||||
assert(r);
|
||||
assert(in);
|
||||
|
|
@ -441,55 +473,23 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun
|
|||
|
||||
u = r->impl_data;
|
||||
|
||||
input = ((uint8_t*) in->memblock->data + in->index);
|
||||
n_frames = in->length / r->i_fz;
|
||||
assert(n_frames > 0);
|
||||
buf = convert_to_float(r, (pa_memchunk*) in);
|
||||
buf = remap_channels(r, buf);
|
||||
buf = resample(r, buf);
|
||||
|
||||
if (buf->length) {
|
||||
buf = convert_from_float(r, buf);
|
||||
*out = *buf;
|
||||
|
||||
if (buf == in)
|
||||
pa_memblock_ref(buf->memblock);
|
||||
else
|
||||
pa_memchunk_reset(buf);
|
||||
} else
|
||||
pa_memchunk_reset(out);
|
||||
|
||||
pa_memblock_release(in->memblock);
|
||||
|
||||
buf = convert_to_float(r, input, n_frames);
|
||||
buf = remap_channels(r, buf, n_frames);
|
||||
buf = resample(r, buf, &n_frames);
|
||||
|
||||
if (n_frames) {
|
||||
output = convert_from_float(r, buf, n_frames);
|
||||
|
||||
if (output == input) {
|
||||
/* Mm, no adjustment has been necessary, so let's return the original block */
|
||||
out->memblock = pa_memblock_ref(in->memblock);
|
||||
out->index = in->index;
|
||||
out->length = in->length;
|
||||
} else {
|
||||
out->length = n_frames * r->o_fz;
|
||||
out->index = 0;
|
||||
out->memblock = NULL;
|
||||
|
||||
if (output == u->buf1) {
|
||||
u->buf1 = NULL;
|
||||
u->buf1_samples = 0;
|
||||
out->memblock = u->buf1_block;
|
||||
u->buf1_block = NULL;
|
||||
} else if (output == u->buf2) {
|
||||
u->buf2 = NULL;
|
||||
u->buf2_samples = 0;
|
||||
out->memblock = u->buf2_block;
|
||||
u->buf2_block = NULL;
|
||||
} else if (output == u->buf3) {
|
||||
u->buf3 = NULL;
|
||||
u->buf3_samples = 0;
|
||||
out->memblock = u->buf3_block;
|
||||
u->buf3_block = NULL;
|
||||
} else if (output == u->buf4) {
|
||||
u->buf4 = NULL;
|
||||
u->buf4_samples = 0;
|
||||
out->memblock = u->buf4_block;
|
||||
u->buf4_block = NULL;
|
||||
}
|
||||
|
||||
assert(out->memblock);
|
||||
}
|
||||
} else {
|
||||
out->memblock = NULL;
|
||||
out->index = out->length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) {
|
||||
|
|
@ -516,8 +516,10 @@ static int libsamplerate_init(pa_resampler *r) {
|
|||
|
||||
r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1);
|
||||
|
||||
u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL;
|
||||
u->buf1_block = u->buf2_block = u->buf3_block = u->buf4_block = NULL;
|
||||
pa_memchunk_reset(&u->buf1);
|
||||
pa_memchunk_reset(&u->buf2);
|
||||
pa_memchunk_reset(&u->buf3);
|
||||
pa_memchunk_reset(&u->buf4);
|
||||
u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0;
|
||||
|
||||
if (r->i_ss.format == PA_SAMPLE_FLOAT32NE)
|
||||
|
|
@ -578,12 +580,16 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out
|
|||
/* Do real resampling */
|
||||
size_t l;
|
||||
unsigned o_index;
|
||||
void *src, *dst;
|
||||
|
||||
/* The length of the new memory block rounded up */
|
||||
l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz;
|
||||
|
||||
out->index = 0;
|
||||
out->memblock = pa_memblock_new(r->mempool, l);
|
||||
|
||||
src = (uint8_t*) pa_memblock_acquire(in->memblock) + in->index;
|
||||
dst = pa_memblock_acquire(out->memblock);
|
||||
|
||||
for (o_index = 0;; o_index++, u->o_counter++) {
|
||||
unsigned j;
|
||||
|
|
@ -594,13 +600,16 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out
|
|||
if (j >= n_frames)
|
||||
break;
|
||||
|
||||
assert(o_index*fz < out->memblock->length);
|
||||
assert(o_index*fz < pa_memblock_get_length(out->memblock));
|
||||
|
||||
memcpy((uint8_t*) out->memblock->data + fz*o_index,
|
||||
(uint8_t*) in->memblock->data + in->index + fz*j, fz);
|
||||
memcpy((uint8_t*) dst + fz*o_index,
|
||||
(uint8_t*) src + fz*j, fz);
|
||||
|
||||
}
|
||||
|
||||
|
||||
pa_memblock_release(in->memblock);
|
||||
pa_memblock_release(out->memblock);
|
||||
|
||||
out->length = o_index*fz;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue