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

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

Add frame count to event report.

This enables applications to detect underruns.

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