mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	sink-input,source-output: Add an update_rate() function
This factors out the resampler updating code from finish_move() and makes a separate function for use from other points.
This commit is contained in:
		
							parent
							
								
									75573435a0
								
							
						
					
					
						commit
						8616f82a67
					
				
					 4 changed files with 136 additions and 105 deletions
				
			
		| 
						 | 
				
			
			@ -1596,8 +1596,6 @@ static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
 | 
			
		|||
 | 
			
		||||
/* Called from main context */
 | 
			
		||||
int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
 | 
			
		||||
    pa_resampler *new_resampler;
 | 
			
		||||
 | 
			
		||||
    pa_sink_input_assert_ref(i);
 | 
			
		||||
    pa_assert_ctl_context();
 | 
			
		||||
    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 | 
			
		||||
| 
						 | 
				
			
			@ -1633,34 +1631,6 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
 | 
			
		|||
                        dest->sample_spec.rate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (i->thread_info.resampler &&
 | 
			
		||||
        pa_sample_spec_equal(pa_resampler_output_sample_spec(i->thread_info.resampler), &dest->sample_spec) &&
 | 
			
		||||
        pa_channel_map_equal(pa_resampler_output_channel_map(i->thread_info.resampler), &dest->channel_map))
 | 
			
		||||
 | 
			
		||||
        /* Try to reuse the old resampler if possible */
 | 
			
		||||
        new_resampler = i->thread_info.resampler;
 | 
			
		||||
 | 
			
		||||
    else if (!pa_sink_input_is_passthrough(i) &&
 | 
			
		||||
             ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
 | 
			
		||||
              !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) ||
 | 
			
		||||
              !pa_channel_map_equal(&i->channel_map, &dest->channel_map))) {
 | 
			
		||||
 | 
			
		||||
        /* Okay, we need a new resampler for the new sink */
 | 
			
		||||
 | 
			
		||||
        if (!(new_resampler = pa_resampler_new(
 | 
			
		||||
                      i->core->mempool,
 | 
			
		||||
                      &i->sample_spec, &i->channel_map,
 | 
			
		||||
                      &dest->sample_spec, &dest->channel_map,
 | 
			
		||||
                      i->requested_resample_method,
 | 
			
		||||
                      ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
 | 
			
		||||
                      ((i->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
 | 
			
		||||
                      (i->core->disable_remixing || (i->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
 | 
			
		||||
            pa_log_warn("Unsupported resampling operation.");
 | 
			
		||||
            return -PA_ERR_NOTSUPPORTED;
 | 
			
		||||
        }
 | 
			
		||||
    } else
 | 
			
		||||
        new_resampler = NULL;
 | 
			
		||||
 | 
			
		||||
    if (i->moving)
 | 
			
		||||
        i->moving(i, dest);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1673,30 +1643,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
 | 
			
		|||
    if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED)
 | 
			
		||||
        i->sink->n_corked++;
 | 
			
		||||
 | 
			
		||||
    /* Replace resampler and render queue */
 | 
			
		||||
    if (new_resampler != i->thread_info.resampler) {
 | 
			
		||||
        char *memblockq_name;
 | 
			
		||||
 | 
			
		||||
        if (i->thread_info.resampler)
 | 
			
		||||
            pa_resampler_free(i->thread_info.resampler);
 | 
			
		||||
        i->thread_info.resampler = new_resampler;
 | 
			
		||||
 | 
			
		||||
        pa_memblockq_free(i->thread_info.render_memblockq);
 | 
			
		||||
 | 
			
		||||
        memblockq_name = pa_sprintf_malloc("sink input render_memblockq [%u]", i->index);
 | 
			
		||||
        i->thread_info.render_memblockq = pa_memblockq_new(
 | 
			
		||||
                memblockq_name,
 | 
			
		||||
                0,
 | 
			
		||||
                MEMBLOCKQ_MAXLENGTH,
 | 
			
		||||
                0,
 | 
			
		||||
                &i->sink->sample_spec,
 | 
			
		||||
                0,
 | 
			
		||||
                1,
 | 
			
		||||
                0,
 | 
			
		||||
                &i->sink->silence);
 | 
			
		||||
        pa_xfree(memblockq_name);
 | 
			
		||||
        i->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
 | 
			
		||||
    }
 | 
			
		||||
    pa_sink_input_update_rate(i);
 | 
			
		||||
 | 
			
		||||
    pa_sink_update_status(dest);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2043,3 +1990,69 @@ finish:
 | 
			
		|||
    if (pl)
 | 
			
		||||
        pa_proplist_free(pl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called from main context */
 | 
			
		||||
/* Updates the sink input's resampler with whatever the current sink requires
 | 
			
		||||
 * -- useful when the underlying sink's rate might have changed */
 | 
			
		||||
int pa_sink_input_update_rate(pa_sink_input *i) {
 | 
			
		||||
    pa_resampler *new_resampler;
 | 
			
		||||
    char *memblockq_name;
 | 
			
		||||
 | 
			
		||||
    pa_sink_input_assert_ref(i);
 | 
			
		||||
    pa_assert_ctl_context();
 | 
			
		||||
 | 
			
		||||
    if (i->thread_info.resampler &&
 | 
			
		||||
        pa_sample_spec_equal(pa_resampler_output_sample_spec(i->thread_info.resampler), &i->sink->sample_spec) &&
 | 
			
		||||
        pa_channel_map_equal(pa_resampler_output_channel_map(i->thread_info.resampler), &i->sink->channel_map))
 | 
			
		||||
 | 
			
		||||
        new_resampler = i->thread_info.resampler;
 | 
			
		||||
 | 
			
		||||
    else if (!pa_sink_input_is_passthrough(i) &&
 | 
			
		||||
        ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
 | 
			
		||||
         !pa_sample_spec_equal(&i->sample_spec, &i->sink->sample_spec) ||
 | 
			
		||||
         !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map))) {
 | 
			
		||||
 | 
			
		||||
        new_resampler = pa_resampler_new(i->core->mempool,
 | 
			
		||||
                                     &i->sample_spec, &i->channel_map,
 | 
			
		||||
                                     &i->sink->sample_spec, &i->sink->channel_map,
 | 
			
		||||
                                     i->requested_resample_method,
 | 
			
		||||
                                     ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
 | 
			
		||||
                                     ((i->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
 | 
			
		||||
                                     (i->core->disable_remixing || (i->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0));
 | 
			
		||||
 | 
			
		||||
        if (!new_resampler) {
 | 
			
		||||
            pa_log_warn("Unsupported resampling operation.");
 | 
			
		||||
            return -PA_ERR_NOTSUPPORTED;
 | 
			
		||||
        }
 | 
			
		||||
    } else
 | 
			
		||||
        new_resampler = NULL;
 | 
			
		||||
 | 
			
		||||
    if (new_resampler == i->thread_info.resampler)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    if (i->thread_info.resampler)
 | 
			
		||||
        pa_resampler_free(i->thread_info.resampler);
 | 
			
		||||
 | 
			
		||||
    i->thread_info.resampler = new_resampler;
 | 
			
		||||
 | 
			
		||||
    pa_memblockq_free(i->thread_info.render_memblockq);
 | 
			
		||||
 | 
			
		||||
    memblockq_name = pa_sprintf_malloc("sink input render_memblockq [%u]", i->index);
 | 
			
		||||
    i->thread_info.render_memblockq = pa_memblockq_new(
 | 
			
		||||
            memblockq_name,
 | 
			
		||||
            0,
 | 
			
		||||
            MEMBLOCKQ_MAXLENGTH,
 | 
			
		||||
            0,
 | 
			
		||||
            &i->sink->sample_spec,
 | 
			
		||||
            0,
 | 
			
		||||
            1,
 | 
			
		||||
            0,
 | 
			
		||||
            &i->sink->silence);
 | 
			
		||||
    pa_xfree(memblockq_name);
 | 
			
		||||
 | 
			
		||||
    i->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
 | 
			
		||||
 | 
			
		||||
    pa_log_debug("Updated resmpler for sink input %d", i->index);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -338,6 +338,7 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes, pa_bool_t rew
 | 
			
		|||
void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b);
 | 
			
		||||
 | 
			
		||||
int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate);
 | 
			
		||||
int pa_sink_input_update_rate(pa_sink_input *i);
 | 
			
		||||
 | 
			
		||||
/* This returns the sink's fields converted into out sample type */
 | 
			
		||||
size_t pa_sink_input_get_max_rewind(pa_sink_input *i);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1376,8 +1376,6 @@ static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) {
 | 
			
		|||
 | 
			
		||||
/* Called from main context */
 | 
			
		||||
int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t save) {
 | 
			
		||||
    pa_resampler *new_resampler;
 | 
			
		||||
 | 
			
		||||
    pa_source_output_assert_ref(o);
 | 
			
		||||
    pa_assert_ctl_context();
 | 
			
		||||
    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
 | 
			
		||||
| 
						 | 
				
			
			@ -1413,34 +1411,6 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
 | 
			
		|||
                        dest->sample_spec.rate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (o->thread_info.resampler &&
 | 
			
		||||
        pa_sample_spec_equal(pa_resampler_input_sample_spec(o->thread_info.resampler), &dest->sample_spec) &&
 | 
			
		||||
        pa_channel_map_equal(pa_resampler_input_channel_map(o->thread_info.resampler), &dest->channel_map))
 | 
			
		||||
 | 
			
		||||
        /* Try to reuse the old resampler if possible */
 | 
			
		||||
        new_resampler = o->thread_info.resampler;
 | 
			
		||||
 | 
			
		||||
    else if (!pa_source_output_is_passthrough(o) &&
 | 
			
		||||
             ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
 | 
			
		||||
              !pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) ||
 | 
			
		||||
              !pa_channel_map_equal(&o->channel_map, &dest->channel_map))) {
 | 
			
		||||
 | 
			
		||||
        /* Okay, we need a new resampler for the new source */
 | 
			
		||||
 | 
			
		||||
        if (!(new_resampler = pa_resampler_new(
 | 
			
		||||
                      o->core->mempool,
 | 
			
		||||
                      &dest->sample_spec, &dest->channel_map,
 | 
			
		||||
                      &o->sample_spec, &o->channel_map,
 | 
			
		||||
                      o->requested_resample_method,
 | 
			
		||||
                      ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
 | 
			
		||||
                      ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
 | 
			
		||||
                      (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
 | 
			
		||||
            pa_log_warn("Unsupported resampling operation.");
 | 
			
		||||
            return -PA_ERR_NOTSUPPORTED;
 | 
			
		||||
        }
 | 
			
		||||
    } else
 | 
			
		||||
        new_resampler = NULL;
 | 
			
		||||
 | 
			
		||||
    if (o->moving)
 | 
			
		||||
        o->moving(o, dest);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1453,27 +1423,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
 | 
			
		|||
    if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED)
 | 
			
		||||
        o->source->n_corked++;
 | 
			
		||||
 | 
			
		||||
    /* Replace resampler */
 | 
			
		||||
    if (new_resampler != o->thread_info.resampler) {
 | 
			
		||||
 | 
			
		||||
        if (o->thread_info.resampler)
 | 
			
		||||
            pa_resampler_free(o->thread_info.resampler);
 | 
			
		||||
        o->thread_info.resampler = new_resampler;
 | 
			
		||||
 | 
			
		||||
        pa_memblockq_free(o->thread_info.delay_memblockq);
 | 
			
		||||
 | 
			
		||||
        o->thread_info.delay_memblockq = pa_memblockq_new(
 | 
			
		||||
                "source output delay_memblockq",
 | 
			
		||||
                0,
 | 
			
		||||
                MEMBLOCKQ_MAXLENGTH,
 | 
			
		||||
                0,
 | 
			
		||||
                &o->source->sample_spec,
 | 
			
		||||
                0,
 | 
			
		||||
                1,
 | 
			
		||||
                0,
 | 
			
		||||
                &o->source->silence);
 | 
			
		||||
        o->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
 | 
			
		||||
    }
 | 
			
		||||
    pa_source_output_update_rate(o);
 | 
			
		||||
 | 
			
		||||
    pa_source_update_status(dest);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1646,3 +1596,69 @@ finish:
 | 
			
		|||
    if (pl)
 | 
			
		||||
        pa_proplist_free(pl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called from main context */
 | 
			
		||||
/* Updates the source output's resampler with whatever the current source
 | 
			
		||||
 * requires -- useful when the underlying source's rate might have changed */
 | 
			
		||||
int pa_source_output_update_rate(pa_source_output *o) {
 | 
			
		||||
    pa_resampler *new_resampler;
 | 
			
		||||
    char *memblockq_name;
 | 
			
		||||
 | 
			
		||||
    pa_source_output_assert_ref(o);
 | 
			
		||||
    pa_assert_ctl_context();
 | 
			
		||||
 | 
			
		||||
    if (o->thread_info.resampler &&
 | 
			
		||||
        pa_sample_spec_equal(pa_resampler_input_sample_spec(o->thread_info.resampler), &o->source->sample_spec) &&
 | 
			
		||||
        pa_channel_map_equal(pa_resampler_input_channel_map(o->thread_info.resampler), &o->source->channel_map))
 | 
			
		||||
 | 
			
		||||
        new_resampler = o->thread_info.resampler;
 | 
			
		||||
 | 
			
		||||
    else if (!pa_source_output_is_passthrough(o) &&
 | 
			
		||||
        ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
 | 
			
		||||
         !pa_sample_spec_equal(&o->sample_spec, &o->source->sample_spec) ||
 | 
			
		||||
         !pa_channel_map_equal(&o->channel_map, &o->source->channel_map))) {
 | 
			
		||||
 | 
			
		||||
        new_resampler = pa_resampler_new(o->core->mempool,
 | 
			
		||||
                                     &o->source->sample_spec, &o->source->channel_map,
 | 
			
		||||
                                     &o->sample_spec, &o->channel_map,
 | 
			
		||||
                                     o->requested_resample_method,
 | 
			
		||||
                                     ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
 | 
			
		||||
                                     ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
 | 
			
		||||
                                     (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0));
 | 
			
		||||
 | 
			
		||||
        if (!new_resampler) {
 | 
			
		||||
            pa_log_warn("Unsupported resampling operation.");
 | 
			
		||||
            return -PA_ERR_NOTSUPPORTED;
 | 
			
		||||
        }
 | 
			
		||||
    } else
 | 
			
		||||
        new_resampler = NULL;
 | 
			
		||||
 | 
			
		||||
    if (new_resampler == o->thread_info.resampler)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    if (o->thread_info.resampler)
 | 
			
		||||
        pa_resampler_free(o->thread_info.resampler);
 | 
			
		||||
 | 
			
		||||
    o->thread_info.resampler = new_resampler;
 | 
			
		||||
 | 
			
		||||
    pa_memblockq_free(o->thread_info.delay_memblockq);
 | 
			
		||||
 | 
			
		||||
    memblockq_name = pa_sprintf_malloc("source output delay_memblockq [%u]", o->index);
 | 
			
		||||
    o->thread_info.delay_memblockq = pa_memblockq_new(
 | 
			
		||||
            memblockq_name,
 | 
			
		||||
            0,
 | 
			
		||||
            MEMBLOCKQ_MAXLENGTH,
 | 
			
		||||
            0,
 | 
			
		||||
            &o->source->sample_spec,
 | 
			
		||||
            0,
 | 
			
		||||
            1,
 | 
			
		||||
            0,
 | 
			
		||||
            &o->source->silence);
 | 
			
		||||
    pa_xfree(memblockq_name);
 | 
			
		||||
 | 
			
		||||
    o->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
 | 
			
		||||
 | 
			
		||||
    pa_log_debug("Updated resmpler for source output %d", o->index);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -301,6 +301,7 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t
 | 
			
		|||
void pa_source_output_cork(pa_source_output *o, pa_bool_t b);
 | 
			
		||||
 | 
			
		||||
int pa_source_output_set_rate(pa_source_output *o, uint32_t rate);
 | 
			
		||||
int pa_source_output_update_rate(pa_source_output *o);
 | 
			
		||||
 | 
			
		||||
size_t pa_source_output_get_max_rewind(pa_source_output *o);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue