source: roaraudio/libroarpulse/context.c @ 3476:772b0a7aa509

Last change on this file since 3476:772b0a7aa509 was 3438:a40a55ea0254, checked in by phi, 14 years ago

add support to get api

File size: 8.5 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
177struct roar_connection * roar_pa_context_get_con(pa_context * c) {
178 if ( c == NULL )
179  return NULL;
180
181 if ( c->state != PA_CONTEXT_READY )
182  return NULL;
183
184 return &(c->con);
185}
186
187pa_mainloop_api * roar_pa_context_get_api(pa_context * c) {
188 if ( c == NULL )
189  return NULL;
190
191 return c->mainloop;
192}
193
194/** Set a callback function that is called whenever the context status changes */
195void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
196 if ( c == NULL )
197  return;
198
199 c->cb.state_change.cb.ncb   = cb;
200 c->cb.state_change.userdata = userdata;
201}
202
203void pa_context_set_state(pa_context *c, pa_context_state_t st) {
204 if ( c == NULL )
205  return;
206
207 c->state = st;
208
209 _call_cbn(c->cb.state_change, c);
210}
211
212/** Return the error number of the last failed operation */
213int pa_context_errno(pa_context *c) {
214 if ( c == NULL )
215  return PA_ERR_INVALID;
216
217 return c->errnum;
218}
219
220/** Return non-zero if some data is pending to be written to the connection */
221int pa_context_is_pending(pa_context *c) {
222 return 0;
223}
224
225/** Return the current context status */
226pa_context_state_t pa_context_get_state(pa_context *c) {
227 if ( c == NULL )
228  return PA_CONTEXT_FAILED;
229
230 return c->state;
231}
232
233/** Drain the context. If there is nothing to drain, the function returns NULL */
234pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
235
236 if ( cb != NULL )
237  cb(c, userdata);
238
239 return NULL;
240}
241
242/** Tell the daemon to exit. The returned operation is unlikely to
243 * complete succesfully, since the daemon probably died before
244 * returning a success notification */
245pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
246 int s = 1;
247
248 if ( c == NULL )
249  return roar_pa_operation_new(PA_OPERATION_DONE);
250
251 if ( c->state == PA_CONTEXT_READY ) {
252  if ( roar_exit(&(c->con)) == -1 ) {
253   c->errnum = PA_ERR_INTERNAL;
254   s = 0;
255  }
256 } else {
257  c->errnum = PA_ERR_BADSTATE;
258  s = 0;
259 }
260
261 if ( cb != NULL )
262  cb(c, s, userdata);
263
264 return roar_pa_operation_new(PA_OPERATION_DONE);
265}
266
267/** Set the name of the default sink. \since 0.4 */
268pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
269 if ( c != NULL )
270  c->errnum = PA_ERR_NOTSUPPORTED;
271
272 if ( cb != NULL )
273  cb(c, strcasecmp(name, ROAR_PA_DEFAULT_SINK) == 0 ? 1 : 0, userdata);
274
275 return roar_pa_operation_new(PA_OPERATION_DONE);
276}
277
278/** Set the name of the default source. \since 0.4 */
279pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
280 if ( c != NULL )
281  c->errnum = PA_ERR_NOTSUPPORTED;
282
283 if ( cb != NULL )
284  cb(c, strcasecmp(name, ROAR_PA_DEFAULT_SOURCE) == 0 ? 1 : 0, userdata);
285
286 return roar_pa_operation_new(PA_OPERATION_DONE);
287}
288
289/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */
290int pa_context_is_local(pa_context *c) {
291 if ( c == NULL )
292  return -1;
293
294 if ( c->state != PA_CONTEXT_READY )
295  return -1;
296
297 // how is /local/ defined?
298 return 0;
299}
300
301/** Set a different application name for context on the server. \since 0.5 */
302pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
303 if ( c == NULL )
304  return roar_pa_operation_new(PA_OPERATION_DONE);
305
306 if ( c->state != PA_CONTEXT_UNCONNECTED ) {
307  c->errnum = PA_ERR_BADSTATE;
308
309  if ( cb != NULL )
310   cb(c, 0, userdata);
311
312  return roar_pa_operation_new(PA_OPERATION_DONE);
313 }
314
315 if ( c->name != NULL )
316  roar_mm_free(c->name);
317
318 c->name = roar_mm_strdup(name);
319 c->cb.set_name.cb.scb   = cb;
320 c->cb.set_name.userdata = userdata;
321
322 return roar_pa_operation_new(PA_OPERATION_DONE);
323}
324
325/** Return the server name this context is connected to. \since 0.7 */
326const char* pa_context_get_server(pa_context *c) {
327 if ( c == NULL )
328  return NULL;
329
330 return c->server;
331}
332
333/** Return the protocol version of the library. \since 0.8 */
334uint32_t pa_context_get_protocol_version(pa_context *c) {
335 return 0;
336}
337
338/** Return the protocol version of the connected server. \since 0.8 */
339uint32_t pa_context_get_server_protocol_version(pa_context *c) {
340 return 0;
341}
342
343
344//ll
Note: See TracBrowser for help on using the repository browser.