source: roaraudio/libroarpulse/context.c @ 3397:e6a0b746f3e1

Last change on this file since 3397:e6a0b746f3e1 was 3397:e6a0b746f3e1, checked in by phi, 14 years ago

handle server == NULL case

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