9 #include "sample-util.h"
12 #define MAX_MIX_CHANNELS 32
14 struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) {
21 s = malloc(sizeof(struct pa_sink));
24 if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) {
29 s->name = strdup(name);
31 s->sample_spec = *spec;
32 s->inputs = pa_idxset_new(NULL, NULL);
35 n = malloc(strlen(name)+9);
36 sprintf(n, "%s_monitor", name);
39 s->monitor_source = pa_source_new(core, n, 0, spec);
40 assert(s->monitor_source);
42 s->monitor_source->monitor_of = s;
44 s->volume = PA_VOLUME_NORM;
47 s->get_latency = NULL;
50 r = pa_idxset_put(core->sinks, s, &s->index);
51 assert(s->index != PA_IDXSET_INVALID && r >= 0);
53 pa_sample_snprint(st, sizeof(st), spec);
54 fprintf(stderr, "sink: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st);
59 void pa_sink_free(struct pa_sink *s) {
60 struct pa_sink_input *i, *j = NULL;
63 pa_namereg_unregister(s->core, s->name);
65 while ((i = pa_idxset_first(s->inputs, NULL))) {
67 pa_sink_input_kill(i);
70 pa_idxset_free(s->inputs, NULL, NULL);
72 pa_source_free(s->monitor_source);
73 pa_idxset_remove_by_data(s->core->sinks, s, NULL);
75 fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name);
81 void pa_sink_notify(struct pa_sink*s) {
88 static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo) {
89 uint32_t index = PA_IDXSET_INVALID;
90 struct pa_sink_input *i;
95 for (i = pa_idxset_first(s->inputs, &index); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &index)) {
96 if (pa_sink_input_peek(i, &info->chunk) < 0)
99 info->volume = i->volume;
101 assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length);
112 static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo, size_t length) {
115 for (; maxinfo > 0; maxinfo--, info++) {
116 struct pa_sink_input *i = info->userdata;
117 assert(i && info->chunk.memblock);
119 pa_memblock_unref(info->chunk.memblock);
120 pa_sink_input_drop(i, length);
124 int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) {
125 struct pa_mix_info info[MAX_MIX_CHANNELS];
128 assert(s && length && result);
130 n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
136 uint32_t volume = PA_VOLUME_NORM;
137 struct pa_sink_input *i = info[0].userdata;
139 *result = info[0].chunk;
140 pa_memblock_ref(result->memblock);
142 if (result->length > length)
143 result->length = length;
147 if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM)
148 volume = pa_volume_multiply(s->volume, info[0].volume);
150 if (volume != PA_VOLUME_NORM) {
151 pa_memchunk_make_writable(result);
152 pa_volume_memchunk(result, &s->sample_spec, volume);
155 result->memblock = pa_memblock_new(length);
156 assert(result->memblock);
158 result->length = l = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, s->volume);
164 inputs_drop(s, info, n, l);
166 assert(s->monitor_source);
167 pa_source_post(s->monitor_source, result);
172 int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) {
173 struct pa_mix_info info[MAX_MIX_CHANNELS];
176 assert(s && target && target->length && target->memblock && target->memblock->data);
178 n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
184 uint32_t volume = PA_VOLUME_NORM;
185 struct pa_sink_info *i = info[0].userdata;
189 if (l > info[0].chunk.length)
190 l = info[0].chunk.length;
192 memcpy(target->memblock->data+target->index, info[0].chunk.memblock->data + info[0].chunk.index, l);
195 if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM)
196 volume = pa_volume_multiply(s->volume, info[0].volume);
198 if (volume != PA_VOLUME_NORM)
199 pa_volume_memchunk(target, &s->sample_spec, volume);
201 target->length = l = pa_mix(info, n, target->memblock->data+target->index, target->length, &s->sample_spec, s->volume);
204 inputs_drop(s, info, n, l);
206 assert(s->monitor_source);
207 pa_source_post(s->monitor_source, target);
212 void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) {
213 struct pa_memchunk chunk;
215 assert(s && target && target->memblock && target->length && target->memblock->data);
224 if (pa_sink_render_into(s, &chunk) < 0)
235 pa_silence_memchunk(&chunk, &s->sample_spec);
239 uint32_t pa_sink_get_latency(struct pa_sink *s) {
245 return s->get_latency(s);
248 struct pa_sink* pa_sink_get_default(struct pa_core *c) {
249 struct pa_sink *sink;
252 if ((sink = pa_idxset_get_by_index(c->sinks, c->default_sink_index)))
255 if (!(sink = pa_idxset_first(c->sinks, &c->default_sink_index)))
258 fprintf(stderr, "core: default sink vanished, setting to %u.\n", sink->index);
262 char *pa_sink_list_to_string(struct pa_core *c) {
264 struct pa_sink *sink, *default_sink;
265 uint32_t index = PA_IDXSET_INVALID;
271 pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks));
273 default_sink = pa_sink_get_default(c);
275 for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) {
276 char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH];
277 pa_sample_snprint(ss, sizeof(ss), &sink->sample_spec);
278 assert(sink->monitor_source);
281 " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x>\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n",
282 sink == default_sink ? '*' : ' ',
283 sink->index, sink->name,
284 (unsigned) sink->volume,
285 pa_sink_get_latency(sink),
286 sink->monitor_source->index,
290 return pa_strbuf_tostring_free(s);