5 #include "protocol-native-spec.h"
9 static const char *command_names
[PA_COMMAND_MAX
] = {
10 [PA_COMMAND_ERROR
] = "ERROR",
11 [PA_COMMAND_TIMEOUT
] = "TIMEOUT",
12 [PA_COMMAND_REPLY
] = "REPLY",
13 [PA_COMMAND_CREATE_PLAYBACK_STREAM
] = "CREATE_PLAYBACK_STREAM",
14 [PA_COMMAND_DELETE_PLAYBACK_STREAM
] = "DELETE_PLAYBACK_STREAM",
15 [PA_COMMAND_CREATE_RECORD_STREAM
] = "CREATE_RECORD_STREAM",
16 [PA_COMMAND_DELETE_RECORD_STREAM
] = "DELETE_RECORD_STREAM",
17 [PA_COMMAND_AUTH
] = "AUTH",
18 [PA_COMMAND_REQUEST
] = "REQUEST",
19 [PA_COMMAND_EXIT
] = "EXIT",
20 [PA_COMMAND_SET_NAME
] = "SET_NAME",
21 [PA_COMMAND_LOOKUP_SINK
] = "LOOKUP_SINK",
22 [PA_COMMAND_LOOKUP_SOURCE
] = "LOOKUP_SOURCE",
23 [PA_COMMAND_DRAIN_PLAYBACK_STREAM
] = "DRAIN_PLAYBACK_STREAM",
24 [PA_COMMAND_PLAYBACK_STREAM_KILLED
] = "PLAYBACK_STREAM_KILLED",
25 [PA_COMMAND_RECORD_STREAM_KILLED
] = "RECORD_STREAM_KILLED",
26 [PA_COMMAND_STAT
] = "STAT",
27 [PA_COMMAND_GET_PLAYBACK_LATENCY
] = "PLAYBACK_LATENCY",
33 struct pa_pdispatch
*pdispatch
;
34 struct reply_info
*next
, *previous
;
35 void (*callback
)(struct pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, struct pa_tagstruct
*t
, void *userdata
);
38 void *mainloop_timeout
;
39 int callback_is_running
;
43 struct pa_mainloop_api
*mainloop
;
44 const struct pa_pdispatch_command
*command_table
;
46 struct reply_info
*replies
;
47 void (*drain_callback
)(struct pa_pdispatch
*pd
, void *userdata
);
49 int in_use
, shall_free
;
52 static void reply_info_free(struct reply_info
*r
) {
53 assert(r
&& r
->pdispatch
&& r
->pdispatch
->mainloop
);
56 r
->pdispatch
->mainloop
->cancel_time(r
->pdispatch
->mainloop
, r
->mainloop_timeout
);
59 r
->previous
->next
= r
->next
;
61 r
->pdispatch
->replies
= r
->next
;
64 r
->next
->previous
= r
->previous
;
69 struct pa_pdispatch
* pa_pdispatch_new(struct pa_mainloop_api
*mainloop
, const struct pa_pdispatch_command
*table
, unsigned entries
) {
70 struct pa_pdispatch
*pd
;
73 assert((entries
&& table
) || (!entries
&& !table
));
75 pd
= malloc(sizeof(struct pa_pdispatch
));
77 pd
->mainloop
= mainloop
;
78 pd
->command_table
= table
;
79 pd
->n_commands
= entries
;
81 pd
->drain_callback
= NULL
;
82 pd
->drain_userdata
= NULL
;
84 pd
->in_use
= pd
->shall_free
= 0;
88 void pa_pdispatch_free(struct pa_pdispatch
*pd
) {
97 reply_info_free(pd
->replies
);
101 int pa_pdispatch_run(struct pa_pdispatch
*pd
, struct pa_packet
*packet
, void *userdata
) {
102 uint32_t tag
, command
;
103 struct pa_tagstruct
*ts
= NULL
;
105 assert(pd
&& packet
&& packet
->data
&& !pd
->in_use
);
107 if (packet
->length
<= 8)
110 ts
= pa_tagstruct_new(packet
->data
, packet
->length
);
113 if (pa_tagstruct_getu32(ts
, &command
) < 0 ||
114 pa_tagstruct_getu32(ts
, &tag
) < 0)
118 fprintf(stderr
, __FILE__
": Recieved opcode <%s>\n", command_names
[command
]);
121 if (command
== PA_COMMAND_ERROR
|| command
== PA_COMMAND_REPLY
) {
122 struct reply_info
*r
;
124 for (r
= pd
->replies
; r
; r
= r
->next
)
129 pd
->in_use
= r
->callback_is_running
= 1;
131 r
->callback(r
->pdispatch
, command
, tag
, ts
, r
->userdata
);
132 pd
->in_use
= r
->callback_is_running
= 0;
136 pa_pdispatch_free(pd
);
138 if (pd
->drain_callback
&& !pa_pdispatch_is_pending(pd
))
139 pd
->drain_callback(pd
, pd
->drain_userdata
);
143 } else if (pd
->command_table
&& command
< pd
->n_commands
) {
144 const struct pa_pdispatch_command
*c
= pd
->command_table
+command
;
147 c
->proc(pd
, command
, tag
, ts
, userdata
);
155 pa_tagstruct_free(ts
);
160 static void timeout_callback(struct pa_mainloop_api
*m
, void *id
, const struct timeval
*tv
, void *userdata
) {
161 struct reply_info
*r
= userdata
;
162 assert (r
&& r
->mainloop_timeout
== id
&& r
->pdispatch
&& r
->pdispatch
->mainloop
== m
&& r
->callback
);
164 r
->callback(r
->pdispatch
, PA_COMMAND_TIMEOUT
, r
->tag
, NULL
, r
->userdata
);
167 if (r
->pdispatch
->drain_callback
&& !pa_pdispatch_is_pending(r
->pdispatch
))
168 r
->pdispatch
->drain_callback(r
->pdispatch
, r
->pdispatch
->drain_userdata
);
171 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
) {
172 struct reply_info
*r
;
176 r
= malloc(sizeof(struct reply_info
));
180 r
->userdata
= userdata
;
182 r
->callback_is_running
= 0;
184 gettimeofday(&tv
, NULL
);
185 tv
.tv_sec
+= timeout
;
187 r
->mainloop_timeout
= pd
->mainloop
->source_time(pd
->mainloop
, &tv
, timeout_callback
, r
);
188 assert(r
->mainloop_timeout
);
191 r
->next
= pd
->replies
;
193 r
->next
->previous
= r
;
197 int pa_pdispatch_is_pending(struct pa_pdispatch
*pd
) {
200 return !!pd
->replies
;
203 void pa_pdispatch_set_drain_callback(struct pa_pdispatch
*pd
, void (*cb
)(struct pa_pdispatch
*pd
, void *userdata
), void *userdata
) {
205 assert(!cb
|| pa_pdispatch_is_pending(pd
));
207 pd
->drain_callback
= cb
;
208 pd
->drain_userdata
= userdata
;
211 void pa_pdispatch_unregister_reply(struct pa_pdispatch
*pd
, void *userdata
) {
212 struct reply_info
*r
, *n
;
215 for (r
= pd
->replies
; r
; r
= n
) {
218 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 */