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 "pdispatch.h"
31 #include "native-common.h"
35 /*#define DEBUG_OPCODES*/
39 static const char *command_names
[PA_COMMAND_MAX
] = {
40 [PA_COMMAND_ERROR
] = "ERROR",
41 [PA_COMMAND_TIMEOUT
] = "TIMEOUT",
42 [PA_COMMAND_REPLY
] = "REPLY",
43 [PA_COMMAND_CREATE_PLAYBACK_STREAM
] = "CREATE_PLAYBACK_STREAM",
44 [PA_COMMAND_DELETE_PLAYBACK_STREAM
] = "DELETE_PLAYBACK_STREAM",
45 [PA_COMMAND_CREATE_RECORD_STREAM
] = "CREATE_RECORD_STREAM",
46 [PA_COMMAND_DELETE_RECORD_STREAM
] = "DELETE_RECORD_STREAM",
47 [PA_COMMAND_AUTH
] = "AUTH",
48 [PA_COMMAND_REQUEST
] = "REQUEST",
49 [PA_COMMAND_EXIT
] = "EXIT",
50 [PA_COMMAND_SET_NAME
] = "SET_NAME",
51 [PA_COMMAND_LOOKUP_SINK
] = "LOOKUP_SINK",
52 [PA_COMMAND_LOOKUP_SOURCE
] = "LOOKUP_SOURCE",
53 [PA_COMMAND_DRAIN_PLAYBACK_STREAM
] = "DRAIN_PLAYBACK_STREAM",
54 [PA_COMMAND_PLAYBACK_STREAM_KILLED
] = "PLAYBACK_STREAM_KILLED",
55 [PA_COMMAND_RECORD_STREAM_KILLED
] = "RECORD_STREAM_KILLED",
56 [PA_COMMAND_STAT
] = "STAT",
57 [PA_COMMAND_GET_PLAYBACK_LATENCY
] = "PLAYBACK_LATENCY",
58 [PA_COMMAND_CREATE_UPLOAD_STREAM
] = "CREATE_UPLOAD_STREAM",
59 [PA_COMMAND_DELETE_UPLOAD_STREAM
] = "DELETE_UPLOAD_STREAM",
60 [PA_COMMAND_FINISH_UPLOAD_STREAM
] = "FINISH_UPLOAD_STREAM",
61 [PA_COMMAND_PLAY_SAMPLE
] = "PLAY_SAMPLE",
62 [PA_COMMAND_REMOVE_SAMPLE
] = "REMOVE_SAMPLE",
68 struct pa_pdispatch
*pdispatch
;
69 PA_LLIST_FIELDS(struct reply_info
);
70 void (*callback
)(struct pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, struct pa_tagstruct
*t
, void *userdata
);
73 struct pa_time_event
*time_event
;
78 struct pa_mainloop_api
*mainloop
;
79 const struct pa_pdispatch_command
*command_table
;
81 PA_LLIST_HEAD(struct reply_info
, replies
);
82 void (*drain_callback
)(struct pa_pdispatch
*pd
, void *userdata
);
86 static void reply_info_free(struct reply_info
*r
) {
87 assert(r
&& r
->pdispatch
&& r
->pdispatch
->mainloop
);
90 r
->pdispatch
->mainloop
->time_free(r
->time_event
);
92 PA_LLIST_REMOVE(struct reply_info
, r
->pdispatch
->replies
, r
);
97 struct pa_pdispatch
* pa_pdispatch_new(struct pa_mainloop_api
*mainloop
, const struct pa_pdispatch_command
*table
, unsigned entries
) {
98 struct pa_pdispatch
*pd
;
101 assert((entries
&& table
) || (!entries
&& !table
));
103 pd
= pa_xmalloc(sizeof(struct pa_pdispatch
));
105 pd
->mainloop
= mainloop
;
106 pd
->command_table
= table
;
107 pd
->n_commands
= entries
;
108 PA_LLIST_HEAD_INIT(struct pa_reply_info
, pd
->replies
);
109 pd
->drain_callback
= NULL
;
110 pd
->drain_userdata
= NULL
;
115 void pdispatch_free(struct pa_pdispatch
*pd
) {
119 reply_info_free(pd
->replies
);
124 static void run_action(struct pa_pdispatch
*pd
, struct reply_info
*r
, uint32_t command
, struct pa_tagstruct
*ts
) {
125 void (*callback
)(struct pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, struct pa_tagstruct
*t
, void *userdata
);
130 pa_pdispatch_ref(pd
);
132 callback
= r
->callback
;
133 userdata
= r
->userdata
;
138 callback(pd
, command
, tag
, ts
, userdata
);
140 if (pd
->drain_callback
&& !pa_pdispatch_is_pending(pd
))
141 pd
->drain_callback(pd
, pd
->drain_userdata
);
143 pa_pdispatch_unref(pd
);
146 int pa_pdispatch_run(struct pa_pdispatch
*pd
, struct pa_packet
*packet
, void *userdata
) {
147 uint32_t tag
, command
;
148 struct pa_tagstruct
*ts
= NULL
;
150 assert(pd
&& packet
&& packet
->data
);
152 pa_pdispatch_ref(pd
);
154 if (packet
->length
<= 8)
157 ts
= pa_tagstruct_new(packet
->data
, packet
->length
);
160 if (pa_tagstruct_getu32(ts
, &command
) < 0 ||
161 pa_tagstruct_getu32(ts
, &tag
) < 0)
165 fprintf(stderr
, __FILE__
": Recieved opcode <%s>\n", command_names
[command
]);
168 if (command
== PA_COMMAND_ERROR
|| command
== PA_COMMAND_REPLY
) {
169 struct reply_info
*r
;
171 for (r
= pd
->replies
; r
; r
= r
->next
)
176 run_action(pd
, r
, command
, ts
);
178 } else if (pd
->command_table
&& (command
< pd
->n_commands
) && pd
->command_table
[command
].proc
) {
179 const struct pa_pdispatch_command
*c
= pd
->command_table
+command
;
181 c
->proc(pd
, command
, tag
, ts
, userdata
);
183 fprintf(stderr
, "Recieved unsupported command %u\n", command
);
191 pa_tagstruct_free(ts
);
193 pa_pdispatch_unref(pd
);
198 static void timeout_callback(struct pa_mainloop_api
*m
, struct pa_time_event
*e
, const struct timeval
*tv
, void *userdata
) {
199 struct reply_info
*r
= userdata
;
200 assert(r
&& r
->time_event
== e
&& r
->pdispatch
&& r
->pdispatch
->mainloop
== m
&& r
->callback
);
202 run_action(r
->pdispatch
, r
, PA_COMMAND_TIMEOUT
, NULL
);
205 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
) {
206 struct reply_info
*r
;
208 assert(pd
&& pd
->ref
>= 1 && cb
);
210 r
= pa_xmalloc(sizeof(struct reply_info
));
213 r
->userdata
= userdata
;
216 gettimeofday(&tv
, NULL
);
217 tv
.tv_sec
+= timeout
;
219 r
->time_event
= pd
->mainloop
->time_new(pd
->mainloop
, &tv
, timeout_callback
, r
);
220 assert(r
->time_event
);
222 PA_LLIST_PREPEND(struct reply_info
, pd
->replies
, r
);
225 int pa_pdispatch_is_pending(struct pa_pdispatch
*pd
) {
228 return !!pd
->replies
;
231 void pa_pdispatch_set_drain_callback(struct pa_pdispatch
*pd
, void (*cb
)(struct pa_pdispatch
*pd
, void *userdata
), void *userdata
) {
233 assert(!cb
|| pa_pdispatch_is_pending(pd
));
235 pd
->drain_callback
= cb
;
236 pd
->drain_userdata
= userdata
;
239 void pa_pdispatch_unregister_reply(struct pa_pdispatch
*pd
, void *userdata
) {
240 struct reply_info
*r
, *n
;
243 for (r
= pd
->replies
; r
; r
= n
) {
246 if (r
->userdata
== userdata
)
251 void pa_pdispatch_unref(struct pa_pdispatch
*pd
) {
252 assert(pd
&& pd
->ref
>= 1);
258 struct pa_pdispatch
* pa_pdispatch_ref(struct pa_pdispatch
*pd
) {
259 assert(pd
&& pd
->ref
>= 1);