5 #include "protocol-native-spec.h"
7 static const char *command_names
[PA_COMMAND_MAX
] = {
8 [PA_COMMAND_ERROR
] = "ERROR",
9 [PA_COMMAND_TIMEOUT
] = "TIMEOUT",
10 [PA_COMMAND_REPLY
] = "REPLY",
11 [PA_COMMAND_CREATE_PLAYBACK_STREAM
] = "CREATE_PLAYBACK_STREAM",
12 [PA_COMMAND_DELETE_PLAYBACK_STREAM
] = "DELETE_PLAYBACK_STREAM",
13 [PA_COMMAND_CREATE_RECORD_STREAM
] = "CREATE_RECORD_STREAM",
14 [PA_COMMAND_DELETE_RECORD_STREAM
] = "DELETE_RECORD_STREAM",
15 [PA_COMMAND_AUTH
] = "AUTH",
16 [PA_COMMAND_REQUEST
] = "REQUEST",
17 [PA_COMMAND_EXIT
] = "EXIT",
18 [PA_COMMAND_SET_NAME
] = "SET_NAME",
19 [PA_COMMAND_LOOKUP_SINK
] = "LOOKUP_SINK",
20 [PA_COMMAND_LOOKUP_SOURCE
] = "LOOKUP_SOURCE",
21 [PA_COMMAND_DRAIN_PLAYBACK_STREAM
] = "DRAIN_PLAYBACK_STREAM",
25 struct pa_pdispatch
*pdispatch
;
26 struct reply_info
*next
, *previous
;
27 void (*callback
)(struct pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, struct pa_tagstruct
*t
, void *userdata
);
30 void *mainloop_timeout
;
31 int callback_is_running
;
35 struct pa_mainloop_api
*mainloop
;
36 const struct pa_pdispatch_command
*command_table
;
38 struct reply_info
*replies
;
39 void (*drain_callback
)(struct pa_pdispatch
*pd
, void *userdata
);
41 int in_use
, shall_free
;
44 static void reply_info_free(struct reply_info
*r
) {
45 assert(r
&& r
->pdispatch
&& r
->pdispatch
->mainloop
);
48 r
->pdispatch
->mainloop
->cancel_time(r
->pdispatch
->mainloop
, r
->mainloop_timeout
);
51 r
->previous
->next
= r
->next
;
53 r
->pdispatch
->replies
= r
->next
;
56 r
->next
->previous
= r
->previous
;
61 struct pa_pdispatch
* pa_pdispatch_new(struct pa_mainloop_api
*mainloop
, const struct pa_pdispatch_command
*table
, unsigned entries
) {
62 struct pa_pdispatch
*pd
;
65 assert((entries
&& table
) || (!entries
&& !table
));
67 pd
= malloc(sizeof(struct pa_pdispatch
));
69 pd
->mainloop
= mainloop
;
70 pd
->command_table
= table
;
71 pd
->n_commands
= entries
;
73 pd
->drain_callback
= NULL
;
74 pd
->drain_userdata
= NULL
;
76 pd
->in_use
= pd
->shall_free
= 0;
80 void pa_pdispatch_free(struct pa_pdispatch
*pd
) {
89 reply_info_free(pd
->replies
);
93 int pa_pdispatch_run(struct pa_pdispatch
*pd
, struct pa_packet
*packet
, void *userdata
) {
94 uint32_t tag
, command
;
95 struct pa_tagstruct
*ts
= NULL
;
97 assert(pd
&& packet
&& packet
->data
&& !pd
->in_use
);
99 if (packet
->length
<= 8)
102 ts
= pa_tagstruct_new(packet
->data
, packet
->length
);
105 if (pa_tagstruct_getu32(ts
, &command
) < 0 ||
106 pa_tagstruct_getu32(ts
, &tag
) < 0)
109 /*fprintf(stderr, __FILE__": Recieved opcode <%s>\n", command_names[command]);*/
111 if (command
== PA_COMMAND_ERROR
|| command
== PA_COMMAND_REPLY
) {
112 struct reply_info
*r
;
114 for (r
= pd
->replies
; r
; r
= r
->next
)
119 pd
->in_use
= r
->callback_is_running
= 1;
121 r
->callback(r
->pdispatch
, command
, tag
, ts
, r
->userdata
);
122 pd
->in_use
= r
->callback_is_running
= 0;
126 pa_pdispatch_free(pd
);
128 if (pd
->drain_callback
&& !pa_pdispatch_is_pending(pd
))
129 pd
->drain_callback(pd
, pd
->drain_userdata
);
133 } else if (pd
->command_table
&& command
< pd
->n_commands
) {
134 const struct pa_pdispatch_command
*c
= pd
->command_table
+command
;
137 c
->proc(pd
, command
, tag
, ts
, userdata
);
145 pa_tagstruct_free(ts
);
150 static void timeout_callback(struct pa_mainloop_api
*m
, void *id
, const struct timeval
*tv
, void *userdata
) {
151 struct reply_info
*r
= userdata
;
152 assert (r
&& r
->mainloop_timeout
== id
&& r
->pdispatch
&& r
->pdispatch
->mainloop
== m
&& r
->callback
);
154 r
->callback(r
->pdispatch
, PA_COMMAND_TIMEOUT
, r
->tag
, NULL
, r
->userdata
);
157 if (r
->pdispatch
->drain_callback
&& !pa_pdispatch_is_pending(r
->pdispatch
))
158 r
->pdispatch
->drain_callback(r
->pdispatch
, r
->pdispatch
->drain_userdata
);
161 void pa_pdispatch_register_reply(struct pa_pdispatch
*pd
, uint32_t tag
, int timeout
, void (*cb
)(struct pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, struct pa_tagstruct
*t
, void *userdata
), void *userdata
) {
162 struct reply_info
*r
;
166 r
= malloc(sizeof(struct reply_info
));
170 r
->userdata
= userdata
;
172 r
->callback_is_running
= 0;
174 gettimeofday(&tv
, NULL
);
175 tv
.tv_sec
+= timeout
;
177 r
->mainloop_timeout
= pd
->mainloop
->source_time(pd
->mainloop
, &tv
, timeout_callback
, r
);
178 assert(r
->mainloop_timeout
);
181 r
->next
= pd
->replies
;
183 r
->next
->previous
= r
;
187 int pa_pdispatch_is_pending(struct pa_pdispatch
*pd
) {
190 return !!pd
->replies
;
193 void pa_pdispatch_set_drain_callback(struct pa_pdispatch
*pd
, void (*cb
)(struct pa_pdispatch
*pd
, void *userdata
), void *userdata
) {
195 assert(!cb
|| pa_pdispatch_is_pending(pd
));
197 pd
->drain_callback
= cb
;
198 pd
->drain_userdata
= userdata
;
201 void pa_pdispatch_unregister_reply(struct pa_pdispatch
*pd
, void *userdata
) {
202 struct reply_info
*r
, *n
;
205 for (r
= pd
->replies
; r
; r
= n
) {
208 if (!r
->callback_is_running
&& r
->userdata
== userdata
) /* when this item's callback is currently running it is destroyed anyway in the very near future */