source: mainline/uspace/lib/drv/generic/remote_audio_pcm.c@ fa91c0f

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

libdrv: Add buffer position query.

Fix cap query:

Close exchange at the end.
Send query number instead of random value.

  • Property mode set to 100644
File size: 19.6 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/** @addtogroup libdrv
29 * @{
30 */
31/** @file
32 */
33
34#include <async.h>
35#include <devman.h>
36#include <ddf/log.h>
37#include <errno.h>
38#include <str.h>
39#include <as.h>
40#include <sys/mman.h>
41
42#include "audio_pcm_iface.h"
43#include "ddf/driver.h"
44
45typedef enum {
46 IPC_M_AUDIO_PCM_GET_INFO_STR,
47 IPC_M_AUDIO_PCM_QUERY_CAPS,
48 IPC_M_AUDIO_PCM_TEST_FORMAT,
49 IPC_M_AUDIO_PCM_GET_BUFFER,
50 IPC_M_AUDIO_PCM_RELEASE_BUFFER,
51 IPC_M_AUDIO_PCM_GET_BUFFER_POS,
52 IPC_M_AUDIO_PCM_START_PLAYBACK,
53 IPC_M_AUDIO_PCM_STOP_PLAYBACK,
54 IPC_M_AUDIO_PCM_START_CAPTURE,
55 IPC_M_AUDIO_PCM_STOP_CAPTURE,
56} audio_pcm_iface_funcs_t;
57
58/*
59 * CLIENT SIDE
60 */
61audio_pcm_sess_t *audio_pcm_open(const char *name)
62{
63 devman_handle_t device_handle = 0;
64 const int ret = devman_fun_get_handle(name, &device_handle, 0);
65 if (ret != EOK)
66 return NULL;
67 return devman_device_connect(EXCHANGE_SERIALIZE, device_handle,
68 IPC_FLAG_BLOCKING);
69}
70
71audio_pcm_sess_t *audio_pcm_open_service(service_id_t id)
72{
73 return loc_service_connect(EXCHANGE_SERIALIZE, id, IPC_FLAG_BLOCKING);
74}
75
76void audio_pcm_close(audio_pcm_sess_t *sess)
77{
78 if (sess)
79 async_hangup(sess);
80}
81
82int audio_pcm_get_info_str(audio_pcm_sess_t *sess, const char **name)
83{
84 async_exch_t *exch = async_exchange_begin(sess);
85 sysarg_t name_size;
86 const int ret = async_req_1_1(exch,
87 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
88 IPC_M_AUDIO_PCM_GET_INFO_STR, &name_size);
89 if (ret == EOK && name) {
90 char *name_place = calloc(1, name_size);
91 if (!name_place) {
92 /* Make the other side fail
93 * as it waits for read request */
94 async_data_read_start(exch, (void*)-1, 0);
95 async_exchange_end(exch);
96 return ENOMEM;
97 }
98 const int ret =
99 async_data_read_start(exch, name_place, name_size);
100 if (ret != EOK) {
101 free(name_place);
102 async_exchange_end(exch);
103 return ret;
104 }
105 *name = name_place;
106 }
107 async_exchange_end(exch);
108 return ret;
109}
110
111int audio_pcm_query_cap(audio_pcm_sess_t *sess, audio_cap_t cap, unsigned *val)
112{
113 if (!val)
114 return EINVAL;
115 async_exch_t *exch = async_exchange_begin(sess);
116 sysarg_t value = 0;
117 const int ret = async_req_2_1(exch,
118 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE), IPC_M_AUDIO_PCM_QUERY_CAPS,
119 cap, &value);
120 if (ret == EOK)
121 *val = value;
122 async_exchange_end(exch);
123 return ret;
124}
125
126int audio_pcm_get_buffer_pos(audio_pcm_sess_t *sess, size_t *pos)
127{
128 if (!pos)
129 return EINVAL;
130 async_exch_t *exch = async_exchange_begin(sess);
131 sysarg_t value = 0;;
132 const int ret = async_req_1_1(exch,
133 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
134 IPC_M_AUDIO_PCM_GET_BUFFER_POS, &value);
135 if (ret == EOK)
136 *pos = value;
137 async_exchange_end(exch);
138 return ret;
139}
140
141int audio_pcm_test_format(audio_pcm_sess_t *sess, unsigned *channels,
142 unsigned *rate, pcm_sample_format_t *format)
143{
144 async_exch_t *exch = async_exchange_begin(sess);
145 sysarg_t channels_arg = channels ? *channels : 0;
146 sysarg_t rate_arg = rate ? *rate : 0;
147 sysarg_t format_arg = format ? *format : 0;
148 const int ret = async_req_4_3(exch,
149 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
150 IPC_M_AUDIO_PCM_TEST_FORMAT, channels_arg, rate_arg, format_arg,
151 &channels_arg, &rate_arg, &format_arg);
152 async_exchange_end(exch);
153
154 /* All OK or something has changed. Verify that it was not one of the
155 * params we care about */
156 if ((ret == EOK || ret == ELIMIT)
157 && (!channels || *channels == channels_arg)
158 && (!rate || *rate == rate_arg)
159 && (!format || *format == format_arg))
160 return EOK;
161 if (channels)
162 *channels = channels_arg;
163 if (rate)
164 *rate = rate_arg;
165 if (format)
166 *format = format_arg;
167 return ret;
168}
169
170int audio_pcm_get_buffer(audio_pcm_sess_t *sess, void **buffer, size_t *size,
171 async_client_conn_t event_rec, void* arg)
172{
173 if (!buffer || !size)
174 return EINVAL;
175
176 async_exch_t *exch = async_exchange_begin(sess);
177
178 sysarg_t buffer_size = *size;
179 const int ret = async_req_2_1(exch,
180 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE), IPC_M_AUDIO_PCM_GET_BUFFER,
181 (sysarg_t)buffer_size, &buffer_size);
182 if (ret == EOK) {
183 void *dst = NULL;
184 int ret = async_share_in_start_0_0(exch, buffer_size, &dst);
185 if (ret != EOK) {
186 async_exchange_end(exch);
187 return ret;
188 }
189 ret = async_connect_to_me(exch, 0, 0, 0, event_rec, arg);
190 if (ret != EOK) {
191 async_exchange_end(exch);
192 return ret;
193 }
194
195 *buffer = dst;
196 *size = buffer_size;
197 }
198 async_exchange_end(exch);
199 return ret;
200}
201
202int audio_pcm_release_buffer(audio_pcm_sess_t *sess)
203{
204 async_exch_t *exch = async_exchange_begin(sess);
205 const int ret = async_req_1_0(exch,
206 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
207 IPC_M_AUDIO_PCM_RELEASE_BUFFER);
208 async_exchange_end(exch);
209 return ret;
210}
211
212int audio_pcm_start_playback(audio_pcm_sess_t *sess, unsigned frames,
213 unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
214{
215 if (channels > UINT16_MAX)
216 return EINVAL;
217 assert((format & UINT16_MAX) == format);
218 const sysarg_t packed = (channels << 16) | (format & UINT16_MAX);
219 async_exch_t *exch = async_exchange_begin(sess);
220 const int ret = async_req_4_0(exch,
221 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
222 IPC_M_AUDIO_PCM_START_PLAYBACK,
223 frames, sample_rate, packed);
224 async_exchange_end(exch);
225 return ret;
226}
227
228int audio_pcm_stop_playback(audio_pcm_sess_t *sess)
229{
230 async_exch_t *exch = async_exchange_begin(sess);
231 const int ret = async_req_1_0(exch,
232 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
233 IPC_M_AUDIO_PCM_STOP_PLAYBACK);
234 async_exchange_end(exch);
235 return ret;
236}
237
238int audio_pcm_start_capture(audio_pcm_sess_t *sess, unsigned frames,
239 unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
240{
241 if (channels > UINT16_MAX)
242 return EINVAL;
243 assert((format & UINT16_MAX) == format);
244 const sysarg_t packed = (channels << 16) | (format & UINT16_MAX);
245 async_exch_t *exch = async_exchange_begin(sess);
246 const int ret = async_req_4_0(exch,
247 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE), IPC_M_AUDIO_PCM_START_CAPTURE,
248 frames, sample_rate, packed);
249 async_exchange_end(exch);
250 return ret;
251}
252
253int audio_pcm_stop_capture(audio_pcm_sess_t *sess)
254{
255 async_exch_t *exch = async_exchange_begin(sess);
256 const int ret = async_req_1_0(exch,
257 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE), IPC_M_AUDIO_PCM_STOP_CAPTURE);
258 async_exchange_end(exch);
259 return ret;
260}
261
262/*
263 * SERVER SIDE
264 */
265static void remote_audio_pcm_get_info_str(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
266static void remote_audio_pcm_query_caps(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
267static void remote_audio_pcm_get_buffer_pos(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
268static void remote_audio_pcm_test_format(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
269static void remote_audio_pcm_get_buffer(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
270static void remote_audio_pcm_release_buffer(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
271static void remote_audio_pcm_start_playback(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
272static void remote_audio_pcm_stop_playback(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
273static void remote_audio_pcm_start_capture(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
274static void remote_audio_pcm_stop_capture(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
275
276/** Remote audio pcm buffer interface operations. */
277static remote_iface_func_ptr_t remote_audio_pcm_iface_ops[] = {
278 [IPC_M_AUDIO_PCM_GET_INFO_STR] = remote_audio_pcm_get_info_str,
279 [IPC_M_AUDIO_PCM_QUERY_CAPS] = remote_audio_pcm_query_caps,
280 [IPC_M_AUDIO_PCM_GET_BUFFER_POS] = remote_audio_pcm_get_buffer_pos,
281 [IPC_M_AUDIO_PCM_TEST_FORMAT] = remote_audio_pcm_test_format,
282 [IPC_M_AUDIO_PCM_GET_BUFFER] = remote_audio_pcm_get_buffer,
283 [IPC_M_AUDIO_PCM_RELEASE_BUFFER] = remote_audio_pcm_release_buffer,
284 [IPC_M_AUDIO_PCM_START_PLAYBACK] = remote_audio_pcm_start_playback,
285 [IPC_M_AUDIO_PCM_STOP_PLAYBACK] = remote_audio_pcm_stop_playback,
286 [IPC_M_AUDIO_PCM_START_CAPTURE] = remote_audio_pcm_start_capture,
287 [IPC_M_AUDIO_PCM_STOP_CAPTURE] = remote_audio_pcm_stop_capture,
288};
289
290/** Remote audio mixer interface structure. */
291remote_iface_t remote_audio_pcm_iface = {
292 .method_count = sizeof(remote_audio_pcm_iface_ops) /
293 sizeof(remote_audio_pcm_iface_ops[0]),
294 .methods = remote_audio_pcm_iface_ops
295};
296
297void remote_audio_pcm_get_info_str(ddf_fun_t *fun, void *iface,
298 ipc_callid_t callid, ipc_call_t *call)
299{
300 const audio_pcm_iface_t *pcm_iface = iface;
301
302 if (!pcm_iface->get_info_str) {
303 async_answer_0(callid, ENOTSUP);
304 return;
305 }
306 const char *name = NULL;
307 const int ret = pcm_iface->get_info_str(fun, &name);
308 const size_t name_size = name ? str_size(name) + 1 : 0;
309 async_answer_1(callid, ret, name_size);
310 /* Send the string. */
311 if (ret == EOK && name_size > 0) {
312 size_t size;
313 ipc_callid_t name_id;
314 if (!async_data_read_receive(&name_id, &size)) {
315 async_answer_0(name_id, EPARTY);
316 return;
317 }
318 if (size != name_size) {
319 async_answer_0(name_id, ELIMIT);
320 return;
321 }
322 async_data_read_finalize(name_id, name, name_size);
323 }
324}
325
326void remote_audio_pcm_query_caps(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
327{
328 const audio_pcm_iface_t *pcm_iface = iface;
329 const audio_cap_t cap = DEV_IPC_GET_ARG1(*call);
330 if (pcm_iface->query_cap) {
331 const unsigned value = pcm_iface->query_cap(fun, cap);
332 async_answer_1(callid, EOK, value);
333 } else {
334 async_answer_0(callid, ENOTSUP);
335 }
336}
337void remote_audio_pcm_get_buffer_pos(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
338{
339 const audio_pcm_iface_t *pcm_iface = iface;
340 size_t pos = 0;
341 const int ret = pcm_iface->get_buffer_pos ?
342 pcm_iface->get_buffer_pos(fun, &pos) : ENOTSUP;
343 async_answer_1(callid, ret, pos);
344}
345
346void remote_audio_pcm_test_format(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
347{
348 const audio_pcm_iface_t *pcm_iface = iface;
349 unsigned channels = DEV_IPC_GET_ARG1(*call);
350 unsigned rate = DEV_IPC_GET_ARG2(*call);
351 pcm_sample_format_t format = DEV_IPC_GET_ARG3(*call);
352 const int ret = pcm_iface->test_format ?
353 pcm_iface->test_format(fun, &channels, &rate, &format) : ENOTSUP;
354 async_answer_3(callid, ret, channels, rate, format);
355}
356
357void remote_audio_pcm_get_buffer(ddf_fun_t *fun, void *iface,
358 ipc_callid_t callid, ipc_call_t *call)
359{
360 const audio_pcm_iface_t *pcm_iface = iface;
361
362 if (!pcm_iface->get_buffer ||
363 !pcm_iface->release_buffer ||
364 !pcm_iface->set_event_session) {
365 async_answer_0(callid, ENOTSUP);
366 return;
367 }
368 void *buffer = NULL;
369 size_t size = DEV_IPC_GET_ARG1(*call);
370 int ret = pcm_iface->get_buffer(fun, &buffer, &size);
371 async_answer_1(callid, ret, size);
372 if (ret != EOK || size == 0)
373 return;
374
375 /* Share the buffer. */
376 size_t share_size = 0;
377 ipc_callid_t share_id = 0;
378
379 ddf_msg(LVL_DEBUG2, "Receiving share request.");
380 if (!async_share_in_receive(&share_id, &share_size)) {
381 ddf_msg(LVL_DEBUG, "Failed to share pcm buffer.");
382 pcm_iface->release_buffer(fun);
383 async_answer_0(share_id, EPARTY);
384 return;
385 }
386
387 ddf_msg(LVL_DEBUG2, "Checking requested share size.");
388 if (share_size != size) {
389 ddf_msg(LVL_DEBUG, "Incorrect pcm buffer size requested.");
390 pcm_iface->release_buffer(fun);
391 async_answer_0(share_id, ELIMIT);
392 return;
393 }
394
395 ddf_msg(LVL_DEBUG2, "Calling share finalize.");
396 ret = async_share_in_finalize(share_id, buffer, AS_AREA_WRITE
397 | AS_AREA_READ);
398 if (ret != EOK) {
399 ddf_msg(LVL_DEBUG, "Failed to share buffer.");
400 pcm_iface->release_buffer(fun);
401 return;
402 }
403
404 ddf_msg(LVL_DEBUG2, "Buffer shared with size %zu, creating callback.",
405 share_size);
406 {
407 ipc_call_t call;
408 ipc_callid_t callid = async_get_call(&call);
409 async_sess_t *sess =
410 async_callback_receive_start(EXCHANGE_ATOMIC, &call);
411 if (sess == NULL) {
412 ddf_msg(LVL_DEBUG, "Failed to create event callback");
413 pcm_iface->release_buffer(fun);
414 async_answer_0(callid, EAGAIN);
415 return;
416 }
417 ret = pcm_iface->set_event_session(fun, sess);
418 if (ret != EOK) {
419 ddf_msg(LVL_DEBUG, "Failed to set event callback.");
420 pcm_iface->release_buffer(fun);
421 async_answer_0(callid, ret);
422 return;
423 }
424 ddf_msg(LVL_DEBUG2, "Buffer and event session setup OK.");
425 async_answer_0(callid, EOK);
426 }
427}
428
429void remote_audio_pcm_release_buffer(ddf_fun_t *fun, void *iface,
430 ipc_callid_t callid, ipc_call_t *call)
431{
432 const audio_pcm_iface_t *pcm_iface = iface;
433
434 const int ret = pcm_iface->release_buffer ?
435 pcm_iface->release_buffer(fun) : ENOTSUP;
436 async_answer_0(callid, ret);
437}
438
439void remote_audio_pcm_start_playback(ddf_fun_t *fun, void *iface,
440 ipc_callid_t callid, ipc_call_t *call)
441{
442 const audio_pcm_iface_t *pcm_iface = iface;
443
444 const unsigned frames = DEV_IPC_GET_ARG1(*call);
445 const unsigned rate = DEV_IPC_GET_ARG2(*call);
446 const unsigned channels = (DEV_IPC_GET_ARG3(*call) >> 16) & UINT8_MAX;
447 const pcm_sample_format_t format = DEV_IPC_GET_ARG3(*call) & UINT16_MAX;
448
449 const int ret = pcm_iface->start_playback
450 ? pcm_iface->start_playback(fun, frames, channels, rate, format)
451 : ENOTSUP;
452 async_answer_0(callid, ret);
453}
454
455void remote_audio_pcm_stop_playback(ddf_fun_t *fun, void *iface,
456 ipc_callid_t callid, ipc_call_t *call)
457{
458 const audio_pcm_iface_t *pcm_iface = iface;
459
460 const int ret = pcm_iface->stop_playback ?
461 pcm_iface->stop_playback(fun) : ENOTSUP;
462 async_answer_0(callid, ret);
463}
464
465void remote_audio_pcm_start_capture(ddf_fun_t *fun, void *iface,
466 ipc_callid_t callid, ipc_call_t *call)
467{
468 const audio_pcm_iface_t *pcm_iface = iface;
469
470 const unsigned frames = DEV_IPC_GET_ARG1(*call);
471 const unsigned rate = DEV_IPC_GET_ARG2(*call);
472 const unsigned channels = (DEV_IPC_GET_ARG3(*call) >> 16) & UINT16_MAX;
473 const pcm_sample_format_t format = DEV_IPC_GET_ARG3(*call) & UINT16_MAX;
474
475 const int ret = pcm_iface->start_capture
476 ? pcm_iface->start_capture(fun, frames, channels, rate, format)
477 : ENOTSUP;
478 async_answer_0(callid, ret);
479}
480
481void remote_audio_pcm_stop_capture(ddf_fun_t *fun, void *iface,
482 ipc_callid_t callid, ipc_call_t *call)
483{
484 const audio_pcm_iface_t *pcm_iface = iface;
485
486 const int ret = pcm_iface->stop_capture ?
487 pcm_iface->stop_capture(fun) : ENOTSUP;
488 async_answer_0(callid, ret);
489}
490
491#if 0
492
493void remote_audio_mixer_get_info(
494 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
495{
496 audio_mixer_iface_t *mixer_iface = iface;
497
498 if (!mixer_iface->get_info) {
499 async_answer_0(callid, ENOTSUP);
500 return;
501 }
502 const char *name = NULL;
503 unsigned items = 0;
504 const int ret = mixer_iface->get_info(fun, &name, &items);
505 const size_t name_size = name ? str_size(name) + 1 : 0;
506 async_answer_2(callid, ret, name_size, items);
507 /* Send the name. */
508 if (ret == EOK && name_size > 0) {
509 size_t size;
510 ipc_callid_t name_id;
511 if (!async_data_read_receive(&name_id, &size)) {
512 async_answer_0(name_id, EPARTY);
513 return;
514 }
515 if (size != name_size) {
516 async_answer_0(name_id, ELIMIT);
517 return;
518 }
519 async_data_read_finalize(name_id, name, name_size);
520 }
521}
522
523void remote_audio_mixer_get_item_info(
524 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
525{
526 audio_mixer_iface_t *mixer_iface = iface;
527
528 if (!mixer_iface->get_item_info) {
529 async_answer_0(callid, ENOTSUP);
530 return;
531 }
532
533 const unsigned item = DEV_IPC_GET_ARG1(*call);
534 const char *name = NULL;
535 unsigned channels = 0;
536 const int ret = mixer_iface->get_item_info(fun, item, &name, &channels);
537 const size_t name_size = name ? str_size(name) + 1 : 0;
538 async_answer_2(callid, ret, name_size, channels);
539 /* Send the name. */
540 if (ret == EOK && name_size > 0) {
541 size_t size;
542 ipc_callid_t name_id;
543 if (!async_data_read_receive(&name_id, &size)) {
544 async_answer_0(name_id, EPARTY);
545 return;
546 }
547 if (size != name_size) {
548 async_answer_0(name_id, ELIMIT);
549 return;
550 }
551 async_data_read_finalize(name_id, name, name_size);
552 }
553}
554
555void remote_audio_mixer_get_channel_info(
556 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
557{
558 audio_mixer_iface_t *mixer_iface = iface;
559
560 if (!mixer_iface->get_channel_info) {
561 async_answer_0(callid, ENOTSUP);
562 return;
563 }
564
565 const unsigned item = DEV_IPC_GET_ARG1(*call);
566 const unsigned channel = DEV_IPC_GET_ARG2(*call);
567 const char *name = NULL;
568 unsigned levels = 0;
569 const int ret =
570 mixer_iface->get_channel_info(fun, item, channel, &name, &levels);
571 const size_t name_size = name ? str_size(name) + 1 : 0;
572 async_answer_2(callid, ret, name_size, levels);
573 /* Send the name. */
574 if (ret == EOK && name_size > 0) {
575 size_t size;
576 ipc_callid_t name_id;
577 if (!async_data_read_receive(&name_id, &size)) {
578 async_answer_0(name_id, EPARTY);
579 return;
580 }
581 if (size != name_size) {
582 async_answer_0(name_id, ELIMIT);
583 return;
584 }
585 async_data_read_finalize(name_id, name, name_size);
586 }
587}
588
589void remote_audio_mixer_channel_mute_set(
590 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
591{
592 audio_mixer_iface_t *mixer_iface = iface;
593
594 if (!mixer_iface->channel_mute_set) {
595 async_answer_0(callid, ENOTSUP);
596 return;
597 }
598 const unsigned item = DEV_IPC_GET_ARG1(*call);
599 const unsigned channel = DEV_IPC_GET_ARG2(*call);
600 const bool mute = DEV_IPC_GET_ARG3(*call);
601 const int ret = mixer_iface->channel_mute_set(fun, item, channel, mute);
602 async_answer_0(callid, ret);
603}
604
605void remote_audio_mixer_channel_mute_get(
606 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
607{
608 audio_mixer_iface_t *mixer_iface = iface;
609
610 if (!mixer_iface->channel_mute_get) {
611 async_answer_0(callid, ENOTSUP);
612 return;
613 }
614 const unsigned item = DEV_IPC_GET_ARG1(*call);
615 const unsigned channel = DEV_IPC_GET_ARG2(*call);
616 bool mute = false;
617 const int ret =
618 mixer_iface->channel_mute_get(fun, item, channel, &mute);
619 async_answer_1(callid, ret, mute);
620}
621
622void remote_audio_mixer_channel_volume_set(
623 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
624{
625 audio_mixer_iface_t *mixer_iface = iface;
626
627 if (!mixer_iface->channel_volume_set) {
628 async_answer_0(callid, ENOTSUP);
629 return;
630 }
631 const unsigned item = DEV_IPC_GET_ARG1(*call);
632 const unsigned channel = DEV_IPC_GET_ARG2(*call);
633 const unsigned level = DEV_IPC_GET_ARG3(*call);
634 const int ret =
635 mixer_iface->channel_volume_set(fun, item, channel, level);
636 async_answer_0(callid, ret);
637}
638
639void remote_audio_mixer_channel_volume_get(
640 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
641{
642 audio_mixer_iface_t *mixer_iface = iface;
643
644 if (!mixer_iface->channel_volume_get) {
645 async_answer_0(callid, ENOTSUP);
646 return;
647 }
648 const unsigned item = DEV_IPC_GET_ARG1(*call);
649 const unsigned channel = DEV_IPC_GET_ARG2(*call);
650 unsigned current = 0, max = 0;
651 const int ret =
652 mixer_iface->channel_volume_get(fun, item, channel, &current, &max);
653 async_answer_2(callid, ret, current, max);
654}
655#endif
656
657/**
658 * @}
659 */
660
Note: See TracBrowser for help on using the repository browser.