#define MEMBLOCKQ_MAXLENGTH (32*1024*1024)
-static PA_DEFINE_CHECK_TYPE(pa_source_output, pa_msgobject);
+PA_DEFINE_PUBLIC_CLASS(pa_source_output, pa_msgobject);
static void source_output_free(pa_object* mo);
o->update_max_rewind = NULL;
o->update_source_requested_latency = NULL;
o->update_source_latency_range = NULL;
+ o->update_source_fixed_latency = NULL;
o->attach = NULL;
o->detach = NULL;
o->suspend = NULL;
int pa_source_output_new(
pa_source_output**_o,
pa_core *core,
- pa_source_output_new_data *data,
- pa_source_output_flags_t flags) {
+ pa_source_output_new_data *data) {
pa_source_output *o;
pa_resampler *resampler = NULL;
char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
int r;
+ char *pt;
pa_assert(_o);
pa_assert(core);
pa_return_val_if_fail(pa_channel_map_valid(&data->channel_map), -PA_ERR_INVALID);
pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID);
- if (flags & PA_SOURCE_OUTPUT_FIX_FORMAT)
+ if (data->flags & PA_SOURCE_OUTPUT_FIX_FORMAT)
data->sample_spec.format = data->source->sample_spec.format;
- if (flags & PA_SOURCE_OUTPUT_FIX_RATE)
+ if (data->flags & PA_SOURCE_OUTPUT_FIX_RATE)
data->sample_spec.rate = data->source->sample_spec.rate;
- if (flags & PA_SOURCE_OUTPUT_FIX_CHANNELS) {
+ if (data->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS) {
data->sample_spec.channels = data->source->sample_spec.channels;
data->channel_map = data->source->channel_map;
}
if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data)) < 0)
return r;
- if ((flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND) &&
+ if ((data->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND) &&
pa_source_get_state(data->source) == PA_SOURCE_SUSPENDED) {
pa_log("Failed to create source output: source is suspended.");
return -PA_ERR_BADSTATE;
return -PA_ERR_TOOLARGE;
}
- if ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
+ if ((data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
!pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) ||
!pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) {
&data->source->sample_spec, &data->source->channel_map,
&data->sample_spec, &data->channel_map,
data->resample_method,
- ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
- ((flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
- (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
+ ((data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
+ ((data->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
+ (core->disable_remixing || (data->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
(core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) {
pa_log_warn("Unsupported resampling operation.");
return -PA_ERR_NOTSUPPORTED;
o->core = core;
o->state = PA_SOURCE_OUTPUT_INIT;
- o->flags = flags;
+ o->flags = data->flags;
o->proplist = pa_proplist_copy(data->proplist);
o->driver = pa_xstrdup(pa_path_get_filename(data->driver));
o->module = data->module;
o->source = data->source;
+ o->destination_source = data->destination_source;
o->client = data->client;
o->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID;
if (o->direct_on_input)
pa_assert_se(pa_idxset_put(o->direct_on_input->direct_outputs, o, NULL) == 0);
- pa_log_info("Created output %u \"%s\" on %s with sample spec %s and channel map %s",
+ pt = pa_proplist_to_string_sep(o->proplist, "\n ");
+ pa_log_info("Created output %u \"%s\" on %s with sample spec %s and channel map %s\n %s",
o->index,
pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME)),
o->source->name,
pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec),
- pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map));
+ pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map),
+ pt);
+ pa_xfree(pt);
/* Don't forget to call pa_source_output_put! */
update_n_corked(o, state);
o->state = state;
- if (state != PA_SOURCE_OUTPUT_UNLINKED)
+ if (state != PA_SOURCE_OUTPUT_UNLINKED) {
pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], o);
+ if (PA_SOURCE_OUTPUT_IS_LINKED(state))
+ pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
+ }
+
pa_source_update_status(o->source);
}
pa_log_info("Freeing output %u \"%s\"", o->index, pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME)));
- pa_assert(!o->thread_info.attached);
-
if (o->thread_info.delay_memblockq)
pa_memblockq_free(o->thread_info.delay_memblockq);
pa_memblockq_rewind(o->thread_info.delay_memblockq, nbytes);
}
+/* Called from thread context */
+size_t pa_source_output_get_max_rewind(pa_source_output *o) {
+ pa_source_output_assert_ref(o);
+ pa_source_output_assert_io_context(o);
+
+ return o->thread_info.resampler ? pa_resampler_request(o->thread_info.resampler, o->source->thread_info.max_rewind) : o->source->thread_info.max_rewind;
+}
+
/* Called from thread context */
void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* in the source's sample spec */) {
pa_source_output_assert_ref(o);
pa_source_output_assert_io_context(o);
if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY))
- usec = o->source->fixed_latency;
+ usec = o->source->thread_info.fixed_latency;
if (usec != (pa_usec_t) -1)
usec = PA_CLAMP(usec, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
o->thread_info.requested_source_latency = usec;
- pa_source_invalidate_requested_latency(o->source);
+ pa_source_invalidate_requested_latency(o->source, TRUE);
return usec;
}
if (o->source) {
if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY))
- usec = o->source->fixed_latency;
+ usec = pa_source_get_fixed_latency(o->source);
if (usec != (pa_usec_t) -1) {
pa_usec_t min_latency, max_latency;
return 0;
}
+/* Called from main context */
+void pa_source_output_fail_move(pa_source_output *o) {
+
+ pa_source_output_assert_ref(o);
+ pa_assert_ctl_context();
+ pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
+ pa_assert(!o->source);
+
+ /* Check if someone wants this source output? */
+ if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_STOP)
+ return;
+
+ if (o->moving)
+ o->moving(o, NULL);
+
+ pa_source_output_kill(o);
+}
+
/* Called from main context */
int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t save) {
int r;
}
if ((r = pa_source_output_finish_move(o, dest, save)) < 0) {
+ pa_source_output_fail_move(o);
pa_source_output_unref(o);
return r;
}