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>
44 #include <pulsecore/macro.h>
48 #define MAX_MIX_CHANNELS 32
49 #define SILENCE_BUFFER_LENGTH (64*1024)
51 static PA_DEFINE_CHECK_TYPE(pa_sink
, sink_check_type
, pa_msgobject_check_type
);
53 static void sink_free(pa_object
*s
);
60 const pa_sample_spec
*spec
,
61 const pa_channel_map
*map
) {
73 pa_return_null_if_fail(pa_sample_spec_valid(spec
));
76 map
= pa_channel_map_init_auto(&tmap
, spec
->channels
, PA_CHANNEL_MAP_DEFAULT
);
78 pa_return_null_if_fail(map
&& pa_channel_map_valid(map
));
79 pa_return_null_if_fail(map
->channels
== spec
->channels
);
80 pa_return_null_if_fail(!driver
|| pa_utf8_valid(driver
));
81 pa_return_null_if_fail(name
&& pa_utf8_valid(name
) && *name
);
83 s
= pa_msgobject_new(pa_sink
, sink_check_type
);
85 if (!(name
= pa_namereg_register(core
, name
, PA_NAMEREG_SINK
, s
, fail
))) {
90 s
->parent
.parent
.free
= sink_free
;
91 s
->parent
.process_msg
= pa_sink_process_msg
;
94 s
->state
= PA_SINK_IDLE
;
95 s
->name
= pa_xstrdup(name
);
96 s
->description
= NULL
;
97 s
->driver
= pa_xstrdup(driver
);
100 s
->sample_spec
= *spec
;
101 s
->channel_map
= *map
;
103 s
->inputs
= pa_idxset_new(NULL
, NULL
);
105 pa_cvolume_reset(&s
->volume
, spec
->channels
);
107 s
->refresh_volume
= s
->refresh_mute
= 0;
111 s
->get_latency
= NULL
;
112 s
->set_volume
= NULL
;
113 s
->get_volume
= NULL
;
122 r
= pa_idxset_put(core
->sinks
, s
, &s
->index
);
123 pa_assert(s
->index
!= PA_IDXSET_INVALID
&& r
>= 0);
125 pa_sample_spec_snprint(st
, sizeof(st
), spec
);
126 pa_log_info("Created sink %u \"%s\" with sample spec \"%s\"", s
->index
, s
->name
, st
);
128 n
= pa_sprintf_malloc("%s.monitor", name
);
130 if (!(s
->monitor_source
= pa_source_new(core
, driver
, n
, 0, spec
, map
)))
131 pa_log_warn("failed to create monitor source.");
134 s
->monitor_source
->monitor_of
= s
;
135 d
= pa_sprintf_malloc("Monitor Source of %s", s
->name
);
136 pa_source_set_description(s
->monitor_source
, d
);
142 s
->thread_info
.inputs
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
143 s
->thread_info
.soft_volume
= s
->volume
;
144 s
->thread_info
.soft_muted
= s
->muted
;
145 s
->thread_info
.state
= s
->state
;
147 pa_subscription_post(core
, PA_SUBSCRIPTION_EVENT_SINK
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
152 static int sink_set_state(pa_sink
*s
, pa_sink_state_t state
) {
157 if (s
->state
== state
)
161 if ((ret
= s
->set_state(s
, state
)) < 0)
164 if (pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_SET_STATE
, PA_UINT_TO_PTR(state
), NULL
) < 0)
171 void pa_sink_disconnect(pa_sink
* s
) {
172 pa_sink_input
*i
, *j
= NULL
;
175 pa_return_if_fail(s
->state
!= PA_SINK_DISCONNECTED
);
177 pa_namereg_unregister(s
->core
, s
->name
);
178 pa_idxset_remove_by_data(s
->core
->sinks
, s
, NULL
);
180 pa_hook_fire(&s
->core
->hook_sink_disconnect
, s
);
182 while ((i
= pa_idxset_first(s
->inputs
, NULL
))) {
184 pa_sink_input_kill(i
);
188 if (s
->monitor_source
)
189 pa_source_disconnect(s
->monitor_source
);
191 sink_set_state(s
, PA_SINK_DISCONNECTED
);
193 s
->get_latency
= NULL
;
194 s
->get_volume
= NULL
;
195 s
->set_volume
= NULL
;
200 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
203 static void sink_free(pa_object
*o
) {
204 pa_sink
*s
= PA_SINK(o
);
208 pa_assert(pa_sink_refcnt(s
) == 0);
210 if (s
->state
!= PA_SINK_DISCONNECTED
)
211 pa_sink_disconnect(s
);
213 pa_log_info("Freeing sink %u \"%s\"", s
->index
, s
->name
);
215 if (s
->monitor_source
) {
216 pa_source_unref(s
->monitor_source
);
217 s
->monitor_source
= NULL
;
220 pa_idxset_free(s
->inputs
, NULL
, NULL
);
222 while ((i
= pa_hashmap_steal_first(s
->thread_info
.inputs
)))
223 pa_sink_input_unref(i
);
225 pa_hashmap_free(s
->thread_info
.inputs
, NULL
, NULL
);
228 pa_memblock_unref(s
->silence
);
231 pa_xfree(s
->description
);
236 void pa_sink_set_asyncmsgq(pa_sink
*s
, pa_asyncmsgq
*q
) {
237 pa_sink_assert_ref(s
);
242 if (s
->monitor_source
)
243 pa_source_set_asyncmsgq(s
->monitor_source
, q
);
246 int pa_sink_update_status(pa_sink
*s
) {
247 pa_sink_assert_ref(s
);
249 if (s
->state
== PA_SINK_SUSPENDED
)
252 return sink_set_state(s
, pa_sink_used_by(s
) ? PA_SINK_RUNNING
: PA_SINK_IDLE
);
255 int pa_sink_suspend(pa_sink
*s
, int suspend
) {
256 pa_sink_assert_ref(s
);
259 return sink_set_state(s
, PA_SINK_SUSPENDED
);
261 return sink_set_state(s
, pa_sink_used_by(s
) ? PA_SINK_RUNNING
: PA_SINK_IDLE
);
264 void pa_sink_ping(pa_sink
*s
) {
265 pa_sink_assert_ref(s
);
267 pa_asyncmsgq_post(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_PING
, NULL
, NULL
, NULL
);
270 static unsigned fill_mix_info(pa_sink
*s
, pa_mix_info
*info
, unsigned maxinfo
) {
275 pa_sink_assert_ref(s
);
278 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
)) && maxinfo
> 0) {
279 pa_sink_input_assert_ref(i
);
281 if (pa_sink_input_peek(i
, &info
->chunk
, &info
->volume
) < 0)
284 info
->userdata
= pa_sink_input_ref(i
);
286 pa_assert(info
->chunk
.memblock
);
287 pa_assert(info
->chunk
.length
> 0);
297 static void inputs_drop(pa_sink
*s
, pa_mix_info
*info
, unsigned n
, size_t length
) {
301 unsigned n_unreffed
= 0;
303 pa_sink_assert_ref(s
);
305 /* We optimize for the case where the order of the inputs has not changed */
307 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
))) {
311 pa_sink_input_assert_ref(i
);
315 /* Let's try to find the matching entry info the pa_mix_info array */
316 for (j
= 0; j
< n
; j
++) {
318 if (info
[p
].userdata
== i
) {
328 pa_sink_input_drop(i
, m
? &m
->chunk
: NULL
, length
);
331 pa_sink_input_unref(m
->userdata
);
333 if (m
->chunk
.memblock
)
334 pa_memblock_unref(m
->chunk
.memblock
);
335 pa_memchunk_reset(&m
->chunk
);
341 /* Now drop references to entries that are included in the
342 * pa_mix_info array but don't exist anymore */
344 if (n_unreffed
< n
) {
345 for (; n
> 0; info
++, n
--) {
347 pa_sink_input_unref(info
->userdata
);
348 if (info
->chunk
.memblock
)
349 pa_memblock_unref(info
->chunk
.memblock
);
354 void pa_sink_render(pa_sink
*s
, size_t length
, pa_memchunk
*result
) {
355 pa_mix_info info
[MAX_MIX_CHANNELS
];
358 pa_sink_assert_ref(s
);
364 n
= s
->thread_info
.state
== PA_SINK_RUNNING
? fill_mix_info(s
, info
, MAX_MIX_CHANNELS
) : 0;
368 if (length
> SILENCE_BUFFER_LENGTH
)
369 length
= SILENCE_BUFFER_LENGTH
;
371 if (!s
->silence
|| pa_memblock_get_length(s
->silence
) < length
) {
373 pa_memblock_unref(s
->silence
);
374 s
->silence
= pa_silence_memblock_new(s
->core
->mempool
, &s
->sample_spec
, length
);
377 result
->memblock
= pa_memblock_ref(s
->silence
);
378 result
->length
= length
;
384 *result
= info
[0].chunk
;
385 pa_memblock_ref(result
->memblock
);
387 if (result
->length
> length
)
388 result
->length
= length
;
390 pa_sw_cvolume_multiply(&volume
, &s
->thread_info
.soft_volume
, &info
[0].volume
);
392 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&volume
)) {
393 pa_memchunk_make_writable(result
, 0);
394 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&volume
))
395 pa_silence_memchunk(result
, &s
->sample_spec
);
397 pa_volume_memchunk(result
, &s
->sample_spec
, &volume
);
401 result
->memblock
= pa_memblock_new(s
->core
->mempool
, length
);
403 ptr
= pa_memblock_acquire(result
->memblock
);
404 result
->length
= pa_mix(info
, n
, ptr
, length
, &s
->sample_spec
, &s
->thread_info
.soft_volume
, s
->thread_info
.soft_muted
);
405 pa_memblock_release(result
->memblock
);
410 inputs_drop(s
, info
, n
, result
->length
);
412 if (s
->monitor_source
)
413 pa_source_post(s
->monitor_source
, result
);
418 void pa_sink_render_into(pa_sink
*s
, pa_memchunk
*target
) {
419 pa_mix_info info
[MAX_MIX_CHANNELS
];
422 pa_sink_assert_ref(s
);
424 pa_assert(target
->memblock
);
425 pa_assert(target
->length
);
429 n
= s
->thread_info
.state
== PA_SINK_RUNNING
? fill_mix_info(s
, info
, MAX_MIX_CHANNELS
) : 0;
432 pa_silence_memchunk(target
, &s
->sample_spec
);
434 if (target
->length
> info
[0].chunk
.length
)
435 target
->length
= info
[0].chunk
.length
;
437 if (s
->thread_info
.soft_muted
)
438 pa_silence_memchunk(target
, &s
->sample_spec
);
443 ptr
= pa_memblock_acquire(target
->memblock
);
444 src
= pa_memblock_acquire(info
[0].chunk
.memblock
);
446 memcpy((uint8_t*) ptr
+ target
->index
,
447 (uint8_t*) src
+ info
[0].chunk
.index
,
450 pa_memblock_release(target
->memblock
);
451 pa_memblock_release(info
[0].chunk
.memblock
);
453 pa_sw_cvolume_multiply(&volume
, &s
->thread_info
.soft_volume
, &info
[0].volume
);
455 if (!pa_cvolume_is_norm(&volume
))
456 pa_volume_memchunk(target
, &s
->sample_spec
, &volume
);
462 ptr
= pa_memblock_acquire(target
->memblock
);
464 target
->length
= pa_mix(info
, n
,
465 (uint8_t*) ptr
+ target
->index
,
468 &s
->thread_info
.soft_volume
,
469 s
->thread_info
.soft_muted
);
471 pa_memblock_release(target
->memblock
);
474 inputs_drop(s
, info
, n
, target
->length
);
476 if (s
->monitor_source
)
477 pa_source_post(s
->monitor_source
, target
);
482 void pa_sink_render_into_full(pa_sink
*s
, pa_memchunk
*target
) {
486 pa_sink_assert_ref(s
);
488 pa_assert(target
->memblock
);
489 pa_assert(target
->length
);
500 pa_sink_render_into(s
, &chunk
);
509 void pa_sink_render_full(pa_sink
*s
, size_t length
, pa_memchunk
*result
) {
510 pa_sink_assert_ref(s
);
514 /*** This needs optimization ***/
516 result
->memblock
= pa_memblock_new(s
->core
->mempool
, result
->length
= length
);
519 pa_sink_render_into_full(s
, result
);
522 pa_usec_t
pa_sink_get_latency(pa_sink
*s
) {
525 pa_sink_assert_ref(s
);
528 return s
->get_latency(s
);
530 if (pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_LATENCY
, &usec
, NULL
) < 0)
536 void pa_sink_set_volume(pa_sink
*s
, const pa_cvolume
*volume
) {
539 pa_sink_assert_ref(s
);
542 changed
= !pa_cvolume_equal(volume
, &s
->volume
);
545 if (s
->set_volume
&& s
->set_volume(s
) < 0)
546 s
->set_volume
= NULL
;
549 pa_asyncmsgq_post(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_SET_VOLUME
, pa_xnewdup(struct pa_cvolume
, volume
, 1), NULL
, pa_xfree
);
552 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
555 const pa_cvolume
*pa_sink_get_volume(pa_sink
*s
) {
556 struct pa_cvolume old_volume
;
558 pa_sink_assert_ref(s
);
560 old_volume
= s
->volume
;
562 if (s
->get_volume
&& s
->get_volume(s
) < 0)
563 s
->get_volume
= NULL
;
565 if (!s
->get_volume
&& s
->refresh_volume
)
566 pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_VOLUME
, &s
->volume
, NULL
);
568 if (!pa_cvolume_equal(&old_volume
, &s
->volume
))
569 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
574 void pa_sink_set_mute(pa_sink
*s
, int mute
) {
577 pa_sink_assert_ref(s
);
579 changed
= s
->muted
!= mute
;
581 if (s
->set_mute
&& s
->set_mute(s
) < 0)
585 pa_asyncmsgq_post(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_SET_MUTE
, PA_UINT_TO_PTR(mute
), NULL
, NULL
);
588 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
591 int pa_sink_get_mute(pa_sink
*s
) {
594 pa_sink_assert_ref(s
);
596 old_muted
= s
->muted
;
598 if (s
->get_mute
&& s
->get_mute(s
) < 0)
601 if (!s
->get_mute
&& s
->refresh_mute
)
602 pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_MUTE
, &s
->muted
, NULL
);
604 if (old_muted
!= s
->muted
)
605 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
610 void pa_sink_set_module(pa_sink
*s
, pa_module
*m
) {
611 pa_sink_assert_ref(s
);
618 if (s
->monitor_source
)
619 pa_source_set_module(s
->monitor_source
, m
);
621 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
624 void pa_sink_set_description(pa_sink
*s
, const char *description
) {
625 pa_sink_assert_ref(s
);
627 if (!description
&& !s
->description
)
630 if (description
&& s
->description
&& !strcmp(description
, s
->description
))
633 pa_xfree(s
->description
);
634 s
->description
= pa_xstrdup(description
);
636 if (s
->monitor_source
) {
639 n
= pa_sprintf_malloc("Monitor Source of %s", s
->description
? s
->description
: s
->name
);
640 pa_source_set_description(s
->monitor_source
, n
);
644 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
647 unsigned pa_sink_used_by(pa_sink
*s
) {
650 pa_sink_assert_ref(s
);
652 ret
= pa_idxset_size(s
->inputs
);
654 if (s
->monitor_source
)
655 ret
+= pa_source_used_by(s
->monitor_source
);
660 int pa_sink_process_msg(pa_msgobject
*o
, int code
, void *userdata
, pa_memchunk
*chunk
) {
661 pa_sink
*s
= PA_SINK(o
);
662 pa_sink_assert_ref(s
);
664 switch ((pa_sink_message_t
) code
) {
665 case PA_SINK_MESSAGE_ADD_INPUT
: {
666 pa_sink_input
*i
= userdata
;
667 pa_hashmap_put(s
->thread_info
.inputs
, PA_UINT32_TO_PTR(i
->index
), pa_sink_input_ref(i
));
671 case PA_SINK_MESSAGE_REMOVE_INPUT
: {
672 pa_sink_input
*i
= userdata
;
673 pa_hashmap_remove(s
->thread_info
.inputs
, PA_UINT32_TO_PTR(i
->index
));
677 case PA_SINK_MESSAGE_SET_VOLUME
:
678 s
->thread_info
.soft_volume
= *((pa_cvolume
*) userdata
);
681 case PA_SINK_MESSAGE_SET_MUTE
:
682 s
->thread_info
.soft_muted
= PA_PTR_TO_UINT(userdata
);
685 case PA_SINK_MESSAGE_GET_VOLUME
:
686 *((pa_cvolume
*) userdata
) = s
->thread_info
.soft_volume
;
689 case PA_SINK_MESSAGE_GET_MUTE
:
690 *((int*) userdata
) = s
->thread_info
.soft_muted
;
693 case PA_SINK_MESSAGE_PING
:
696 case PA_SINK_MESSAGE_SET_STATE
:
697 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
700 case PA_SINK_MESSAGE_GET_LATENCY
:
701 case PA_SINK_MESSAGE_MAX
: