]> code.delx.au - pulseaudio/blob - src/sink.c
951191dd48bf660949878adbf06f7402d44e4644
[pulseaudio] / src / sink.c
1 #include <stdlib.h>
2 #include <assert.h>
3 #include <string.h>
4 #include <stdio.h>
5
6 #include "sink.h"
7 #include "sinkinput.h"
8
9 #define MAX_MIX_CHANNELS 32
10
11 struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec) {
12 struct sink *s;
13 char *n = NULL;
14 int r;
15 assert(core && spec);
16
17 s = malloc(sizeof(struct sink));
18 assert(s);
19
20 s->name = name ? strdup(name) : NULL;
21 s->core = core;
22 s->sample_spec = *spec;
23 s->inputs = idxset_new(NULL, NULL);
24
25 if (name) {
26 n = malloc(strlen(name)+9);
27 sprintf(n, "%s_monitor", name);
28 }
29
30 s->monitor_source = source_new(core, n, spec);
31 free(n);
32
33 s->volume = 0xFF;
34
35 s->notify = NULL;
36 s->userdata = NULL;
37
38 r = idxset_put(core->sinks, s, &s->index);
39 assert(s->index != IDXSET_INVALID && r >= 0);
40
41 fprintf(stderr, "sink: created %u \"%s\".\n", s->index, s->name);
42
43 return s;
44 }
45
46 void sink_free(struct sink *s) {
47 struct sink_input *i, *j = NULL;
48 assert(s);
49
50 while ((i = idxset_first(s->inputs, NULL))) {
51 assert(i != j);
52 sink_input_kill(i);
53 j = i;
54 }
55 idxset_free(s->inputs, NULL, NULL);
56
57 source_free(s->monitor_source);
58 idxset_remove_by_data(s->core->sinks, s, NULL);
59
60 fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name);
61
62 free(s->name);
63 free(s);
64 }
65
66 void sink_notify(struct sink*s) {
67 assert(s);
68
69 if (s->notify)
70 s->notify(s);
71 }
72
73 static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned maxinfo) {
74 uint32_t index = IDXSET_INVALID;
75 struct sink_input *i;
76 unsigned n = 0;
77
78 assert(s && info);
79
80 for (i = idxset_first(s->inputs, &index); maxinfo > 0 && i; i = idxset_next(s->inputs, &index)) {
81 assert(i->peek);
82 if (i->peek(i, &info->chunk, &info->volume) < 0)
83 continue;
84
85 assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length);
86 info->userdata = i;
87
88 info++;
89 maxinfo--;
90 n++;
91 }
92
93 return n;
94 }
95
96 static void inputs_drop(struct sink *s, struct mix_info *info, unsigned maxinfo, size_t length) {
97 assert(s && info);
98
99 for (; maxinfo > 0; maxinfo--, info++) {
100 struct sink_input *i = info->userdata;
101 assert(i && info->chunk.memblock);
102
103 memblock_unref(info->chunk.memblock);
104 assert(i->drop);
105 i->drop(i, length);
106 }
107 }
108
109 int sink_render(struct sink*s, size_t length, struct memchunk *result) {
110 struct mix_info info[MAX_MIX_CHANNELS];
111 unsigned n;
112 size_t l;
113 assert(s && length && result);
114
115 n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
116
117 if (n <= 0)
118 return -1;
119
120 if (n == 1) {
121 struct sink_info *i = info[0].userdata;
122 assert(i);
123 *result = info[0].chunk;
124 memblock_ref(result->memblock);
125
126 if (result->length > length)
127 result->length = length;
128
129 l = result->length;
130 } else {
131 result->memblock = memblock_new(length);
132 assert(result->memblock);
133
134 result->length = l = mix_chunks(info, n, result->memblock->data, length, &s->sample_spec, s->volume);
135 result->index = 0;
136
137 assert(l);
138 }
139
140 inputs_drop(s, info, n, l);
141 return 0;
142 }
143
144 int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result) {
145 struct mix_info info[MAX_MIX_CHANNELS];
146 unsigned n;
147 size_t l;
148 assert(s && target && target->length && target->data && result);
149
150 n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
151
152 if (n <= 0)
153 return -1;
154
155 if (n == 1) {
156 struct sink_info *i = info[0].userdata;
157 assert(i);
158
159 l = target->length;
160 if (l > info[0].chunk.length)
161 l = info[0].chunk.length;
162
163 result->memblock = target;
164 memcpy(target->data, info[0].chunk.memblock->data + info[0].chunk.index, l);
165 result->length = target->length = l;
166 result->index = 0;
167 } else {
168
169 result->memblock = target;
170 result->length = l = mix_chunks(info, n, target->data, target->length, &s->sample_spec, s->volume);
171 result->index = 0;
172 assert(l);
173 }
174
175 inputs_drop(s, info, n, l);
176 return 0;
177 }