4 This file is part of polypaudio.
6 polypaudio 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.
11 polypaudio 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.
16 You should have received a copy of the GNU Lesser General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
32 #include "sink-input.h"
35 #include "sample-util.h"
37 #include "subscribe.h"
40 #define MAX_MIX_CHANNELS 32
42 struct pa_sink
* pa_sink_new(struct pa_core
*core
, const char *name
, int fail
, const struct pa_sample_spec
*spec
) {
47 assert(core
&& name
&& *name
&& spec
);
49 s
= pa_xmalloc(sizeof(struct pa_sink
));
51 if (!(name
= pa_namereg_register(core
, name
, PA_NAMEREG_SINK
, s
, fail
))) {
56 s
->name
= pa_xstrdup(name
);
57 s
->description
= NULL
;
60 s
->state
= PA_SINK_RUNNING
;
64 s
->sample_spec
= *spec
;
65 s
->inputs
= pa_idxset_new(NULL
, NULL
);
67 n
= pa_sprintf_malloc("%s_monitor", name
);
68 s
->monitor_source
= pa_source_new(core
, n
, 0, spec
);
69 assert(s
->monitor_source
);
71 s
->monitor_source
->monitor_of
= s
;
72 s
->monitor_source
->description
= pa_sprintf_malloc("Monitor source of sink '%s'", s
->name
);
74 s
->volume
= PA_VOLUME_NORM
;
77 s
->get_latency
= NULL
;
80 r
= pa_idxset_put(core
->sinks
, s
, &s
->index
);
81 assert(s
->index
!= PA_IDXSET_INVALID
&& r
>= 0);
83 pa_sample_spec_snprint(st
, sizeof(st
), spec
);
84 pa_log_info(__FILE__
": created %u \"%s\" with sample spec \"%s\"\n", s
->index
, s
->name
, st
);
86 pa_subscription_post(core
, PA_SUBSCRIPTION_EVENT_SINK
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
91 void pa_sink_disconnect(struct pa_sink
* s
) {
92 struct pa_sink_input
*i
, *j
= NULL
;
93 assert(s
&& s
->state
== PA_SINK_RUNNING
);
95 pa_namereg_unregister(s
->core
, s
->name
);
97 while ((i
= pa_idxset_first(s
->inputs
, NULL
))) {
99 pa_sink_input_kill(i
);
103 pa_source_disconnect(s
->monitor_source
);
105 pa_idxset_remove_by_data(s
->core
->sinks
, s
, NULL
);
106 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
109 s
->get_latency
= NULL
;
111 s
->state
= PA_SINK_DISCONNECTED
;
114 static void sink_free(struct pa_sink
*s
) {
115 assert(s
&& s
->ref
== 0);
117 if (s
->state
!= PA_SINK_DISCONNECTED
)
118 pa_sink_disconnect(s
);
120 pa_log_info(__FILE__
": freed %u \"%s\"\n", s
->index
, s
->name
);
122 pa_source_unref(s
->monitor_source
);
123 s
->monitor_source
= NULL
;
125 pa_idxset_free(s
->inputs
, NULL
, NULL
);
128 pa_xfree(s
->description
);
132 void pa_sink_unref(struct pa_sink
*s
) {
133 assert(s
&& s
->ref
>= 1);
139 struct pa_sink
* pa_sink_ref(struct pa_sink
*s
) {
140 assert(s
&& s
->ref
>= 1);
145 void pa_sink_notify(struct pa_sink
*s
) {
146 assert(s
&& s
->ref
>= 1);
152 static unsigned fill_mix_info(struct pa_sink
*s
, struct pa_mix_info
*info
, unsigned maxinfo
) {
153 uint32_t index
= PA_IDXSET_INVALID
;
154 struct pa_sink_input
*i
;
157 assert(s
&& s
->ref
>= 1 && info
);
159 for (i
= pa_idxset_first(s
->inputs
, &index
); maxinfo
> 0 && i
; i
= pa_idxset_next(s
->inputs
, &index
)) {
160 pa_sink_input_ref(i
);
162 if (pa_sink_input_peek(i
, &info
->chunk
) < 0) {
163 pa_sink_input_unref(i
);
167 info
->volume
= i
->volume
;
170 assert(info
->chunk
.memblock
&& info
->chunk
.memblock
->data
&& info
->chunk
.length
);
180 static void inputs_drop(struct pa_sink
*s
, struct pa_mix_info
*info
, unsigned maxinfo
, size_t length
) {
181 assert(s
&& s
->ref
>= 1 && info
);
183 for (; maxinfo
> 0; maxinfo
--, info
++) {
184 struct pa_sink_input
*i
= info
->userdata
;
185 assert(i
&& info
->chunk
.memblock
);
187 pa_sink_input_drop(i
, &info
->chunk
, length
);
188 pa_memblock_unref(info
->chunk
.memblock
);
190 pa_sink_input_unref(i
);
191 info
->userdata
= NULL
;
195 int pa_sink_render(struct pa_sink
*s
, size_t length
, struct pa_memchunk
*result
) {
196 struct pa_mix_info info
[MAX_MIX_CHANNELS
];
207 n
= fill_mix_info(s
, info
, MAX_MIX_CHANNELS
);
213 uint32_t volume
= PA_VOLUME_NORM
;
214 struct pa_sink_input
*i
= info
[0].userdata
;
216 *result
= info
[0].chunk
;
217 pa_memblock_ref(result
->memblock
);
219 if (result
->length
> length
)
220 result
->length
= length
;
224 if (s
->volume
!= PA_VOLUME_NORM
|| info
[0].volume
!= PA_VOLUME_NORM
)
225 volume
= pa_volume_multiply(s
->volume
, info
[0].volume
);
227 if (volume
!= PA_VOLUME_NORM
) {
228 pa_memchunk_make_writable(result
, s
->core
->memblock_stat
, 0);
229 pa_volume_memchunk(result
, &s
->sample_spec
, volume
);
232 result
->memblock
= pa_memblock_new(length
, s
->core
->memblock_stat
);
233 assert(result
->memblock
);
235 result
->length
= l
= pa_mix(info
, n
, result
->memblock
->data
, length
, &s
->sample_spec
, s
->volume
);
241 inputs_drop(s
, info
, n
, l
);
243 assert(s
->monitor_source
);
244 pa_source_post(s
->monitor_source
, result
);
254 int pa_sink_render_into(struct pa_sink
*s
, struct pa_memchunk
*target
) {
255 struct pa_mix_info info
[MAX_MIX_CHANNELS
];
259 assert(s
&& s
->ref
>= 1 && target
&& target
->length
&& target
->memblock
&& target
->memblock
->data
);
263 n
= fill_mix_info(s
, info
, MAX_MIX_CHANNELS
);
269 uint32_t volume
= PA_VOLUME_NORM
;
270 struct pa_sink_info
*i
= info
[0].userdata
;
274 if (l
> info
[0].chunk
.length
)
275 l
= info
[0].chunk
.length
;
277 memcpy((uint8_t*) target
->memblock
->data
+target
->index
, (uint8_t*) info
[0].chunk
.memblock
->data
+ info
[0].chunk
.index
, l
);
280 if (s
->volume
!= PA_VOLUME_NORM
|| info
[0].volume
!= PA_VOLUME_NORM
)
281 volume
= pa_volume_multiply(s
->volume
, info
[0].volume
);
283 if (volume
!= PA_VOLUME_NORM
)
284 pa_volume_memchunk(target
, &s
->sample_spec
, volume
);
286 target
->length
= l
= pa_mix(info
, n
, (uint8_t*) target
->memblock
->data
+target
->index
, target
->length
, &s
->sample_spec
, s
->volume
);
289 inputs_drop(s
, info
, n
, l
);
291 assert(s
->monitor_source
);
292 pa_source_post(s
->monitor_source
, target
);
302 void pa_sink_render_into_full(struct pa_sink
*s
, struct pa_memchunk
*target
) {
303 struct pa_memchunk chunk
;
305 assert(s
&& s
->ref
>= 1 && target
&& target
->memblock
&& target
->length
&& target
->memblock
->data
);
316 if (pa_sink_render_into(s
, &chunk
) < 0)
327 pa_silence_memchunk(&chunk
, &s
->sample_spec
);
333 void pa_sink_render_full(struct pa_sink
*s
, size_t length
, struct pa_memchunk
*result
) {
334 assert(s
&& s
->ref
>= 1 && length
&& result
);
336 /*** This needs optimization ***/
338 result
->memblock
= pa_memblock_new(result
->length
= length
, s
->core
->memblock_stat
);
341 pa_sink_render_into_full(s
, result
);
344 pa_usec_t
pa_sink_get_latency(struct pa_sink
*s
) {
345 assert(s
&& s
->ref
>= 1);
350 return s
->get_latency(s
);
353 void pa_sink_set_owner(struct pa_sink
*s
, struct pa_module
*m
) {
354 assert(s
&& s
->ref
>= 1);
358 if (s
->monitor_source
)
359 pa_source_set_owner(s
->monitor_source
, m
);
362 void pa_sink_set_volume(struct pa_sink
*s
, pa_volume_t volume
) {
363 assert(s
&& s
->ref
>= 1);
365 if (s
->volume
!= volume
) {
367 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);