mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
source: Introduce vsource structure
This patch introduces a vsource structure analog to the vsink structure. The structure will be used for virtual source consolidation.
This commit is contained in:
parent
95be21c736
commit
b6ccb7e76d
5 changed files with 134 additions and 15 deletions
|
|
@ -272,7 +272,10 @@ static bool find_paired_master(struct userdata *u, struct filter *filter, pa_obj
|
|||
}
|
||||
/* Make sure we're not routing to another instance of
|
||||
* the same filter. */
|
||||
filter->source_master = so->source->output_from_master->source;
|
||||
if (so->source->vsource)
|
||||
filter->source_master = so->source->vsource->output_from_master->source;
|
||||
else
|
||||
filter->source_master = so->source->output_from_master->source;
|
||||
} else {
|
||||
filter->source_master = so->source;
|
||||
}
|
||||
|
|
@ -474,12 +477,18 @@ static void find_filters_for_module(struct userdata *u, pa_module *m, const char
|
|||
pa_assert(pa_source_is_filter(source));
|
||||
|
||||
if (!fltr) {
|
||||
fltr = filter_new(name, parameters, NULL, source->output_from_master->source);
|
||||
if (source->vsource)
|
||||
fltr = filter_new(name, parameters, NULL, source->vsource->output_from_master->source);
|
||||
else
|
||||
fltr = filter_new(name, parameters, NULL, source->output_from_master->source);
|
||||
fltr->module_index = m->index;
|
||||
fltr->source = source;
|
||||
} else {
|
||||
fltr->source = source;
|
||||
fltr->source_master = source->output_from_master->source;
|
||||
if (source->vsource)
|
||||
fltr->source_master = source->vsource->output_from_master->source;
|
||||
else
|
||||
fltr->source_master = source->output_from_master->source;
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -529,6 +529,7 @@ void pa_core_update_default_sink(pa_core *core) {
|
|||
* a > b -> return 1 */
|
||||
static int compare_sources(pa_source *a, pa_source *b, bool ignore_configured_virtual_default) {
|
||||
pa_core *core;
|
||||
bool a_is_vsource, b_is_vsource;
|
||||
|
||||
core = a->core;
|
||||
|
||||
|
|
@ -572,10 +573,25 @@ static int compare_sources(pa_source *a, pa_source *b, bool ignore_configured_vi
|
|||
if (a->priority > b->priority)
|
||||
return 1;
|
||||
|
||||
/* Let sources like pipe source or null source win against filter sources */
|
||||
if (a->output_from_master && !b->output_from_master)
|
||||
/* Let sources like pipe source or null source win against filter sources
|
||||
During consolidation, we have to detect the presence of the vsource or
|
||||
output_to_master variable. When the virtual sources have been migrated,
|
||||
this will simplify. */
|
||||
a_is_vsource = false;
|
||||
if (a->vsource)
|
||||
a_is_vsource = true;
|
||||
else if (a->output_from_master)
|
||||
a_is_vsource = true;
|
||||
|
||||
b_is_vsource = false;
|
||||
if (b->vsource)
|
||||
b_is_vsource = true;
|
||||
else if (b->output_from_master)
|
||||
b_is_vsource = true;
|
||||
|
||||
if (a_is_vsource && !b_is_vsource)
|
||||
return -1;
|
||||
if (!a->output_from_master && b->output_from_master)
|
||||
if (!a_is_vsource && b_is_vsource)
|
||||
return 1;
|
||||
|
||||
/* If the sources are monitors, we can compare the monitored sinks. */
|
||||
|
|
|
|||
|
|
@ -1306,10 +1306,20 @@ bool pa_source_output_may_move(pa_source_output *o) {
|
|||
|
||||
bool pa_source_output_is_filter_loop(pa_source_output *target, pa_source *s) {
|
||||
unsigned PA_UNUSED i = 0;
|
||||
while (s && s->output_from_master) {
|
||||
if (s->output_from_master == target)
|
||||
return true;
|
||||
s = s->output_from_master->source;
|
||||
|
||||
/* During consolidation, we have to support s->output_from_master and
|
||||
* s->vsource->output_from_master. The first will disappear after all
|
||||
* virtual sources use the new code. */
|
||||
while (s && (s->output_from_master || (s->vsource && s->vsource->output_from_master))) {
|
||||
if (s->vsource) {
|
||||
if (s->vsource->output_from_master == target)
|
||||
return true;
|
||||
s = s->vsource->output_from_master->source;
|
||||
} else {
|
||||
if (s->output_from_master == target)
|
||||
return true;
|
||||
s = s->output_from_master->source;
|
||||
}
|
||||
pa_assert(i++ < 100);
|
||||
}
|
||||
return false;
|
||||
|
|
@ -1321,8 +1331,11 @@ static bool is_filter_source_moving(pa_source_output *o) {
|
|||
if (!source)
|
||||
return false;
|
||||
|
||||
while (source->output_from_master) {
|
||||
source = source->output_from_master->source;
|
||||
while (source->output_from_master || (source->vsource && source->vsource->output_from_master)) {
|
||||
if (source->vsource)
|
||||
source = source->vsource->output_from_master->source;
|
||||
else
|
||||
source = source->output_from_master->source;
|
||||
|
||||
if (!source)
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1234,11 +1234,19 @@ bool pa_source_flat_volume_enabled(pa_source *s) {
|
|||
pa_source *pa_source_get_master(pa_source *s) {
|
||||
pa_source_assert_ref(s);
|
||||
|
||||
/* During consolidation, we have to support s->output_from_master and
|
||||
* s->vsource->output_from_master. The first will disappear after all
|
||||
* virtual sources use the new code. */
|
||||
while (s && (s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)) {
|
||||
if (PA_UNLIKELY(!s->output_from_master))
|
||||
if (PA_UNLIKELY(s->vsource && !s->vsource->output_from_master))
|
||||
return NULL;
|
||||
if (PA_UNLIKELY(!s->vsource && !s->output_from_master))
|
||||
return NULL;
|
||||
|
||||
s = s->output_from_master->source;
|
||||
if (s->output_from_master)
|
||||
s = s->output_from_master->source;
|
||||
else
|
||||
s = s->vsource->output_from_master->source;
|
||||
}
|
||||
|
||||
return s;
|
||||
|
|
@ -1248,7 +1256,7 @@ pa_source *pa_source_get_master(pa_source *s) {
|
|||
bool pa_source_is_filter(pa_source *s) {
|
||||
pa_source_assert_ref(s);
|
||||
|
||||
return (s->output_from_master != NULL);
|
||||
return ((s->output_from_master != NULL || s->vsource->output_from_master != NULL));
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
|
|
|
|||
|
|
@ -57,6 +57,78 @@ typedef void(*pa_source_cb_t)(pa_source *s);
|
|||
|
||||
typedef int (*pa_source_get_mute_cb_t)(pa_source *s, bool *mute);
|
||||
|
||||
/* Virtual source structure */
|
||||
typedef struct pa_vsource {
|
||||
pa_msgobject parent; /* Message object */
|
||||
pa_core *core; /* Pointer to core */
|
||||
pa_source *source; /* A pointer to the virtual source */
|
||||
pa_source_output *output_from_master; /* source output from the master source */
|
||||
pa_memblockq *memblockq; /* Memblockq of the virtual source, may be NULL */
|
||||
|
||||
bool auto_desc; /* Automatically adapt description on move */
|
||||
bool source_moving; /* Set when master source changes to preserve volume */
|
||||
const char *desc_head; /* Leading part of description string used for the
|
||||
* source and source input when auto_desc is true */
|
||||
const char *source_type; /* Name for the type of source, used as suffix for
|
||||
* the source name if the name is derived from the
|
||||
* master source. */
|
||||
bool autoloaded; /* True if the source was not loaded manually */
|
||||
size_t max_chunk_size; /* Maximum chunk size in bytes that the filter will
|
||||
* accept, set to pa_mempool_block_size_max() by default */
|
||||
size_t fixed_block_size; /* Block size in frames for fixed block size filters,
|
||||
* 0 if block size is controlled by pulseaudio. */
|
||||
size_t fixed_input_block_size; /* Input block size in frames. If not 0, input data for
|
||||
* process_chunk() will always have the same size.
|
||||
* If not enough new data is available, the remaining
|
||||
* samples will be filled with history. */
|
||||
size_t overlap_frames; /* Some filters require old input samples in addtion to
|
||||
* the current data. The variable contains the number of
|
||||
* previous frames that will be passed to process_chunk().
|
||||
* The actual number of history frames may be variable if
|
||||
* the filter defines the get_current_overlap() function.
|
||||
* In this case, overlap_frames contains the maximum
|
||||
* number of history frames. */
|
||||
pa_usec_t max_latency; /* Maximum latency allowed for the source, 0 if unused */
|
||||
|
||||
/* Callback to process a chunk of data by the filter. Called from I/O thread
|
||||
* context. May be NULL */
|
||||
void (*process_chunk)(uint8_t *src, uint8_t *dst, unsigned in_count, unsigned out_count, void *userdata);
|
||||
|
||||
/* Callback to retrieve additional latency caused by the filter. Called from
|
||||
* I/O thread context. May be NULL */
|
||||
pa_usec_t (*get_extra_latency)(pa_source *s);
|
||||
|
||||
/* If defined, this function is called from the source-output push() callback
|
||||
* to retrieve the current number of history frames to include in the next
|
||||
* chunk. Called from I/O thread. */
|
||||
size_t (*get_current_overlap)(pa_source_output *o);
|
||||
|
||||
/* If set and dest is valid, this function is called in the moving() callback
|
||||
* to change the description of source and source-output. Called from main context.
|
||||
* May be NULL */
|
||||
void (*set_description)(pa_source_output *o, pa_source *dest);
|
||||
|
||||
/* If set, this function will be called after update_filter_parameters() to
|
||||
* inform the filter of the block sizes that will be used. These may differ
|
||||
* from the sizes set in update_filter_parameters() if the function tries to
|
||||
* set an invalid combination of block sizes. Called from I/O thread. */
|
||||
void (*update_block_sizes)(size_t fixed_block_size, size_t fixed_input_block_size, size_t overlap_frames, void *userdata);
|
||||
|
||||
/* If set, this function is called in I/O thread context when an update of the
|
||||
* filter parameters is requested. May be NULL. The function must replace
|
||||
* the currently used parameter structure by the new structure in parameters
|
||||
* and return a pointer to the old structure so that it can be freed in the
|
||||
* main thread using free_filter_parameters(). If the old structure can be
|
||||
* re-used, the function may return NULL. update_filter_parameters() may
|
||||
* also modify the block sizes. */
|
||||
void *(*update_filter_parameters)(void *parameters, void *userdata);
|
||||
|
||||
/* Frees a parameter structure. May only be NULL, if update_filter_parameters()
|
||||
* is also NULL or if update_filter_parameters() always returns NULL. Called
|
||||
* from main thread. */
|
||||
void (*free_filter_parameters)(void *parameters);
|
||||
} pa_vsource;
|
||||
|
||||
struct pa_source {
|
||||
pa_msgobject parent;
|
||||
|
||||
|
|
@ -90,6 +162,7 @@ struct pa_source {
|
|||
unsigned n_corked;
|
||||
pa_sink *monitor_of; /* may be NULL */
|
||||
pa_source_output *output_from_master; /* non-NULL only for filter sources */
|
||||
pa_vsource *vsource; /* non-NULL only for filter sources */
|
||||
|
||||
pa_volume_t base_volume; /* shall be constant */
|
||||
unsigned n_volume_steps; /* shall be constant */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue