10 #define MAX_MIX_CHANNELS 32
12 struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec) {
18 s = malloc(sizeof(struct sink));
21 s->name = name ? strdup(name) : NULL;
23 s->sample_spec = *spec;
24 s->inputs = idxset_new(NULL, NULL);
27 n = malloc(strlen(name)+9);
28 sprintf(n, "%s_monitor", name);
31 s->monitor_source = source_new(core, n, spec);
37 s->get_latency = NULL;
40 r = idxset_put(core->sinks, s, &s->index);
41 assert(s->index != IDXSET_INVALID && r >= 0);
43 fprintf(stderr, "sink: created %u \"%s\".\n", s->index, s->name);
48 void sink_free(struct sink *s) {
49 struct sink_input *i, *j = NULL;
52 while ((i = idxset_first(s->inputs, NULL))) {
57 idxset_free(s->inputs, NULL, NULL);
59 source_free(s->monitor_source);
60 idxset_remove_by_data(s->core->sinks, s, NULL);
62 fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name);
68 void sink_notify(struct sink*s) {
75 static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned maxinfo) {
76 uint32_t index = IDXSET_INVALID;
82 for (i = idxset_first(s->inputs, &index); maxinfo > 0 && i; i = idxset_next(s->inputs, &index)) {
84 if (i->peek(i, &info->chunk) < 0)
87 info->volume = i->volume;
89 assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length);
100 static void inputs_drop(struct sink *s, struct mix_info *info, unsigned maxinfo, size_t length) {
103 for (; maxinfo > 0; maxinfo--, info++) {
104 struct sink_input *i = info->userdata;
105 assert(i && info->chunk.memblock);
107 memblock_unref(info->chunk.memblock);
113 int sink_render(struct sink*s, size_t length, struct memchunk *result) {
114 struct mix_info info[MAX_MIX_CHANNELS];
117 assert(s && length && result);
119 n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
125 struct sink_info *i = info[0].userdata;
127 *result = info[0].chunk;
128 memblock_ref(result->memblock);
130 if (result->length > length)
131 result->length = length;
135 result->memblock = memblock_new(length);
136 assert(result->memblock);
138 result->length = l = mix_chunks(info, n, result->memblock->data, length, &s->sample_spec, s->volume);
144 inputs_drop(s, info, n, l);
146 assert(s->monitor_source);
147 source_post(s->monitor_source, result);
152 int sink_render_into(struct sink*s, struct memchunk *target) {
153 struct mix_info info[MAX_MIX_CHANNELS];
156 assert(s && target && target->length && target->memblock && target->memblock->data);
158 n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
164 struct sink_info *i = info[0].userdata;
168 if (l > info[0].chunk.length)
169 l = info[0].chunk.length;
171 memcpy(target->memblock->data+target->index, info[0].chunk.memblock->data + info[0].chunk.index, l);
174 target->length = l = mix_chunks(info, n, target->memblock->data+target->index, target->length, &s->sample_spec, s->volume);
177 inputs_drop(s, info, n, l);
179 assert(s->monitor_source);
180 source_post(s->monitor_source, target);
185 void sink_render_into_full(struct sink *s, struct memchunk *target) {
186 struct memchunk chunk;
188 assert(s && target && target->memblock && target->length && target->memblock->data);
197 if (sink_render_into(s, &chunk) < 0)
208 silence_memchunk(&chunk, &s->sample_spec);
212 uint32_t sink_get_latency(struct sink *s) {
218 return s->get_latency(s);
221 struct sink* sink_get_default(struct core *c) {
225 if ((sink = idxset_get_by_index(c->sinks, c->default_sink_index)))
228 if (!(sink = idxset_first(c->sinks, &c->default_sink_index)))
231 fprintf(stderr, "core: default sink vanished, setting to %u.\n", sink->index);
235 char *sink_list_to_string(struct core *c) {
237 struct sink *sink, *default_sink;
238 uint32_t index = IDXSET_INVALID;
244 strbuf_printf(s, "%u sink(s) available.\n", idxset_ncontents(c->sinks));
246 default_sink = sink_get_default(c);
248 for (sink = idxset_first(c->sinks, &index); sink; sink = idxset_next(c->sinks, &index)) {
249 assert(sink->monitor_source);
250 strbuf_printf(s, " %c index: %u, name: <%s>, volume: <0x%02x>, latency: <%u usec>, monitor_source: <%u>\n", sink == default_sink ? '*' : ' ', sink->index, sink->name, (unsigned) sink->volume, sink_get_latency(sink), sink->monitor_source->index);
253 return strbuf_tostring_free(s);