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, see <http://www.gnu.org/licenses/>.
19***/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include <pulse/xmalloc.h>
30#include <pulse/util.h>
31
32#include <pulsecore/core-subscribe.h>
33#include <pulsecore/log.h>
34#include <pulsecore/macro.h>
35#include <pulsecore/core-util.h>
36
37#include "client.h"
38
39pa_client_new_data* pa_client_new_data_init(pa_client_new_data *data) {
40    pa_assert(data);
41
42    memset(data, 0, sizeof(*data));
43    data->proplist = pa_proplist_new();
44
45    return data;
46}
47
48void pa_client_new_data_done(pa_client_new_data *data) {
49    pa_assert(data);
50
51    pa_proplist_free(data->proplist);
52}
53
54pa_client *pa_client_new(pa_core *core, pa_client_new_data *data) {
55    pa_client *c;
56
57    pa_core_assert_ref(core);
58    pa_assert(data);
59
60    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_NEW], data) < 0)
61        return NULL;
62
63    c = pa_xnew0(pa_client, 1);
64    c->core = core;
65    c->proplist = pa_proplist_copy(data->proplist);
66    c->driver = pa_xstrdup(pa_path_get_filename(data->driver));
67    c->module = data->module;
68
69    c->sink_inputs = pa_idxset_new(NULL, NULL);
70    c->source_outputs = pa_idxset_new(NULL, NULL);
71
72    pa_assert_se(pa_idxset_put(core->clients, c, &c->index) >= 0);
73
74    pa_log_info("Created %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)));
75    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index);
76
77    pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_PUT], c);
78
79    pa_core_check_idle(core);
80
81    return c;
82}
83
84void pa_client_free(pa_client *c) {
85    pa_core *core;
86
87    pa_assert(c);
88    pa_assert(c->core);
89
90    core = c->core;
91
92    pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_UNLINK], c);
93
94    pa_idxset_remove_by_data(c->core->clients, c, NULL);
95
96    pa_log_info("Freed %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)));
97    pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);
98
99    pa_assert(pa_idxset_isempty(c->sink_inputs));
100    pa_idxset_free(c->sink_inputs, NULL);
101    pa_assert(pa_idxset_isempty(c->source_outputs));
102    pa_idxset_free(c->source_outputs, NULL);
103
104    pa_proplist_free(c->proplist);
105    pa_xfree(c->driver);
106    pa_xfree(c);
107
108    pa_core_check_idle(core);
109}
110
111void pa_client_kill(pa_client *c) {
112    pa_assert(c);
113
114    if (!c->kill) {
115        pa_log_warn("kill() operation not implemented for client %u", c->index);
116        return;
117    }
118
119    c->kill(c);
120}
121
122void pa_client_set_name(pa_client *c, const char *name) {
123    pa_assert(c);
124    pa_assert(name);
125
126    pa_log_info("Client %u changed name from \"%s\" to \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)), name);
127    pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);
128
129    pa_client_update_proplist(c, 0, NULL);
130}
131
132void pa_client_update_proplist(pa_client *c, pa_update_mode_t mode, pa_proplist *p) {
133    pa_assert(c);
134
135    if (p)
136        pa_proplist_update(c->proplist, mode, p);
137
138    pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED], c);
139    pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->index);
140}
141
142void pa_client_send_event(pa_client *c, const char *event, pa_proplist *data) {
143    pa_proplist *pl = NULL;
144    pa_client_send_event_hook_data hook_data;
145
146    pa_assert(c);
147    pa_assert(event);
148
149    if (!c->send_event)
150        return;
151
152    if (!data)
153        data = pl = pa_proplist_new();
154
155    hook_data.client = c;
156    hook_data.data = data;
157    hook_data.event = event;
158
159    if (pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CLIENT_SEND_EVENT], &hook_data) < 0)
160        goto finish;
161
162    c->send_event(c, event, data);
163
164finish:
165
166    if (pl)
167        pa_proplist_free(pl);
168}
169