source: mainline/uspace/lib/hound/src/protocol.c@ 059490c2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 059490c2 was 059490c2, checked in by Jan Vesely <jano.vesely@…>, 12 years ago

libhound: Add protocol header

  • Property mode set to 100644
File size: 10.2 KB
RevLine 
[afa7c17]1/*
2 * Copyright (c) 2012 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libhound
30 * @addtogroup audio
31 * @{
32 */
33/** @file
34 * Common USB functions.
35 */
[89d3946f]36#include <adt/list.h>
[afa7c17]37#include <errno.h>
38#include <loc.h>
39#include <str.h>
40#include <stdlib.h>
[89d3946f]41#include <stdio.h>
42#include <libarch/types.h>
[afa7c17]43
[059490c2]44#include "protocol.h"
[afa7c17]45#include "client.h"
46#include "server.h"
47
[059490c2]48const char *HOUND_SERVICE = "audio/hound";
49
50hound_sess_t *hound_service_connect(const char *service)
51{
52 service_id_t id = 0;
53 const int ret =
54 loc_service_get_id(service, &id, IPC_FLAG_BLOCKING);
55 if (ret != EOK)
56 return NULL;
57 return loc_service_connect(EXCHANGE_PARALLEL, id, IPC_FLAG_BLOCKING);
58}
59
60void hound_service_disconnect(hound_sess_t *sess)
61{
62 if (sess)
63 async_hangup(sess);
64}
[afa7c17]65
66/***
67 * CLIENT SIDE
68 ***/
69
70typedef struct {
71 data_callback_t cb;
72 void *arg;
73} callback_t;
74
[059490c2]75hound_sess_t *hound_get_session(void)
76{
77 return hound_service_connect(HOUND_SERVICE);
78}
79
80void hound_release_session(hound_sess_t *sess)
81{
82 hound_service_disconnect(sess);
83}
84
[afa7c17]85
86static int hound_register(hound_sess_t *sess, unsigned cmd, const char *name,
87 unsigned channels, unsigned rate, pcm_sample_format_t format,
88 data_callback_t data_callback, void *arg);
89static int hound_unregister(hound_sess_t *sess, unsigned cmd, const char *name);
90static int hound_connection(hound_sess_t *sess, unsigned cmd,
91 const char *source, const char *sink);
92static void callback_pb(ipc_callid_t iid, ipc_call_t *call, void *arg);
93static void callback_rec(ipc_callid_t iid, ipc_call_t *call, void *arg);
94
95
96int hound_register_playback(hound_sess_t *sess, const char *name,
97 unsigned channels, unsigned rate, pcm_sample_format_t format,
98 data_callback_t data_callback, void *arg)
99{
100 return hound_register(sess, HOUND_REGISTER_PLAYBACK, name, channels,
101 rate, format, data_callback, arg);
102}
103int hound_register_recording(hound_sess_t *sess, const char *name,
104 unsigned channels, unsigned rate, pcm_sample_format_t format,
105 data_callback_t data_callback, void *arg)
106{
107 return hound_register(sess, HOUND_REGISTER_RECORDING, name, channels,
108 rate, format, data_callback, arg);
109
110}
111int hound_unregister_playback(hound_sess_t *sess, const char *name)
112{
113 return hound_unregister(sess, HOUND_UNREGISTER_PLAYBACK, name);
114}
115int hound_unregister_recording(hound_sess_t *sess, const char *name)
116{
117 return hound_unregister(sess, HOUND_UNREGISTER_RECORDING, name);
118}
119int hound_create_connection(hound_sess_t *sess, const char *source, const char *sink)
120{
121 return hound_connection(sess, HOUND_CONNECT, source, sink);
122}
123int hound_destroy_connection(hound_sess_t *sess, const char *source, const char *sink)
124{
125 return hound_connection(sess, HOUND_DISCONNECT, source, sink);
126}
127
128static int hound_register(hound_sess_t *sess, unsigned cmd, const char *name,
129 unsigned channels, unsigned rate, pcm_sample_format_t format,
130 data_callback_t data_callback, void *arg)
131{
132 assert(cmd == HOUND_REGISTER_PLAYBACK || cmd == HOUND_REGISTER_RECORDING);
133 if (!name || !data_callback || !sess)
134 return EINVAL;
135
136 async_exch_t *exch = async_exchange_begin(sess);
137 if (!exch)
138 return ENOMEM;
139
140 aid_t id = async_send_0(exch, cmd, NULL);
141
142 int ret = async_data_write_start(exch, name, str_size(name));
143 if (ret != EOK) {
144 async_forget(id);
145 async_exchange_end(exch);
146 return ret;
147 }
148
149 callback_t *cb = malloc(sizeof(callback_t));
150 if (!cb) {
151 async_forget(id);
152 async_exchange_end(exch);
153 return ENOMEM;
154 }
155
156 cb->cb = data_callback;
157 cb->arg = arg;
158 async_client_conn_t callback =
159 (cmd == HOUND_REGISTER_PLAYBACK) ? callback_pb : callback_rec;
160
161 ret = async_connect_to_me(exch, channels, rate, format, callback, cb);
162 if (ret != EOK) {
163 async_forget(id);
164 async_exchange_end(exch);
165 free(cb);
166 return ret;
167 }
168
169 async_wait_for(id, (sysarg_t*)&ret);
170 if (ret != EOK) {
171 async_exchange_end(exch);
172 free(cb);
173 return ret;
174 }
175
176 async_exchange_end(exch);
177 return EOK;
178}
179
180static int hound_unregister(hound_sess_t *sess, unsigned cmd, const char *name)
181{
182 assert(cmd == HOUND_UNREGISTER_PLAYBACK || cmd == HOUND_UNREGISTER_RECORDING);
183 if (!name || !sess)
184 return EINVAL;
185
186 async_exch_t *exch = async_exchange_begin(sess);
187 if (!exch)
188 return ENOMEM;
189 aid_t id = async_send_0(exch, cmd, NULL);
190 sysarg_t ret = async_data_write_start(exch, name, str_size(name));
191 if (ret != EOK) {
192 async_forget(id);
193 async_exchange_end(exch);
194 return ret;
195 }
196
197 async_wait_for(id, &ret);
198 async_exchange_end(exch);
199 return ret;
200}
201
202static int hound_connection(hound_sess_t *sess, unsigned cmd,
203 const char *source, const char *sink)
204{
205 assert(cmd == HOUND_CONNECT || cmd == HOUND_DISCONNECT);
206 if (!source || !sink || !sess)
207 return EINVAL;
208
209 async_exch_t *exch = async_exchange_begin(sess);
210 if (!exch)
211 return ENOMEM;
212
213 aid_t id = async_send_0(exch, cmd, NULL);
214 sysarg_t ret = async_data_write_start(exch, source, str_size(source));
215 if (ret != EOK) {
216 async_forget(id);
217 async_exchange_end(exch);
218 return ret;
219 }
220 ret = async_data_write_start(exch, sink, str_size(sink));
221 if (ret != EOK) {
222 async_forget(id);
223 async_exchange_end(exch);
224 return ret;
225 }
226 async_wait_for(id, &ret);
227 async_exchange_end(exch);
228 return ret;
229}
230static void callback_gen(ipc_callid_t iid, ipc_call_t *call, void *arg,
231 bool read)
232{
233 async_answer_0(iid, EOK);
234 callback_t *cb = arg;
235 assert(cb);
236 void *buffer = NULL;
237 size_t buffer_size = 0;
238
239 bool (*receive)(ipc_callid_t *, size_t *) = read ?
240 async_data_read_receive : async_data_write_receive;
241
242 while (1) {
243 size_t size = 0;
244 ipc_callid_t id = 0;
245 if (!receive(&id, &size)) {
[a9aae16e]246 ipc_call_t failed_call;
247 async_get_call(&failed_call);
248 /* Protocol error or hangup */
249 if (IPC_GET_IMETHOD(failed_call) != 0)
250 cb->cb(cb->arg, NULL, EIO);
[afa7c17]251 free(cb);
252 return;
253 }
254
255 if (buffer_size < size) {
256 buffer = realloc(buffer, size);
257 if (!buffer) {
258 cb->cb(cb->arg, NULL, ENOMEM);
259 free(cb);
260 return;
261 }
262 buffer_size = size;
263 }
264 if (read)
265 cb->cb(cb->arg, buffer, size);
266 const int ret = read ?
267 async_data_read_finalize(id, buffer, size):
268 async_data_write_finalize(id, buffer, size);
269 if (ret != EOK) {
270 cb->cb(cb->arg, NULL, ret);
271 free(cb);
272 return;
273 }
274 if (!read)
275 cb->cb(cb->arg, buffer, size);
276 }
277}
278
279static void callback_pb(ipc_callid_t iid, ipc_call_t *call, void *arg)
280{
281 callback_gen(iid, call, arg, true);
282}
283
284static void callback_rec(ipc_callid_t iid, ipc_call_t *call, void *arg)
285{
286 callback_gen(iid, call, arg, false);
287}
288
289/***
290 * SERVER SIDE
291 ***/
292static const char * get_name(void);
293
294int hound_server_register(const char *name, service_id_t *id)
295{
296 if (!name || !id)
297 return EINVAL;
298
299 int ret = loc_server_register(name);
300 if (ret != EOK)
301 return ret;
302
303 return loc_service_register(HOUND_SERVICE, id);
304}
305
306void hound_server_unregister(service_id_t id)
307{
308 loc_service_unregister(id);
309}
310
311int hound_server_set_device_change_callback(dev_change_callback_t cb)
312{
313 return loc_register_cat_change_cb(cb);
314}
315
316int hound_server_devices_iterate(device_callback_t callback)
317{
318 if (!callback)
319 return EINVAL;
320 static bool resolved = false;
321 static category_id_t cat_id = 0;
322
323 if (!resolved) {
324 const int ret = loc_category_get_id("audio-pcm", &cat_id,
325 IPC_FLAG_BLOCKING);
326 if (ret != EOK)
327 return ret;
328 resolved = true;
329 }
330
331 service_id_t *svcs = NULL;
332 size_t count = 0;
333 const int ret = loc_category_get_svcs(cat_id, &svcs, &count);
334 if (ret != EOK)
335 return ret;
336
337 for (unsigned i = 0; i < count; ++i) {
338 char *name = NULL;
339 loc_service_get_name(svcs[i], &name);
340 callback(svcs[i], name);
341 free(name);
342 }
343 free(svcs);
344 return EOK;
345}
346
347int hound_server_get_register_params(const char **name, async_sess_t **sess,
348 unsigned *channels, unsigned *rate, pcm_sample_format_t *format)
349{
350 if (!name || !sess || !channels || !rate || !format)
351 return EINVAL;
352
353 const char *n = get_name();
354 if (!n)
355 return ENOMEM;
356
357 ipc_call_t call;
358 ipc_callid_t callid = async_get_call(&call);
359
360 unsigned ch = IPC_GET_ARG1(call);
361 unsigned r = IPC_GET_ARG2(call);
362 pcm_sample_format_t f = IPC_GET_ARG3(call);
363
364 async_sess_t *s = async_callback_receive_start(EXCHANGE_ATOMIC, &call);
365 async_answer_0(callid, s ? EOK : ENOMEM);
366
367 *name = n;
368 *sess = s;
369 *channels = ch;
370 *rate = r;
371 *format = f;
372
373 return ENOTSUP;
374}
375
376int hound_server_get_unregister_params(const char **name)
377{
378 if (!name)
379 return EINVAL;
380 *name = get_name();
381 if (!*name)
382 return ENOMEM;
383 return EOK;
384}
385
386int hound_server_get_connection_params(const char **source, const char **sink)
387{
388 if (!source || !sink)
389 return EINVAL;
390
391 const char *source_name = get_name();
392 if (!source_name)
393 return ENOMEM;
394
395 const char *sink_name = get_name();
396 if (!sink_name)
397 return ENOMEM;
398
399 *source = source_name;
400 *sink = sink_name;
401 return EOK;
402}
403
404static const char * get_name(void)
405{
406 size_t size = 0;
407 ipc_callid_t callid;
408 async_data_write_receive(&callid, &size);
409 char *buffer = malloc(size + 1);
410 if (buffer) {
411 async_data_write_finalize(callid, buffer, size);
412 buffer[size] = 0;
413 }
414 return buffer;
415}
416
417/**
418 * @}
419 */
Note: See TracBrowser for help on using the repository browser.