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