6 #include "native-common.h"
10 static const char *command_names
[PA_COMMAND_MAX
] = {
11 [PA_COMMAND_ERROR
] = "ERROR",
12 [PA_COMMAND_TIMEOUT
] = "TIMEOUT",
13 [PA_COMMAND_REPLY
] = "REPLY",
14 [PA_COMMAND_CREATE_PLAYBACK_STREAM
] = "CREATE_PLAYBACK_STREAM",
15 [PA_COMMAND_DELETE_PLAYBACK_STREAM
] = "DELETE_PLAYBACK_STREAM",
16 [PA_COMMAND_CREATE_RECORD_STREAM
] = "CREATE_RECORD_STREAM",
17 [PA_COMMAND_DELETE_RECORD_STREAM
] = "DELETE_RECORD_STREAM",
18 [PA_COMMAND_AUTH
] = "AUTH",
19 [PA_COMMAND_REQUEST
] = "REQUEST",
20 [PA_COMMAND_EXIT
] = "EXIT",
21 [PA_COMMAND_SET_NAME
] = "SET_NAME",
22 [PA_COMMAND_LOOKUP_SINK
] = "LOOKUP_SINK",
23 [PA_COMMAND_LOOKUP_SOURCE
] = "LOOKUP_SOURCE",
24 [PA_COMMAND_DRAIN_PLAYBACK_STREAM
] = "DRAIN_PLAYBACK_STREAM",
25 [PA_COMMAND_PLAYBACK_STREAM_KILLED
] = "PLAYBACK_STREAM_KILLED",
26 [PA_COMMAND_RECORD_STREAM_KILLED
] = "RECORD_STREAM_KILLED",
27 [PA_COMMAND_STAT
] = "STAT",
28 [PA_COMMAND_GET_PLAYBACK_LATENCY
] = "PLAYBACK_LATENCY",
34 struct pa_pdispatch
*pdispatch
;
35 struct reply_info
*next
, *previous
;
36 void (*callback
)(struct pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, struct pa_tagstruct
*t
, void *userdata
);
39 void *mainloop_timeout
;
40 int callback_is_running
;
44 struct pa_mainloop_api
*mainloop
;
45 const struct pa_pdispatch_command
*command_table
;
47 struct reply_info
*replies
;
48 void (*drain_callback
)(struct pa_pdispatch
*pd
, void *userdata
);
50 int in_use
, shall_free
;
53 static void reply_info_free(struct reply_info
*r
) {
54 assert(r
&& r
->pdispatch
&& r
->pdispatch
->mainloop
);
57 r
->pdispatch
->mainloop
->cancel_time(r
->pdispatch
->mainloop
, r
->mainloop_timeout
);
60 r
->previous
->next
= r
->next
;
62 r
->pdispatch
->replies
= r
->next
;
65 r
->next
->previous
= r
->previous
;
70 struct pa_pdispatch
* pa_pdispatch_new(struct pa_mainloop_api
*mainloop
, const struct pa_pdispatch_command
*table
, unsigned entries
) {
71 struct pa_pdispatch
*pd
;
74 assert((entries
&& table
) || (!entries
&& !table
));
76 pd
= malloc(sizeof(struct pa_pdispatch
));
78 pd
->mainloop
= mainloop
;
79 pd
->command_table
= table
;
80 pd
->n_commands
= entries
;
82 pd
->drain_callback
= NULL
;
83 pd
->drain_userdata
= NULL
;
85 pd
->in_use
= pd
->shall_free
= 0;
89 void pa_pdispatch_free(struct pa_pdispatch
*pd
) {
98 reply_info_free(pd
->replies
);
102 int pa_pdispatch_run(struct pa_pdispatch
*pd
, struct pa_packet
*packet
, void *userdata
) {
103 uint32_t tag
, command
;
104 struct pa_tagstruct
*ts
= NULL
;
106 assert(pd
&& packet
&& packet
->data
&& !pd
->in_use
);
108 if (packet
->length
<= 8)
111 ts
= pa_tagstruct_new(packet
->data
, packet
->length
);
114 if (pa_tagstruct_getu32(ts
, &command
) < 0 ||
115 pa_tagstruct_getu32(ts
, &tag
) < 0)
119 fprintf(stderr
, __FILE__
": Recieved opcode <%s>\n", command_names
[command
]);
122 if (command
== PA_COMMAND_ERROR
|| command
== PA_COMMAND_REPLY
) {
123 struct reply_info
*r
;
125 for (r
= pd
->replies
; r
; r
= r
->next
)
130 pd
->in_use
= r
->callback_is_running
= 1;
132 r
->callback(r
->pdispatch
, command
, tag
, ts
, r
->userdata
);
133 pd
->in_use
= r
->callback_is_running
= 0;
137 pa_pdispatch_free(pd
);
139 if (pd
->drain_callback
&& !pa_pdispatch_is_pending(pd
))
140 pd
->drain_callback(pd
, pd
->drain_userdata
);
144 } else if (pd
->command_table
&& command
< pd
->n_commands
) {
145 const struct pa_pdispatch_command
*c
= pd
->command_table
+command
;
148 c
->proc(pd
, command
, tag
, ts
, userdata
);
156 pa_tagstruct_free(ts
);
161 static void timeout_callback(struct pa_mainloop_api
*m
, void *id
, const struct timeval
*tv
, void *userdata
) {
162 struct reply_info
*r
= userdata
;
163 assert (r
&& r
->mainloop_timeout
== id
&& r
->pdispatch
&& r
->pdispatch
->mainloop
== m
&& r
->callback
);
165 r
->callback(r
->pdispatch
, PA_COMMAND_TIMEOUT
, r
->tag
, NULL
, r
->userdata
);
168 if (r
->pdispatch
->drain_callback
&& !pa_pdispatch_is_pending(r
->pdispatch
))
169 r
->pdispatch
->drain_callback(r
->pdispatch
, r
->pdispatch
->drain_userdata
);
172 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
) {
173 struct reply_info
*r
;
177 r
= malloc(sizeof(struct reply_info
));
181 r
->userdata
= userdata
;
183 r
->callback_is_running
= 0;
185 gettimeofday(&tv
, NULL
);
186 tv
.tv_sec
+= timeout
;
188 r
->mainloop_timeout
= pd
->mainloop
->source_time(pd
->mainloop
, &tv
, timeout_callback
, r
);
189 assert(r
->mainloop_timeout
);
192 r
->next
= pd
->replies
;
194 r
->next
->previous
= r
;
198 int pa_pdispatch_is_pending(struct pa_pdispatch
*pd
) {
201 return !!pd
->replies
;
204 void pa_pdispatch_set_drain_callback(struct pa_pdispatch
*pd
, void (*cb
)(struct pa_pdispatch
*pd
, void *userdata
), void *userdata
) {
206 assert(!cb
|| pa_pdispatch_is_pending(pd
));
208 pd
->drain_callback
= cb
;
209 pd
->drain_userdata
= userdata
;
212 void pa_pdispatch_unregister_reply(struct pa_pdispatch
*pd
, void *userdata
) {
213 struct reply_info
*r
, *n
;
216 for (r
= pd
->replies
; r
; r
= n
) {
219 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 */