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
);