Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : : Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 : :
7 : : PulseAudio is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU Lesser General Public License as published
9 : : by the Free Software Foundation; either version 2.1 of the License,
10 : : or (at your option) any later version.
11 : :
12 : : PulseAudio is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU Lesser General Public License
18 : : along with PulseAudio; if not, write to the Free Software
19 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 : : USA.
21 : : ***/
22 : :
23 : : #ifdef HAVE_CONFIG_H
24 : : #include <config.h>
25 : : #endif
26 : :
27 : : #include <stdlib.h>
28 : : #include <stdio.h>
29 : : #include <signal.h>
30 : :
31 : : #include <pulse/rtclock.h>
32 : : #include <pulse/timeval.h>
33 : : #include <pulse/xmalloc.h>
34 : :
35 : : #include <pulsecore/module.h>
36 : : #include <pulsecore/core-rtclock.h>
37 : : #include <pulsecore/core-util.h>
38 : : #include <pulsecore/core-scache.h>
39 : : #include <pulsecore/core-subscribe.h>
40 : : #include <pulsecore/random.h>
41 : : #include <pulsecore/log.h>
42 : : #include <pulsecore/macro.h>
43 : :
44 : : #include "core.h"
45 : :
46 [ # # ]: 0 : PA_DEFINE_PUBLIC_CLASS(pa_core, pa_msgobject);
47 : :
48 : 0 : static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
49 : 0 : pa_core *c = PA_CORE(o);
50 : :
51 : : pa_core_assert_ref(c);
52 : :
53 [ # # ]: 0 : switch (code) {
54 : :
55 : : case PA_CORE_MESSAGE_UNLOAD_MODULE:
56 : 0 : pa_module_unload(c, userdata, TRUE);
57 : 0 : return 0;
58 : :
59 : : default:
60 : : return -1;
61 : : }
62 : : }
63 : :
64 : : static void core_free(pa_object *o);
65 : :
66 : 0 : pa_core* pa_core_new(pa_mainloop_api *m, pa_bool_t shared, size_t shm_size) {
67 : : pa_core* c;
68 : : pa_mempool *pool;
69 : : int j;
70 : :
71 [ # # ]: 0 : pa_assert(m);
72 : :
73 [ # # ]: 0 : if (shared) {
74 [ # # ]: 0 : if (!(pool = pa_mempool_new(shared, shm_size))) {
75 : 0 : pa_log_warn("failed to allocate shared memory pool. Falling back to a normal memory pool.");
76 : 0 : shared = FALSE;
77 : : }
78 : : }
79 : :
80 [ # # ]: 0 : if (!shared) {
81 [ # # ]: 0 : if (!(pool = pa_mempool_new(shared, shm_size))) {
82 : 0 : pa_log("pa_mempool_new() failed.");
83 : 0 : return NULL;
84 : : }
85 : : }
86 : :
87 : 0 : c = pa_msgobject_new(pa_core);
88 : 0 : c->parent.parent.free = core_free;
89 : 0 : c->parent.process_msg = core_process_msg;
90 : :
91 : 0 : c->state = PA_CORE_STARTUP;
92 : 0 : c->mainloop = m;
93 : :
94 : 0 : c->clients = pa_idxset_new(NULL, NULL);
95 : 0 : c->cards = pa_idxset_new(NULL, NULL);
96 : 0 : c->sinks = pa_idxset_new(NULL, NULL);
97 : 0 : c->sources = pa_idxset_new(NULL, NULL);
98 : 0 : c->sink_inputs = pa_idxset_new(NULL, NULL);
99 : 0 : c->source_outputs = pa_idxset_new(NULL, NULL);
100 : 0 : c->modules = pa_idxset_new(NULL, NULL);
101 : 0 : c->scache = pa_idxset_new(NULL, NULL);
102 : :
103 : 0 : c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
104 : 0 : c->shared = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
105 : :
106 : 0 : c->default_source = NULL;
107 : 0 : c->default_sink = NULL;
108 : :
109 : 0 : c->default_sample_spec.format = PA_SAMPLE_S16NE;
110 : 0 : c->default_sample_spec.rate = 44100;
111 : 0 : c->default_sample_spec.channels = 2;
112 : 0 : pa_channel_map_init_extend(&c->default_channel_map, c->default_sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
113 : 0 : c->default_n_fragments = 4;
114 : 0 : c->default_fragment_size_msec = 25;
115 : :
116 : 0 : c->deferred_volume_safety_margin_usec = 8000;
117 : 0 : c->deferred_volume_extra_delay_usec = 0;
118 : :
119 : 0 : c->module_defer_unload_event = NULL;
120 : 0 : c->scache_auto_unload_event = NULL;
121 : :
122 : 0 : c->subscription_defer_event = NULL;
123 : 0 : PA_LLIST_HEAD_INIT(pa_subscription, c->subscriptions);
124 : 0 : PA_LLIST_HEAD_INIT(pa_subscription_event, c->subscription_event_queue);
125 : 0 : c->subscription_event_last = NULL;
126 : :
127 : 0 : c->mempool = pool;
128 : 0 : pa_silence_cache_init(&c->silence_cache);
129 : :
130 : 0 : c->exit_event = NULL;
131 : :
132 : 0 : c->exit_idle_time = -1;
133 : 0 : c->scache_idle_time = 20;
134 : :
135 : 0 : c->flat_volumes = TRUE;
136 : 0 : c->disallow_module_loading = FALSE;
137 : 0 : c->disallow_exit = FALSE;
138 : 0 : c->running_as_daemon = FALSE;
139 : 0 : c->realtime_scheduling = FALSE;
140 : 0 : c->realtime_priority = 5;
141 : 0 : c->disable_remixing = FALSE;
142 : 0 : c->disable_lfe_remixing = FALSE;
143 : 0 : c->deferred_volume = TRUE;
144 : 0 : c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3;
145 : :
146 [ # # ]: 0 : for (j = 0; j < PA_CORE_HOOK_MAX; j++)
147 : 0 : pa_hook_init(&c->hooks[j], c);
148 : :
149 : 0 : pa_random(&c->cookie, sizeof(c->cookie));
150 : :
151 : : #ifdef SIGPIPE
152 : 0 : pa_check_signal_is_blocked(SIGPIPE);
153 : : #endif
154 : :
155 : 0 : pa_core_check_idle(c);
156 : :
157 : 0 : c->state = PA_CORE_RUNNING;
158 : :
159 : 0 : return c;
160 : : }
161 : :
162 : 0 : static void core_free(pa_object *o) {
163 : 0 : pa_core *c = PA_CORE(o);
164 : : int j;
165 [ # # ]: 0 : pa_assert(c);
166 : :
167 : 0 : c->state = PA_CORE_SHUTDOWN;
168 : :
169 : : /* Note: All modules and samples in the cache should be unloaded before
170 : : * we get here */
171 : :
172 [ # # ]: 0 : pa_assert(pa_idxset_isempty(c->scache));
173 : 0 : pa_idxset_free(c->scache, NULL, NULL);
174 : :
175 [ # # ]: 0 : pa_assert(pa_idxset_isempty(c->modules));
176 : 0 : pa_idxset_free(c->modules, NULL, NULL);
177 : :
178 [ # # ]: 0 : pa_assert(pa_idxset_isempty(c->clients));
179 : 0 : pa_idxset_free(c->clients, NULL, NULL);
180 : :
181 [ # # ]: 0 : pa_assert(pa_idxset_isempty(c->cards));
182 : 0 : pa_idxset_free(c->cards, NULL, NULL);
183 : :
184 [ # # ]: 0 : pa_assert(pa_idxset_isempty(c->sinks));
185 : 0 : pa_idxset_free(c->sinks, NULL, NULL);
186 : :
187 [ # # ]: 0 : pa_assert(pa_idxset_isempty(c->sources));
188 : 0 : pa_idxset_free(c->sources, NULL, NULL);
189 : :
190 [ # # ]: 0 : pa_assert(pa_idxset_isempty(c->source_outputs));
191 : 0 : pa_idxset_free(c->source_outputs, NULL, NULL);
192 : :
193 [ # # ]: 0 : pa_assert(pa_idxset_isempty(c->sink_inputs));
194 : 0 : pa_idxset_free(c->sink_inputs, NULL, NULL);
195 : :
196 [ # # ]: 0 : pa_assert(pa_hashmap_isempty(c->namereg));
197 : 0 : pa_hashmap_free(c->namereg, NULL, NULL);
198 : :
199 [ # # ]: 0 : pa_assert(pa_hashmap_isempty(c->shared));
200 : 0 : pa_hashmap_free(c->shared, NULL, NULL);
201 : :
202 : 0 : pa_subscription_free_all(c);
203 : :
204 [ # # ]: 0 : if (c->exit_event)
205 : 0 : c->mainloop->time_free(c->exit_event);
206 : :
207 [ # # ]: 0 : pa_assert(!c->default_source);
208 [ # # ]: 0 : pa_assert(!c->default_sink);
209 : :
210 : 0 : pa_silence_cache_done(&c->silence_cache);
211 : 0 : pa_mempool_free(c->mempool);
212 : :
213 [ # # ]: 0 : for (j = 0; j < PA_CORE_HOOK_MAX; j++)
214 : 0 : pa_hook_done(&c->hooks[j]);
215 : :
216 : 0 : pa_xfree(c);
217 : 0 : }
218 : :
219 : 0 : static void exit_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
220 : 0 : pa_core *c = userdata;
221 [ # # ]: 0 : pa_assert(c->exit_event == e);
222 : :
223 : 0 : pa_log_info("We are idle, quitting...");
224 : 0 : pa_core_exit(c, TRUE, 0);
225 : 0 : }
226 : :
227 : 0 : void pa_core_check_idle(pa_core *c) {
228 [ # # ]: 0 : pa_assert(c);
229 : :
230 [ # # ][ # # ]: 0 : if (!c->exit_event &&
231 [ # # ]: 0 : c->exit_idle_time >= 0 &&
232 : 0 : pa_idxset_size(c->clients) == 0) {
233 : :
234 : 0 : c->exit_event = pa_core_rttime_new(c, pa_rtclock_now() + c->exit_idle_time * PA_USEC_PER_SEC, exit_callback, c);
235 : :
236 [ # # ][ # # ]: 0 : } else if (c->exit_event && pa_idxset_size(c->clients) > 0) {
237 : 0 : c->mainloop->time_free(c->exit_event);
238 : 0 : c->exit_event = NULL;
239 : : }
240 : 0 : }
241 : :
242 : 0 : int pa_core_exit(pa_core *c, pa_bool_t force, int retval) {
243 [ # # ]: 0 : pa_assert(c);
244 : :
245 [ # # ][ # # ]: 0 : if (c->disallow_exit && !force)
246 : : return -1;
247 : :
248 : 0 : c->mainloop->quit(c->mainloop, retval);
249 : 0 : return 0;
250 : : }
251 : :
252 : 0 : void pa_core_maybe_vacuum(pa_core *c) {
253 [ # # ]: 0 : pa_assert(c);
254 : :
255 [ # # ][ # # ]: 0 : if (pa_idxset_isempty(c->sink_inputs) && pa_idxset_isempty(c->source_outputs)) {
256 : 0 : pa_log_debug("Hmm, no streams around, trying to vacuum.");
257 : 0 : pa_mempool_vacuum(c->mempool);
258 : : } else {
259 : : pa_sink *si;
260 : : pa_source *so;
261 : : uint32_t idx;
262 : :
263 : 0 : idx = 0;
264 [ # # ]: 0 : PA_IDXSET_FOREACH(si, c->sinks, idx)
265 [ # # ]: 0 : if (pa_sink_get_state(si) != PA_SINK_SUSPENDED)
266 : : return;
267 : :
268 : 0 : idx = 0;
269 [ # # ]: 0 : PA_IDXSET_FOREACH(so, c->sources, idx)
270 [ # # ]: 0 : if (pa_source_get_state(so) != PA_SOURCE_SUSPENDED)
271 : : return;
272 : :
273 : 0 : pa_log_info("All sinks and sources are suspended, vacuuming memory");
274 : 0 : pa_mempool_vacuum(c->mempool);
275 : : }
276 : : }
277 : :
278 : 0 : pa_time_event* pa_core_rttime_new(pa_core *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
279 : : struct timeval tv;
280 : :
281 [ # # ]: 0 : pa_assert(c);
282 [ # # ]: 0 : pa_assert(c->mainloop);
283 : :
284 : 0 : return c->mainloop->time_new(c->mainloop, pa_timeval_rtstore(&tv, usec, TRUE), cb, userdata);
285 : : }
286 : :
287 : 0 : void pa_core_rttime_restart(pa_core *c, pa_time_event *e, pa_usec_t usec) {
288 : : struct timeval tv;
289 : :
290 [ # # ]: 0 : pa_assert(c);
291 [ # # ]: 0 : pa_assert(c->mainloop);
292 : :
293 : 0 : c->mainloop->time_restart(e, pa_timeval_rtstore(&tv, usec, TRUE));
294 : 0 : }
|