source: roaraudio/libroarpulse/context.c @ 5509:cd1927035f25

Last change on this file since 5509:cd1927035f25 was 5381:430b1d26e12d, checked in by phi, 12 years ago

updated copyright years

File size: 9.6 KB
Line 
1//context.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2012
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 pa_context_flags_t flags_left = flags;
133
134 if ( c == NULL )
135  return -1;
136
137 flags_left |= PA_CONTEXT_NOAUTOSPAWN;
138 flags_left -= PA_CONTEXT_NOAUTOSPAWN;
139#ifdef PA_CONTEXT_NOFAIL
140 flags_left |= PA_CONTEXT_NOFAIL;
141 flags_left -= PA_CONTEXT_NOFAIL;
142#endif
143#ifdef PA_CONTEXT_NOFLAGS
144 flags_left |= PA_CONTEXT_NOFLAGS;
145 flags_left -= PA_CONTEXT_NOFLAGS;
146#endif
147
148 if ( flags_left != 0 )
149  return -1;
150
151 if ( c->state != PA_CONTEXT_UNCONNECTED ) {
152  c->errnum = PA_ERR_BADSTATE;
153  pa_context_set_state(c, PA_CONTEXT_FAILED);
154  return -1;
155 }
156
157 // flags may contain the following values:
158#if 0
159    PA_CONTEXT_NOFLAGS = 0x0000U,
160    /**< Flag to pass when no specific options are needed (used to avoid casting)  \since 0.9.19 */
161    PA_CONTEXT_NOAUTOSPAWN = 0x0001U,
162    /**< Disabled autospawning of the PulseAudio daemon if required */
163    PA_CONTEXT_NOFAIL = 0x0002U
164    /**< Don't fail if the daemon is not available when pa_context_connect() is called, instead enter PA_CONTEXT_CONNECTING state and wait for the daemon to appear.  \since 0.9.15 */
165#endif
166
167 // we do currently not support to spawn a daemon, so we ignore flags and api.
168
169 server = roar_pa_find_server(server);
170
171 if ( roar_simple_connect(&(c->con), server,
172                          c->name != NULL ? c->name : "libroarpulse [pa_context_connect()]") == -1 ) {
173  c->errnum = PA_ERR_CONNECTIONREFUSED;
174  pa_context_set_state(c, PA_CONTEXT_FAILED);
175
176#ifdef PA_CONTEXT_NOFAIL
177  if ( flags & PA_CONTEXT_NOFAIL ) {
178   pa_context_set_state(c, PA_CONTEXT_CONNECTING);
179   return 0;
180  }
181#endif
182  return -1;
183 }
184
185 if ( server == NULL ) {
186  c->server = NULL;
187 } else {
188  c->server = roar_mm_strdup(server);
189 }
190
191 pa_context_set_state(c, PA_CONTEXT_READY);
192
193 _call_cbs(c->cb.set_name, c, 1);
194
195 return 0;
196}
197
198void pa_context_disconnect(pa_context *c) {
199 if ( c == NULL )
200  return;
201
202 if ( c->state != PA_CONTEXT_READY )
203  return;
204
205 roar_disconnect(&(c->con));
206
207 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
208}
209
210struct roar_connection * roar_pa_context_get_con(pa_context * c) {
211 if ( c == NULL )
212  return NULL;
213
214 if ( c->state != PA_CONTEXT_READY )
215  return NULL;
216
217 return &(c->con);
218}
219
220pa_mainloop_api * roar_pa_context_get_api(pa_context * c) {
221 if ( c == NULL )
222  return NULL;
223
224 return c->mainloop;
225}
226
227/** Set a callback function that is called whenever the context status changes */
228void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
229 if ( c == NULL )
230  return;
231
232 c->cb.state_change.cb.ncb   = cb;
233 c->cb.state_change.userdata = userdata;
234}
235
236void pa_context_set_state(pa_context *c, pa_context_state_t st) {
237 if ( c == NULL )
238  return;
239
240 c->state = st;
241
242 _call_cbn(c->cb.state_change, c);
243}
244
245/** Return the error number of the last failed operation */
246int pa_context_errno(pa_context *c) {
247 if ( c == NULL )
248  return PA_ERR_INVALID;
249
250 return c->errnum;
251}
252
253/** Return non-zero if some data is pending to be written to the connection */
254int pa_context_is_pending(pa_context *c) {
255 (void)c;
256 return 0;
257}
258
259/** Return the current context status */
260pa_context_state_t pa_context_get_state(pa_context *c) {
261 if ( c == NULL )
262  return PA_CONTEXT_FAILED;
263
264 return c->state;
265}
266
267/** Drain the context. If there is nothing to drain, the function returns NULL */
268pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
269
270 if ( cb != NULL )
271  cb(c, userdata);
272
273 return NULL;
274}
275
276/** Tell the daemon to exit. The returned operation is unlikely to
277 * complete succesfully, since the daemon probably died before
278 * returning a success notification */
279pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
280 int s = 1;
281
282 if ( c == NULL )
283  return roar_pa_operation_new(PA_OPERATION_DONE);
284
285 if ( c->state == PA_CONTEXT_READY ) {
286  if ( roar_terminate(&(c->con), 0) == -1 ) {
287   c->errnum = PA_ERR_INTERNAL;
288   s = 0;
289  }
290 } else {
291  c->errnum = PA_ERR_BADSTATE;
292  s = 0;
293 }
294
295 if ( cb != NULL )
296  cb(c, s, userdata);
297
298 return roar_pa_operation_new(PA_OPERATION_DONE);
299}
300
301/** Set the name of the default sink. \since 0.4 */
302pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
303 if ( c != NULL )
304  c->errnum = PA_ERR_NOTSUPPORTED;
305
306 if ( cb != NULL )
307  cb(c, strcasecmp(name, ROAR_PA_DEFAULT_SINK) == 0 ? 1 : 0, userdata);
308
309 return roar_pa_operation_new(PA_OPERATION_DONE);
310}
311
312/** Set the name of the default source. \since 0.4 */
313pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
314 if ( c != NULL )
315  c->errnum = PA_ERR_NOTSUPPORTED;
316
317 if ( cb != NULL )
318  cb(c, strcasecmp(name, ROAR_PA_DEFAULT_SOURCE) == 0 ? 1 : 0, userdata);
319
320 return roar_pa_operation_new(PA_OPERATION_DONE);
321}
322
323/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */
324int pa_context_is_local(pa_context *c) {
325 if ( c == NULL )
326  return -1;
327
328 if ( c->state != PA_CONTEXT_READY )
329  return -1;
330
331 // how is /local/ defined?
332 return 0;
333}
334
335/** Set a different application name for context on the server. \since 0.5 */
336pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
337 if ( c == NULL )
338  return roar_pa_operation_new(PA_OPERATION_DONE);
339
340 if ( c->state != PA_CONTEXT_UNCONNECTED ) {
341  c->errnum = PA_ERR_BADSTATE;
342
343  if ( cb != NULL )
344   cb(c, 0, userdata);
345
346  return roar_pa_operation_new(PA_OPERATION_DONE);
347 }
348
349 if ( c->name != NULL )
350  roar_mm_free(c->name);
351
352 c->name = roar_mm_strdup(name);
353 c->cb.set_name.cb.scb   = cb;
354 c->cb.set_name.userdata = userdata;
355
356 return roar_pa_operation_new(PA_OPERATION_DONE);
357}
358
359/** Return the server name this context is connected to. \since 0.7 */
360const char* pa_context_get_server(pa_context *c) {
361 if ( c == NULL )
362  return NULL;
363
364 return c->server;
365}
366
367/** Return the protocol version of the library. \since 0.8 */
368uint32_t pa_context_get_protocol_version(pa_context *c) {
369 (void)c;
370 return 0;
371}
372
373/** Return the protocol version of the connected server. \since 0.8 */
374uint32_t pa_context_get_server_protocol_version(pa_context *c) {
375 (void)c;
376 return 0;
377}
378
379
380//ll
Note: See TracBrowser for help on using the repository browser.