4 This file is part of polypaudio.
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <sys/types.h>
31 #include <sys/socket.h>
34 #include "polyplib-internal.h"
35 #include "polyplib-context.h"
36 #include "native-common.h"
37 #include "pdispatch.h"
40 #include "socket-client.h"
41 #include "pstream-util.h"
46 static const struct pa_pdispatch_command command_table
[PA_COMMAND_MAX
] = {
47 [PA_COMMAND_REQUEST
] = { pa_command_request
},
48 [PA_COMMAND_PLAYBACK_STREAM_KILLED
] = { pa_command_stream_killed
},
49 [PA_COMMAND_RECORD_STREAM_KILLED
] = { pa_command_stream_killed
},
50 [PA_COMMAND_SUBSCRIBE_EVENT
] = { pa_command_subscribe_event
},
53 struct pa_context
*pa_context_new(struct pa_mainloop_api
*mainloop
, const char *name
) {
55 assert(mainloop
&& name
);
57 c
= pa_xmalloc(sizeof(struct pa_context
));
59 c
->name
= pa_xstrdup(name
);
60 c
->mainloop
= mainloop
;
64 c
->playback_streams
= pa_dynarray_new();
65 c
->record_streams
= pa_dynarray_new();
66 assert(c
->playback_streams
&& c
->record_streams
);
68 PA_LLIST_HEAD_INIT(struct pa_stream
, c
->streams
);
69 PA_LLIST_HEAD_INIT(struct pa_operation
, c
->operations
);
71 c
->error
= PA_ERROR_OK
;
72 c
->state
= PA_CONTEXT_UNCONNECTED
;
75 c
->state_callback
= NULL
;
76 c
->state_userdata
= NULL
;
78 c
->subscribe_callback
= NULL
;
79 c
->subscribe_userdata
= NULL
;
81 c
->memblock_stat
= pa_memblock_stat_new();
83 pa_check_for_sigpipe();
87 static void context_free(struct pa_context
*c
) {
91 pa_operation_cancel(c
->operations
);
94 pa_stream_set_state(c
->streams
, PA_STREAM_TERMINATED
);
97 pa_socket_client_unref(c
->client
);
99 pa_pdispatch_unref(c
->pdispatch
);
101 pa_pstream_close(c
->pstream
);
102 pa_pstream_unref(c
->pstream
);
105 if (c
->record_streams
)
106 pa_dynarray_free(c
->record_streams
, NULL
, NULL
);
107 if (c
->playback_streams
)
108 pa_dynarray_free(c
->playback_streams
, NULL
, NULL
);
110 pa_memblock_stat_unref(c
->memblock_stat
);
116 struct pa_context
* pa_context_ref(struct pa_context
*c
) {
117 assert(c
&& c
->ref
>= 1);
122 void pa_context_unref(struct pa_context
*c
) {
123 assert(c
&& c
->ref
>= 1);
125 if ((--(c
->ref
)) == 0)
129 void pa_context_set_state(struct pa_context
*c
, enum pa_context_state st
) {
137 if (st
== PA_CONTEXT_FAILED
|| st
== PA_CONTEXT_TERMINATED
) {
140 s
= c
->streams
? pa_stream_ref(c
->streams
) : NULL
;
142 struct pa_stream
*n
= s
->next
? pa_stream_ref(s
->next
) : NULL
;
143 pa_stream_set_state(s
, st
== PA_CONTEXT_FAILED
? PA_STREAM_FAILED
: PA_STREAM_TERMINATED
);
149 pa_pdispatch_unref(c
->pdispatch
);
153 pa_pstream_close(c
->pstream
);
154 pa_pstream_unref(c
->pstream
);
159 pa_socket_client_unref(c
->client
);
164 if (c
->state_callback
)
165 c
->state_callback(c
, c
->state_userdata
);
170 void pa_context_fail(struct pa_context
*c
, int error
) {
173 pa_context_set_state(c
, PA_CONTEXT_FAILED
);
176 static void pstream_die_callback(struct pa_pstream
*p
, void *userdata
) {
177 struct pa_context
*c
= userdata
;
179 pa_context_fail(c
, PA_ERROR_CONNECTIONTERMINATED
);
182 static void pstream_packet_callback(struct pa_pstream
*p
, struct pa_packet
*packet
, void *userdata
) {
183 struct pa_context
*c
= userdata
;
184 assert(p
&& packet
&& c
);
188 if (pa_pdispatch_run(c
->pdispatch
, packet
, c
) < 0) {
189 fprintf(stderr
, "polyp.c: invalid packet.\n");
190 pa_context_fail(c
, PA_ERROR_PROTOCOL
);
196 static void pstream_memblock_callback(struct pa_pstream
*p
, uint32_t channel
, int32_t delta
, const struct pa_memchunk
*chunk
, void *userdata
) {
197 struct pa_context
*c
= userdata
;
199 assert(p
&& chunk
&& c
&& chunk
->memblock
&& chunk
->memblock
->data
);
203 if ((s
= pa_dynarray_get(c
->record_streams
, channel
))) {
204 if (s
->read_callback
)
205 s
->read_callback(s
, chunk
->memblock
->data
+ chunk
->index
, chunk
->length
, s
->read_userdata
);
211 int pa_context_handle_error(struct pa_context
*c
, uint32_t command
, struct pa_tagstruct
*t
) {
214 if (command
== PA_COMMAND_ERROR
) {
215 if (pa_tagstruct_getu32(t
, &c
->error
) < 0) {
216 pa_context_fail(c
, PA_ERROR_PROTOCOL
);
220 } else if (command
== PA_COMMAND_TIMEOUT
)
221 c
->error
= PA_ERROR_TIMEOUT
;
223 pa_context_fail(c
, PA_ERROR_PROTOCOL
);
230 static void setup_complete_callback(struct pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, struct pa_tagstruct
*t
, void *userdata
) {
231 struct pa_context
*c
= userdata
;
232 assert(pd
&& c
&& (c
->state
== PA_CONTEXT_AUTHORIZING
|| c
->state
== PA_CONTEXT_SETTING_NAME
));
236 if (command
!= PA_COMMAND_REPLY
) {
237 if (pa_context_handle_error(c
, command
, t
) < 0)
238 pa_context_fail(c
, PA_ERROR_PROTOCOL
);
244 case PA_CONTEXT_AUTHORIZING
: {
245 struct pa_tagstruct
*t
;
246 t
= pa_tagstruct_new(NULL
, 0);
248 pa_tagstruct_putu32(t
, PA_COMMAND_SET_NAME
);
249 pa_tagstruct_putu32(t
, tag
= c
->ctag
++);
250 pa_tagstruct_puts(t
, c
->name
);
251 pa_pstream_send_tagstruct(c
->pstream
, t
);
252 pa_pdispatch_register_reply(c
->pdispatch
, tag
, DEFAULT_TIMEOUT
, setup_complete_callback
, c
);
254 pa_context_set_state(c
, PA_CONTEXT_SETTING_NAME
);
258 case PA_CONTEXT_SETTING_NAME
:
259 pa_context_set_state(c
, PA_CONTEXT_READY
);
270 static void on_connection(struct pa_socket_client
*client
, struct pa_iochannel
*io
, void *userdata
) {
271 struct pa_context
*c
= userdata
;
272 struct pa_tagstruct
*t
;
274 assert(client
&& c
&& c
->state
== PA_CONTEXT_CONNECTING
);
278 pa_socket_client_unref(client
);
282 pa_context_fail(c
, PA_ERROR_CONNECTIONREFUSED
);
287 c
->pstream
= pa_pstream_new(c
->mainloop
, io
, c
->memblock_stat
);
290 pa_pstream_set_die_callback(c
->pstream
, pstream_die_callback
, c
);
291 pa_pstream_set_recieve_packet_callback(c
->pstream
, pstream_packet_callback
, c
);
292 pa_pstream_set_recieve_memblock_callback(c
->pstream
, pstream_memblock_callback
, c
);
294 assert(!c
->pdispatch
);
295 c
->pdispatch
= pa_pdispatch_new(c
->mainloop
, command_table
, PA_COMMAND_MAX
);
296 assert(c
->pdispatch
);
298 t
= pa_tagstruct_new(NULL
, 0);
300 pa_tagstruct_putu32(t
, PA_COMMAND_AUTH
);
301 pa_tagstruct_putu32(t
, tag
= c
->ctag
++);
302 pa_tagstruct_put_arbitrary(t
, c
->auth_cookie
, sizeof(c
->auth_cookie
));
303 pa_pstream_send_tagstruct(c
->pstream
, t
);
304 pa_pdispatch_register_reply(c
->pdispatch
, tag
, DEFAULT_TIMEOUT
, setup_complete_callback
, c
);
306 pa_context_set_state(c
, PA_CONTEXT_AUTHORIZING
);
312 static struct sockaddr
*resolve_server(const char *server
, size_t *len
) {
314 struct addrinfo hints
, *result
= NULL
;
316 assert(server
&& len
);
318 if ((port
= strrchr(server
, ':')))
323 memset(&hints
, 0, sizeof(hints
));
324 hints
.ai_family
= PF_UNSPEC
;
325 hints
.ai_socktype
= SOCK_STREAM
;
326 hints
.ai_protocol
= 0;
328 if (getaddrinfo(server
, port
, &hints
, &result
) != 0)
332 sa
= pa_xmalloc(*len
= result
->ai_addrlen
);
333 memcpy(sa
, result
->ai_addr
, *len
);
335 freeaddrinfo(result
);
340 int pa_context_connect(struct pa_context
*c
, const char *server
) {
342 assert(c
&& c
->ref
>= 1 && c
->state
== PA_CONTEXT_UNCONNECTED
);
346 if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE
, c
->auth_cookie
, sizeof(c
->auth_cookie
)) < 0) {
347 pa_context_fail(c
, PA_ERROR_AUTHKEY
);
352 if (!(server
= getenv(ENV_DEFAULT_SERVER
)))
353 server
= DEFAULT_SERVER
;
357 if (*server
== '/') {
358 if (!(c
->client
= pa_socket_client_new_unix(c
->mainloop
, server
))) {
359 pa_context_fail(c
, PA_ERROR_CONNECTIONREFUSED
);
366 if (!(sa
= resolve_server(server
, &sa_len
))) {
367 pa_context_fail(c
, PA_ERROR_INVALIDSERVER
);
371 c
->client
= pa_socket_client_new_sockaddr(c
->mainloop
, sa
, sa_len
);
375 pa_context_fail(c
, PA_ERROR_CONNECTIONREFUSED
);
380 pa_socket_client_set_callback(c
->client
, on_connection
, c
);
381 pa_context_set_state(c
, PA_CONTEXT_CONNECTING
);
391 void pa_context_disconnect(struct pa_context
*c
) {
393 pa_context_set_state(c
, PA_CONTEXT_TERMINATED
);
396 enum pa_context_state
pa_context_get_state(struct pa_context
*c
) {
397 assert(c
&& c
->ref
>= 1);
401 int pa_context_errno(struct pa_context
*c
) {
402 assert(c
&& c
->ref
>= 1);
406 void pa_context_set_state_callback(struct pa_context
*c
, void (*cb
)(struct pa_context
*c
, void *userdata
), void *userdata
) {
407 assert(c
&& c
->ref
>= 1);
408 c
->state_callback
= cb
;
409 c
->state_userdata
= userdata
;
412 int pa_context_is_pending(struct pa_context
*c
) {
413 assert(c
&& c
->ref
>= 1);
415 if (c
->state
!= PA_CONTEXT_READY
)
418 assert(c
->pstream
&& c
->pdispatch
);
419 return pa_pstream_is_pending(c
->pstream
) || pa_pdispatch_is_pending(c
->pdispatch
);
422 static void set_dispatch_callbacks(struct pa_operation
*o
);
424 static void pdispatch_drain_callback(struct pa_pdispatch
*pd
, void *userdata
) {
425 set_dispatch_callbacks(userdata
);
428 static void pstream_drain_callback(struct pa_pstream
*s
, void *userdata
) {
429 set_dispatch_callbacks(userdata
);
432 static void set_dispatch_callbacks(struct pa_operation
*o
) {
434 assert(o
&& o
->context
&& o
->context
->ref
>= 1 && o
->ref
>= 1 && o
->context
->state
== PA_CONTEXT_READY
);
436 pa_pstream_set_drain_callback(o
->context
->pstream
, NULL
, NULL
);
437 pa_pdispatch_set_drain_callback(o
->context
->pdispatch
, NULL
, NULL
);
439 if (pa_pdispatch_is_pending(o
->context
->pdispatch
)) {
440 pa_pdispatch_set_drain_callback(o
->context
->pdispatch
, pdispatch_drain_callback
, o
);
444 if (pa_pstream_is_pending(o
->context
->pstream
)) {
445 pa_pstream_set_drain_callback(o
->context
->pstream
, pstream_drain_callback
, o
);
453 void (*cb
)(struct pa_context
*c
, void *userdata
);
454 cb
= (void*) o
->callback
;
455 cb(o
->context
, o
->userdata
);
458 pa_operation_done(o
);
461 pa_operation_unref(o
);
464 struct pa_operation
* pa_context_drain(struct pa_context
*c
, void (*cb
) (struct pa_context
*c
, void *userdata
), void *userdata
) {
465 struct pa_operation
*o
;
466 assert(c
&& c
->ref
>= 1 && c
->state
== PA_CONTEXT_READY
);
468 if (!pa_context_is_pending(c
))
471 o
= pa_operation_new(c
, NULL
);
474 o
->userdata
= userdata
;
476 set_dispatch_callbacks(pa_operation_ref(o
));
481 void pa_context_exit_daemon(struct pa_context
*c
) {
482 struct pa_tagstruct
*t
;
483 assert(c
&& c
->ref
>= 1);
485 t
= pa_tagstruct_new(NULL
, 0);
487 pa_tagstruct_putu32(t
, PA_COMMAND_EXIT
);
488 pa_tagstruct_putu32(t
, c
->ctag
++);
489 pa_pstream_send_tagstruct(c
->pstream
, t
);
492 void pa_context_simple_ack_callback(struct pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, struct pa_tagstruct
*t
, void *userdata
) {
493 struct pa_operation
*o
= userdata
;
495 assert(pd
&& o
&& o
->context
&& o
->ref
>= 1);
497 if (command
!= PA_COMMAND_REPLY
) {
498 if (pa_context_handle_error(o
->context
, command
, t
) < 0)
502 } else if (!pa_tagstruct_eof(t
)) {
503 pa_context_fail(o
->context
, PA_ERROR_PROTOCOL
);
508 void (*cb
)(struct pa_context
*c
, int success
, void *userdata
) = o
->callback
;
509 cb(o
->context
, success
, o
->userdata
);
513 pa_operation_done(o
);
514 pa_operation_unref(o
);
517 struct pa_operation
* pa_context_send_simple_command(struct pa_context
*c
, uint32_t command
, void (*internal_callback
)(struct pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, struct pa_tagstruct
*t
, void *userdata
), void (*cb
)(), void *userdata
) {
518 struct pa_tagstruct
*t
;
519 struct pa_operation
*o
;
523 o
= pa_operation_new(c
, NULL
);
525 o
->userdata
= userdata
;
527 t
= pa_tagstruct_new(NULL
, 0);
528 pa_tagstruct_putu32(t
, command
);
529 pa_tagstruct_putu32(t
, tag
= c
->ctag
++);
530 pa_pstream_send_tagstruct(c
->pstream
, t
);
531 pa_pdispatch_register_reply(c
->pdispatch
, tag
, DEFAULT_TIMEOUT
, internal_callback
, o
);
533 return pa_operation_ref(o
);
536 const char* pa_get_library_version(void) {
537 return PACKAGE_VERSION
;