source: mainline/uspace/lib/hound/src/protocol.c@ 5bf4310

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

libhound: Fix switch to to stream

  • Property mode set to 100644
File size: 21.0 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]);
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->add_stream
415 || !server_iface->is_record_context) {
416 async_answer_0(callid, ENOTSUP);
417 break;
418 }
419
420 hound_context_id_t id = IPC_GET_ARG1(call);
421 int flags = IPC_GET_ARG2(call);
422 union {
423 sysarg_t arg;
424 pcm_format_t format;
425 } convert = { .arg = IPC_GET_ARG3(call) };
426 size_t bsize = IPC_GET_ARG4(call);
427 void *stream;
428 int ret = server_iface->add_stream(server_iface->server,
429 id, flags, convert.format, bsize, &stream);
430 if (ret != EOK) {
431 async_answer_0(callid, ret);
432 break;
433 }
434 const bool rec = server_iface->is_record_context(
435 server_iface->server, id);
436 if (rec) {
437 if(server_iface->stream_data_read) {
438 async_answer_0(callid, EOK);
439 hound_server_write_data(stream);
440 } else {
441 async_answer_0(callid, ENOTSUP);
442 }
443 } else {
444 if (server_iface->stream_data_write) {
445 async_answer_0(callid, EOK);
446 hound_server_read_data(stream);
447 } else {
448 async_answer_0(callid, ENOTSUP);
449 }
450 }
451 break;
452 }
453 case IPC_M_HOUND_STREAM_EXIT:
454 case IPC_M_HOUND_STREAM_DRAIN:
455 /* Stream exit/drain is only allowed in stream context*/
456 async_answer_0(callid, EINVAL);
457 break;
458 default:
459 async_answer_0(callid, ENOTSUP);
460 return;
461 }
462 }
463}
464
465static void hound_server_read_data(void *stream)
466{
467 ipc_callid_t callid;
468 ipc_call_t call;
469 size_t size = 0;
470 while (async_data_write_receive_call(&callid, &call, &size)) {
471 char *buffer = malloc(size);
472 if (!buffer) {
473 async_answer_0(callid, ENOMEM);
474 continue;
475 }
476 int ret = async_data_write_finalize(callid, buffer, size);
477 if (ret == EOK) {
478 ret = server_iface->stream_data_write(stream, buffer, size);
479 }
480 async_answer_0(callid, ret);
481 }
482 //TODO drain?
483 const int ret = IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_EXIT
484 ? EOK : EINVAL;
485
486 async_answer_0(callid, ret);
487}
488
489static void hound_server_write_data(void *stream)
490{
491
492 ipc_callid_t callid;
493 ipc_call_t call;
494 size_t size = 0;
495 while (async_data_read_receive_call(&callid, &call, &size)) {
496 char *buffer = malloc(size);
497 if (!buffer) {
498 async_answer_0(callid, ENOMEM);
499 continue;
500 }
501 int ret = server_iface->stream_data_read(stream, buffer, size);
502 if (ret == EOK) {
503 ret = async_data_read_finalize(callid, buffer, size);
504 }
505 async_answer_0(callid, ret);
506 }
507 const int ret = IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_EXIT
508 ? EOK : EINVAL;
509
510 async_answer_0(callid, ret);
511}
512
513/***
514 * CLIENT SIDE -DEPRECATED
515 ***/
516
517typedef struct {
518 data_callback_t cb;
519 void *arg;
520} callback_t;
521
522hound_sess_t *hound_get_session(void)
523{
524 return hound_service_connect(HOUND_SERVICE);
525}
526
527void hound_release_session(hound_sess_t *sess)
528{
529 hound_service_disconnect(sess);
530}
531
532
533static int hound_register(hound_sess_t *sess, unsigned cmd, const char *name,
534 unsigned channels, unsigned rate, pcm_sample_format_t format,
535 data_callback_t data_callback, void *arg);
536static int hound_unregister(hound_sess_t *sess, unsigned cmd, const char *name);
537static int hound_connection(hound_sess_t *sess, unsigned cmd,
538 const char *source, const char *sink);
539static void callback_pb(ipc_callid_t iid, ipc_call_t *call, void *arg);
540static void callback_rec(ipc_callid_t iid, ipc_call_t *call, void *arg);
541
542
543int hound_register_playback(hound_sess_t *sess, const char *name,
544 unsigned channels, unsigned rate, pcm_sample_format_t format,
545 data_callback_t data_callback, void *arg)
546{
547 return hound_register(sess, HOUND_REGISTER_PLAYBACK, name, channels,
548 rate, format, data_callback, arg);
549}
550int hound_register_recording(hound_sess_t *sess, const char *name,
551 unsigned channels, unsigned rate, pcm_sample_format_t format,
552 data_callback_t data_callback, void *arg)
553{
554 return hound_register(sess, HOUND_REGISTER_RECORDING, name, channels,
555 rate, format, data_callback, arg);
556
557}
558int hound_unregister_playback(hound_sess_t *sess, const char *name)
559{
560 return hound_unregister(sess, HOUND_UNREGISTER_PLAYBACK, name);
561}
562int hound_unregister_recording(hound_sess_t *sess, const char *name)
563{
564 return hound_unregister(sess, HOUND_UNREGISTER_RECORDING, name);
565}
566int hound_create_connection(hound_sess_t *sess, const char *source, const char *sink)
567{
568 return hound_connection(sess, HOUND_CONNECT, source, sink);
569}
570int hound_destroy_connection(hound_sess_t *sess, const char *source, const char *sink)
571{
572 return hound_connection(sess, HOUND_DISCONNECT, source, sink);
573}
574
575static int hound_register(hound_sess_t *sess, unsigned cmd, const char *name,
576 unsigned channels, unsigned rate, pcm_sample_format_t format,
577 data_callback_t data_callback, void *arg)
578{
579 assert(cmd == HOUND_REGISTER_PLAYBACK || cmd == HOUND_REGISTER_RECORDING);
580 if (!name || !data_callback || !sess)
581 return EINVAL;
582
583 async_exch_t *exch = async_exchange_begin(sess);
584 if (!exch)
585 return ENOMEM;
586
587 aid_t id = async_send_0(exch, cmd, NULL);
588
589 int ret = async_data_write_start(exch, name, str_size(name));
590 if (ret != EOK) {
591 async_forget(id);
592 async_exchange_end(exch);
593 return ret;
594 }
595
596 callback_t *cb = malloc(sizeof(callback_t));
597 if (!cb) {
598 async_forget(id);
599 async_exchange_end(exch);
600 return ENOMEM;
601 }
602
603 cb->cb = data_callback;
604 cb->arg = arg;
605 async_client_conn_t callback =
606 (cmd == HOUND_REGISTER_PLAYBACK) ? callback_pb : callback_rec;
607
608 ret = async_connect_to_me(exch, channels, rate, format, callback, cb);
609 if (ret != EOK) {
610 async_forget(id);
611 async_exchange_end(exch);
612 free(cb);
613 return ret;
614 }
615
616 async_wait_for(id, (sysarg_t*)&ret);
617 if (ret != EOK) {
618 async_exchange_end(exch);
619 free(cb);
620 return ret;
621 }
622
623 async_exchange_end(exch);
624 return EOK;
625}
626
627static int hound_unregister(hound_sess_t *sess, unsigned cmd, const char *name)
628{
629 assert(cmd == HOUND_UNREGISTER_PLAYBACK || cmd == HOUND_UNREGISTER_RECORDING);
630 if (!name || !sess)
631 return EINVAL;
632
633 async_exch_t *exch = async_exchange_begin(sess);
634 if (!exch)
635 return ENOMEM;
636 aid_t id = async_send_0(exch, cmd, NULL);
637 sysarg_t ret = async_data_write_start(exch, name, str_size(name));
638 if (ret != EOK) {
639 async_forget(id);
640 async_exchange_end(exch);
641 return ret;
642 }
643
644 async_wait_for(id, &ret);
645 async_exchange_end(exch);
646 return ret;
647}
648
649static int hound_connection(hound_sess_t *sess, unsigned cmd,
650 const char *source, const char *sink)
651{
652 assert(cmd == HOUND_CONNECT || cmd == HOUND_DISCONNECT);
653 if (!source || !sink || !sess)
654 return EINVAL;
655
656 async_exch_t *exch = async_exchange_begin(sess);
657 if (!exch)
658 return ENOMEM;
659
660 aid_t id = async_send_0(exch, cmd, NULL);
661 sysarg_t ret = async_data_write_start(exch, source, str_size(source));
662 if (ret != EOK) {
663 async_forget(id);
664 async_exchange_end(exch);
665 return ret;
666 }
667 ret = async_data_write_start(exch, sink, str_size(sink));
668 if (ret != EOK) {
669 async_forget(id);
670 async_exchange_end(exch);
671 return ret;
672 }
673 async_wait_for(id, &ret);
674 async_exchange_end(exch);
675 return ret;
676}
677static void callback_gen(ipc_callid_t iid, ipc_call_t *call, void *arg,
678 bool read)
679{
680 async_answer_0(iid, EOK);
681 callback_t *cb = arg;
682 assert(cb);
683 void *buffer = NULL;
684 size_t buffer_size = 0;
685
686 bool (*receive)(ipc_callid_t *, size_t *) = read ?
687 async_data_read_receive : async_data_write_receive;
688
689 while (1) {
690 size_t size = 0;
691 ipc_callid_t id = 0;
692 if (!receive(&id, &size)) {
693 ipc_call_t failed_call;
694 async_get_call(&failed_call);
695 /* Protocol error or hangup */
696 if (IPC_GET_IMETHOD(failed_call) != 0)
697 cb->cb(cb->arg, NULL, EIO);
698 free(cb);
699 return;
700 }
701
702 if (buffer_size < size) {
703 buffer = realloc(buffer, size);
704 if (!buffer) {
705 cb->cb(cb->arg, NULL, ENOMEM);
706 free(cb);
707 return;
708 }
709 buffer_size = size;
710 }
711 if (read)
712 cb->cb(cb->arg, buffer, size);
713 const int ret = read ?
714 async_data_read_finalize(id, buffer, size):
715 async_data_write_finalize(id, buffer, size);
716 if (ret != EOK) {
717 cb->cb(cb->arg, NULL, ret);
718 free(cb);
719 return;
720 }
721 if (!read)
722 cb->cb(cb->arg, buffer, size);
723 }
724}
725
726static void callback_pb(ipc_callid_t iid, ipc_call_t *call, void *arg)
727{
728 callback_gen(iid, call, arg, true);
729}
730
731static void callback_rec(ipc_callid_t iid, ipc_call_t *call, void *arg)
732{
733 callback_gen(iid, call, arg, false);
734}
735
736/***
737 * SERVER SIDE - DEPRECATED
738 ***/
739
740static const char * get_name(void);
741
742int hound_server_register(const char *name, service_id_t *id)
743{
744 if (!name || !id)
745 return EINVAL;
746
747 int ret = loc_server_register(name);
748 if (ret != EOK)
749 return ret;
750
751 return loc_service_register(HOUND_SERVICE, id);
752}
753
754void hound_server_unregister(service_id_t id)
755{
756 loc_service_unregister(id);
757}
758
759int hound_server_set_device_change_callback(dev_change_callback_t cb)
760{
761 return loc_register_cat_change_cb(cb);
762}
763
764int hound_server_devices_iterate(device_callback_t callback)
765{
766 if (!callback)
767 return EINVAL;
768 static bool resolved = false;
769 static category_id_t cat_id = 0;
770
771 if (!resolved) {
772 const int ret = loc_category_get_id("audio-pcm", &cat_id,
773 IPC_FLAG_BLOCKING);
774 if (ret != EOK)
775 return ret;
776 resolved = true;
777 }
778
779 service_id_t *svcs = NULL;
780 size_t count = 0;
781 const int ret = loc_category_get_svcs(cat_id, &svcs, &count);
782 if (ret != EOK)
783 return ret;
784
785 for (unsigned i = 0; i < count; ++i) {
786 char *name = NULL;
787 loc_service_get_name(svcs[i], &name);
788 callback(svcs[i], name);
789 free(name);
790 }
791 free(svcs);
792 return EOK;
793}
794
795int hound_server_get_register_params(const char **name, async_sess_t **sess,
796 unsigned *channels, unsigned *rate, pcm_sample_format_t *format)
797{
798 if (!name || !sess || !channels || !rate || !format)
799 return EINVAL;
800
801 const char *n = get_name();
802 if (!n)
803 return ENOMEM;
804
805 ipc_call_t call;
806 ipc_callid_t callid = async_get_call(&call);
807
808 unsigned ch = IPC_GET_ARG1(call);
809 unsigned r = IPC_GET_ARG2(call);
810 pcm_sample_format_t f = IPC_GET_ARG3(call);
811
812 async_sess_t *s = async_callback_receive_start(EXCHANGE_ATOMIC, &call);
813 async_answer_0(callid, s ? EOK : ENOMEM);
814
815 *name = n;
816 *sess = s;
817 *channels = ch;
818 *rate = r;
819 *format = f;
820
821 return ENOTSUP;
822}
823
824int hound_server_get_unregister_params(const char **name)
825{
826 if (!name)
827 return EINVAL;
828 *name = get_name();
829 if (!*name)
830 return ENOMEM;
831 return EOK;
832}
833
834int hound_server_get_connection_params(const char **source, const char **sink)
835{
836 if (!source || !sink)
837 return EINVAL;
838
839 const char *source_name = get_name();
840 if (!source_name)
841 return ENOMEM;
842
843 const char *sink_name = get_name();
844 if (!sink_name)
845 return ENOMEM;
846
847 *source = source_name;
848 *sink = sink_name;
849 return EOK;
850}
851
852static const char * get_name(void)
853{
854 size_t size = 0;
855 ipc_callid_t callid;
856 async_data_write_receive(&callid, &size);
857 char *buffer = malloc(size + 1);
858 if (buffer) {
859 async_data_write_finalize(callid, buffer, size);
860 buffer[size] = 0;
861 }
862 return buffer;
863}
864
865/**
866 * @}
867 */
Note: See TracBrowser for help on using the repository browser.