]> code.delx.au - pulseaudio/blob - src/pulsecore/source-output.c
rework memory block management to be thread-safe and mostly lock-free.
[pulseaudio] / src / pulsecore / source-output.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <pulse/utf8.h>
32 #include <pulse/xmalloc.h>
33
34 #include <pulsecore/core-subscribe.h>
35 #include <pulsecore/log.h>
36 #include <pulsecore/namereg.h>
37
38 #include "source-output.h"
39
40 #define CHECK_VALIDITY_RETURN_NULL(condition) \
41 do {\
42 if (!(condition)) \
43 return NULL; \
44 } while (0)
45
46 pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) {
47 assert(data);
48
49 memset(data, 0, sizeof(*data));
50 data->resample_method = PA_RESAMPLER_INVALID;
51 return data;
52 }
53
54 void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map) {
55 assert(data);
56
57 if ((data->channel_map_is_set = !!map))
58 data->channel_map = *map;
59 }
60
61 void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, const pa_sample_spec *spec) {
62 assert(data);
63
64 if ((data->sample_spec_is_set = !!spec))
65 data->sample_spec = *spec;
66 }
67
68 pa_source_output* pa_source_output_new(
69 pa_core *core,
70 pa_source_output_new_data *data,
71 pa_source_output_flags_t flags) {
72
73 pa_source_output *o;
74 pa_resampler *resampler = NULL;
75 int r;
76 char st[PA_SAMPLE_SPEC_SNPRINT_MAX];
77
78 assert(core);
79 assert(data);
80
81 if (!(flags & PA_SOURCE_OUTPUT_NO_HOOKS))
82 if (pa_hook_fire(&core->hook_source_output_new, data) < 0)
83 return NULL;
84
85 CHECK_VALIDITY_RETURN_NULL(!data->driver || pa_utf8_valid(data->driver));
86 CHECK_VALIDITY_RETURN_NULL(!data->name || pa_utf8_valid(data->name));
87
88 if (!data->source)
89 data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, 1);
90
91 CHECK_VALIDITY_RETURN_NULL(data->source);
92 CHECK_VALIDITY_RETURN_NULL(data->source->state == PA_SOURCE_RUNNING);
93
94 if (!data->sample_spec_is_set)
95 data->sample_spec = data->source->sample_spec;
96
97 CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec));
98
99 if (!data->channel_map_is_set)
100 pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
101
102 CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map));
103 CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels);
104
105 if (data->resample_method == PA_RESAMPLER_INVALID)
106 data->resample_method = core->resample_method;
107
108 CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX);
109
110 if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
111 pa_log("Failed to create source output: too many outputs per source.");
112 return NULL;
113 }
114
115 if (!pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) ||
116 !pa_channel_map_equal(&data->channel_map, &data->source->channel_map))
117 if (!(resampler = pa_resampler_new(
118 core->mempool,
119 &data->source->sample_spec, &data->source->channel_map,
120 &data->sample_spec, &data->channel_map,
121 data->resample_method))) {
122 pa_log_warn("Unsupported resampling operation.");
123 return NULL;
124 }
125
126 o = pa_xnew(pa_source_output, 1);
127 o->ref = 1;
128 o->state = PA_SOURCE_OUTPUT_RUNNING;
129 o->name = pa_xstrdup(data->name);
130 o->driver = pa_xstrdup(data->driver);
131 o->module = data->module;
132 o->source = data->source;
133 o->client = data->client;
134
135 o->sample_spec = data->sample_spec;
136 o->channel_map = data->channel_map;
137
138 o->push = NULL;
139 o->kill = NULL;
140 o->get_latency = NULL;
141 o->userdata = NULL;
142
143 o->resampler = resampler;
144 o->resample_method = data->resample_method;
145
146 r = pa_idxset_put(core->source_outputs, o, &o->index);
147 assert(r == 0);
148 r = pa_idxset_put(o->source->outputs, o, NULL);
149 assert(r == 0);
150
151 pa_log_info("created %u \"%s\" on %s with sample spec %s",
152 o->index,
153 o->name,
154 o->source->name,
155 pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec));
156
157 pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index);
158
159 /* We do not call pa_source_notify() here, because the virtual
160 * functions have not yet been initialized */
161
162 return o;
163 }
164
165 void pa_source_output_disconnect(pa_source_output*o) {
166 assert(o);
167 assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED);
168 assert(o->source);
169 assert(o->source->core);
170
171 pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL);
172 pa_idxset_remove_by_data(o->source->outputs, o, NULL);
173
174 pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index);
175 o->source = NULL;
176
177 o->push = NULL;
178 o->kill = NULL;
179 o->get_latency = NULL;
180
181 o->state = PA_SOURCE_OUTPUT_DISCONNECTED;
182 }
183
184 static void source_output_free(pa_source_output* o) {
185 assert(o);
186
187 if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED)
188 pa_source_output_disconnect(o);
189
190 pa_log_info("freed %u \"%s\"", o->index, o->name);
191
192 if (o->resampler)
193 pa_resampler_free(o->resampler);
194
195 pa_xfree(o->name);
196 pa_xfree(o->driver);
197 pa_xfree(o);
198 }
199
200 void pa_source_output_unref(pa_source_output* o) {
201 assert(o);
202 assert(o->ref >= 1);
203
204 if (!(--o->ref))
205 source_output_free(o);
206 }
207
208 pa_source_output* pa_source_output_ref(pa_source_output *o) {
209 assert(o);
210 assert(o->ref >= 1);
211
212 o->ref++;
213 return o;
214 }
215
216 void pa_source_output_kill(pa_source_output*o) {
217 assert(o);
218 assert(o->ref >= 1);
219
220 if (o->kill)
221 o->kill(o);
222 }
223
224 void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
225 pa_memchunk rchunk;
226
227 assert(o);
228 assert(chunk);
229 assert(chunk->length);
230 assert(o->push);
231
232 if (o->state == PA_SOURCE_OUTPUT_CORKED)
233 return;
234
235 if (!o->resampler) {
236 o->push(o, chunk);
237 return;
238 }
239
240 pa_resampler_run(o->resampler, chunk, &rchunk);
241 if (!rchunk.length)
242 return;
243
244 assert(rchunk.memblock);
245 o->push(o, &rchunk);
246 pa_memblock_unref(rchunk.memblock);
247 }
248
249 void pa_source_output_set_name(pa_source_output *o, const char *name) {
250 assert(o);
251 assert(o->ref >= 1);
252
253 if (!o->name && !name)
254 return;
255
256 if (o->name && name && !strcmp(o->name, name))
257 return;
258
259 pa_xfree(o->name);
260 o->name = pa_xstrdup(name);
261
262 pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
263 }
264
265 pa_usec_t pa_source_output_get_latency(pa_source_output *o) {
266 assert(o);
267 assert(o->ref >= 1);
268
269 if (o->get_latency)
270 return o->get_latency(o);
271
272 return 0;
273 }
274
275 void pa_source_output_cork(pa_source_output *o, int b) {
276 int n;
277
278 assert(o);
279 assert(o->ref >= 1);
280
281 if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED)
282 return;
283
284 n = o->state == PA_SOURCE_OUTPUT_CORKED && !b;
285
286 o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING;
287
288 if (n)
289 pa_source_notify(o->source);
290 }
291
292 pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
293 assert(o);
294 assert(o->ref >= 1);
295
296 if (!o->resampler)
297 return o->resample_method;
298
299 return pa_resampler_get_method(o->resampler);
300 }
301
302 int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
303 pa_source *origin;
304 pa_resampler *new_resampler = NULL;
305
306 assert(o);
307 assert(o->ref >= 1);
308 assert(dest);
309
310 origin = o->source;
311
312 if (dest == origin)
313 return 0;
314
315 if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
316 pa_log_warn("Failed to move source output: too many outputs per source.");
317 return -1;
318 }
319
320 if (o->resampler &&
321 pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) &&
322 pa_channel_map_equal(&origin->channel_map, &dest->channel_map))
323
324 /* Try to reuse the old resampler if possible */
325 new_resampler = o->resampler;
326
327 else if (!pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) ||
328 !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) {
329
330 /* Okey, we need a new resampler for the new sink */
331
332 if (!(new_resampler = pa_resampler_new(
333 dest->core->mempool,
334 &dest->sample_spec, &dest->channel_map,
335 &o->sample_spec, &o->channel_map,
336 o->resample_method))) {
337 pa_log_warn("Unsupported resampling operation.");
338 return -1;
339 }
340 }
341
342 /* Okey, let's move it */
343 pa_idxset_remove_by_data(origin->outputs, o, NULL);
344 pa_idxset_put(dest->outputs, o, NULL);
345 o->source = dest;
346
347 /* Replace resampler */
348 if (new_resampler != o->resampler) {
349 if (o->resampler)
350 pa_resampler_free(o->resampler);
351 o->resampler = new_resampler;
352 }
353
354 /* Notify everyone */
355 pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
356 pa_source_notify(o->source);
357
358 return 0;
359 }