device-manager: Provide a way for clients to enable/disable role-based device-priorit...
[profile/ivi/pulseaudio.git] / src / modules / module-device-manager.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2006-2008 Lennart Poettering
5   Copyright 2009 Colin Guthrie
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 <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34
35 #include <pulse/xmalloc.h>
36 #include <pulse/volume.h>
37 #include <pulse/timeval.h>
38 #include <pulse/util.h>
39 #include <pulse/rtclock.h>
40
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/module.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/modargs.h>
45 #include <pulsecore/log.h>
46 #include <pulsecore/core-subscribe.h>
47 #include <pulsecore/sink-input.h>
48 #include <pulsecore/source-output.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/protocol-native.h>
51 #include <pulsecore/pstream.h>
52 #include <pulsecore/pstream-util.h>
53 #include <pulsecore/database.h>
54
55 #include "module-device-manager-symdef.h"
56
57 PA_MODULE_AUTHOR("Colin Guthrie");
58 PA_MODULE_DESCRIPTION("Keep track of devices (and their descriptions) both past and present");
59 PA_MODULE_VERSION(PACKAGE_VERSION);
60 PA_MODULE_LOAD_ONCE(TRUE);
61 PA_MODULE_USAGE("This module does not take any arguments");
62
63 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
64
65 static const char* const valid_modargs[] = {
66     NULL
67 };
68
69 struct userdata {
70     pa_core *core;
71     pa_module *module;
72     pa_subscription *subscription;
73     pa_hook_slot
74         *sink_new_hook_slot,
75         *source_new_hook_slot,
76         *connection_unlink_hook_slot;
77     pa_time_event *save_time_event;
78     pa_database *database;
79
80     pa_native_protocol *protocol;
81     pa_idxset *subscribed;
82
83     pa_bool_t role_device_priority_routing;
84     pa_bool_t stream_restore_used;
85     pa_bool_t checked_stream_restore;
86 };
87
88 #define ENTRY_VERSION 1
89
90 struct entry {
91     uint8_t version;
92     char description[PA_NAME_MAX];
93 } PA_GCC_PACKED;
94
95 enum {
96     SUBCOMMAND_TEST,
97     SUBCOMMAND_READ,
98     SUBCOMMAND_WRITE,
99     SUBCOMMAND_DELETE,
100     SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
101     SUBCOMMAND_SUBSCRIBE,
102     SUBCOMMAND_EVENT
103 };
104
105 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
106     struct userdata *u = userdata;
107
108     pa_assert(a);
109     pa_assert(e);
110     pa_assert(u);
111
112     pa_assert(e == u->save_time_event);
113     u->core->mainloop->time_free(u->save_time_event);
114     u->save_time_event = NULL;
115
116     pa_database_sync(u->database);
117     pa_log_info("Synced.");
118 }
119
120 static struct entry* read_entry(struct userdata *u, const char *name) {
121     pa_datum key, data;
122     struct entry *e;
123
124     pa_assert(u);
125     pa_assert(name);
126
127     key.data = (char*) name;
128     key.size = strlen(name);
129
130     pa_zero(data);
131
132     if (!pa_database_get(u->database, &key, &data))
133         goto fail;
134
135     if (data.size != sizeof(struct entry)) {
136         pa_log_debug("Database contains entry for device %s of wrong size %lu != %lu. Probably due to upgrade, ignoring.", name, (unsigned long) data.size, (unsigned long) sizeof(struct entry));
137         goto fail;
138     }
139
140     e = (struct entry*) data.data;
141
142     if (e->version != ENTRY_VERSION) {
143         pa_log_debug("Version of database entry for device %s doesn't match our version. Probably due to upgrade, ignoring.", name);
144         goto fail;
145     }
146
147     if (!memchr(e->description, 0, sizeof(e->description))) {
148         pa_log_warn("Database contains entry for device %s with missing NUL byte in description", name);
149         goto fail;
150     }
151
152     return e;
153
154 fail:
155
156     pa_datum_free(&data);
157     return NULL;
158 }
159
160 static void trigger_save(struct userdata *u) {
161     if (u->save_time_event)
162         return;
163
164     u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
165 }
166
167 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
168     if (strncmp(a->description, b->description, sizeof(a->description)))
169         return FALSE;
170
171     return TRUE;
172 }
173
174 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
175     struct userdata *u = userdata;
176     struct entry entry, *old = NULL;
177     char *name = NULL;
178     pa_datum key, data;
179
180     pa_assert(c);
181     pa_assert(u);
182
183     if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
184         t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
185         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
186         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE))
187         return;
188
189     pa_zero(entry);
190     entry.version = ENTRY_VERSION;
191
192     if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
193         pa_sink *sink;
194
195         if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
196             return;
197
198         name = pa_sprintf_malloc("sink:%s", sink->name);
199
200         if ((old = read_entry(u, name)))
201             entry = *old;
202
203         pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
204
205     } else {
206         pa_source *source;
207
208         pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
209
210         if (!(source = pa_idxset_get_by_index(c->sources, idx)))
211             return;
212
213         if (source->monitor_of)
214             return;
215
216         name = pa_sprintf_malloc("source:%s", source->name);
217
218         if ((old = read_entry(u, name)))
219             entry = *old;
220
221         pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
222     }
223
224     if (old) {
225
226         if (entries_equal(old, &entry)) {
227             pa_xfree(old);
228             pa_xfree(name);
229             return;
230         }
231
232         pa_xfree(old);
233     }
234
235     key.data = name;
236     key.size = strlen(name);
237
238     data.data = &entry;
239     data.size = sizeof(entry);
240
241     pa_log_info("Storing device description for %s.", name);
242
243     pa_database_set(u->database, &key, &data, TRUE);
244
245     pa_xfree(name);
246
247     trigger_save(u);
248 }
249
250 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
251     char *name;
252     struct entry *e;
253
254     pa_assert(c);
255     pa_assert(new_data);
256     pa_assert(u);
257
258     name = pa_sprintf_malloc("sink:%s", new_data->name);
259
260     if ((e = read_entry(u, name))) {
261         if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
262             pa_log_info("Restoring description for sink %s.", new_data->name);
263             pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
264         }
265
266         pa_xfree(e);
267     }
268
269     pa_xfree(name);
270
271     return PA_HOOK_OK;
272 }
273
274 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
275     char *name;
276     struct entry *e;
277
278     pa_assert(c);
279     pa_assert(new_data);
280     pa_assert(u);
281
282     name = pa_sprintf_malloc("source:%s", new_data->name);
283
284     if ((e = read_entry(u, name))) {
285
286         if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
287             /* NB, We cannot detect if we are a monitor here... this could mess things up a bit... */
288             pa_log_info("Restoring description for sink %s.", new_data->name);
289             pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
290         }
291
292         pa_xfree(e);
293     }
294
295     pa_xfree(name);
296
297     return PA_HOOK_OK;
298 }
299
300 static char *get_name(const char *key, const char *prefix) {
301     char *t;
302
303     if (strncmp(key, prefix, strlen(prefix)))
304         return NULL;
305
306     t = pa_xstrdup(key + strlen(prefix));
307     return t;
308 }
309
310 static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
311     pa_sink *sink;
312     pa_source *source;
313     uint32_t idx;
314     char *n;
315
316     pa_assert(u);
317     pa_assert(name);
318     pa_assert(e);
319
320     if ((n = get_name(name, "sink:"))) {
321         for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx)) {
322             if (!pa_streq(sink->name, n)) {
323                 continue;
324             }
325
326             pa_log_info("Setting description for sink %s.", sink->name);
327             pa_sink_set_description(sink, e->description);
328         }
329         pa_xfree(n);
330     }
331     else if ((n = get_name(name, "source:"))) {
332         for (source = pa_idxset_first(u->core->sources, &idx); source; source = pa_idxset_next(u->core->sources, &idx)) {
333             if (!pa_streq(source->name, n)) {
334                 continue;
335             }
336
337             if (source->monitor_of) {
338                 pa_log_warn("Cowardly refusing to set the description for monitor source %s.", source->name);
339                 continue;
340             }
341
342             pa_log_info("Setting description for source %s.", source->name);
343             pa_source_set_description(source, e->description);
344         }
345         pa_xfree(n);
346     }
347 }
348
349 #define EXT_VERSION 1
350
351 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
352   struct userdata *u;
353   uint32_t command;
354   pa_tagstruct *reply = NULL;
355
356   pa_assert(p);
357   pa_assert(m);
358   pa_assert(c);
359   pa_assert(t);
360
361   u = m->userdata;
362
363   if (pa_tagstruct_getu32(t, &command) < 0)
364     goto fail;
365
366   reply = pa_tagstruct_new(NULL, 0);
367   pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
368   pa_tagstruct_putu32(reply, tag);
369
370   switch (command) {
371     case SUBCOMMAND_TEST: {
372       if (!pa_tagstruct_eof(t))
373         goto fail;
374
375       pa_tagstruct_putu32(reply, EXT_VERSION);
376       break;
377     }
378
379     case SUBCOMMAND_READ: {
380       pa_datum key;
381       pa_bool_t done;
382
383       if (!pa_tagstruct_eof(t))
384         goto fail;
385
386       done = !pa_database_first(u->database, &key, NULL);
387
388       while (!done) {
389         pa_datum next_key;
390         struct entry *e;
391         char *name;
392
393         done = !pa_database_next(u->database, &key, &next_key, NULL);
394
395         name = pa_xstrndup(key.data, key.size);
396         pa_datum_free(&key);
397
398         if ((e = read_entry(u, name))) {
399           pa_tagstruct_puts(reply, name);
400           pa_tagstruct_puts(reply, e->description);
401
402           pa_xfree(e);
403         }
404
405         pa_xfree(name);
406
407         key = next_key;
408       }
409
410       break;
411     }
412
413     case SUBCOMMAND_WRITE: {
414       uint32_t mode;
415       pa_bool_t apply_immediately = FALSE;
416
417       if (pa_tagstruct_getu32(t, &mode) < 0 ||
418         pa_tagstruct_get_boolean(t, &apply_immediately) < 0)
419         goto fail;
420
421       if (mode != PA_UPDATE_MERGE &&
422         mode != PA_UPDATE_REPLACE &&
423         mode != PA_UPDATE_SET)
424         goto fail;
425
426       if (mode == PA_UPDATE_SET)
427         pa_database_clear(u->database);
428
429       while (!pa_tagstruct_eof(t)) {
430         const char *name, *description;
431         struct entry entry;
432         pa_datum key, data;
433
434         pa_zero(entry);
435         entry.version = ENTRY_VERSION;
436
437         if (pa_tagstruct_gets(t, &name) < 0 ||
438           pa_tagstruct_gets(t, &description) < 0)
439           goto fail;
440
441         if (!name || !*name)
442           goto fail;
443
444         pa_strlcpy(entry.description, description, sizeof(entry.description));
445
446         key.data = (char*) name;
447         key.size = strlen(name);
448
449         data.data = &entry;
450         data.size = sizeof(entry);
451
452         if (pa_database_set(u->database, &key, &data, mode == PA_UPDATE_REPLACE) == 0)
453           if (apply_immediately)
454             apply_entry(u, name, &entry);
455       }
456
457       trigger_save(u);
458
459       break;
460     }
461
462     case SUBCOMMAND_DELETE:
463
464       while (!pa_tagstruct_eof(t)) {
465         const char *name;
466         pa_datum key;
467
468         if (pa_tagstruct_gets(t, &name) < 0)
469           goto fail;
470
471         key.data = (char*) name;
472         key.size = strlen(name);
473
474         pa_database_unset(u->database, &key);
475       }
476
477       trigger_save(u);
478
479       break;
480
481     case SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING:
482
483         while (!pa_tagstruct_eof(t)) {
484             pa_bool_t enable;
485             uint32_t sridx = PA_INVALID_INDEX;
486             uint32_t idx;
487             pa_module *module;
488
489             if (pa_tagstruct_get_boolean(t, &enable) < 0)
490                 goto fail;
491
492             /* If this is the first run, check for stream restore module */
493             if (!u->checked_stream_restore) {
494                 u->checked_stream_restore = TRUE;
495
496                 for (module = pa_idxset_first(u->core->modules, &idx); module; module = pa_idxset_next(u->core->modules, &idx)) {
497                     if (strcmp(module->name, "module-stream-restore") == 0) {
498                         pa_log_debug("Detected module-stream-restore is currently in use");
499                         u->stream_restore_used = TRUE;
500                         sridx = module->index;
501                     }
502                 }
503             }
504
505             u->role_device_priority_routing = enable;
506             if (enable) {
507                 if (u->stream_restore_used) {
508                     if (PA_INVALID_INDEX == sridx) {
509                         /* As a shortcut on first load, we have sridx filled in, but otherwise we search for it. */
510                         for (module = pa_idxset_first(u->core->modules, &idx); module; module = pa_idxset_next(u->core->modules, &idx)) {
511                             if (strcmp(module->name, "module-stream-restore") == 0) {
512                                 sridx = module->index;
513                             }
514                         }
515                     }
516                     if (PA_INVALID_INDEX != sridx) {
517                         pa_log_debug("Unloading module-stream-restore to enable role-based device-priority routing");
518                         pa_module_unload_request_by_index(u->core, sridx, TRUE);
519                     }
520                 }
521             } else if (u->stream_restore_used) {
522                 /* We want to reload module-stream-restore */
523                 if (!pa_module_load(u->core, "module-stream-restore", ""))
524                     pa_log_warn("Failed to load module-stream-restore while disabling role-based device-priority routing");
525             }
526         }
527
528         trigger_save(u);
529
530         break;
531
532     case SUBCOMMAND_SUBSCRIBE: {
533
534       pa_bool_t enabled;
535
536       if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
537         !pa_tagstruct_eof(t))
538         goto fail;
539
540       if (enabled)
541         pa_idxset_put(u->subscribed, c, NULL);
542       else
543         pa_idxset_remove_by_data(u->subscribed, c, NULL);
544
545       break;
546     }
547
548     default:
549       goto fail;
550   }
551
552   pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
553   return 0;
554
555   fail:
556
557   if (reply)
558     pa_tagstruct_free(reply);
559
560   return -1;
561 }
562
563 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
564     pa_assert(p);
565     pa_assert(c);
566     pa_assert(u);
567
568     pa_idxset_remove_by_data(u->subscribed, c, NULL);
569     return PA_HOOK_OK;
570 }
571
572 int pa__init(pa_module*m) {
573     pa_modargs *ma = NULL;
574     struct userdata *u;
575     char *fname;
576     pa_sink *sink;
577     pa_source *source;
578     uint32_t idx;
579
580     pa_assert(m);
581
582     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
583         pa_log("Failed to parse module arguments");
584         goto fail;
585     }
586
587     m->userdata = u = pa_xnew0(struct userdata, 1);
588     u->core = m->core;
589     u->module = m;
590     u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
591
592     u->protocol = pa_native_protocol_get(m->core);
593     pa_native_protocol_install_ext(u->protocol, m, extension_cb);
594
595     u->connection_unlink_hook_slot = pa_hook_connect(&pa_native_protocol_hooks(u->protocol)[PA_NATIVE_HOOK_CONNECTION_UNLINK], PA_HOOK_NORMAL, (pa_hook_cb_t) connection_unlink_hook_cb, u);
596
597     u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
598
599     u->sink_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_new_hook_callback, u);
600     u->source_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) source_new_hook_callback, u);
601
602     if (!(fname = pa_state_path("device-manager", TRUE)))
603         goto fail;
604
605     if (!(u->database = pa_database_open(fname, TRUE))) {
606         pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
607         pa_xfree(fname);
608         goto fail;
609     }
610
611     pa_log_info("Sucessfully opened database file '%s'.", fname);
612     pa_xfree(fname);
613
614     for (sink = pa_idxset_first(m->core->sinks, &idx); sink; sink = pa_idxset_next(m->core->sinks, &idx))
615         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
616
617     for (source = pa_idxset_first(m->core->sources, &idx); source; source = pa_idxset_next(m->core->sources, &idx))
618         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
619
620     pa_modargs_free(ma);
621     return 0;
622
623 fail:
624     pa__done(m);
625
626     if (ma)
627         pa_modargs_free(ma);
628
629     return  -1;
630 }
631
632 void pa__done(pa_module*m) {
633     struct userdata* u;
634
635     pa_assert(m);
636
637     if (!(u = m->userdata))
638         return;
639
640     if (u->subscription)
641         pa_subscription_free(u->subscription);
642
643     if (u->sink_new_hook_slot)
644         pa_hook_slot_free(u->sink_new_hook_slot);
645     if (u->source_new_hook_slot)
646         pa_hook_slot_free(u->source_new_hook_slot);
647
648     if (u->save_time_event)
649         u->core->mainloop->time_free(u->save_time_event);
650
651     if (u->database)
652         pa_database_close(u->database);
653
654     if (u->protocol) {
655         pa_native_protocol_remove_ext(u->protocol, m);
656         pa_native_protocol_unref(u->protocol);
657     }
658
659     if (u->subscribed)
660         pa_idxset_free(u->subscribed, NULL, NULL);
661
662     pa_xfree(u);
663 }