source: roaraudio/libroarpulse/context.c @ 4960:60cdebcb83ef

Last change on this file since 4960:60cdebcb83ef was 4708:c9d40761088a, checked in by phi, 13 years ago

updated copyright statements

File size: 8.6 KB
Line 
1//context.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
5 *  The code (may) include prototypes and comments (and maybe
6 *  other code fragements) from libpulse*. They are mostly copyrighted by:
7 *  Lennart Poettering <poettering@users.sourceforge.net> and
8 *  Pierre Ossman <drzeus@drzeus.cx>
9 *
10 *  This file is part of libroarpulse a part of RoarAudio,
11 *  a cross-platform sound system for both, home and professional use.
12 *  See README for details.
13 *
14 *  This file is free software; you can redistribute it and/or modify
15 *  it under the terms of the GNU General Public License version 3
16 *  as published by the Free Software Foundation.
17 *
18 *  RoarAudio is distributed in the hope that it will be useful,
19 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 *  GNU General Public License for more details.
22 *
23 *  You should have received a copy of the GNU General Public License
24 *  along with this software; see the file COPYING.  If not, write to
25 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
26 *  Boston, MA 02110-1301, USA.
27 *
28 *  NOTE for everyone want's to change something and send patches:
29 *  read README and HACKING! There a addition information on
30 *  the license of this document you need to read before you send
31 *  any patches.
32 *
33 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
34 *  or libpulse*:
35 *  The libs libroaresd, libroararts and libroarpulse link this libroar
36 *  and are therefore GPL. Because of this it may be illigal to use
37 *  them with any software that uses libesd, libartsc or libpulse*.
38 */
39
40#include <libroarpulse/libroarpulse.h>
41
42struct _roar_pa_cb_st {
43 union {
44  pa_context_success_cb_t scb;
45  pa_context_notify_cb_t  ncb;
46 } cb;
47 void * userdata;
48};
49
50#define _call_cbs(x,c,s) ((x).cb.scb == NULL ? (void)0 : (x).cb.scb((c), (s), (x).userdata))
51#define _call_cbn(x,c)   ((x).cb.ncb == NULL ? (void)0 : (x).cb.ncb((c), (x).userdata))
52
53struct pa_context {
54 size_t refc;
55 struct roar_connection con;
56 char * server;
57 char * name;
58 int state;
59 int errnum;
60 struct {
61  struct _roar_pa_cb_st set_name;
62  struct _roar_pa_cb_st state_change;
63 } cb;
64 pa_mainloop_api * mainloop;
65};
66
67// older versions:
68typedef struct pa_proplist pa_proplist;
69pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist);
70
71void pa_context_set_state(pa_context *c, pa_context_state_t st);
72
73pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) {
74 return pa_context_new_with_proplist(mainloop, name, NULL);
75}
76
77pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist) {
78 pa_context * c;
79
80 if ( proplist != NULL )
81  return NULL;
82
83 if ( (c = roar_mm_malloc(sizeof(pa_context))) == NULL )
84  return NULL;
85
86 memset(c, 0, sizeof(pa_context));
87
88 c->refc  = 1;
89
90 c->state = PA_CONTEXT_UNCONNECTED;
91
92 c->errnum = PA_OK;
93
94 if ( name != NULL ) {
95  c->name = roar_mm_strdup(name);
96 }
97
98 c->mainloop = mainloop;
99
100 return c;
101}
102
103static void _context_free(pa_context *c) {
104 pa_context_disconnect(c);
105
106 if ( c->server != NULL )
107  roar_mm_free(c->server);
108
109 if ( c->name != NULL )
110  roar_mm_free(c->name);
111
112 roar_mm_free(c);
113}
114
115pa_context* pa_context_ref(pa_context *c) {
116 c->refc++;
117 return c;
118}
119
120void pa_context_unref(pa_context *c) {
121 c->refc--;
122
123 if ( c->refc < 1 )
124  _context_free(c);
125}
126
127int pa_context_connect(
128        pa_context *c,
129        const char *server,
130        pa_context_flags_t flags,
131        const pa_spawn_api *api) {
132
133 if ( c == NULL )
134  return -1;
135
136 if ( c->state != PA_CONTEXT_UNCONNECTED ) {
137  c->errnum = PA_ERR_BADSTATE;
138  pa_context_set_state(c, PA_CONTEXT_FAILED);
139  return -1;
140 }
141
142 // we do currently not support to spawn a daemon, so we ignore flags and api.
143
144 server = roar_pa_find_server((char*)server);
145
146 if ( roar_simple_connect(&(c->con), (char*)server,
147                          c->name != NULL ? c->name : "libroarpulse [pa_context_connect()]") == -1 ) {
148  c->errnum = PA_ERR_CONNECTIONREFUSED;
149  pa_context_set_state(c, PA_CONTEXT_FAILED);
150  return -1;
151 }
152
153 if ( server == NULL ) {
154  c->server = NULL;
155 } else {
156  c->server = roar_mm_strdup(server);
157 }
158
159 pa_context_set_state(c, PA_CONTEXT_READY);
160
161 _call_cbs(c->cb.set_name, c, 1);
162
163 return 0;
164}
165
166void pa_context_disconnect(pa_context *c) {
167 if ( c == NULL )
168  return;
169
170 if ( c->state != PA_CONTEXT_READY )
171  return;
172
173 roar_disconnect(&(c->con));
174
175 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
176}
177
178struct roar_connection * roar_pa_context_get_con(pa_context * c) {
179 if ( c == NULL )
180  return NULL;
181
182 if ( c->state != PA_CONTEXT_READY )
183  return NULL;
184
185 return &(c->con);
186}
187
188pa_mainloop_api * roar_pa_context_get_api(pa_context * c) {
189 if ( c == NULL )
190  return NULL;
191
192 return c->mainloop;
193}
194
195/** Set a callback function that is called whenever the context status changes */
196void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
197 if ( c == NULL )
198  return;
199
200 c->cb.state_change.cb.ncb   = cb;
201 c->cb.state_change.userdata = userdata;
202}
203
204void pa_context_set_state(pa_context *c, pa_context_state_t st) {
205 if ( c == NULL )
206  return;
207
208 c->state = st;
209
210 _call_cbn(c->cb.state_change, c);
211}
212
213/** Return the error number of the last failed operation */
214int pa_context_errno(pa_context *c) {
215 if ( c == NULL )
216  return PA_ERR_INVALID;
217
218 return c->errnum;
219}
220
221/** Return non-zero if some data is pending to be written to the connection */
222int pa_context_is_pending(pa_context *c) {
223 return 0;
224}
225
226/** Return the current context status */
227pa_context_state_t pa_context_get_state(pa_context *c) {
228 if ( c == NULL )
229  return PA_CONTEXT_FAILED;
230
231 return c->state;
232}
233
234/** Drain the context. If there is nothing to drain, the function returns NULL */
235pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
236
237 if ( cb != NULL )
238  cb(c, userdata);
239
240 return NULL;
241}
242
243/** Tell the daemon to exit. The returned operation is unlikely to
244 * complete succesfully, since the daemon probably died before
245 * returning a success notification */
246pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
247 int s = 1;
248
249 if ( c == NULL )
250  return roar_pa_operation_new(PA_OPERATION_DONE);
251
252 if ( c->state == PA_CONTEXT_READY ) {
253  if ( roar_terminate(&(c->con), 0) == -1 ) {
254   c->errnum = PA_ERR_INTERNAL;
255   s = 0;
256  }
257 } else {
258  c->errnum = PA_ERR_BADSTATE;
259  s = 0;
260 }
261
262 if ( cb != NULL )
263  cb(c, s, userdata);
264
265 return roar_pa_operation_new(PA_OPERATION_DONE);
266}
267
268/** Set the name of the default sink. \since 0.4 */
269pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
270 if ( c != NULL )
271  c->errnum = PA_ERR_NOTSUPPORTED;
272
273 if ( cb != NULL )
274  cb(c, strcasecmp(name, ROAR_PA_DEFAULT_SINK) == 0 ? 1 : 0, userdata);
275
276 return roar_pa_operation_new(PA_OPERATION_DONE);
277}
278
279/** Set the name of the default source. \since 0.4 */
280pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
281 if ( c != NULL )
282  c->errnum = PA_ERR_NOTSUPPORTED;
283
284 if ( cb != NULL )
285  cb(c, strcasecmp(name, ROAR_PA_DEFAULT_SOURCE) == 0 ? 1 : 0, userdata);
286
287 return roar_pa_operation_new(PA_OPERATION_DONE);
288}
289
290/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */
291int pa_context_is_local(pa_context *c) {
292 if ( c == NULL )
293  return -1;
294
295 if ( c->state != PA_CONTEXT_READY )
296  return -1;
297
298 // how is /local/ defined?
299 return 0;
300}
301
302/** Set a different application name for context on the server. \since 0.5 */
303pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
304 if ( c == NULL )
305  return roar_pa_operation_new(PA_OPERATION_DONE);
306
307 if ( c->state != PA_CONTEXT_UNCONNECTED ) {
308  c->errnum = PA_ERR_BADSTATE;
309
310  if ( cb != NULL )
311   cb(c, 0, userdata);
312
313  return roar_pa_operation_new(PA_OPERATION_DONE);
314 }
315
316 if ( c->name != NULL )
317  roar_mm_free(c->name);
318
319 c->name = roar_mm_strdup(name);
320 c->cb.set_name.cb.scb   = cb;
321 c->cb.set_name.userdata = userdata;
322
323 return roar_pa_operation_new(PA_OPERATION_DONE);
324}
325
326/** Return the server name this context is connected to. \since 0.7 */
327const char* pa_context_get_server(pa_context *c) {
328 if ( c == NULL )
329  return NULL;
330
331 return c->server;
332}
333
334/** Return the protocol version of the library. \since 0.8 */
335uint32_t pa_context_get_protocol_version(pa_context *c) {
336 return 0;
337}
338
339/** Return the protocol version of the connected server. \since 0.8 */
340uint32_t pa_context_get_server_protocol_version(pa_context *c) {
341 return 0;
342}
343
344
345//ll
Note: See TracBrowser for help on using the repository browser.