source: roaraudio/libroarpulse/context.c @ 5270:e25346c13638

Last change on this file since 5270:e25346c13638 was 5270:e25346c13638, checked in by phi, 12 years ago

fixed some gcc -Wextra warnings

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 (void)c;
224 return 0;
225}
226
227/** Return the current context status */
228pa_context_state_t pa_context_get_state(pa_context *c) {
229 if ( c == NULL )
230  return PA_CONTEXT_FAILED;
231
232 return c->state;
233}
234
235/** Drain the context. If there is nothing to drain, the function returns NULL */
236pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
237
238 if ( cb != NULL )
239  cb(c, userdata);
240
241 return NULL;
242}
243
244/** Tell the daemon to exit. The returned operation is unlikely to
245 * complete succesfully, since the daemon probably died before
246 * returning a success notification */
247pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
248 int s = 1;
249
250 if ( c == NULL )
251  return roar_pa_operation_new(PA_OPERATION_DONE);
252
253 if ( c->state == PA_CONTEXT_READY ) {
254  if ( roar_terminate(&(c->con), 0) == -1 ) {
255   c->errnum = PA_ERR_INTERNAL;
256   s = 0;
257  }
258 } else {
259  c->errnum = PA_ERR_BADSTATE;
260  s = 0;
261 }
262
263 if ( cb != NULL )
264  cb(c, s, userdata);
265
266 return roar_pa_operation_new(PA_OPERATION_DONE);
267}
268
269/** Set the name of the default sink. \since 0.4 */
270pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
271 if ( c != NULL )
272  c->errnum = PA_ERR_NOTSUPPORTED;
273
274 if ( cb != NULL )
275  cb(c, strcasecmp(name, ROAR_PA_DEFAULT_SINK) == 0 ? 1 : 0, userdata);
276
277 return roar_pa_operation_new(PA_OPERATION_DONE);
278}
279
280/** Set the name of the default source. \since 0.4 */
281pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
282 if ( c != NULL )
283  c->errnum = PA_ERR_NOTSUPPORTED;
284
285 if ( cb != NULL )
286  cb(c, strcasecmp(name, ROAR_PA_DEFAULT_SOURCE) == 0 ? 1 : 0, userdata);
287
288 return roar_pa_operation_new(PA_OPERATION_DONE);
289}
290
291/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */
292int pa_context_is_local(pa_context *c) {
293 if ( c == NULL )
294  return -1;
295
296 if ( c->state != PA_CONTEXT_READY )
297  return -1;
298
299 // how is /local/ defined?
300 return 0;
301}
302
303/** Set a different application name for context on the server. \since 0.5 */
304pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
305 if ( c == NULL )
306  return roar_pa_operation_new(PA_OPERATION_DONE);
307
308 if ( c->state != PA_CONTEXT_UNCONNECTED ) {
309  c->errnum = PA_ERR_BADSTATE;
310
311  if ( cb != NULL )
312   cb(c, 0, userdata);
313
314  return roar_pa_operation_new(PA_OPERATION_DONE);
315 }
316
317 if ( c->name != NULL )
318  roar_mm_free(c->name);
319
320 c->name = roar_mm_strdup(name);
321 c->cb.set_name.cb.scb   = cb;
322 c->cb.set_name.userdata = userdata;
323
324 return roar_pa_operation_new(PA_OPERATION_DONE);
325}
326
327/** Return the server name this context is connected to. \since 0.7 */
328const char* pa_context_get_server(pa_context *c) {
329 if ( c == NULL )
330  return NULL;
331
332 return c->server;
333}
334
335/** Return the protocol version of the library. \since 0.8 */
336uint32_t pa_context_get_protocol_version(pa_context *c) {
337 (void)c;
338 return 0;
339}
340
341/** Return the protocol version of the connected server. \since 0.8 */
342uint32_t pa_context_get_server_protocol_version(pa_context *c) {
343 (void)c;
344 return 0;
345}
346
347
348//ll
Note: See TracBrowser for help on using the repository browser.