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/utf8.h>
35 #include <pulse/xmalloc.h>
37 #include <pulsecore/source-output.h>
38 #include <pulsecore/namereg.h>
39 #include <pulsecore/core-subscribe.h>
40 #include <pulsecore/log.h>
41 #include <pulsecore/sample-util.h>
45 #define CHECK_VALIDITY_RETURN_NULL(condition) \
51 pa_source
* pa_source_new(
56 const pa_sample_spec
*spec
,
57 const pa_channel_map
*map
) {
68 CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec
));
71 map
= pa_channel_map_init_auto(&tmap
, spec
->channels
, PA_CHANNEL_MAP_DEFAULT
);
73 CHECK_VALIDITY_RETURN_NULL(map
&& pa_channel_map_valid(map
));
74 CHECK_VALIDITY_RETURN_NULL(map
->channels
== spec
->channels
);
75 CHECK_VALIDITY_RETURN_NULL(!driver
|| pa_utf8_valid(driver
));
76 CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name
) && *name
);
78 s
= pa_xnew(pa_source
, 1);
80 if (!(name
= pa_namereg_register(core
, name
, PA_NAMEREG_SOURCE
, s
, fail
))) {
87 s
->state
= PA_SOURCE_RUNNING
;
88 s
->name
= pa_xstrdup(name
);
89 s
->description
= NULL
;
90 s
->driver
= pa_xstrdup(driver
);
93 s
->sample_spec
= *spec
;
94 s
->channel_map
= *map
;
96 s
->outputs
= pa_idxset_new(NULL
, NULL
);
99 pa_cvolume_reset(&s
->sw_volume
, spec
->channels
);
100 pa_cvolume_reset(&s
->hw_volume
, spec
->channels
);
106 s
->get_latency
= NULL
;
108 s
->set_hw_volume
= NULL
;
109 s
->get_hw_volume
= NULL
;
110 s
->set_hw_mute
= NULL
;
111 s
->get_hw_mute
= NULL
;
114 r
= pa_idxset_put(core
->sources
, s
, &s
->index
);
115 assert(s
->index
!= PA_IDXSET_INVALID
&& r
>= 0);
117 pa_sample_spec_snprint(st
, sizeof(st
), spec
);
118 pa_log_info("created %u \"%s\" with sample spec \"%s\"", s
->index
, s
->name
, st
);
120 pa_subscription_post(core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
125 void pa_source_disconnect(pa_source
*s
) {
126 pa_source_output
*o
, *j
= NULL
;
129 assert(s
->state
== PA_SOURCE_RUNNING
);
131 s
->state
= PA_SOURCE_DISCONNECTED
;
132 pa_namereg_unregister(s
->core
, s
->name
);
134 pa_hook_fire(&s
->core
->hook_source_disconnect
, s
);
136 while ((o
= pa_idxset_first(s
->outputs
, NULL
))) {
138 pa_source_output_kill(o
);
142 pa_idxset_remove_by_data(s
->core
->sources
, s
, NULL
);
144 s
->get_latency
= NULL
;
146 s
->get_hw_volume
= NULL
;
147 s
->set_hw_volume
= NULL
;
148 s
->set_hw_mute
= NULL
;
149 s
->get_hw_mute
= NULL
;
151 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
154 static void source_free(pa_source
*s
) {
158 if (s
->state
!= PA_SOURCE_DISCONNECTED
)
159 pa_source_disconnect(s
);
161 pa_log_info("freed %u \"%s\"", s
->index
, s
->name
);
163 pa_idxset_free(s
->outputs
, NULL
, NULL
);
166 pa_xfree(s
->description
);
171 void pa_source_unref(pa_source
*s
) {
179 pa_source
* pa_source_ref(pa_source
*s
) {
187 void pa_source_notify(pa_source
*s
) {
195 static int do_post(void *p
, PA_GCC_UNUSED
uint32_t idx
, PA_GCC_UNUSED
int *del
, void*userdata
) {
196 pa_source_output
*o
= p
;
197 const pa_memchunk
*chunk
= userdata
;
202 pa_source_output_push(o
, chunk
);
206 void pa_source_post(pa_source
*s
, const pa_memchunk
*chunk
) {
213 if (s
->sw_muted
|| !pa_cvolume_is_norm(&s
->sw_volume
)) {
214 pa_memchunk vchunk
= *chunk
;
216 pa_memblock_ref(vchunk
.memblock
);
217 pa_memchunk_make_writable(&vchunk
, 0);
219 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
221 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->sw_volume
);
222 pa_idxset_foreach(s
->outputs
, do_post
, &vchunk
);
223 pa_memblock_unref(vchunk
.memblock
);
225 pa_idxset_foreach(s
->outputs
, do_post
, (void*) chunk
);
230 void pa_source_set_owner(pa_source
*s
, pa_module
*m
) {
238 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
241 pa_usec_t
pa_source_get_latency(pa_source
*s
) {
248 return s
->get_latency(s
);
251 void pa_source_set_volume(pa_source
*s
, pa_mixer_t m
, const pa_cvolume
*volume
) {
258 if (m
== PA_MIXER_HARDWARE
&& s
->set_hw_volume
)
263 if (pa_cvolume_equal(v
, volume
))
268 if (v
== &s
->hw_volume
)
269 if (s
->set_hw_volume(s
) < 0)
270 s
->sw_volume
= *volume
;
272 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
275 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_mixer_t m
) {
279 if (m
== PA_MIXER_HARDWARE
&& s
->set_hw_volume
) {
281 if (s
->get_hw_volume
)
284 return &s
->hw_volume
;
286 return &s
->sw_volume
;
289 void pa_source_set_mute(pa_source
*s
, pa_mixer_t m
, int mute
) {
295 if (m
== PA_MIXER_HARDWARE
&& s
->set_hw_mute
)
305 if (t
== &s
->hw_muted
)
306 if (s
->set_hw_mute(s
) < 0)
307 s
->sw_muted
= !!mute
;
309 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
312 int pa_source_get_mute(pa_source
*s
, pa_mixer_t m
) {
316 if (m
== PA_MIXER_HARDWARE
&& s
->set_hw_mute
) {
326 void pa_source_set_description(pa_source
*s
, const char *description
) {
330 if (!description
&& !s
->description
)
333 if (description
&& s
->description
&& !strcmp(description
, s
->description
))
336 pa_xfree(s
->description
);
337 s
->description
= pa_xstrdup(description
);
339 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
342 unsigned pa_source_used_by(pa_source
*s
) {
346 return pa_idxset_size(s
->outputs
);