diff options
Diffstat (limited to 'src/pulsecore/source-output.c')
-rw-r--r-- | src/pulsecore/source-output.c | 100 |
1 files changed, 78 insertions, 22 deletions
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 4ba25ae4..57ccc067 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -41,14 +41,14 @@ #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); pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) { pa_assert(data); - memset(data, 0, sizeof(*data)); + pa_zero(*data); data->resample_method = PA_RESAMPLER_INVALID; data->proplist = pa_proplist_new(); @@ -84,6 +84,7 @@ static void reset_callbacks(pa_source_output *o) { 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; @@ -100,17 +101,18 @@ static void reset_callbacks(pa_source_output *o) { 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_assert(data); + pa_assert_ctl_context(); if (data->client) pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist); @@ -144,13 +146,13 @@ int pa_source_output_new( 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; } @@ -166,7 +168,7 @@ int pa_source_output_new( 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; @@ -177,7 +179,7 @@ int pa_source_output_new( 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)) { @@ -186,9 +188,9 @@ int pa_source_output_new( &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; @@ -201,7 +203,7 @@ int pa_source_output_new( 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; @@ -246,12 +248,15 @@ int pa_source_output_new( 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! */ @@ -262,6 +267,7 @@ int pa_source_output_new( /* Called from main context */ static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) { pa_assert(o); + pa_assert_ctl_context(); if (!o->source) return; @@ -275,6 +281,7 @@ static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) /* Called from main context */ static void source_output_set_state(pa_source_output *o, pa_source_output_state_t state) { pa_assert(o); + pa_assert_ctl_context(); if (o->state == state) return; @@ -294,6 +301,7 @@ static void source_output_set_state(pa_source_output *o, pa_source_output_state_ void pa_source_output_unlink(pa_source_output*o) { pa_bool_t linked; pa_assert(o); + pa_assert_ctl_context(); /* See pa_sink_unlink() for a couple of comments how this function * works */ @@ -346,6 +354,7 @@ static void source_output_free(pa_object* mo) { pa_source_output *o = PA_SOURCE_OUTPUT(mo); pa_assert(o); + pa_assert_ctl_context(); pa_assert(pa_source_output_refcnt(o) == 0); if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) @@ -353,8 +362,6 @@ static void source_output_free(pa_object* mo) { 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); @@ -371,7 +378,9 @@ static void source_output_free(pa_object* mo) { /* Called from main context */ void pa_source_output_put(pa_source_output *o) { pa_source_output_state_t state; + pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(o->state == PA_SOURCE_OUTPUT_INIT); @@ -395,6 +404,7 @@ void pa_source_output_put(pa_source_output *o) { /* Called from main context */ void pa_source_output_kill(pa_source_output*o) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); o->kill(o); @@ -405,6 +415,7 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o, pa_usec_t *source_la pa_usec_t r[2] = { 0, 0 }; pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0); @@ -424,6 +435,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { size_t limit, mbs = 0; pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state)); pa_assert(chunk); pa_assert(pa_frame_aligned(chunk->length, &o->source->sample_spec)); @@ -499,8 +511,9 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { /* Called from thread context */ void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in source sample spec */) { - pa_source_output_assert_ref(o); + pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state)); pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec)); @@ -526,8 +539,17 @@ void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in so } /* 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); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state)); pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec)); @@ -538,15 +560,16 @@ void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* i /* Called from thread context */ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec) { 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; } @@ -554,6 +577,7 @@ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output /* Called from main context */ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) { pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); @@ -565,7 +589,7 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t 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; @@ -582,6 +606,7 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t /* Called from main context */ pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) { pa_usec_t usec = 0; @@ -598,6 +623,7 @@ pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) { /* Called from main context */ void pa_source_output_cork(pa_source_output *o, pa_bool_t b) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING); @@ -606,6 +632,7 @@ void pa_source_output_cork(pa_source_output *o, pa_bool_t b) { /* Called from main context */ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_return_val_if_fail(o->thread_info.resampler, -PA_ERR_BADSTATE); @@ -623,6 +650,7 @@ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) { /* Called from main context */ void pa_source_output_set_name(pa_source_output *o, const char *name) { const char *old; + pa_assert_ctl_context(); pa_source_output_assert_ref(o); if (!name && !pa_proplist_contains(o->proplist, PA_PROP_MEDIA_NAME)) @@ -647,11 +675,12 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) { /* Called from main thread */ void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); if (p) pa_proplist_update(o->proplist, mode, p); - if (PA_SINK_IS_LINKED(o->state)) { + if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) { pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o); pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); } @@ -660,6 +689,7 @@ void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode /* Called from main context */ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); return o->actual_resample_method; } @@ -667,6 +697,7 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { /* Called from main context */ pa_bool_t pa_source_output_may_move(pa_source_output *o) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE) @@ -708,6 +739,7 @@ int pa_source_output_start_move(pa_source_output *o) { int r; pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_assert(o->source); @@ -739,6 +771,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t pa_resampler *new_resampler; pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_assert(!o->source); pa_source_assert_ref(dest); @@ -816,10 +849,29 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t } /* 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; pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_assert(o->source); pa_source_assert_ref(dest); @@ -838,6 +890,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav } if ((r = pa_source_output_finish_move(o, dest, save)) < 0) { + pa_source_output_fail_move(o); pa_source_output_unref(o); return r; } @@ -850,6 +903,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav /* Called from IO thread context */ void pa_source_output_set_state_within_thread(pa_source_output *o, pa_source_output_state_t state) { pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); if (state == o->thread_info.state) return; @@ -906,11 +960,13 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int return -PA_ERR_NOTIMPLEMENTED; } +/* Called from main context */ void pa_source_output_send_event(pa_source_output *o, const char *event, pa_proplist *data) { pa_proplist *pl = NULL; pa_source_output_send_event_hook_data hook_data; pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(event); if (!o->send_event) |