4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
34 #include <pulse/introspect.h>
35 #include <pulse/utf8.h>
36 #include <pulse/xmalloc.h>
38 #include <pulsecore/sink-input.h>
39 #include <pulsecore/namereg.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/sample-util.h>
42 #include <pulsecore/core-subscribe.h>
43 #include <pulsecore/log.h>
47 #define MAX_MIX_CHANNELS 32
49 #define CHECK_VALIDITY_RETURN_NULL(condition) \
60 const pa_sample_spec
*spec
,
61 const pa_channel_map
*map
) {
73 CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec
));
76 map
= pa_channel_map_init_auto(&tmap
, spec
->channels
, PA_CHANNEL_MAP_DEFAULT
);
78 CHECK_VALIDITY_RETURN_NULL(map
&& pa_channel_map_valid(map
));
79 CHECK_VALIDITY_RETURN_NULL(map
->channels
== spec
->channels
);
80 CHECK_VALIDITY_RETURN_NULL(!driver
|| pa_utf8_valid(driver
));
81 CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name
) && *name
);
83 s
= pa_xnew(pa_sink
, 1);
85 if (!(name
= pa_namereg_register(core
, name
, PA_NAMEREG_SINK
, s
, fail
))) {
92 s
->state
= PA_SINK_RUNNING
;
93 s
->name
= pa_xstrdup(name
);
94 s
->description
= NULL
;
95 s
->driver
= pa_xstrdup(driver
);
98 s
->sample_spec
= *spec
;
99 s
->channel_map
= *map
;
101 s
->inputs
= pa_idxset_new(NULL
, NULL
);
103 pa_cvolume_reset(&s
->sw_volume
, spec
->channels
);
104 pa_cvolume_reset(&s
->hw_volume
, spec
->channels
);
110 s
->get_latency
= NULL
;
112 s
->set_hw_volume
= NULL
;
113 s
->get_hw_volume
= NULL
;
114 s
->set_hw_mute
= NULL
;
115 s
->get_hw_mute
= NULL
;
118 r
= pa_idxset_put(core
->sinks
, s
, &s
->index
);
119 assert(s
->index
!= PA_IDXSET_INVALID
&& r
>= 0);
121 pa_sample_spec_snprint(st
, sizeof(st
), spec
);
122 pa_log_info("created %u \"%s\" with sample spec \"%s\"", s
->index
, s
->name
, st
);
124 n
= pa_sprintf_malloc("%s.monitor", name
);
126 if (!(s
->monitor_source
= pa_source_new(core
, driver
, n
, 0, spec
, map
)))
127 pa_log_warn("failed to create monitor source.");
130 s
->monitor_source
->monitor_of
= s
;
131 d
= pa_sprintf_malloc("Monitor Source of %s", s
->name
);
132 pa_source_set_description(s
->monitor_source
, d
);
138 pa_subscription_post(core
, PA_SUBSCRIPTION_EVENT_SINK
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
143 void pa_sink_disconnect(pa_sink
* s
) {
144 pa_sink_input
*i
, *j
= NULL
;
147 assert(s
->state
== PA_SINK_RUNNING
);
149 s
->state
= PA_SINK_DISCONNECTED
;
150 pa_namereg_unregister(s
->core
, s
->name
);
152 pa_hook_fire(&s
->core
->hook_sink_disconnect
, s
);
154 while ((i
= pa_idxset_first(s
->inputs
, NULL
))) {
156 pa_sink_input_kill(i
);
160 if (s
->monitor_source
)
161 pa_source_disconnect(s
->monitor_source
);
163 pa_idxset_remove_by_data(s
->core
->sinks
, s
, NULL
);
165 s
->get_latency
= NULL
;
167 s
->get_hw_volume
= NULL
;
168 s
->set_hw_volume
= NULL
;
169 s
->set_hw_mute
= NULL
;
170 s
->get_hw_mute
= NULL
;
172 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
175 static void sink_free(pa_sink
*s
) {
179 if (s
->state
!= PA_SINK_DISCONNECTED
)
180 pa_sink_disconnect(s
);
182 pa_log_info("freed %u \"%s\"", s
->index
, s
->name
);
184 if (s
->monitor_source
) {
185 pa_source_unref(s
->monitor_source
);
186 s
->monitor_source
= NULL
;
189 pa_idxset_free(s
->inputs
, NULL
, NULL
);
192 pa_xfree(s
->description
);
197 void pa_sink_unref(pa_sink
*s
) {
205 pa_sink
* pa_sink_ref(pa_sink
*s
) {
213 void pa_sink_notify(pa_sink
*s
) {
221 static unsigned fill_mix_info(pa_sink
*s
, pa_mix_info
*info
, unsigned maxinfo
) {
222 uint32_t idx
= PA_IDXSET_INVALID
;
230 for (i
= pa_idxset_first(s
->inputs
, &idx
); maxinfo
> 0 && i
; i
= pa_idxset_next(s
->inputs
, &idx
)) {
231 /* Increase ref counter, to make sure that this input doesn't
232 * vanish while we still need it */
233 pa_sink_input_ref(i
);
235 if (pa_sink_input_peek(i
, &info
->chunk
, &info
->volume
) < 0) {
236 pa_sink_input_unref(i
);
242 assert(info
->chunk
.memblock
);
243 assert(info
->chunk
.memblock
->data
);
244 assert(info
->chunk
.length
);
254 static void inputs_drop(pa_sink
*s
, pa_mix_info
*info
, unsigned maxinfo
, size_t length
) {
259 for (; maxinfo
> 0; maxinfo
--, info
++) {
260 pa_sink_input
*i
= info
->userdata
;
263 assert(info
->chunk
.memblock
);
266 pa_sink_input_drop(i
, &info
->chunk
, length
);
267 pa_memblock_unref(info
->chunk
.memblock
);
269 /* Decrease ref counter */
270 pa_sink_input_unref(i
);
271 info
->userdata
= NULL
;
275 int pa_sink_render(pa_sink
*s
, size_t length
, pa_memchunk
*result
) {
276 pa_mix_info info
[MAX_MIX_CHANNELS
];
287 n
= fill_mix_info(s
, info
, MAX_MIX_CHANNELS
);
295 *result
= info
[0].chunk
;
296 pa_memblock_ref(result
->memblock
);
298 if (result
->length
> length
)
299 result
->length
= length
;
301 pa_sw_cvolume_multiply(&volume
, &s
->sw_volume
, &info
[0].volume
);
303 if (s
->sw_muted
|| !pa_cvolume_is_norm(&volume
)) {
304 pa_memchunk_make_writable(result
, 0);
306 pa_silence_memchunk(result
, &s
->sample_spec
);
308 pa_volume_memchunk(result
, &s
->sample_spec
, &volume
);
311 result
->memblock
= pa_memblock_new(s
->core
->mempool
, length
);
312 assert(result
->memblock
);
314 /* pa_log("mixing %i", n); */
316 result
->length
= pa_mix(info
, n
, result
->memblock
->data
, length
,
317 &s
->sample_spec
, &s
->sw_volume
, s
->sw_muted
);
321 inputs_drop(s
, info
, n
, result
->length
);
323 if (s
->monitor_source
)
324 pa_source_post(s
->monitor_source
, result
);
334 int pa_sink_render_into(pa_sink
*s
, pa_memchunk
*target
) {
335 pa_mix_info info
[MAX_MIX_CHANNELS
];
342 assert(target
->memblock
);
343 assert(target
->length
);
344 assert(target
->memblock
->data
);
348 n
= fill_mix_info(s
, info
, MAX_MIX_CHANNELS
);
356 if (target
->length
> info
[0].chunk
.length
)
357 target
->length
= info
[0].chunk
.length
;
359 memcpy((uint8_t*) target
->memblock
->data
+ target
->index
,
360 (uint8_t*) info
[0].chunk
.memblock
->data
+ info
[0].chunk
.index
,
363 pa_sw_cvolume_multiply(&volume
, &s
->sw_volume
, &info
[0].volume
);
366 pa_silence_memchunk(target
, &s
->sample_spec
);
367 else if (!pa_cvolume_is_norm(&volume
))
368 pa_volume_memchunk(target
, &s
->sample_spec
, &volume
);
370 target
->length
= pa_mix(info
, n
,
371 (uint8_t*) target
->memblock
->data
+ target
->index
,
377 inputs_drop(s
, info
, n
, target
->length
);
379 if (s
->monitor_source
)
380 pa_source_post(s
->monitor_source
, target
);
390 void pa_sink_render_into_full(pa_sink
*s
, pa_memchunk
*target
) {
397 assert(target
->memblock
);
398 assert(target
->length
);
399 assert(target
->memblock
->data
);
410 if (pa_sink_render_into(s
, &chunk
) < 0)
421 pa_silence_memchunk(&chunk
, &s
->sample_spec
);
427 void pa_sink_render_full(pa_sink
*s
, size_t length
, pa_memchunk
*result
) {
433 /*** This needs optimization ***/
435 result
->memblock
= pa_memblock_new(s
->core
->mempool
, result
->length
= length
);
438 pa_sink_render_into_full(s
, result
);
441 pa_usec_t
pa_sink_get_latency(pa_sink
*s
) {
448 return s
->get_latency(s
);
451 void pa_sink_set_owner(pa_sink
*s
, pa_module
*m
) {
460 if (s
->monitor_source
)
461 pa_source_set_owner(s
->monitor_source
, m
);
463 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
466 void pa_sink_set_volume(pa_sink
*s
, pa_mixer_t m
, const pa_cvolume
*volume
) {
473 if (m
== PA_MIXER_HARDWARE
&& s
->set_hw_volume
)
478 if (pa_cvolume_equal(v
, volume
))
483 if (v
== &s
->hw_volume
)
484 if (s
->set_hw_volume(s
) < 0)
485 s
->sw_volume
= *volume
;
487 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
490 const pa_cvolume
*pa_sink_get_volume(pa_sink
*s
, pa_mixer_t m
) {
494 if (m
== PA_MIXER_HARDWARE
&& s
->set_hw_volume
) {
496 if (s
->get_hw_volume
)
499 return &s
->hw_volume
;
501 return &s
->sw_volume
;
504 void pa_sink_set_mute(pa_sink
*s
, pa_mixer_t m
, int mute
) {
510 if (m
== PA_MIXER_HARDWARE
&& s
->set_hw_mute
)
520 if (t
== &s
->hw_muted
)
521 if (s
->set_hw_mute(s
) < 0)
522 s
->sw_muted
= !!mute
;
524 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
527 int pa_sink_get_mute(pa_sink
*s
, pa_mixer_t m
) {
531 if (m
== PA_MIXER_HARDWARE
&& s
->set_hw_mute
) {
541 void pa_sink_set_description(pa_sink
*s
, const char *description
) {
545 if (!description
&& !s
->description
)
548 if (description
&& s
->description
&& !strcmp(description
, s
->description
))
551 pa_xfree(s
->description
);
552 s
->description
= pa_xstrdup(description
);
554 if (s
->monitor_source
) {
557 n
= pa_sprintf_malloc("Monitor Source of %s", s
->description
? s
->description
: s
->name
);
558 pa_source_set_description(s
->monitor_source
, n
);
562 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
565 unsigned pa_sink_used_by(pa_sink
*s
) {
571 ret
= pa_idxset_size(s
->inputs
);
573 if (s
->monitor_source
)
574 ret
+= pa_source_used_by(s
->monitor_source
);