source: mainline/uspace/lib/hound/src/protocol.c@ 35ab943

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

libhound: zero entire allocated space

  • Property mode set to 100644
File size: 21.2 KB
Line 
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 */
36#include <adt/list.h>
37#include <errno.h>
38#include <loc.h>
39#include <macros.h>
40#include <str.h>
41#include <stdlib.h>
42#include <stdio.h>
43#include <libarch/types.h>
44
45#include "protocol.h"
46#include "client.h"
47#include "server.h"
48
49enum ipc_methods {
50 IPC_M_HOUND_CONTEXT_REGISTER = IPC_FIRST_USER_METHOD,
51 IPC_M_HOUND_CONTEXT_UNREGISTER,
52 IPC_M_HOUND_GET_LIST,
53 IPC_M_HOUND_CONNECT,
54 IPC_M_HOUND_DISCONNECT,
55 IPC_M_HOUND_STREAM_ENTER,
56 IPC_M_HOUND_STREAM_EXIT,
57 IPC_M_HOUND_STREAM_DRAIN,
58};
59
60/****
61 * CLIENT
62 ****/
63
64const char *HOUND_SERVICE = "audio/hound";
65
66hound_sess_t *hound_service_connect(const char *service)
67{
68 service_id_t id = 0;
69 const int ret =
70 loc_service_get_id(service, &id, IPC_FLAG_BLOCKING);
71 if (ret != EOK)
72 return NULL;
73 return loc_service_connect(EXCHANGE_PARALLEL, id, IPC_FLAG_BLOCKING);
74}
75
76void hound_service_disconnect(hound_sess_t *sess)
77{
78 if (sess)
79 async_hangup(sess);
80}
81
82hound_context_id_t hound_service_register_context(hound_sess_t *sess,
83 const char *name, bool record)
84{
85 assert(sess);
86 assert(name);
87 ipc_call_t call;
88 async_exch_t *exch = async_exchange_begin(sess);
89 aid_t mid =
90 async_send_1(exch, IPC_M_HOUND_CONTEXT_REGISTER, record, &call);
91 int ret = mid ? EOK : EPARTY;
92
93 if (ret == EOK)
94 ret = async_data_write_start(exch, name, str_size(name));
95 else
96 async_forget(mid);
97
98 if (ret == EOK)
99 async_wait_for(mid, (sysarg_t *)&ret);
100
101 async_exchange_end(exch);
102 return ret == EOK ? (hound_context_id_t)IPC_GET_ARG1(call) : ret;
103}
104
105int hound_service_unregister_context(hound_sess_t *sess, hound_context_id_t id)
106{
107 assert(sess);
108 async_exch_t *exch = async_exchange_begin(sess);
109 const int ret =
110 async_req_1_0(exch, IPC_M_HOUND_CONTEXT_UNREGISTER, id);
111 async_exchange_end(exch);
112 return ret;
113}
114
115int hound_service_get_list(hound_sess_t *sess, const char ***ids, size_t *count,
116 int flags, const char *connection)
117{
118 assert(sess);
119 assert(ids);
120 assert(count);
121
122 if (connection && !(flags & HOUND_CONNECTED))
123 return EINVAL;
124
125 async_exch_t *exch = async_exchange_begin(sess);
126 if (!exch)
127 return ENOMEM;
128
129 ipc_call_t res_call;
130 aid_t mid = async_send_3(exch, IPC_M_HOUND_GET_LIST, flags, *count,
131 (bool)connection, &res_call);
132
133 int ret = EOK;
134 if (mid && connection)
135 ret = async_data_write_start(exch, connection,
136 str_size(connection));
137
138 if (ret == EOK)
139 async_wait_for(mid, (sysarg_t*)&ret);
140
141 if (ret != EOK) {
142 async_exchange_end(exch);
143 return ret;
144 }
145 unsigned name_count = IPC_GET_ARG1(res_call);
146
147 /* Start receiving names */
148 const char **names = NULL;
149 if (name_count) {
150 size_t *sizes = calloc(name_count, sizeof(size_t));
151 names = calloc(name_count, sizeof(char *));
152 if (!names || !sizes)
153 ret = ENOMEM;
154
155 if (ret == EOK)
156 ret = async_data_read_start(exch, sizes,
157 name_count * sizeof(size_t));
158 for (unsigned i = 0; i < name_count && ret == EOK; ++i) {
159 char *name = malloc(sizes[i] + 1);
160 if (name) {
161 bzero(name, sizes[i] + 1);
162 ret = async_data_read_start(exch, name, sizes[i]);
163 names[i] = name;
164 } else {
165 ret = ENOMEM;
166 }
167 }
168 free(sizes);
169 }
170 async_exchange_end(exch);
171 if (ret != EOK) {
172 for (unsigned i = 0; i < name_count; ++i)
173 free(names[i]);
174 free(names);
175 } else {
176 *ids = names;
177 *count = name_count;
178 }
179 return ret;
180}
181
182int hound_service_connect_source_sink(hound_sess_t *sess, const char *source,
183 const char *sink)
184{
185 assert(sess);
186 assert(source);
187 assert(sink);
188
189 async_exch_t *exch = async_exchange_begin(sess);
190 if (!exch)
191 return ENOMEM;
192 ipc_call_t call;
193 aid_t id = async_send_0(exch, IPC_M_HOUND_CONNECT, &call);
194 int ret = id ? EOK : EPARTY;
195 if (ret == EOK)
196 ret = async_data_write_start(exch, source, str_size(source));
197 if (ret == EOK)
198 ret = async_data_write_start(exch, sink, str_size(sink));
199 async_wait_for(id, (sysarg_t*)&ret);
200 async_exchange_end(exch);
201 return ret;
202}
203
204int hound_service_disconnect_source_sink(hound_sess_t *sess, const char *source,
205 const char *sink)
206{
207 assert(sess);
208 async_exch_t *exch = async_exchange_begin(sess);
209 if (!exch)
210 return ENOMEM;
211 ipc_call_t call;
212 aid_t id = async_send_0(exch, IPC_M_HOUND_DISCONNECT, &call);
213 int ret = id ? EOK : EPARTY;
214 if (ret == EOK)
215 ret = async_data_write_start(exch, source, str_size(source));
216 if (ret == EOK)
217 ret = async_data_write_start(exch, sink, str_size(sink));
218 async_wait_for(id, (sysarg_t*)&ret);
219 async_exchange_end(exch);
220 return ENOTSUP;
221}
222
223int hound_service_stream_enter(async_exch_t *exch, hound_context_id_t id,
224 int flags, pcm_format_t format, size_t bsize)
225{
226 union {
227 sysarg_t arg;
228 pcm_format_t format;
229 } convert = { .format = format };
230 return async_req_4_0(exch, IPC_M_HOUND_STREAM_ENTER, id, flags,
231 convert.arg, bsize);
232}
233
234int hound_service_stream_exit(async_exch_t *exch)
235{
236 return async_req_0_0(exch, IPC_M_HOUND_STREAM_EXIT);
237}
238
239int hound_service_stream_drain(async_exch_t *exch)
240{
241 return async_req_0_0(exch, IPC_M_HOUND_STREAM_DRAIN);
242}
243
244int hound_service_stream_write(async_exch_t *exch, const void *data, size_t size)
245{
246 return async_data_write_start(exch, data, size);
247}
248
249int hound_service_stream_read(async_exch_t *exch, void *data, size_t size)
250{
251 return async_data_read_start(exch, data, size);
252}
253
254/****
255 * SERVER
256 ****/
257
258static void hound_server_read_data(void *stream);
259static void hound_server_write_data(void *stream);
260static const hound_server_iface_t *server_iface;
261
262void hound_service_set_server_iface(const hound_server_iface_t *iface)
263{
264 server_iface = iface;
265}
266
267void hound_connection_handler(ipc_callid_t iid, ipc_call_t *icall, void *arg)
268{
269 /* Accept connection if there is a valid iface*/
270 if (server_iface) {
271 async_answer_0(iid, EOK);
272 } else {
273 async_answer_0(iid, ENOTSUP);
274 return;
275 }
276
277 while (1) {
278 ipc_call_t call;
279 ipc_callid_t callid = async_get_call(&call);
280 switch (IPC_GET_IMETHOD(call)) {
281 case IPC_M_HOUND_CONTEXT_REGISTER: {
282 if (!server_iface || !server_iface->add_context) {
283 async_answer_0(callid, ENOTSUP);
284 break;
285 }
286 bool record = IPC_GET_ARG1(call);
287 void *name;
288 int ret =
289 async_data_write_accept(&name, true, 0, 0, 0, 0);
290 if (ret != EOK) {
291 async_answer_0(callid, ret);
292 break;
293 }
294 hound_context_id_t id = 0;
295 ret = server_iface->add_context(server_iface->server,
296 &id, name, record);
297 if (ret != EOK) {
298 free(name);
299 async_answer_0(callid, ret);
300 } else {
301 async_answer_1(callid, EOK, id);
302 }
303 break;
304 }
305 case IPC_M_HOUND_CONTEXT_UNREGISTER: {
306 if (!server_iface || !server_iface->rem_context) {
307 async_answer_0(callid, ENOTSUP);
308 break;
309 }
310 hound_context_id_t id = IPC_GET_ARG1(call);
311 const int ret =
312 server_iface->rem_context(server_iface->server, id);
313 async_answer_0(callid, ret);
314 break;
315 }
316 case IPC_M_HOUND_GET_LIST: {
317 if (!server_iface || !server_iface->get_list) {
318 async_answer_0(callid, ENOTSUP);
319 break;
320 }
321 const char **list = NULL;
322 const int flags = IPC_GET_ARG1(call);
323 size_t count = IPC_GET_ARG2(call);
324 const bool conn = IPC_GET_ARG3(call);
325 char *conn_name = NULL;
326 int ret = EOK;
327 if (conn)
328 ret = async_data_write_accept(
329 (void**)&conn_name, true, 0, 0, 0, 0);
330
331 if (ret == EOK)
332 ret = server_iface->get_list(
333 server_iface->server, &list, &count,
334 conn_name, flags);
335 free(conn_name);
336 size_t *sizes = NULL;
337 if (count)
338 sizes = calloc(count, sizeof(size_t));
339 if (count && !sizes)
340 ret = ENOMEM;
341 async_answer_1(callid, ret, count);
342
343 /* We are done */
344 if (count == 0 || ret != EOK)
345 break;
346
347 /* Prepare sizes table */
348 for (unsigned i = 0; i < count; ++i)
349 sizes[i] = str_size(list[i]);
350
351 /* Send sizes table */
352 ipc_callid_t id;
353 if (async_data_read_receive(&id, NULL)) {
354 ret = async_data_read_finalize(id, sizes,
355 count * sizeof(size_t));
356 }
357 free(sizes);
358
359 /* Proceed to send names */
360 for (unsigned i = 0; i < count; ++i) {
361 size_t size = str_size(list[i]);
362 ipc_callid_t id;
363 if (ret == EOK &&
364 async_data_read_receive(&id, NULL)) {
365 ret = async_data_read_finalize(id,
366 list[i], size);
367 }
368 free(list[i]);
369 }
370 free(list);
371 break;
372 }
373 case IPC_M_HOUND_CONNECT: {
374 if (!server_iface || !server_iface->connect) {
375 async_answer_0(callid, ENOTSUP);
376 break;
377 }
378 void *source = NULL;
379 void *sink = NULL;
380 int ret =
381 async_data_write_accept(&source, true, 0, 0, 0, 0);
382 if (ret == EOK)
383 ret = async_data_write_accept(&sink,
384 true, 0, 0, 0, 0);
385 if (ret == EOK)
386 ret = server_iface->connect(
387 server_iface->server, source, sink);
388 free(source);
389 free(sink);
390 async_answer_0(callid, ret);
391 break;
392 }
393 case IPC_M_HOUND_DISCONNECT: {
394 if (!server_iface || !server_iface->disconnect) {
395 async_answer_0(callid, ENOTSUP);
396 break;
397 }
398 void *source = NULL;
399 void *sink = NULL;
400 int ret =
401 async_data_write_accept(&source, true, 0, 0, 0, 0);
402 if (ret == EOK)
403 ret = async_data_write_accept(&sink,
404 true, 0, 0, 0, 0);
405 if (ret == EOK)
406 ret = server_iface->connect(
407 server_iface->server, source, sink);
408 free(source);
409 free(sink);
410 async_answer_0(callid, ret);
411 break;
412 }
413 case IPC_M_HOUND_STREAM_ENTER: {
414 if (!server_iface || !server_iface->is_record_context
415 || !server_iface->add_stream
416 || !server_iface->rem_stream) {
417 async_answer_0(callid, ENOTSUP);
418 break;
419 }
420
421 hound_context_id_t id = IPC_GET_ARG1(call);
422 int flags = IPC_GET_ARG2(call);
423 union {
424 sysarg_t arg;
425 pcm_format_t format;
426 } convert = { .arg = IPC_GET_ARG3(call) };
427 size_t bsize = IPC_GET_ARG4(call);
428 void *stream;
429 int ret = server_iface->add_stream(server_iface->server,
430 id, flags, convert.format, bsize, &stream);
431 if (ret != EOK) {
432 async_answer_0(callid, ret);
433 break;
434 }
435 const bool rec = server_iface->is_record_context(
436 server_iface->server, id);
437 if (rec) {
438 if(server_iface->stream_data_read) {
439 async_answer_0(callid, EOK);
440 hound_server_write_data(stream);
441 server_iface->rem_stream(
442 server_iface->server, stream);
443 } else {
444 async_answer_0(callid, ENOTSUP);
445 }
446 } else {
447 if (server_iface->stream_data_write) {
448 async_answer_0(callid, EOK);
449 hound_server_read_data(stream);
450 server_iface->rem_stream(
451 server_iface->server, stream);
452 } else {
453 async_answer_0(callid, ENOTSUP);
454 }
455 }
456 break;
457 }
458 case IPC_M_HOUND_STREAM_EXIT:
459 case IPC_M_HOUND_STREAM_DRAIN:
460 /* Stream exit/drain is only allowed in stream context*/
461 async_answer_0(callid, EINVAL);
462 break;
463 default:
464 async_answer_0(callid, ENOTSUP);
465 return;
466 }
467 }
468}
469
470static void hound_server_read_data(void *stream)
471{
472 ipc_callid_t callid;
473 ipc_call_t call;
474 size_t size = 0;
475 while (async_data_write_receive_call(&callid, &call, &size)) {
476 char *buffer = malloc(size);
477 if (!buffer) {
478 async_answer_0(callid, ENOMEM);
479 continue;
480 }
481 int ret = async_data_write_finalize(callid, buffer, size);
482 if (ret == EOK) {
483 ret = server_iface->stream_data_write(stream, buffer, size);
484 }
485 async_answer_0(callid, ret);
486 }
487 //TODO drain?
488 const int ret = IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_EXIT
489 ? EOK : EINVAL;
490
491 async_answer_0(callid, ret);
492}
493
494static void hound_server_write_data(void *stream)
495{
496
497 ipc_callid_t callid;
498 ipc_call_t call;
499 size_t size = 0;
500 while (async_data_read_receive_call(&callid, &call, &size)) {
501 char *buffer = malloc(size);
502 if (!buffer) {
503 async_answer_0(callid, ENOMEM);
504 continue;
505 }
506 int ret = server_iface->stream_data_read(stream, buffer, size);
507 if (ret == EOK) {
508 ret = async_data_read_finalize(callid, buffer, size);
509 }
510 async_answer_0(callid, ret);
511 }
512 const int ret = IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_EXIT
513 ? EOK : EINVAL;
514
515 async_answer_0(callid, ret);
516}
517
518/***
519 * CLIENT SIDE -DEPRECATED
520 ***/
521
522typedef struct {
523 data_callback_t cb;
524 void *arg;
525} callback_t;
526
527hound_sess_t *hound_get_session(void)
528{
529 return hound_service_connect(HOUND_SERVICE);
530}
531
532void hound_release_session(hound_sess_t *sess)
533{
534 hound_service_disconnect(sess);
535}
536
537
538static int hound_register(hound_sess_t *sess, unsigned cmd, const char *name,
539 unsigned channels, unsigned rate, pcm_sample_format_t format,
540 data_callback_t data_callback, void *arg);
541static int hound_unregister(hound_sess_t *sess, unsigned cmd, const char *name);
542static int hound_connection(hound_sess_t *sess, unsigned cmd,
543 const char *source, const char *sink);
544static void callback_pb(ipc_callid_t iid, ipc_call_t *call, void *arg);
545static void callback_rec(ipc_callid_t iid, ipc_call_t *call, void *arg);
546
547
548int hound_register_playback(hound_sess_t *sess, const char *name,
549 unsigned channels, unsigned rate, pcm_sample_format_t format,
550 data_callback_t data_callback, void *arg)
551{
552 return hound_register(sess, HOUND_REGISTER_PLAYBACK, name, channels,
553 rate, format, data_callback, arg);
554}
555int hound_register_recording(hound_sess_t *sess, const char *name,
556 unsigned channels, unsigned rate, pcm_sample_format_t format,
557 data_callback_t data_callback, void *arg)
558{
559 return hound_register(sess, HOUND_REGISTER_RECORDING, name, channels,
560 rate, format, data_callback, arg);
561
562}
563int hound_unregister_playback(hound_sess_t *sess, const char *name)
564{
565 return hound_unregister(sess, HOUND_UNREGISTER_PLAYBACK, name);
566}
567int hound_unregister_recording(hound_sess_t *sess, const char *name)
568{
569 return hound_unregister(sess, HOUND_UNREGISTER_RECORDING, name);
570}
571int hound_create_connection(hound_sess_t *sess, const char *source, const char *sink)
572{
573 return hound_connection(sess, HOUND_CONNECT, source, sink);
574}
575int hound_destroy_connection(hound_sess_t *sess, const char *source, const char *sink)
576{
577 return hound_connection(sess, HOUND_DISCONNECT, source, sink);
578}
579
580static int hound_register(hound_sess_t *sess, unsigned cmd, const char *name,
581 unsigned channels, unsigned rate, pcm_sample_format_t format,
582 data_callback_t data_callback, void *arg)
583{
584 assert(cmd == HOUND_REGISTER_PLAYBACK || cmd == HOUND_REGISTER_RECORDING);
585 if (!name || !data_callback || !sess)
586 return EINVAL;
587
588 async_exch_t *exch = async_exchange_begin(sess);
589 if (!exch)
590 return ENOMEM;
591
592 aid_t id = async_send_0(exch, cmd, NULL);
593
594 int ret = async_data_write_start(exch, name, str_size(name));
595 if (ret != EOK) {
596 async_forget(id);
597 async_exchange_end(exch);
598 return ret;
599 }
600
601 callback_t *cb = malloc(sizeof(callback_t));
602 if (!cb) {
603 async_forget(id);
604 async_exchange_end(exch);
605 return ENOMEM;
606 }
607
608 cb->cb = data_callback;
609 cb->arg = arg;
610 async_client_conn_t callback =
611 (cmd == HOUND_REGISTER_PLAYBACK) ? callback_pb : callback_rec;
612
613 ret = async_connect_to_me(exch, channels, rate, format, callback, cb);
614 if (ret != EOK) {
615 async_forget(id);
616 async_exchange_end(exch);
617 free(cb);
618 return ret;
619 }
620
621 async_wait_for(id, (sysarg_t*)&ret);
622 if (ret != EOK) {
623 async_exchange_end(exch);
624 free(cb);
625 return ret;
626 }
627
628 async_exchange_end(exch);
629 return EOK;
630}
631
632static int hound_unregister(hound_sess_t *sess, unsigned cmd, const char *name)
633{
634 assert(cmd == HOUND_UNREGISTER_PLAYBACK || cmd == HOUND_UNREGISTER_RECORDING);
635 if (!name || !sess)
636 return EINVAL;
637
638 async_exch_t *exch = async_exchange_begin(sess);
639 if (!exch)
640 return ENOMEM;
641 aid_t id = async_send_0(exch, cmd, NULL);
642 sysarg_t ret = async_data_write_start(exch, name, str_size(name));
643 if (ret != EOK) {
644 async_forget(id);
645 async_exchange_end(exch);
646 return ret;
647 }
648
649 async_wait_for(id, &ret);
650 async_exchange_end(exch);
651 return ret;
652}
653
654static int hound_connection(hound_sess_t *sess, unsigned cmd,
655 const char *source, const char *sink)
656{
657 assert(cmd == HOUND_CONNECT || cmd == HOUND_DISCONNECT);
658 if (!source || !sink || !sess)
659 return EINVAL;
660
661 async_exch_t *exch = async_exchange_begin(sess);
662 if (!exch)
663 return ENOMEM;
664
665 aid_t id = async_send_0(exch, cmd, NULL);
666 sysarg_t ret = async_data_write_start(exch, source, str_size(source));
667 if (ret != EOK) {
668 async_forget(id);
669 async_exchange_end(exch);
670 return ret;
671 }
672 ret = async_data_write_start(exch, sink, str_size(sink));
673 if (ret != EOK) {
674 async_forget(id);
675 async_exchange_end(exch);
676 return ret;
677 }
678 async_wait_for(id, &ret);
679 async_exchange_end(exch);
680 return ret;
681}
682static void callback_gen(ipc_callid_t iid, ipc_call_t *call, void *arg,
683 bool read)
684{
685 async_answer_0(iid, EOK);
686 callback_t *cb = arg;
687 assert(cb);
688 void *buffer = NULL;
689 size_t buffer_size = 0;
690
691 bool (*receive)(ipc_callid_t *, size_t *) = read ?
692 async_data_read_receive : async_data_write_receive;
693
694 while (1) {
695 size_t size = 0;
696 ipc_callid_t id = 0;
697 if (!receive(&id, &size)) {
698 ipc_call_t failed_call;
699 async_get_call(&failed_call);
700 /* Protocol error or hangup */
701 if (IPC_GET_IMETHOD(failed_call) != 0)
702 cb->cb(cb->arg, NULL, EIO);
703 free(cb);
704 return;
705 }
706
707 if (buffer_size < size) {
708 buffer = realloc(buffer, size);
709 if (!buffer) {
710 cb->cb(cb->arg, NULL, ENOMEM);
711 free(cb);
712 return;
713 }
714 buffer_size = size;
715 }
716 if (read)
717 cb->cb(cb->arg, buffer, size);
718 const int ret = read ?
719 async_data_read_finalize(id, buffer, size):
720 async_data_write_finalize(id, buffer, size);
721 if (ret != EOK) {
722 cb->cb(cb->arg, NULL, ret);
723 free(cb);
724 return;
725 }
726 if (!read)
727 cb->cb(cb->arg, buffer, size);
728 }
729}
730
731static void callback_pb(ipc_callid_t iid, ipc_call_t *call, void *arg)
732{
733 callback_gen(iid, call, arg, true);
734}
735
736static void callback_rec(ipc_callid_t iid, ipc_call_t *call, void *arg)
737{
738 callback_gen(iid, call, arg, false);
739}
740
741/***
742 * SERVER SIDE - DEPRECATED
743 ***/
744
745static const char * get_name(void);
746
747int hound_server_register(const char *name, service_id_t *id)
748{
749 if (!name || !id)
750 return EINVAL;
751
752 int ret = loc_server_register(name);
753 if (ret != EOK)
754 return ret;
755
756 return loc_service_register(HOUND_SERVICE, id);
757}
758
759void hound_server_unregister(service_id_t id)
760{
761 loc_service_unregister(id);
762}
763
764int hound_server_set_device_change_callback(dev_change_callback_t cb)
765{
766 return loc_register_cat_change_cb(cb);
767}
768
769int hound_server_devices_iterate(device_callback_t callback)
770{
771 if (!callback)
772 return EINVAL;
773 static bool resolved = false;
774 static category_id_t cat_id = 0;
775
776 if (!resolved) {
777 const int ret = loc_category_get_id("audio-pcm", &cat_id,
778 IPC_FLAG_BLOCKING);
779 if (ret != EOK)
780 return ret;
781 resolved = true;
782 }
783
784 service_id_t *svcs = NULL;
785 size_t count = 0;
786 const int ret = loc_category_get_svcs(cat_id, &svcs, &count);
787 if (ret != EOK)
788 return ret;
789
790 for (unsigned i = 0; i < count; ++i) {
791 char *name = NULL;
792 loc_service_get_name(svcs[i], &name);
793 callback(svcs[i], name);
794 free(name);
795 }
796 free(svcs);
797 return EOK;
798}
799
800int hound_server_get_register_params(const char **name, async_sess_t **sess,
801 unsigned *channels, unsigned *rate, pcm_sample_format_t *format)
802{
803 if (!name || !sess || !channels || !rate || !format)
804 return EINVAL;
805
806 const char *n = get_name();
807 if (!n)
808 return ENOMEM;
809
810 ipc_call_t call;
811 ipc_callid_t callid = async_get_call(&call);
812
813 unsigned ch = IPC_GET_ARG1(call);
814 unsigned r = IPC_GET_ARG2(call);
815 pcm_sample_format_t f = IPC_GET_ARG3(call);
816
817 async_sess_t *s = async_callback_receive_start(EXCHANGE_ATOMIC, &call);
818 async_answer_0(callid, s ? EOK : ENOMEM);
819
820 *name = n;
821 *sess = s;
822 *channels = ch;
823 *rate = r;
824 *format = f;
825
826 return ENOTSUP;
827}
828
829int hound_server_get_unregister_params(const char **name)
830{
831 if (!name)
832 return EINVAL;
833 *name = get_name();
834 if (!*name)
835 return ENOMEM;
836 return EOK;
837}
838
839int hound_server_get_connection_params(const char **source, const char **sink)
840{
841 if (!source || !sink)
842 return EINVAL;
843
844 const char *source_name = get_name();
845 if (!source_name)
846 return ENOMEM;
847
848 const char *sink_name = get_name();
849 if (!sink_name)
850 return ENOMEM;
851
852 *source = source_name;
853 *sink = sink_name;
854 return EOK;
855}
856
857static const char * get_name(void)
858{
859 size_t size = 0;
860 ipc_callid_t callid;
861 async_data_write_receive(&callid, &size);
862 char *buffer = malloc(size + 1);
863 if (buffer) {
864 async_data_write_finalize(callid, buffer, size);
865 buffer[size] = 0;
866 }
867 return buffer;
868}
869
870/**
871 * @}
872 */
Note: See TracBrowser for help on using the repository browser.