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 Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, 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 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include "pdispatch.h"
31 #include "native-common.h"
37 /*#define DEBUG_OPCODES */
41 static const char *command_names
[PA_COMMAND_MAX
] = {
42 [PA_COMMAND_ERROR
] = "ERROR",
43 [PA_COMMAND_TIMEOUT
] = "TIMEOUT",
44 [PA_COMMAND_REPLY
] = "REPLY",
45 [PA_COMMAND_CREATE_PLAYBACK_STREAM
] = "CREATE_PLAYBACK_STREAM",
46 [PA_COMMAND_DELETE_PLAYBACK_STREAM
] = "DELETE_PLAYBACK_STREAM",
47 [PA_COMMAND_CREATE_RECORD_STREAM
] = "CREATE_RECORD_STREAM",
48 [PA_COMMAND_DELETE_RECORD_STREAM
] = "DELETE_RECORD_STREAM",
49 [PA_COMMAND_AUTH
] = "AUTH",
50 [PA_COMMAND_REQUEST
] = "REQUEST",
51 [PA_COMMAND_EXIT
] = "EXIT",
52 [PA_COMMAND_SET_CLIENT_NAME
] = "SET_CLIENT_NAME",
53 [PA_COMMAND_LOOKUP_SINK
] = "LOOKUP_SINK",
54 [PA_COMMAND_LOOKUP_SOURCE
] = "LOOKUP_SOURCE",
55 [PA_COMMAND_DRAIN_PLAYBACK_STREAM
] = "DRAIN_PLAYBACK_STREAM",
56 [PA_COMMAND_PLAYBACK_STREAM_KILLED
] = "PLAYBACK_STREAM_KILLED",
57 [PA_COMMAND_RECORD_STREAM_KILLED
] = "RECORD_STREAM_KILLED",
58 [PA_COMMAND_STAT
] = "STAT",
59 [PA_COMMAND_GET_PLAYBACK_LATENCY
] = "PLAYBACK_LATENCY",
60 [PA_COMMAND_CREATE_UPLOAD_STREAM
] = "CREATE_UPLOAD_STREAM",
61 [PA_COMMAND_DELETE_UPLOAD_STREAM
] = "DELETE_UPLOAD_STREAM",
62 [PA_COMMAND_FINISH_UPLOAD_STREAM
] = "FINISH_UPLOAD_STREAM",
63 [PA_COMMAND_PLAY_SAMPLE
] = "PLAY_SAMPLE",
64 [PA_COMMAND_REMOVE_SAMPLE
] = "REMOVE_SAMPLE",
65 [PA_COMMAND_GET_SERVER_INFO
] = "GET_SERVER_INFO",
66 [PA_COMMAND_GET_SINK_INFO
] = "GET_SINK_INFO",
67 [PA_COMMAND_GET_SINK_INFO_LIST
] = "GET_SINK_INFO_LIST",
68 [PA_COMMAND_GET_SOURCE_INFO
] = "GET_SOURCE_INFO",
69 [PA_COMMAND_GET_SOURCE_INFO_LIST
] = "GET_SOURCE_INFO_LIST",
70 [PA_COMMAND_GET_MODULE_INFO
] = "GET_MODULE_INFO",
71 [PA_COMMAND_GET_MODULE_INFO_LIST
] = "GET_MODULE_INFO_LIST",
72 [PA_COMMAND_GET_CLIENT_INFO
] = "GET_CLIENT_INFO",
73 [PA_COMMAND_GET_CLIENT_INFO_LIST
] = "GET_CLIENT_INFO_LIST",
74 [PA_COMMAND_GET_SAMPLE_INFO
] = "GET_SAMPLE_INFO",
75 [PA_COMMAND_GET_SAMPLE_INFO_LIST
] = "GET_SAMPLE_INFO_LIST",
76 [PA_COMMAND_GET_SINK_INPUT_INFO
] = "GET_SINK_INPUT_INFO",
77 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST
] = "GET_SINK_INPUT_INFO_LIST",
78 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO
] = "GET_SOURCE_OUTPUT_INFO",
79 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
] = "GET_SOURCE_OUTPUT_INFO_LIST",
80 [PA_COMMAND_SUBSCRIBE
] = "SUBSCRIBE",
81 [PA_COMMAND_SUBSCRIBE_EVENT
] = "SUBSCRIBE_EVENT",
82 [PA_COMMAND_SET_SINK_VOLUME
] = "SET_SINK_VOLUME",
83 [PA_COMMAND_SET_SINK_INPUT_VOLUME
] = "SET_SINK_INPUT_VOLUME",
84 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM
] = "TRIGGER_PLAYBACK_STREAM",
85 [PA_COMMAND_FLUSH_PLAYBACK_STREAM
] = "FLUSH_PLAYBACK_STREAM",
86 [PA_COMMAND_CORK_PLAYBACK_STREAM
] = "CORK_PLAYBACK_STREAM",
87 [PA_COMMAND_GET_AUTOLOAD_INFO
] = "GET_AUTOLOAD_INFO",
88 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST
] = "GET_AUTOLOAD_INFO_LIST",
94 pa_pdispatch
*pdispatch
;
95 PA_LLIST_FIELDS(struct reply_info
);
96 pa_pdispatch_callback callback
;
99 pa_time_event
*time_event
;
102 struct pa_pdispatch
{
104 pa_mainloop_api
*mainloop
;
105 const pa_pdispatch_callback
*callback_table
;
107 PA_LLIST_HEAD(struct reply_info
, replies
);
108 pa_pdispatch_drain_callback drain_callback
;
109 void *drain_userdata
;
112 static void reply_info_free(struct reply_info
*r
) {
113 assert(r
&& r
->pdispatch
&& r
->pdispatch
->mainloop
);
116 r
->pdispatch
->mainloop
->time_free(r
->time_event
);
118 PA_LLIST_REMOVE(struct reply_info
, r
->pdispatch
->replies
, r
);
123 pa_pdispatch
* pa_pdispatch_new(pa_mainloop_api
*mainloop
, const pa_pdispatch_callback
*table
, unsigned entries
) {
127 assert((entries
&& table
) || (!entries
&& !table
));
129 pd
= pa_xmalloc(sizeof(pa_pdispatch
));
131 pd
->mainloop
= mainloop
;
132 pd
->callback_table
= table
;
133 pd
->n_commands
= entries
;
134 PA_LLIST_HEAD_INIT(pa_reply_info
, pd
->replies
);
135 pd
->drain_callback
= NULL
;
136 pd
->drain_userdata
= NULL
;
141 static void pdispatch_free(pa_pdispatch
*pd
) {
145 reply_info_free(pd
->replies
);
150 static void run_action(pa_pdispatch
*pd
, struct reply_info
*r
, uint32_t command
, pa_tagstruct
*ts
) {
151 pa_pdispatch_callback callback
;
156 pa_pdispatch_ref(pd
);
158 callback
= r
->callback
;
159 userdata
= r
->userdata
;
164 callback(pd
, command
, tag
, ts
, userdata
);
166 if (pd
->drain_callback
&& !pa_pdispatch_is_pending(pd
))
167 pd
->drain_callback(pd
, pd
->drain_userdata
);
169 pa_pdispatch_unref(pd
);
172 int pa_pdispatch_run(pa_pdispatch
*pd
, pa_packet
*packet
, void *userdata
) {
173 uint32_t tag
, command
;
174 pa_tagstruct
*ts
= NULL
;
176 assert(pd
&& packet
&& packet
->data
);
178 pa_pdispatch_ref(pd
);
180 if (packet
->length
<= 8)
183 ts
= pa_tagstruct_new(packet
->data
, packet
->length
);
186 if (pa_tagstruct_getu32(ts
, &command
) < 0 ||
187 pa_tagstruct_getu32(ts
, &tag
) < 0)
194 if (!(p
= command_names
[command
]))
195 snprintf((char*) (p
= t
), sizeof(t
), "%u", command
);
197 pa_log(__FILE__
": Recieved opcode <%s>\n", p
);
201 if (command
== PA_COMMAND_ERROR
|| command
== PA_COMMAND_REPLY
) {
202 struct reply_info
*r
;
204 for (r
= pd
->replies
; r
; r
= r
->next
)
209 run_action(pd
, r
, command
, ts
);
211 } else if (pd
->callback_table
&& (command
< pd
->n_commands
) && pd
->callback_table
[command
]) {
212 const pa_pdispatch_callback
*c
= pd
->callback_table
+command
;
214 (*c
)(pd
, command
, tag
, ts
, userdata
);
216 pa_log(__FILE__
": Recieved unsupported command %u\n", command
);
224 pa_tagstruct_free(ts
);
226 pa_pdispatch_unref(pd
);
231 static void timeout_callback(pa_mainloop_api
*m
, pa_time_event
*e
, PA_GCC_UNUSED
const struct timeval
*tv
, void *userdata
) {
232 struct reply_info
*r
= userdata
;
233 assert(r
&& r
->time_event
== e
&& r
->pdispatch
&& r
->pdispatch
->mainloop
== m
&& r
->callback
);
235 run_action(r
->pdispatch
, r
, PA_COMMAND_TIMEOUT
, NULL
);
238 void pa_pdispatch_register_reply(pa_pdispatch
*pd
, uint32_t tag
, int timeout
, pa_pdispatch_callback cb
, void *userdata
) {
239 struct reply_info
*r
;
241 assert(pd
&& pd
->ref
>= 1 && cb
);
243 r
= pa_xmalloc(sizeof(struct reply_info
));
246 r
->userdata
= userdata
;
249 pa_gettimeofday(&tv
);
250 tv
.tv_sec
+= timeout
;
252 r
->time_event
= pd
->mainloop
->time_new(pd
->mainloop
, &tv
, timeout_callback
, r
);
253 assert(r
->time_event
);
255 PA_LLIST_PREPEND(struct reply_info
, pd
->replies
, r
);
258 int pa_pdispatch_is_pending(pa_pdispatch
*pd
) {
261 return !!pd
->replies
;
264 void pa_pdispatch_set_drain_callback(pa_pdispatch
*pd
, void (*cb
)(pa_pdispatch
*pd
, void *userdata
), void *userdata
) {
266 assert(!cb
|| pa_pdispatch_is_pending(pd
));
268 pd
->drain_callback
= cb
;
269 pd
->drain_userdata
= userdata
;
272 void pa_pdispatch_unregister_reply(pa_pdispatch
*pd
, void *userdata
) {
273 struct reply_info
*r
, *n
;
276 for (r
= pd
->replies
; r
; r
= n
) {
279 if (r
->userdata
== userdata
)
284 void pa_pdispatch_unref(pa_pdispatch
*pd
) {
285 assert(pd
&& pd
->ref
>= 1);
291 pa_pdispatch
* pa_pdispatch_ref(pa_pdispatch
*pd
) {
292 assert(pd
&& pd
->ref
>= 1);