• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2006-2008 Lennart Poettering
5 
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10 
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15 
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18 ***/
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #include <errno.h>
25 #include <stdio.h>
26 
27 #include <pulse/rtclock.h>
28 #include <pulse/timeval.h>
29 #include <pulse/xmalloc.h>
30 
31 #include <pulsecore/core-util.h>
32 #include <pulsecore/module.h>
33 #include <pulsecore/log.h>
34 #include <pulsecore/namereg.h>
35 #include <pulsecore/core-error.h>
36 
37 PA_MODULE_AUTHOR("Lennart Poettering");
38 PA_MODULE_DESCRIPTION("Automatically restore the default sink and source");
39 PA_MODULE_VERSION(PACKAGE_VERSION);
40 PA_MODULE_LOAD_ONCE(true);
41 
42 #define SAVE_INTERVAL (5 * PA_USEC_PER_SEC)
43 
44 struct userdata {
45     pa_core *core;
46     pa_subscription *subscription;
47     pa_time_event *time_event;
48     char *sink_filename, *source_filename;
49     bool modified;
50 };
51 
load(struct userdata * u)52 static void load(struct userdata *u) {
53     FILE *f;
54 
55     /* We never overwrite manually configured settings */
56 
57     if (u->core->configured_default_sink)
58         pa_log_info("Manually configured default sink, not overwriting.");
59     else if ((f = pa_fopen_cloexec(u->sink_filename, "r"))) {
60         char ln[256] = "";
61 
62         if (fgets(ln, sizeof(ln)-1, f))
63             pa_strip_nl(ln);
64         fclose(f);
65 
66         if (!ln[0])
67             pa_log_info("No previous default sink setting, ignoring.");
68         else if (!pa_namereg_is_valid_name(ln))
69             pa_log_warn("Invalid sink name: %s", ln);
70         else {
71             pa_log_info("Restoring default sink '%s'.", ln);
72             pa_core_set_configured_default_sink(u->core, ln);
73         }
74 
75     } else if (errno != ENOENT)
76         pa_log("Failed to load default sink: %s", pa_cstrerror(errno));
77 
78     if (u->core->configured_default_source)
79         pa_log_info("Manually configured default source, not overwriting.");
80     else if ((f = pa_fopen_cloexec(u->source_filename, "r"))) {
81         char ln[256] = "";
82 
83         if (fgets(ln, sizeof(ln)-1, f))
84             pa_strip_nl(ln);
85         fclose(f);
86 
87         if (!ln[0])
88             pa_log_info("No previous default source setting, ignoring.");
89         else if (!pa_namereg_is_valid_name(ln))
90             pa_log_warn("Invalid source name: %s", ln);
91         else {
92             pa_log_info("Restoring default source '%s'.", ln);
93             pa_core_set_configured_default_source(u->core, ln);
94         }
95 
96     } else if (errno != ENOENT)
97         pa_log("Failed to load default source: %s", pa_cstrerror(errno));
98 }
99 
save(struct userdata * u)100 static void save(struct userdata *u) {
101     FILE *f;
102 
103     if (!u->modified)
104         return;
105 
106     if (u->sink_filename) {
107         if ((f = pa_fopen_cloexec(u->sink_filename, "w"))) {
108             fprintf(f, "%s\n", u->core->configured_default_sink ? u->core->configured_default_sink : "");
109             fclose(f);
110         } else
111             pa_log("Failed to save default sink: %s", pa_cstrerror(errno));
112     }
113 
114     if (u->source_filename) {
115         if ((f = pa_fopen_cloexec(u->source_filename, "w"))) {
116             fprintf(f, "%s\n", u->core->configured_default_source ? u->core->configured_default_source : "");
117             fclose(f);
118         } else
119             pa_log("Failed to save default source: %s", pa_cstrerror(errno));
120     }
121 
122     u->modified = false;
123 }
124 
time_cb(pa_mainloop_api * a,pa_time_event * e,const struct timeval * t,void * userdata)125 static void time_cb(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) {
126     struct userdata *u = userdata;
127 
128     pa_assert(u);
129     save(u);
130 
131     if (u->time_event) {
132         u->core->mainloop->time_free(u->time_event);
133         u->time_event = NULL;
134     }
135 }
136 
subscribe_cb(pa_core * c,pa_subscription_event_type_t t,uint32_t idx,void * userdata)137 static void subscribe_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
138     struct userdata *u = userdata;
139 
140     pa_assert(u);
141 
142     u->modified = true;
143 
144     if (!u->time_event)
145         u->time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, time_cb, u);
146 }
147 
pa__init(pa_module * m)148 int pa__init(pa_module *m) {
149     struct userdata *u;
150 
151     pa_assert(m);
152 
153     m->userdata = u = pa_xnew0(struct userdata, 1);
154     u->core = m->core;
155 
156     if (!(u->sink_filename = pa_state_path("default-sink", true)))
157         goto fail;
158 
159     if (!(u->source_filename = pa_state_path("default-source", true)))
160         goto fail;
161 
162     load(u);
163 
164     u->subscription = pa_subscription_new(u->core, PA_SUBSCRIPTION_MASK_SERVER, subscribe_cb, u);
165 
166     return 0;
167 
168 fail:
169     pa__done(m);
170 
171     return -1;
172 }
173 
pa__done(pa_module * m)174 void pa__done(pa_module*m) {
175     struct userdata *u;
176 
177     pa_assert(m);
178 
179     if (!(u = m->userdata))
180         return;
181 
182     save(u);
183 
184     if (u->subscription)
185         pa_subscription_free(u->subscription);
186 
187     if (u->time_event)
188         m->core->mainloop->time_free(u->time_event);
189 
190     pa_xfree(u->sink_filename);
191     pa_xfree(u->source_filename);
192     pa_xfree(u);
193 }
194