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

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

libdrv/audio: Add 'test_format' call.

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