mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-10-29 05:40:23 -04:00 
			
		
		
		
	add refernce counting for sinks, sources, sink-inputs and source-outputs
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@200 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
		
							parent
							
								
									8c6593dabf
								
							
						
					
					
						commit
						6e019795bf
					
				
					 27 changed files with 426 additions and 132 deletions
				
			
		|  | @ -294,7 +294,7 @@ static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, stru | |||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     pa_module_unload_request(c, m); | ||||
|     pa_module_unload_request(m); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -62,6 +62,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) { | |||
|     c->default_sample_spec.channels = 2; | ||||
| 
 | ||||
|     c->auto_unload_event = NULL; | ||||
|     c->defer_unload_event = NULL; | ||||
| 
 | ||||
|     c->subscription_defer_event = NULL; | ||||
|     c->subscription_event_queue = NULL; | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ struct pa_core { | |||
| 
 | ||||
|     struct pa_sample_spec default_sample_spec; | ||||
|     struct pa_time_event *auto_unload_event; | ||||
|     struct pa_defer_event *defer_unload_event; | ||||
| 
 | ||||
|     struct pa_defer_event *subscription_defer_event; | ||||
|     struct pa_queue *subscription_event_queue; | ||||
|  |  | |||
|  | @ -259,8 +259,10 @@ void pa__done(struct pa_core *c, struct pa_module*m) { | |||
|     if (!(u = m->userdata)) | ||||
|         return; | ||||
|      | ||||
|     if (u->sink) | ||||
|         pa_sink_free(u->sink); | ||||
|     if (u->sink) { | ||||
|         pa_sink_disconnect(u->sink); | ||||
|         pa_sink_unref(u->sink); | ||||
|     } | ||||
|      | ||||
|     if (u->io_events) | ||||
|         pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); | ||||
|  |  | |||
|  | @ -232,8 +232,10 @@ void pa__done(struct pa_core *c, struct pa_module*m) { | |||
|     if (!(u = m->userdata)) | ||||
|         return; | ||||
|      | ||||
|     if (u->source) | ||||
|         pa_source_free(u->source); | ||||
|     if (u->source) { | ||||
|         pa_source_disconnect(u->source); | ||||
|         pa_source_unref(u->source); | ||||
|     } | ||||
|      | ||||
|     if (u->io_events) | ||||
|         pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ static void eof_cb(struct pa_cli*c, void *userdata) { | |||
|     struct pa_module *m = userdata; | ||||
|     assert(c && m); | ||||
| 
 | ||||
|     pa_module_unload_request(m->core, m); | ||||
|     pa_module_unload_request(m); | ||||
| } | ||||
| 
 | ||||
| int pa__init(struct pa_core *c, struct pa_module*m) { | ||||
|  |  | |||
|  | @ -38,7 +38,7 @@ | |||
| #include "namereg.h" | ||||
| 
 | ||||
| PA_MODULE_AUTHOR("Lennart Poettering") | ||||
| PA_MODULE_DESCRIPTION("Makes one playback device out of many") | ||||
| PA_MODULE_DESCRIPTION("Combine multiple sinks to one") | ||||
| PA_MODULE_VERSION(PACKAGE_VERSION) | ||||
| PA_MODULE_USAGE("sink_name=<name for the sink> master=<master sink> slave=<slave sinks>") | ||||
| 
 | ||||
|  | @ -85,7 +85,7 @@ static void adjust_rates(struct userdata *u) { | |||
|     assert(u && u->sink); | ||||
| 
 | ||||
|     for (o = u->outputs; o; o = o->next) { | ||||
|         o->sink_latency = pa_sink_get_latency(o->sink_input->sink); | ||||
|         o->sink_latency = o->sink_input->sink ? pa_sink_get_latency(o->sink_input->sink) : 0; | ||||
| 
 | ||||
|         if (o->sink_latency > max) | ||||
|             max = o->sink_latency; | ||||
|  | @ -165,6 +165,7 @@ static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk | |||
| static void sink_input_kill_cb(struct pa_sink_input *i) { | ||||
|     struct output *o = i->userdata; | ||||
|     assert(i && o && o->sink_input); | ||||
|     pa_module_unload_request(o->userdata->module); | ||||
|     clear_up(o->userdata); | ||||
| } | ||||
| 
 | ||||
|  | @ -211,8 +212,10 @@ static struct output *output_new(struct userdata *u, struct pa_sink *sink) { | |||
| fail: | ||||
| 
 | ||||
|     if (o) { | ||||
|         if (o->sink_input) | ||||
|             pa_sink_input_free(o->sink_input); | ||||
|         if (o->sink_input) { | ||||
|             pa_sink_input_disconnect(o->sink_input); | ||||
|             pa_sink_input_unref(o->sink_input); | ||||
|         } | ||||
| 
 | ||||
|         if (o->memblockq) | ||||
|             pa_memblockq_free(o->memblockq); | ||||
|  | @ -228,7 +231,8 @@ static void output_free(struct output *o) { | |||
|     PA_LLIST_REMOVE(struct output, o->userdata->outputs, o); | ||||
|     o->userdata->n_outputs--; | ||||
|     pa_memblockq_free(o->memblockq); | ||||
|     pa_sink_input_free(o->sink_input); | ||||
|     pa_sink_input_disconnect(o->sink_input); | ||||
|     pa_sink_input_unref(o->sink_input); | ||||
|     pa_xfree(o); | ||||
| } | ||||
| 
 | ||||
|  | @ -247,7 +251,8 @@ static void clear_up(struct userdata *u) { | |||
|     u->master = NULL; | ||||
|      | ||||
|     if (u->sink) { | ||||
|         pa_sink_free(u->sink); | ||||
|         pa_sink_disconnect(u->sink); | ||||
|         pa_sink_unref(u->sink); | ||||
|         u->sink = NULL; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -403,11 +403,15 @@ void pa__done(struct pa_core *c, struct pa_module*m) { | |||
|     if (u->out_mmap && u->out_mmap != MAP_FAILED) | ||||
|         munmap(u->out_mmap, u->out_mmap_length); | ||||
|      | ||||
|     if (u->sink) | ||||
|         pa_sink_free(u->sink); | ||||
|     if (u->sink) { | ||||
|         pa_sink_disconnect(u->sink); | ||||
|         pa_sink_unref(u->sink); | ||||
|     } | ||||
| 
 | ||||
|     if (u->source) | ||||
|         pa_source_free(u->source); | ||||
|     if (u->source) { | ||||
|         pa_source_disconnect(u->source); | ||||
|         pa_source_unref(u->source); | ||||
|     } | ||||
| 
 | ||||
|     if (u->io_event) | ||||
|         u->core->mainloop->io_free(u->io_event); | ||||
|  |  | |||
|  | @ -322,10 +322,15 @@ void pa__done(struct pa_core *c, struct pa_module*m) { | |||
|     if (u->silence.memblock) | ||||
|         pa_memblock_unref(u->silence.memblock); | ||||
| 
 | ||||
|     if (u->sink) | ||||
|         pa_sink_free(u->sink); | ||||
|     if (u->source) | ||||
|         pa_source_free(u->source); | ||||
|     if (u->sink) { | ||||
|         pa_sink_disconnect(u->sink); | ||||
|         pa_sink_unref(u->sink); | ||||
|     } | ||||
|      | ||||
|     if (u->source) { | ||||
|         pa_source_disconnect(u->source); | ||||
|         pa_source_unref(u->source); | ||||
|     } | ||||
|      | ||||
|     pa_iochannel_free(u->io); | ||||
|     pa_xfree(u); | ||||
|  |  | |||
|  | @ -215,7 +215,8 @@ void pa__done(struct pa_core *c, struct pa_module*m) { | |||
|     if (u->memchunk.memblock) | ||||
|         pa_memblock_unref(u->memchunk.memblock); | ||||
|          | ||||
|     pa_sink_free(u->sink); | ||||
|     pa_sink_disconnect(u->sink); | ||||
|     pa_sink_unref(u->sink); | ||||
|     pa_iochannel_free(u->io); | ||||
|     u->core->mainloop->defer_free(u->defer_event); | ||||
| 
 | ||||
|  |  | |||
|  | @ -195,7 +195,8 @@ void pa__done(struct pa_core *c, struct pa_module*m) { | |||
|     if (u->chunk.memblock) | ||||
|         pa_memblock_unref(u->chunk.memblock); | ||||
|          | ||||
|     pa_source_free(u->source); | ||||
|     pa_source_disconnect(u->source); | ||||
|     pa_source_unref(u->source); | ||||
|     pa_iochannel_free(u->io); | ||||
| 
 | ||||
|     assert(u->filename); | ||||
|  |  | |||
|  | @ -41,6 +41,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) | |||
| 
 | ||||
| struct userdata { | ||||
|     struct pa_core *core; | ||||
|     struct pa_module *module; | ||||
|     struct pa_sink_input *sink_input; | ||||
|     struct pa_memblock *memblock; | ||||
|     size_t peek_index; | ||||
|  | @ -81,8 +82,11 @@ static void sink_input_kill(struct pa_sink_input *i) { | |||
|     assert(i && i->userdata); | ||||
|     u = i->userdata; | ||||
| 
 | ||||
|     pa_sink_input_free(u->sink_input); | ||||
|     pa_sink_input_disconnect(u->sink_input); | ||||
|     pa_sink_input_unref(u->sink_input); | ||||
|     u->sink_input = NULL; | ||||
| 
 | ||||
|     pa_module_unload_request(u->module); | ||||
| } | ||||
| 
 | ||||
| static void calc_sine(float *f, size_t l, float freq) { | ||||
|  | @ -110,6 +114,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { | |||
|      | ||||
|     m->userdata = u = pa_xmalloc(sizeof(struct userdata)); | ||||
|     u->core = c; | ||||
|     u->module = m; | ||||
|     u->sink_input = NULL; | ||||
|     u->memblock = NULL; | ||||
| 
 | ||||
|  | @ -163,8 +168,11 @@ void pa__done(struct pa_core *c, struct pa_module*m) { | |||
|     if (!u) | ||||
|         return; | ||||
| 
 | ||||
|     if (u->sink_input) | ||||
|         pa_sink_input_free(u->sink_input); | ||||
|     if (u->sink_input) { | ||||
|         pa_sink_input_disconnect(u->sink_input); | ||||
|         pa_sink_input_unref(u->sink_input); | ||||
|     } | ||||
|      | ||||
|     if (u->memblock) | ||||
|         pa_memblock_unref(u->memblock); | ||||
|     pa_xfree(u); | ||||
|  |  | |||
|  | @ -85,6 +85,7 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char | |||
|     m->core = c; | ||||
|     m->n_used = -1; | ||||
|     m->auto_unload = 0; | ||||
|     m->unload_requested = 0; | ||||
| 
 | ||||
|     assert(m->init); | ||||
|     if (m->init(c, m) < 0) { | ||||
|  | @ -183,11 +184,17 @@ void pa_module_unload_all(struct pa_core *c) { | |||
|     pa_idxset_free(c->modules, free_callback, NULL); | ||||
|     c->modules = NULL; | ||||
| 
 | ||||
|     if (c->auto_unload_event) | ||||
|     if (c->auto_unload_event) { | ||||
|         c->mainloop->time_free(c->auto_unload_event); | ||||
|         c->auto_unload_event = NULL; | ||||
|     } | ||||
| 
 | ||||
|     if (c->defer_unload_event) { | ||||
|         c->mainloop->defer_free(c->defer_unload_event); | ||||
|         c->defer_unload_event = NULL; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static int unused_callback(void *p, uint32_t index, int *del, void *userdata) { | ||||
|     struct pa_module *m = p; | ||||
|     time_t *now = userdata; | ||||
|  | @ -212,26 +219,38 @@ void pa_module_unload_unused(struct pa_core *c) { | |||
|     pa_idxset_foreach(c->modules, unused_callback, &now); | ||||
| } | ||||
| 
 | ||||
| struct once_info { | ||||
|     struct pa_core *core; | ||||
|     uint32_t index; | ||||
| }; | ||||
| static int unload_callback(void *p, uint32_t index, int *del, void *userdata) { | ||||
|     struct pa_module *m = p; | ||||
|     assert(m); | ||||
| 
 | ||||
| static void module_unload_once_callback(struct pa_mainloop_api *m, void *userdata) { | ||||
|     struct once_info *i = userdata; | ||||
|     assert(i); | ||||
|     pa_module_unload_by_index(i->core, i->index); | ||||
|     pa_xfree(i); | ||||
|     if (m->unload_requested) { | ||||
|         pa_module_free(m); | ||||
|         *del = 1; | ||||
|     } | ||||
| 
 | ||||
| void pa_module_unload_request(struct pa_core *c, struct pa_module *m) { | ||||
|     struct once_info *i; | ||||
|     assert(c && m); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
|     i = pa_xmalloc(sizeof(struct once_info)); | ||||
|     i->core = c; | ||||
|     i->index = m->index; | ||||
|     pa_mainloop_api_once(c->mainloop, module_unload_once_callback, i); | ||||
| static void defer_cb(struct pa_mainloop_api*api, struct pa_defer_event *e, void *userdata) { | ||||
|     struct pa_core *core = userdata; | ||||
|     api->defer_enable(e, 0); | ||||
| 
 | ||||
|     if (!core->modules) | ||||
|         return; | ||||
| 
 | ||||
|     pa_idxset_foreach(core->modules, unload_callback, NULL); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void pa_module_unload_request(struct pa_module *m) { | ||||
|     assert(m); | ||||
| 
 | ||||
|     m->unload_requested = 1; | ||||
| 
 | ||||
|     if (!m->core->defer_unload_event) | ||||
|         m->core->defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core); | ||||
| 
 | ||||
|     m->core->mainloop->defer_enable(m->core->defer_unload_event, 1); | ||||
| } | ||||
| 
 | ||||
| void pa_module_set_used(struct pa_module*m, int used) { | ||||
|  |  | |||
|  | @ -43,16 +43,18 @@ struct pa_module { | |||
|     int n_used; | ||||
|     int auto_unload; | ||||
|     time_t last_used_time; | ||||
| 
 | ||||
|     int unload_requested; | ||||
| }; | ||||
| 
 | ||||
| struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char*argument); | ||||
| void pa_module_unload(struct pa_core *c, struct pa_module *m); | ||||
| void pa_module_unload_by_index(struct pa_core *c, uint32_t index); | ||||
| /* void pa_module_unload(struct pa_core *c, struct pa_module *m); */ | ||||
| /* void pa_module_unload_by_index(struct pa_core *c, uint32_t index); */ | ||||
| 
 | ||||
| void pa_module_unload_all(struct pa_core *c); | ||||
| void pa_module_unload_unused(struct pa_core *c); | ||||
| 
 | ||||
| void pa_module_unload_request(struct pa_core *c, struct pa_module *m); | ||||
| void pa_module_unload_request(struct pa_module *m); | ||||
| 
 | ||||
| void pa_module_set_used(struct pa_module*m, int used); | ||||
| 
 | ||||
|  |  | |||
|  | @ -37,9 +37,12 @@ static void sink_input_kill(struct pa_sink_input *i) { | |||
|     assert(i && i->userdata); | ||||
|     c = i->userdata; | ||||
| 
 | ||||
|     pa_sink_input_disconnect(i); | ||||
|     pa_sink_input_unref(i); | ||||
| 
 | ||||
|     pa_memblock_unref(c->memblock); | ||||
|     pa_xfree(c); | ||||
|     pa_sink_input_free(i); | ||||
|      | ||||
| } | ||||
| 
 | ||||
| static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { | ||||
|  |  | |||
|  | @ -167,10 +167,16 @@ static void connection_free(struct connection *c) { | |||
|      | ||||
|     pa_client_free(c->client); | ||||
| 
 | ||||
|     if (c->sink_input) | ||||
|         pa_sink_input_free(c->sink_input); | ||||
|     if (c->source_output) | ||||
|         pa_source_output_free(c->source_output); | ||||
|     if (c->sink_input) { | ||||
|         pa_sink_input_disconnect(c->sink_input); | ||||
|         pa_sink_input_unref(c->sink_input); | ||||
|     } | ||||
|      | ||||
|     if (c->source_output) { | ||||
|         pa_source_output_disconnect(c->source_output); | ||||
|         pa_source_output_unref(c->source_output); | ||||
|     } | ||||
|      | ||||
|     if (c->input_memblockq) | ||||
|         pa_memblockq_free(c->input_memblockq); | ||||
|     if (c->output_memblockq) | ||||
|  |  | |||
|  | @ -255,7 +255,8 @@ static void record_stream_free(struct record_stream* r) { | |||
|     assert(r && r->connection); | ||||
| 
 | ||||
|     pa_idxset_remove_by_data(r->connection->record_streams, r, NULL); | ||||
|     pa_source_output_free(r->source_output); | ||||
|     pa_source_output_disconnect(r->source_output); | ||||
|     pa_source_output_unref(r->source_output); | ||||
|     pa_memblockq_free(r->memblockq); | ||||
|     pa_xfree(r); | ||||
| } | ||||
|  | @ -302,7 +303,8 @@ static void playback_stream_free(struct playback_stream* p) { | |||
|         pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERROR_NOENTITY); | ||||
| 
 | ||||
|     pa_idxset_remove_by_data(p->connection->output_streams, p, NULL); | ||||
|     pa_sink_input_free(p->sink_input); | ||||
|     pa_sink_input_disconnect(p->sink_input); | ||||
|     pa_sink_input_unref(p->sink_input); | ||||
|     pa_memblockq_free(p->memblockq); | ||||
|     pa_xfree(p); | ||||
| } | ||||
|  |  | |||
|  | @ -80,10 +80,14 @@ static void connection_free(struct connection *c) { | |||
| 
 | ||||
|     if (c->playback.current_memblock) | ||||
|         pa_memblock_unref(c->playback.current_memblock); | ||||
|     if (c->sink_input) | ||||
|         pa_sink_input_free(c->sink_input); | ||||
|     if (c->source_output) | ||||
|         pa_source_output_free(c->source_output); | ||||
|     if (c->sink_input) { | ||||
|         pa_sink_input_disconnect(c->sink_input); | ||||
|         pa_sink_input_unref(c->sink_input); | ||||
|     } | ||||
|     if (c->source_output) { | ||||
|         pa_source_output_disconnect(c->source_output); | ||||
|         pa_source_output_unref(c->source_output); | ||||
|     } | ||||
|     if (c->client) | ||||
|         pa_client_free(c->client); | ||||
|     if (c->io) | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con | |||
|     struct pa_resampler *resampler = NULL; | ||||
|     int r; | ||||
|     char st[256]; | ||||
|     assert(s && spec); | ||||
|     assert(s && spec && s->state == PA_SINK_RUNNING); | ||||
| 
 | ||||
|     if (pa_idxset_ncontents(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { | ||||
|         pa_log(__FILE__": Failed to create sink input: too many inputs per sink.\n"); | ||||
|  | @ -53,6 +53,8 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con | |||
|             return NULL; | ||||
|      | ||||
|     i = pa_xmalloc(sizeof(struct pa_sink_input)); | ||||
|     i->ref = 1; | ||||
|     i->state = PA_SINK_INPUT_RUNNING; | ||||
|     i->name = pa_xstrdup(name); | ||||
|     i->client = NULL; | ||||
|     i->owner = NULL; | ||||
|  | @ -86,26 +88,53 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con | |||
|     return i;     | ||||
| } | ||||
| 
 | ||||
| void pa_sink_input_free(struct pa_sink_input* i) { | ||||
|     assert(i); | ||||
| void pa_sink_input_disconnect(struct pa_sink_input *i) { | ||||
|     assert(i && i->state == PA_SINK_INPUT_RUNNING && i->sink && i->sink->core); | ||||
| 
 | ||||
|     assert(i->sink && i->sink->core); | ||||
|     pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); | ||||
|     pa_idxset_remove_by_data(i->sink->inputs, i, NULL); | ||||
| 
 | ||||
|     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); | ||||
|     i->sink = NULL; | ||||
| 
 | ||||
|     i->peek = NULL; | ||||
|     i->drop = NULL; | ||||
|     i->kill = NULL; | ||||
|     i->get_latency = NULL; | ||||
| 
 | ||||
|     i->state = PA_SINK_INPUT_DISCONNECTED; | ||||
| } | ||||
| 
 | ||||
| static void sink_input_free(struct pa_sink_input* i) { | ||||
|     assert(i); | ||||
| 
 | ||||
|     if (i->state != PA_SINK_INPUT_DISCONNECTED) | ||||
|         pa_sink_input_disconnect(i); | ||||
| 
 | ||||
|     if (i->resampled_chunk.memblock) | ||||
|         pa_memblock_unref(i->resampled_chunk.memblock); | ||||
|     if (i->resampler) | ||||
|         pa_resampler_free(i->resampler); | ||||
| 
 | ||||
|     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index); | ||||
|      | ||||
|     pa_xfree(i->name); | ||||
|     pa_xfree(i); | ||||
| } | ||||
| 
 | ||||
| void pa_sink_input_unref(struct pa_sink_input *i) { | ||||
|     assert(i && i->ref >= 1); | ||||
| 
 | ||||
|     if (!(--i->ref)) | ||||
|         sink_input_free(i); | ||||
| } | ||||
| 
 | ||||
| struct pa_sink_input* pa_sink_input_ref(struct pa_sink_input *i) { | ||||
|     assert(i && i->ref >= 1); | ||||
|     i->ref++; | ||||
|     return i; | ||||
| } | ||||
| 
 | ||||
| void pa_sink_input_kill(struct pa_sink_input*i) { | ||||
|     assert(i); | ||||
|     assert(i && i->ref >= 1); | ||||
| 
 | ||||
|     if (i->kill) | ||||
|         i->kill(i); | ||||
|  | @ -113,7 +142,7 @@ void pa_sink_input_kill(struct pa_sink_input*i) { | |||
| 
 | ||||
| pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i) { | ||||
|     pa_usec_t r = 0; | ||||
|     assert(i); | ||||
|     assert(i && i->ref >= 1); | ||||
|      | ||||
|     if (i->get_latency) | ||||
|         r += i->get_latency(i); | ||||
|  | @ -125,7 +154,11 @@ pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i) { | |||
| } | ||||
| 
 | ||||
| int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { | ||||
|     assert(i && chunk && i->peek && i->drop); | ||||
|     int ret = 0; | ||||
|     assert(i && chunk && i->ref >= 1); | ||||
| 
 | ||||
|     if (!i->peek || !i->drop) | ||||
|         return -1; | ||||
| 
 | ||||
|     if (i->corked) | ||||
|         return -1; | ||||
|  | @ -133,13 +166,14 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { | |||
|     if (!i->resampler) | ||||
|         return i->peek(i, chunk); | ||||
| 
 | ||||
|     pa_sink_input_ref(i); | ||||
| 
 | ||||
|     while (!i->resampled_chunk.memblock) { | ||||
|         struct pa_memchunk tchunk; | ||||
|         size_t l; | ||||
|         int ret; | ||||
|          | ||||
|         if ((ret = i->peek(i, &tchunk)) < 0) | ||||
|             return ret; | ||||
|             goto finish; | ||||
| 
 | ||||
|         assert(tchunk.length); | ||||
|          | ||||
|  | @ -158,13 +192,21 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { | |||
|     assert(i->resampled_chunk.memblock && i->resampled_chunk.length); | ||||
|     *chunk = i->resampled_chunk; | ||||
|     pa_memblock_ref(i->resampled_chunk.memblock); | ||||
|     return 0; | ||||
| 
 | ||||
|     ret = 0; | ||||
| 
 | ||||
| finish: | ||||
| 
 | ||||
|     pa_sink_input_unref(i); | ||||
|      | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { | ||||
|     assert(i && length); | ||||
|     assert(i && length && i->ref >= 1); | ||||
| 
 | ||||
|     if (!i->resampler) { | ||||
|         if (i->drop) | ||||
|             i->drop(i, chunk, length); | ||||
|         return; | ||||
|     } | ||||
|  | @ -182,7 +224,7 @@ void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk | |||
| } | ||||
| 
 | ||||
| void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) { | ||||
|     assert(i && i->sink && i->sink->core); | ||||
|     assert(i && i->sink && i->sink->core && i->ref >= 1); | ||||
| 
 | ||||
|     if (i->volume != volume) { | ||||
|         i->volume = volume; | ||||
|  | @ -192,7 +234,8 @@ void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) { | |||
| 
 | ||||
| void pa_sink_input_cork(struct pa_sink_input *i, int b) { | ||||
|     int n; | ||||
|     assert(i); | ||||
|     assert(i && i->ref >= 1); | ||||
|      | ||||
|     n = i->corked && !b; | ||||
|     i->corked = b; | ||||
| 
 | ||||
|  | @ -201,7 +244,7 @@ void pa_sink_input_cork(struct pa_sink_input *i, int b) { | |||
| } | ||||
| 
 | ||||
| void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate) { | ||||
|     assert(i && i->resampler); | ||||
|     assert(i && i->resampler && i->ref >= 1); | ||||
| 
 | ||||
|     if (i->sample_spec.rate == rate) | ||||
|         return; | ||||
|  | @ -209,3 +252,10 @@ void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate) { | |||
|     i->sample_spec.rate = rate; | ||||
|     pa_resampler_set_input_rate(i->resampler, rate); | ||||
| } | ||||
| 
 | ||||
| void pa_sink_input_set_name(struct pa_sink_input *i, const char *name) { | ||||
|     assert(i && i->ref >= 1); | ||||
| 
 | ||||
|     pa_xfree(i->name); | ||||
|     i->name = pa_xstrdup(name); | ||||
| } | ||||
|  |  | |||
|  | @ -31,7 +31,15 @@ | |||
| #include "module.h" | ||||
| #include "client.h" | ||||
| 
 | ||||
| enum pa_sink_input_state { | ||||
|     PA_SINK_INPUT_RUNNING, | ||||
|     PA_SINK_INPUT_DISCONNECTED | ||||
| }; | ||||
| 
 | ||||
| struct pa_sink_input { | ||||
|     int ref; | ||||
|     enum pa_sink_input_state state; | ||||
|      | ||||
|     uint32_t index; | ||||
| 
 | ||||
|     int corked; | ||||
|  | @ -55,10 +63,13 @@ struct pa_sink_input { | |||
| }; | ||||
| 
 | ||||
| struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate); | ||||
| void pa_sink_input_free(struct pa_sink_input* i); | ||||
| void pa_sink_input_unref(struct pa_sink_input* i); | ||||
| struct pa_sink_input* pa_sink_input_ref(struct pa_sink_input* i); | ||||
| 
 | ||||
| /* Code that didn't create the input stream should call this function to
 | ||||
|  * request destruction of it */ | ||||
| /* To be called by the implementing module only */ | ||||
| void pa_sink_input_disconnect(struct pa_sink_input* i); | ||||
| 
 | ||||
| /* External code may request disconnection with this funcion */ | ||||
| void pa_sink_input_kill(struct pa_sink_input*i); | ||||
| 
 | ||||
| pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i); | ||||
|  | @ -72,4 +83,6 @@ void pa_sink_input_cork(struct pa_sink_input *i, int b); | |||
| 
 | ||||
| void pa_sink_input_set_rate(struct pa_sink_input *i, uint32_t rate); | ||||
| 
 | ||||
| void pa_sink_input_set_name(struct pa_sink_input *i, const char *name); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										117
									
								
								polyp/sink.c
									
										
									
									
									
								
							
							
						
						
									
										117
									
								
								polyp/sink.c
									
										
									
									
									
								
							|  | @ -56,6 +56,9 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co | |||
|     s->name = pa_xstrdup(name); | ||||
|     s->description = NULL; | ||||
| 
 | ||||
|     s->ref = 1; | ||||
|     s->state = PA_SINK_RUNNING; | ||||
|      | ||||
|     s->owner = NULL; | ||||
|     s->core = core; | ||||
|     s->sample_spec = *spec; | ||||
|  | @ -85,9 +88,9 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co | |||
|     return s; | ||||
| } | ||||
| 
 | ||||
| void pa_sink_free(struct pa_sink *s) { | ||||
| void pa_sink_disconnect(struct pa_sink* s) { | ||||
|     struct pa_sink_input *i, *j = NULL; | ||||
|     assert(s); | ||||
|     assert(s && s->state == PA_SINK_RUNNING); | ||||
| 
 | ||||
|     pa_namereg_unregister(s->core, s->name); | ||||
|      | ||||
|  | @ -96,22 +99,51 @@ void pa_sink_free(struct pa_sink *s) { | |||
|         pa_sink_input_kill(i); | ||||
|         j = i; | ||||
|     } | ||||
|     pa_idxset_free(s->inputs, NULL, NULL); | ||||
| 
 | ||||
|     pa_source_free(s->monitor_source); | ||||
|     pa_source_disconnect(s->monitor_source); | ||||
| 
 | ||||
|     pa_idxset_remove_by_data(s->core->sinks, s, NULL); | ||||
|     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); | ||||
| 
 | ||||
|     s->notify = NULL; | ||||
|     s->get_latency = NULL; | ||||
|      | ||||
|     s->state = PA_SINK_DISCONNECTED; | ||||
| } | ||||
| 
 | ||||
| static void sink_free(struct pa_sink *s) { | ||||
|     assert(s && s->ref == 0); | ||||
|      | ||||
|     if (s->state != PA_SINK_DISCONNECTED) | ||||
|         pa_sink_disconnect(s); | ||||
| 
 | ||||
|     pa_log(__FILE__": freed %u \"%s\"\n", s->index, s->name); | ||||
| 
 | ||||
|     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); | ||||
|     pa_source_unref(s->monitor_source); | ||||
|     s->monitor_source = NULL; | ||||
|      | ||||
|     pa_idxset_free(s->inputs, NULL, NULL); | ||||
| 
 | ||||
|     pa_xfree(s->name); | ||||
|     pa_xfree(s->description); | ||||
|     pa_xfree(s); | ||||
| } | ||||
| 
 | ||||
| void pa_sink_unref(struct pa_sink*s) { | ||||
|     assert(s && s->ref >= 1); | ||||
| 
 | ||||
|     if (!(--s->ref)) | ||||
|         sink_free(s); | ||||
| } | ||||
| 
 | ||||
| struct pa_sink* pa_sink_ref(struct pa_sink *s) { | ||||
|     assert(s && s->ref >= 1); | ||||
|     s->ref++; | ||||
|     return s; | ||||
| } | ||||
| 
 | ||||
| void pa_sink_notify(struct pa_sink*s) { | ||||
|     assert(s); | ||||
|     assert(s && s->ref >= 1); | ||||
| 
 | ||||
|     if (s->notify) | ||||
|         s->notify(s); | ||||
|  | @ -122,16 +154,20 @@ static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsig | |||
|     struct pa_sink_input *i; | ||||
|     unsigned n = 0; | ||||
|      | ||||
|     assert(s && info); | ||||
|     assert(s && s->ref >= 1 && info); | ||||
| 
 | ||||
|     for (i = pa_idxset_first(s->inputs, &index); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &index)) { | ||||
|         if (pa_sink_input_peek(i, &info->chunk) < 0) | ||||
|         pa_sink_input_ref(i); | ||||
| 
 | ||||
|         if (pa_sink_input_peek(i, &info->chunk) < 0) { | ||||
|             pa_sink_input_unref(i); | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         info->volume = i->volume; | ||||
|         info->userdata = i; | ||||
|          | ||||
|         assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length); | ||||
|         info->userdata = i; | ||||
|          | ||||
|         info++; | ||||
|         maxinfo--; | ||||
|  | @ -142,7 +178,7 @@ static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsig | |||
| } | ||||
| 
 | ||||
| static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo, size_t length) { | ||||
|     assert(s && info); | ||||
|     assert(s && s->ref >= 1 && info); | ||||
| 
 | ||||
|     for (; maxinfo > 0; maxinfo--, info++) { | ||||
|         struct pa_sink_input *i = info->userdata; | ||||
|  | @ -150,6 +186,9 @@ static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned ma | |||
|          | ||||
|         pa_sink_input_drop(i, &info->chunk, length); | ||||
|         pa_memblock_unref(info->chunk.memblock); | ||||
| 
 | ||||
|         pa_sink_input_unref(i); | ||||
|         info->userdata = NULL; | ||||
|     } | ||||
| } | ||||
|          | ||||
|  | @ -157,12 +196,15 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) | |||
|     struct pa_mix_info info[MAX_MIX_CHANNELS]; | ||||
|     unsigned n; | ||||
|     size_t l; | ||||
|     assert(s && length && result); | ||||
|     int r = -1; | ||||
|     assert(s && s->ref >= 1 && length && result); | ||||
| 
 | ||||
|     pa_sink_ref(s); | ||||
|      | ||||
|     n = fill_mix_info(s, info, MAX_MIX_CHANNELS); | ||||
| 
 | ||||
|     if (n <= 0) | ||||
|         return -1; | ||||
|         goto finish; | ||||
| 
 | ||||
|     if (n == 1) { | ||||
|         uint32_t volume = PA_VOLUME_NORM; | ||||
|  | @ -198,19 +240,27 @@ int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) | |||
|     assert(s->monitor_source); | ||||
|     pa_source_post(s->monitor_source, result); | ||||
| 
 | ||||
|     return 0; | ||||
|     r = 0; | ||||
| 
 | ||||
| finish: | ||||
|     pa_sink_unref(s); | ||||
| 
 | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { | ||||
|     struct pa_mix_info info[MAX_MIX_CHANNELS]; | ||||
|     unsigned n; | ||||
|     size_t l; | ||||
|     assert(s && target && target->length && target->memblock && target->memblock->data); | ||||
|     int r = -1; | ||||
|     assert(s && s->ref >= 1 && target && target->length && target->memblock && target->memblock->data); | ||||
| 
 | ||||
|     pa_sink_ref(s); | ||||
|      | ||||
|     n = fill_mix_info(s, info, MAX_MIX_CHANNELS); | ||||
| 
 | ||||
|     if (n <= 0) | ||||
|         return -1; | ||||
|         goto finish; | ||||
| 
 | ||||
|     if (n == 1) { | ||||
|         uint32_t volume = PA_VOLUME_NORM; | ||||
|  | @ -238,13 +288,20 @@ int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) { | |||
|     assert(s->monitor_source); | ||||
|     pa_source_post(s->monitor_source, target); | ||||
| 
 | ||||
|     return 0; | ||||
|     r = 0; | ||||
| 
 | ||||
| finish: | ||||
|     pa_sink_unref(s); | ||||
|      | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) { | ||||
|     struct pa_memchunk chunk; | ||||
|     size_t l, d; | ||||
|     assert(s && target && target->memblock && target->length && target->memblock->data); | ||||
|     assert(s && s->ref >= 1 && target && target->memblock && target->length && target->memblock->data); | ||||
| 
 | ||||
|     pa_sink_ref(s); | ||||
|      | ||||
|     l = target->length; | ||||
|     d = 0; | ||||
|  | @ -266,10 +323,12 @@ void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) { | |||
|         chunk.length -= d; | ||||
|         pa_silence_memchunk(&chunk, &s->sample_spec); | ||||
|     } | ||||
| 
 | ||||
|     pa_sink_unref(s); | ||||
| } | ||||
| 
 | ||||
| void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *result) { | ||||
|     assert(s && length && result); | ||||
|     assert(s && s->ref >= 1 && length && result); | ||||
| 
 | ||||
|     /*** This needs optimization ***/ | ||||
|      | ||||
|  | @ -280,7 +339,7 @@ void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *r | |||
| } | ||||
| 
 | ||||
| pa_usec_t pa_sink_get_latency(struct pa_sink *s) { | ||||
|     assert(s); | ||||
|     assert(s && s->ref >= 1); | ||||
| 
 | ||||
|     if (!s->get_latency) | ||||
|         return 0; | ||||
|  | @ -288,18 +347,20 @@ pa_usec_t pa_sink_get_latency(struct pa_sink *s) { | |||
|     return s->get_latency(s); | ||||
| } | ||||
| 
 | ||||
| void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) { | ||||
|     sink->owner = m; | ||||
| void pa_sink_set_owner(struct pa_sink *s, struct pa_module *m) { | ||||
|     assert(s && s->ref >= 1); | ||||
|             | ||||
|     if (sink->monitor_source) | ||||
|         pa_source_set_owner(sink->monitor_source, m); | ||||
|     s->owner = m; | ||||
| 
 | ||||
|     if (s->monitor_source) | ||||
|         pa_source_set_owner(s->monitor_source, m); | ||||
| } | ||||
| 
 | ||||
| void pa_sink_set_volume(struct pa_sink *sink, pa_volume_t volume) { | ||||
|     assert(sink); | ||||
| void pa_sink_set_volume(struct pa_sink *s, pa_volume_t volume) { | ||||
|     assert(s && s->ref >= 1); | ||||
|      | ||||
|     if (sink->volume != volume) { | ||||
|         sink->volume = volume; | ||||
|         pa_subscription_post(sink->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, sink->index); | ||||
|     if (s->volume != volume) { | ||||
|         s->volume = volume; | ||||
|         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); | ||||
|     } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										13
									
								
								polyp/sink.h
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								polyp/sink.h
									
										
									
									
									
								
							|  | @ -33,7 +33,15 @@ struct pa_sink; | |||
| 
 | ||||
| #define PA_MAX_INPUTS_PER_SINK 6 | ||||
| 
 | ||||
| enum pa_sink_state { | ||||
|     PA_SINK_RUNNING, | ||||
|     PA_SINK_DISCONNECTED | ||||
| }; | ||||
| 
 | ||||
| struct pa_sink { | ||||
|     int ref; | ||||
|     enum pa_sink_state state; | ||||
|      | ||||
|     uint32_t index; | ||||
| 
 | ||||
|     char *name, *description; | ||||
|  | @ -52,7 +60,10 @@ struct pa_sink { | |||
| }; | ||||
| 
 | ||||
| struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); | ||||
| void pa_sink_free(struct pa_sink* s); | ||||
| void pa_sink_disconnect(struct pa_sink* s); | ||||
| void pa_sink_unref(struct pa_sink*s); | ||||
| struct pa_sink* pa_sink_ref(struct pa_sink *s); | ||||
| 
 | ||||
| 
 | ||||
| int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result); | ||||
| void pa_sink_render_full(struct pa_sink *s, size_t length, struct pa_memchunk *result); | ||||
|  |  | |||
|  | @ -45,8 +45,11 @@ struct userdata { | |||
| 
 | ||||
| static void free_userdata(struct userdata *u) { | ||||
|     assert(u); | ||||
|     if (u->sink_input) | ||||
|         pa_sink_input_free(u->sink_input); | ||||
|     if (u->sink_input) { | ||||
|         pa_sink_input_disconnect(u->sink_input); | ||||
|         pa_sink_input_unref(u->sink_input); | ||||
|     } | ||||
|      | ||||
|     if (u->memchunk.memblock) | ||||
|         pa_memblock_unref(u->memchunk.memblock); | ||||
|     if (u->sndfile) | ||||
|  |  | |||
|  | @ -49,6 +49,8 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n | |||
|             return NULL; | ||||
|      | ||||
|     o = pa_xmalloc(sizeof(struct pa_source_output)); | ||||
|     o->ref = 1; | ||||
|     o->state = PA_SOURCE_OUTPUT_RUNNING; | ||||
|     o->name = pa_xstrdup(name); | ||||
|     o->client = NULL; | ||||
|     o->owner = NULL; | ||||
|  | @ -71,27 +73,55 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n | |||
|     return o;     | ||||
| } | ||||
| 
 | ||||
| void pa_source_output_free(struct pa_source_output* o) { | ||||
|     assert(o); | ||||
| void pa_source_output_disconnect(struct pa_source_output*o) { | ||||
|     assert(o && o->state == PA_SOURCE_OUTPUT_RUNNING && o->source && o->source->core); | ||||
|      | ||||
|     assert(o->source && o->source->core); | ||||
|     pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); | ||||
|     pa_idxset_remove_by_data(o->source->outputs, o, NULL); | ||||
| 
 | ||||
|     pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); | ||||
|     o->source = NULL; | ||||
| 
 | ||||
|     o->push = NULL; | ||||
|     o->kill = NULL; | ||||
|      | ||||
|      | ||||
|     o->state = PA_SOURCE_OUTPUT_DISCONNECTED; | ||||
| } | ||||
| 
 | ||||
| static void source_output_free(struct pa_source_output* o) { | ||||
|     assert(o); | ||||
| 
 | ||||
|     if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED) | ||||
|         pa_source_output_disconnect(o); | ||||
| 
 | ||||
|     if (o->resampler) | ||||
|         pa_resampler_free(o->resampler); | ||||
| 
 | ||||
|     pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index); | ||||
|      | ||||
|     pa_xfree(o->name); | ||||
|     pa_xfree(o); | ||||
| } | ||||
| 
 | ||||
| void pa_source_output_kill(struct pa_source_output*i) { | ||||
|     assert(i); | ||||
| 
 | ||||
|     if (i->kill) | ||||
|         i->kill(i); | ||||
| void pa_source_output_unref(struct pa_source_output* o) { | ||||
|     assert(o && o->ref >= 1); | ||||
| 
 | ||||
|     if (!(--o->ref)) | ||||
|         source_output_free(o); | ||||
| } | ||||
| 
 | ||||
| struct pa_source_output* pa_source_output_ref(struct pa_source_output *o) { | ||||
|     assert(o && o->ref >= 1); | ||||
|     o->ref++; | ||||
|     return o; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void pa_source_output_kill(struct pa_source_output*o) { | ||||
|     assert(o && o->ref >= 1); | ||||
| 
 | ||||
|     if (o->kill) | ||||
|         o->kill(o); | ||||
| } | ||||
| 
 | ||||
| void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk) { | ||||
|  | @ -111,3 +141,9 @@ void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk | |||
|     o->push(o, &rchunk); | ||||
|     pa_memblock_unref(rchunk.memblock); | ||||
| } | ||||
| 
 | ||||
| void pa_source_output_set_name(struct pa_source_output *o, const char *name) { | ||||
|     assert(o && o->ref >= 1); | ||||
|     pa_xfree(o->name); | ||||
|     o->name = pa_xstrdup(name); | ||||
| } | ||||
|  |  | |||
|  | @ -31,7 +31,15 @@ | |||
| #include "module.h" | ||||
| #include "client.h" | ||||
| 
 | ||||
| enum pa_source_output_state { | ||||
|     PA_SOURCE_OUTPUT_RUNNING, | ||||
|     PA_SOURCE_OUTPUT_DISCONNECTED | ||||
| }; | ||||
| 
 | ||||
| struct pa_source_output { | ||||
|     int ref; | ||||
|     enum pa_source_output_state state; | ||||
|      | ||||
|     uint32_t index; | ||||
| 
 | ||||
|     char *name; | ||||
|  | @ -49,10 +57,17 @@ struct pa_source_output { | |||
| }; | ||||
| 
 | ||||
| struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec); | ||||
| void pa_source_output_free(struct pa_source_output* o); | ||||
| void pa_source_output_unref(struct pa_source_output* o); | ||||
| struct pa_source_output* pa_source_output_ref(struct pa_source_output *o); | ||||
| 
 | ||||
| /* To be called by the implementing module only */ | ||||
| void pa_source_output_disconnect(struct pa_source_output*o); | ||||
| 
 | ||||
| /* External code may request disconnection with this funcion */ | ||||
| void pa_source_output_kill(struct pa_source_output*o); | ||||
| 
 | ||||
| void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk *chunk); | ||||
| 
 | ||||
| void pa_source_output_set_name(struct pa_source_output *i, const char *name); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -48,6 +48,9 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail | |||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     s->ref = 1; | ||||
|     s->state = PA_SOURCE_RUNNING; | ||||
|      | ||||
|     s->name = pa_xstrdup(name); | ||||
|     s->description = NULL; | ||||
| 
 | ||||
|  | @ -71,9 +74,9 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail | |||
|     return s; | ||||
| } | ||||
| 
 | ||||
| void pa_source_free(struct pa_source *s) { | ||||
| void pa_source_disconnect(struct pa_source *s) { | ||||
|     struct pa_source_output *o, *j = NULL; | ||||
|     assert(s); | ||||
|     assert(s && s->state == PA_SOURCE_RUNNING); | ||||
| 
 | ||||
|     pa_namereg_unregister(s->core, s->name); | ||||
|      | ||||
|  | @ -82,21 +85,45 @@ void pa_source_free(struct pa_source *s) { | |||
|         pa_source_output_kill(o); | ||||
|         j = o; | ||||
|     } | ||||
|     pa_idxset_free(s->outputs, NULL, NULL); | ||||
| 
 | ||||
|     pa_idxset_remove_by_data(s->core->sources, s, NULL); | ||||
|     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); | ||||
| 
 | ||||
|     s->notify = NULL; | ||||
|      | ||||
|     s->state = PA_SOURCE_DISCONNECTED; | ||||
| } | ||||
| 
 | ||||
| static void source_free(struct pa_source *s) { | ||||
|     assert(s && !s->ref); | ||||
|      | ||||
|     if (s->state != PA_SOURCE_DISCONNECTED) | ||||
|         pa_source_disconnect(s); | ||||
|      | ||||
|     pa_log(__FILE__": freed %u \"%s\"\n", s->index, s->name); | ||||
| 
 | ||||
|     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); | ||||
|     pa_idxset_free(s->outputs, NULL, NULL); | ||||
| 
 | ||||
|     pa_xfree(s->name); | ||||
|     pa_xfree(s->description); | ||||
|     pa_xfree(s); | ||||
| } | ||||
| 
 | ||||
| void pa_source_unref(struct pa_source *s) { | ||||
|     assert(s && s->ref >= 1); | ||||
| 
 | ||||
|     if (!(--s->ref)) | ||||
|         source_free(s); | ||||
| } | ||||
| 
 | ||||
| struct pa_source* pa_source_ref(struct pa_source *s) { | ||||
|     assert(s && s->ref >= 1); | ||||
|     s->ref++; | ||||
|     return s; | ||||
| } | ||||
| 
 | ||||
| void pa_source_notify(struct pa_source*s) { | ||||
|     assert(s); | ||||
|     assert(s && s->ref >= 1); | ||||
| 
 | ||||
|     if (s->notify) | ||||
|         s->notify(s); | ||||
|  | @ -112,9 +139,11 @@ static int do_post(void *p, uint32_t index, int *del, void*userdata) { | |||
| } | ||||
| 
 | ||||
| void pa_source_post(struct pa_source*s, struct pa_memchunk *chunk) { | ||||
|     assert(s && chunk); | ||||
|     assert(s && s->ref >= 1 && chunk); | ||||
| 
 | ||||
|     pa_source_ref(s); | ||||
|     pa_idxset_foreach(s->outputs, do_post, chunk); | ||||
|     pa_source_unref(s); | ||||
| } | ||||
| 
 | ||||
| void pa_source_set_owner(struct pa_source *s, struct pa_module *m) { | ||||
|  |  | |||
|  | @ -34,7 +34,15 @@ struct pa_source; | |||
| 
 | ||||
| #define PA_MAX_OUTPUTS_PER_SOURCE 16 | ||||
| 
 | ||||
| enum pa_source_state { | ||||
|     PA_SOURCE_RUNNING, | ||||
|     PA_SOURCE_DISCONNECTED, | ||||
| }; | ||||
| 
 | ||||
| struct pa_source { | ||||
|     int ref; | ||||
|     enum pa_source_state state; | ||||
|      | ||||
|     uint32_t index; | ||||
|      | ||||
|     char *name, *description; | ||||
|  | @ -49,7 +57,9 @@ struct pa_source { | |||
| }; | ||||
| 
 | ||||
| struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); | ||||
| void pa_source_free(struct pa_source *s); | ||||
| void pa_source_disconnect(struct pa_source *s); | ||||
| void pa_source_unref(struct pa_source *s); | ||||
| struct pa_source* pa_source_ref(struct pa_source *c); | ||||
| 
 | ||||
| /* Pass a new memory block to all output streams */ | ||||
| void pa_source_post(struct pa_source*s, struct pa_memchunk *b); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lennart Poettering
						Lennart Poettering