mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	sink,source: Handle missing in the shared volume case
This makes sure that when we're traversing the device chain for sources and sinks with shared volume, we handle the case that a sink-input or source-output of one of these might be unlinked (while unloading a module, for example).
This commit is contained in:
		
							parent
							
								
									fde703be75
								
							
						
					
					
						commit
						cae3235369
					
				
					 6 changed files with 74 additions and 32 deletions
				
			
		| 
						 | 
					@ -1438,12 +1438,12 @@ static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
 | 
				
			||||||
    pa_assert(i->sink); /* The destination sink should already be set. */
 | 
					    pa_assert(i->sink); /* The destination sink should already be set. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
 | 
					    if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
 | 
				
			||||||
        pa_sink *root_sink = i->sink;
 | 
					        pa_sink *root_sink = pa_sink_get_master(i->sink);
 | 
				
			||||||
        pa_sink_input *origin_sink_input;
 | 
					        pa_sink_input *origin_sink_input;
 | 
				
			||||||
        uint32_t idx;
 | 
					        uint32_t idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
 | 
					        if (PA_UNLIKELY(!root_sink))
 | 
				
			||||||
            root_sink = root_sink->input_to_master->sink;
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (pa_sink_flat_volume_enabled(i->sink)) {
 | 
					        if (pa_sink_flat_volume_enabled(i->sink)) {
 | 
				
			||||||
            /* Ok, so the origin sink uses volume sharing, and flat volume is
 | 
					            /* Ok, so the origin sink uses volume sharing, and flat volume is
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -618,10 +618,9 @@ void pa_sink_put(pa_sink* s) {
 | 
				
			||||||
        enable_flat_volume(s, TRUE);
 | 
					        enable_flat_volume(s, TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) {
 | 
					    if (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) {
 | 
				
			||||||
        pa_sink *root_sink = s->input_to_master->sink;
 | 
					        pa_sink *root_sink = pa_sink_get_master(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
 | 
					        pa_assert(root_sink);
 | 
				
			||||||
            root_sink = root_sink->input_to_master->sink;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        s->reference_volume = root_sink->reference_volume;
 | 
					        s->reference_volume = root_sink->reference_volume;
 | 
				
			||||||
        pa_cvolume_remap(&s->reference_volume, &root_sink->channel_map, &s->channel_map);
 | 
					        pa_cvolume_remap(&s->reference_volume, &root_sink->channel_map, &s->channel_map);
 | 
				
			||||||
| 
						 | 
					@ -1370,10 +1369,27 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
 | 
				
			||||||
pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s) {
 | 
					pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s) {
 | 
				
			||||||
    pa_sink_assert_ref(s);
 | 
					    pa_sink_assert_ref(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
 | 
					    s = pa_sink_get_master(s);
 | 
				
			||||||
        s = s->input_to_master->sink;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (s->flags & PA_SINK_FLAT_VOLUME);
 | 
					    if (PA_LIKELY(s))
 | 
				
			||||||
 | 
					        return (s->flags & PA_SINK_FLAT_VOLUME);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        return FALSE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Called from the main thread (and also from the IO thread while the main
 | 
				
			||||||
 | 
					 * thread is waiting). */
 | 
				
			||||||
 | 
					pa_sink *pa_sink_get_master(pa_sink *s) {
 | 
				
			||||||
 | 
					    pa_sink_assert_ref(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (s && (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
 | 
				
			||||||
 | 
					        if (PA_UNLIKELY(!s->input_to_master))
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s = s->input_to_master->sink;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Called from main context */
 | 
					/* Called from main context */
 | 
				
			||||||
| 
						 | 
					@ -1804,7 +1820,7 @@ void pa_sink_set_volume(
 | 
				
			||||||
        pa_bool_t save) {
 | 
					        pa_bool_t save) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_cvolume new_reference_volume;
 | 
					    pa_cvolume new_reference_volume;
 | 
				
			||||||
    pa_sink *root_sink = s;
 | 
					    pa_sink *root_sink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_sink_assert_ref(s);
 | 
					    pa_sink_assert_ref(s);
 | 
				
			||||||
    pa_assert_ctl_context();
 | 
					    pa_assert_ctl_context();
 | 
				
			||||||
| 
						 | 
					@ -1822,8 +1838,10 @@ void pa_sink_set_volume(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* In case of volume sharing, the volume is set for the root sink first,
 | 
					    /* In case of volume sharing, the volume is set for the root sink first,
 | 
				
			||||||
     * from which it's then propagated to the sharing sinks. */
 | 
					     * from which it's then propagated to the sharing sinks. */
 | 
				
			||||||
    while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
 | 
					    root_sink = pa_sink_get_master(s);
 | 
				
			||||||
        root_sink = root_sink->input_to_master->sink;
 | 
					
 | 
				
			||||||
 | 
					    if (PA_UNLIKELY(!root_sink))
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* As a special exception we accept mono volumes on all sinks --
 | 
					    /* As a special exception we accept mono volumes on all sinks --
 | 
				
			||||||
     * even on those with more complex channel maps */
 | 
					     * even on those with more complex channel maps */
 | 
				
			||||||
| 
						 | 
					@ -2447,12 +2465,11 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case PA_SINK_MESSAGE_SET_SHARED_VOLUME: {
 | 
					        case PA_SINK_MESSAGE_SET_SHARED_VOLUME: {
 | 
				
			||||||
            pa_sink *root_sink = s;
 | 
					            pa_sink *root_sink = pa_sink_get_master(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
 | 
					            if (PA_LIKELY(root_sink))
 | 
				
			||||||
                root_sink = root_sink->input_to_master->sink;
 | 
					                set_shared_volume_within_thread(root_sink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            set_shared_volume_within_thread(root_sink);
 | 
					 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -419,6 +419,9 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause)
 | 
				
			||||||
/* Use this instead of checking s->flags & PA_SINK_FLAT_VOLUME directly. */
 | 
					/* Use this instead of checking s->flags & PA_SINK_FLAT_VOLUME directly. */
 | 
				
			||||||
pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s);
 | 
					pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get the master sink when sharing volumes */
 | 
				
			||||||
 | 
					pa_sink *pa_sink_get_master(pa_sink *s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Is the sink in passthrough mode? (that is, is there a passthrough sink input
 | 
					/* Is the sink in passthrough mode? (that is, is there a passthrough sink input
 | 
				
			||||||
 * connected to this sink? */
 | 
					 * connected to this sink? */
 | 
				
			||||||
pa_bool_t pa_sink_is_passthrough(pa_sink *s);
 | 
					pa_bool_t pa_sink_is_passthrough(pa_sink *s);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1218,12 +1218,14 @@ static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) {
 | 
				
			||||||
    pa_assert(o->source); /* The destination source should already be set. */
 | 
					    pa_assert(o->source); /* The destination source should already be set. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (o->destination_source && (o->destination_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)) {
 | 
					    if (o->destination_source && (o->destination_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)) {
 | 
				
			||||||
        pa_source *root_source = o->source;
 | 
					        pa_source *root_source;
 | 
				
			||||||
        pa_source_output *destination_source_output;
 | 
					        pa_source_output *destination_source_output;
 | 
				
			||||||
        uint32_t idx;
 | 
					        uint32_t idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (root_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)
 | 
					        root_source = pa_source_get_master(o->source);
 | 
				
			||||||
            root_source = root_source->output_from_master->source;
 | 
					
 | 
				
			||||||
 | 
					        if (PA_UNLIKELY(!root_source))
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (pa_source_flat_volume_enabled(o->source)) {
 | 
					        if (pa_source_flat_volume_enabled(o->source)) {
 | 
				
			||||||
            /* Ok, so the origin source uses volume sharing, and flat volume is
 | 
					            /* Ok, so the origin source uses volume sharing, and flat volume is
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -549,10 +549,9 @@ void pa_source_put(pa_source *s) {
 | 
				
			||||||
        enable_flat_volume(s, TRUE);
 | 
					        enable_flat_volume(s, TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER) {
 | 
					    if (s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER) {
 | 
				
			||||||
        pa_source *root_source = s->output_from_master->source;
 | 
					        pa_source *root_source = pa_source_get_master(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (root_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)
 | 
					        pa_assert(PA_LIKELY(root_source));
 | 
				
			||||||
            root_source = root_source->output_from_master->source;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        s->reference_volume = root_source->reference_volume;
 | 
					        s->reference_volume = root_source->reference_volume;
 | 
				
			||||||
        pa_cvolume_remap(&s->reference_volume, &root_source->channel_map, &s->channel_map);
 | 
					        pa_cvolume_remap(&s->reference_volume, &root_source->channel_map, &s->channel_map);
 | 
				
			||||||
| 
						 | 
					@ -963,10 +962,27 @@ pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
 | 
				
			||||||
pa_bool_t pa_source_flat_volume_enabled(pa_source *s) {
 | 
					pa_bool_t pa_source_flat_volume_enabled(pa_source *s) {
 | 
				
			||||||
    pa_source_assert_ref(s);
 | 
					    pa_source_assert_ref(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)
 | 
					    s = pa_source_get_master(s);
 | 
				
			||||||
        s = s->output_from_master->source;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (s->flags & PA_SOURCE_FLAT_VOLUME);
 | 
					    if (PA_LIKELY(s))
 | 
				
			||||||
 | 
					        return (s->flags & PA_SOURCE_FLAT_VOLUME);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        return FALSE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Called from the main thread (and also from the IO thread while the main
 | 
				
			||||||
 | 
					 * thread is waiting). */
 | 
				
			||||||
 | 
					pa_source *pa_source_get_master(pa_source *s) {
 | 
				
			||||||
 | 
					    pa_source_assert_ref(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (s && (s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)) {
 | 
				
			||||||
 | 
					        if (PA_UNLIKELY(!s->output_from_master))
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s = s->output_from_master->source;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Called from main context */
 | 
					/* Called from main context */
 | 
				
			||||||
| 
						 | 
					@ -1380,7 +1396,7 @@ void pa_source_set_volume(
 | 
				
			||||||
        pa_bool_t save) {
 | 
					        pa_bool_t save) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_cvolume new_reference_volume;
 | 
					    pa_cvolume new_reference_volume;
 | 
				
			||||||
    pa_source *root_source = s;
 | 
					    pa_source *root_source;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_source_assert_ref(s);
 | 
					    pa_source_assert_ref(s);
 | 
				
			||||||
    pa_assert_ctl_context();
 | 
					    pa_assert_ctl_context();
 | 
				
			||||||
| 
						 | 
					@ -1398,8 +1414,10 @@ void pa_source_set_volume(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* In case of volume sharing, the volume is set for the root source first,
 | 
					    /* In case of volume sharing, the volume is set for the root source first,
 | 
				
			||||||
     * from which it's then propagated to the sharing sources. */
 | 
					     * from which it's then propagated to the sharing sources. */
 | 
				
			||||||
    while (root_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)
 | 
					    root_source = pa_source_get_master(s);
 | 
				
			||||||
        root_source = root_source->output_from_master->source;
 | 
					
 | 
				
			||||||
 | 
					    if (PA_UNLIKELY(!root_source))
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* As a special exception we accept mono volumes on all sources --
 | 
					    /* As a special exception we accept mono volumes on all sources --
 | 
				
			||||||
     * even on those with more complex channel maps */
 | 
					     * even on those with more complex channel maps */
 | 
				
			||||||
| 
						 | 
					@ -1877,12 +1895,11 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case PA_SOURCE_MESSAGE_SET_SHARED_VOLUME: {
 | 
					        case PA_SOURCE_MESSAGE_SET_SHARED_VOLUME: {
 | 
				
			||||||
            pa_source *root_source = s;
 | 
					            pa_source *root_source = pa_source_get_master(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while (root_source->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)
 | 
					            if (PA_LIKELY(root_source))
 | 
				
			||||||
                root_source = root_source->output_from_master->source;
 | 
					                set_shared_volume_within_thread(root_source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            set_shared_volume_within_thread(root_source);
 | 
					 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -339,6 +339,9 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t caus
 | 
				
			||||||
/* Use this instead of checking s->flags & PA_SOURCE_FLAT_VOLUME directly. */
 | 
					/* Use this instead of checking s->flags & PA_SOURCE_FLAT_VOLUME directly. */
 | 
				
			||||||
pa_bool_t pa_source_flat_volume_enabled(pa_source *s);
 | 
					pa_bool_t pa_source_flat_volume_enabled(pa_source *s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get the master source when sharing volumes */
 | 
				
			||||||
 | 
					pa_source *pa_source_get_master(pa_source *s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Is the source in passthrough mode? (that is, is this a monitor source for a sink
 | 
					/* Is the source in passthrough mode? (that is, is this a monitor source for a sink
 | 
				
			||||||
 * that has a passthrough sink input connected to it. */
 | 
					 * that has a passthrough sink input connected to it. */
 | 
				
			||||||
pa_bool_t pa_source_is_passthrough(pa_source *s);
 | 
					pa_bool_t pa_source_is_passthrough(pa_source *s);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue