mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05: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
 | 
					                        /* Make sure we're not routing to another instance of
 | 
				
			||||||
                         * the same filter. */
 | 
					                         * 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 {
 | 
					                    } else {
 | 
				
			||||||
                        filter->source_master = so->source;
 | 
					                        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));
 | 
					            pa_assert(pa_source_is_filter(source));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!fltr) {
 | 
					            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->module_index = m->index;
 | 
				
			||||||
                fltr->source = source;
 | 
					                fltr->source = source;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                fltr->source = source;
 | 
					                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;
 | 
					            break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -529,6 +529,7 @@ void pa_core_update_default_sink(pa_core *core) {
 | 
				
			||||||
 * a  > b  ->  return  1 */
 | 
					 * a  > b  ->  return  1 */
 | 
				
			||||||
static int compare_sources(pa_source *a, pa_source *b, bool ignore_configured_virtual_default) {
 | 
					static int compare_sources(pa_source *a, pa_source *b, bool ignore_configured_virtual_default) {
 | 
				
			||||||
    pa_core *core;
 | 
					    pa_core *core;
 | 
				
			||||||
 | 
					    bool a_is_vsource, b_is_vsource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    core = a->core;
 | 
					    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)
 | 
					    if (a->priority > b->priority)
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Let sources like pipe source or null source win against filter sources */
 | 
					    /* Let sources like pipe source or null source win against filter sources
 | 
				
			||||||
    if (a->output_from_master && !b->output_from_master)
 | 
					       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;
 | 
					        return -1;
 | 
				
			||||||
    if (!a->output_from_master && b->output_from_master)
 | 
					    if (!a_is_vsource && b_is_vsource)
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* If the sources are monitors, we can compare the monitored sinks. */
 | 
					    /* 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) {
 | 
					bool pa_source_output_is_filter_loop(pa_source_output *target, pa_source *s) {
 | 
				
			||||||
    unsigned PA_UNUSED i = 0;
 | 
					    unsigned PA_UNUSED i = 0;
 | 
				
			||||||
    while (s && s->output_from_master) {
 | 
					
 | 
				
			||||||
        if (s->output_from_master == target)
 | 
					    /* During consolidation, we have to support s->output_from_master and
 | 
				
			||||||
            return true;
 | 
					     * s->vsource->output_from_master. The first will disappear after all
 | 
				
			||||||
        s = s->output_from_master->source;
 | 
					     * 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);
 | 
					        pa_assert(i++ < 100);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
| 
						 | 
					@ -1321,8 +1331,11 @@ static bool is_filter_source_moving(pa_source_output *o) {
 | 
				
			||||||
    if (!source)
 | 
					    if (!source)
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (source->output_from_master) {
 | 
					    while (source->output_from_master || (source->vsource && source->vsource->output_from_master)) {
 | 
				
			||||||
        source = source->output_from_master->source;
 | 
					        if (source->vsource)
 | 
				
			||||||
 | 
					            source = source->vsource->output_from_master->source;
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            source = source->output_from_master->source;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!source)
 | 
					        if (!source)
 | 
				
			||||||
            return true;
 | 
					            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 *pa_source_get_master(pa_source *s) {
 | 
				
			||||||
    pa_source_assert_ref(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)) {
 | 
					    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;
 | 
					            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;
 | 
					    return s;
 | 
				
			||||||
| 
						 | 
					@ -1248,7 +1256,7 @@ pa_source *pa_source_get_master(pa_source *s) {
 | 
				
			||||||
bool pa_source_is_filter(pa_source *s) {
 | 
					bool pa_source_is_filter(pa_source *s) {
 | 
				
			||||||
    pa_source_assert_ref(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 */
 | 
					/* 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);
 | 
					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 {
 | 
					struct pa_source {
 | 
				
			||||||
    pa_msgobject parent;
 | 
					    pa_msgobject parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,6 +162,7 @@ struct pa_source {
 | 
				
			||||||
    unsigned n_corked;
 | 
					    unsigned n_corked;
 | 
				
			||||||
    pa_sink *monitor_of;                     /* may be NULL */
 | 
					    pa_sink *monitor_of;                     /* may be NULL */
 | 
				
			||||||
    pa_source_output *output_from_master;    /* non-NULL only for filter sources */
 | 
					    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 */
 | 
					    pa_volume_t base_volume; /* shall be constant */
 | 
				
			||||||
    unsigned n_volume_steps; /* shall be constant */
 | 
					    unsigned n_volume_steps; /* shall be constant */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue