source: mainline/uspace/lib/drv/generic/remote_audio_mixer.c@ e941bf8

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

libdrv, libc: Add audio mixer interface.

  • Property mode set to 100644
File size: 14.0 KB
Line 
1/*
2 * Copyright (c) 2011 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 libdrv
30 * @{
31 */
32/** @file
33 */
34
35#include <async.h>
36#include <errno.h>
37#include <assert.h>
38#include <str.h>
39
40#include "audio_mixer_iface.h"
41#include "ddf/driver.h"
42
43typedef enum {
44 /** Asks for basic mixer info: Mixer name and number of controllable
45 * items.
46 * Answer:
47 * - ENOTSUP - call not supported
48 * - EOK - call successful, info is valid
49 * Answer arguments:
50 * - Mixer name
51 * - Number of controllable items
52 */
53 IPC_M_AUDIO_MIXER_GET_INFO,
54
55 /** Asks for item mixer info: Item name and number of controllable
56 * channels.
57 * Answer:
58 * - ENOTSUP - call not supported
59 * - ENOENT - no such item
60 * - EOK - call successful, info is valid
61 * Answer arguments:
62 * - Item name
63 * - Number of controllable channels
64 */
65 IPC_M_AUDIO_MIXER_GET_ITEM_INFO,
66
67 /** Asks for channel name and number of volume levels.
68 * Answer:
69 * - ENOTSUP - call not supported
70 * - ENOENT - no such channel
71 * - EOK - call successful, info is valid
72 * Answer arguments:
73 * - Channel name
74 * - Volume levels
75 */
76 IPC_M_AUDIO_MIXER_GET_CHANNEL_INFO,
77
78 /** Set channel mute status
79 * Answer:
80 * - ENOTSUP - call not supported
81 * - ENOENT - no such channel
82 * - EOK - call successful, info is valid
83 */
84 IPC_M_AUDIO_MIXER_CHANNEL_MUTE_SET,
85
86 /** Get channel mute status
87 * Answer:
88 * - ENOTSUP - call not supported
89 * - ENOENT - no such channel
90 * - EOK - call successful, info is valid
91 * Answer arguments:
92 * - Channel mute status
93 */
94 IPC_M_AUDIO_MIXER_CHANNEL_MUTE_GET,
95
96 /** Set channel volume level
97 * Answer:
98 * - ENOTSUP - call not supported
99 * - ENOENT - no such channel
100 * - EOK - call successful, info is valid
101 */
102 IPC_M_AUDIO_MIXER_CHANNEL_VOLUME_SET,
103
104 /** Get channel volume level
105 * Answer:
106 * - ENOTSUP - call not supported
107 * - ENOENT - no such channel
108 * - EOK - call successful, info is valid
109 * Answer arguments:
110 * - Channel volume level
111 * - Channel maximum volume level
112 */
113 IPC_M_AUDIO_MIXER_CHANNEL_VOLUME_GET,
114} audio_mixer_iface_funcs_t;
115
116/*
117 * CLIENT SIDE
118 */
119int audio_mixer_get_info(async_exch_t *exch, const char **name, unsigned *items)
120{
121 if (!exch)
122 return EINVAL;
123 sysarg_t name_size, itemc;
124 const int ret = async_req_1_2(exch, DEV_IFACE_ID(AUDIO_MIXER_IFACE),
125 IPC_M_AUDIO_MIXER_GET_INFO, &name_size, &itemc);
126 if (ret == EOK && name) {
127 char *name_place = calloc(1, name_size);
128 if (!name_place) {
129 /* Make the other side fail
130 * as it waits for read request */
131 async_data_read_start(exch, (void*)-1, 0);
132 return ENOMEM;
133 }
134 const int ret =
135 async_data_read_start(exch, name_place, name_size);
136 if (ret != EOK) {
137 free(name_place);
138 return ret;
139 }
140 *name = name_place;
141 }
142 if (ret == EOK && items)
143 *items = itemc;
144 return ret;
145}
146/*----------------------------------------------------------------------------*/
147int audio_mixer_get_item_info(async_exch_t *exch, unsigned item,
148 const char ** name, unsigned *channels)
149{
150 if (!exch)
151 return EINVAL;
152 sysarg_t name_size, chans;
153 const int ret = async_req_2_2(exch, DEV_IFACE_ID(AUDIO_MIXER_IFACE),
154 IPC_M_AUDIO_MIXER_GET_ITEM_INFO, item, &name_size, &chans);
155 if (ret == EOK && name) {
156 char *name_place = calloc(1, name_size);
157 if (!name_place) {
158 /* Make the other side fail
159 * as it waits for read request */
160 async_data_read_start(exch, (void*)-1, 0);
161 return ENOMEM;
162 }
163 const int ret =
164 async_data_read_start(exch, name_place, name_size);
165 if (ret != EOK) {
166 free(name_place);
167 return ret;
168 }
169 *name = name_place;
170 }
171 if (ret == EOK && chans)
172 *channels = chans;
173 return ret;
174}
175/*----------------------------------------------------------------------------*/
176int audio_mixer_get_channel_info(async_exch_t *exch, unsigned item,
177 unsigned channel, const char **name, unsigned *volume_levels)
178{
179 if (!exch)
180 return EINVAL;
181 sysarg_t name_size, levels;
182 const int ret = async_req_3_2(exch, DEV_IFACE_ID(AUDIO_MIXER_IFACE),
183 IPC_M_AUDIO_MIXER_GET_CHANNEL_INFO, item, channel,
184 &name_size, &levels);
185 if (ret == EOK && name) {
186 char *name_place = calloc(1, name_size);
187 if (!name_place) {
188 /* Make the other side fail
189 * as it waits for read request */
190 async_data_read_start(exch, (void*)-1, 0);
191 return ENOMEM;
192 }
193 const int ret =
194 async_data_read_start(exch, name_place, name_size);
195 if (ret != EOK) {
196 free(name_place);
197 return ret;
198 }
199 *name = name_place;
200 }
201 if (ret == EOK && volume_levels)
202 *volume_levels = levels;
203 return ret;
204}
205/*----------------------------------------------------------------------------*/
206int audio_mixer_channel_mute_set(async_exch_t *exch, unsigned item,
207 unsigned channel, bool mute_status)
208{
209 if (!exch)
210 return EINVAL;
211 return async_req_4_0(exch, DEV_IFACE_ID(AUDIO_MIXER_IFACE),
212 IPC_M_AUDIO_MIXER_CHANNEL_MUTE_SET, item, channel, mute_status);
213}
214/*----------------------------------------------------------------------------*/
215int audio_mixer_channel_mute_get(async_exch_t *exch, unsigned item,
216 unsigned channel, bool *mute_status)
217{
218 if (!exch)
219 return EINVAL;
220 sysarg_t mute;
221 const int ret = async_req_3_1(exch, DEV_IFACE_ID(AUDIO_MIXER_IFACE),
222 IPC_M_AUDIO_MIXER_CHANNEL_MUTE_GET, item, channel, &mute);
223 if (ret == EOK && mute_status)
224 *mute_status = (bool)mute;
225 return ret;
226}
227/*----------------------------------------------------------------------------*/
228int audio_mixer_channel_volume_set(async_exch_t *exch, unsigned item,
229 unsigned channel, unsigned volume)
230{
231 if (!exch)
232 return EINVAL;
233 return async_req_4_0(exch, DEV_IFACE_ID(AUDIO_MIXER_IFACE),
234 IPC_M_AUDIO_MIXER_CHANNEL_VOLUME_SET, item, channel, volume);
235}
236/*----------------------------------------------------------------------------*/
237int audio_mixer_channel_volume_get(async_exch_t *exch, unsigned item,
238 unsigned channel, unsigned *volume_current, unsigned *volume_max)
239{
240 if (!exch)
241 return EINVAL;
242 sysarg_t current, max;
243 const int ret = async_req_3_2(exch, DEV_IFACE_ID(AUDIO_MIXER_IFACE),
244 IPC_M_AUDIO_MIXER_CHANNEL_VOLUME_GET, item, channel,
245 &current, &max);
246 if (ret == EOK && volume_current)
247 *volume_current = current;
248 if (ret == EOK && volume_max)
249 *volume_max = max;
250 return ret;
251}
252
253/*
254 * SERVER SIDE
255 */
256static void remote_audio_mixer_get_info(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
257static void remote_audio_mixer_get_item_info(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
258static void remote_audio_mixer_get_channel_info(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
259static void remote_audio_mixer_channel_mute_set(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
260static void remote_audio_mixer_channel_mute_get(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
261static void remote_audio_mixer_channel_volume_set(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
262static void remote_audio_mixer_channel_volume_get(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
263
264/** Remote audio mixer interface operations. */
265static remote_iface_func_ptr_t remote_audio_mixer_iface_ops[] = {
266 [IPC_M_AUDIO_MIXER_GET_INFO] = remote_audio_mixer_get_info,
267 [IPC_M_AUDIO_MIXER_GET_ITEM_INFO] = remote_audio_mixer_get_item_info,
268 [IPC_M_AUDIO_MIXER_GET_CHANNEL_INFO] = remote_audio_mixer_get_channel_info,
269 [IPC_M_AUDIO_MIXER_CHANNEL_MUTE_SET] = remote_audio_mixer_channel_mute_set,
270 [IPC_M_AUDIO_MIXER_CHANNEL_MUTE_GET] = remote_audio_mixer_channel_mute_get,
271 [IPC_M_AUDIO_MIXER_CHANNEL_VOLUME_SET] = remote_audio_mixer_channel_volume_set,
272 [IPC_M_AUDIO_MIXER_CHANNEL_VOLUME_GET] = remote_audio_mixer_channel_volume_get,
273};
274
275/** Remote audio mixer interface structure. */
276remote_iface_t remote_audio_mixer_iface = {
277 .method_count = sizeof(remote_audio_mixer_iface_ops) /
278 sizeof(remote_audio_mixer_iface_ops[0]),
279 .methods = remote_audio_mixer_iface_ops
280};
281/*----------------------------------------------------------------------------*/
282void remote_audio_mixer_get_info(
283 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
284{
285 audio_mixer_iface_t *mixer_iface = iface;
286
287 if (!mixer_iface->get_info) {
288 async_answer_0(callid, ENOTSUP);
289 return;
290 }
291 const char *name = NULL;
292 unsigned items = 0;
293 const int ret = mixer_iface->get_info(fun, &name, &items);
294 const size_t name_size = name ? str_size(name) + 1 : 0;
295 async_answer_2(callid, ret, name_size, items);
296 /* Send the name. */
297 if (ret == EOK && name_size > 0) {
298 size_t size;
299 ipc_callid_t name_id;
300 if (!async_data_read_receive(&name_id, &size)) {
301 async_answer_0(name_id, EPARTY);
302 return;
303 }
304 if (size != name_size) {
305 async_answer_0(name_id, ELIMIT);
306 return;
307 }
308 async_data_read_finalize(name_id, name, name_size);
309 }
310}
311/*----------------------------------------------------------------------------*/
312void remote_audio_mixer_get_item_info(
313 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
314{
315 audio_mixer_iface_t *mixer_iface = iface;
316
317 if (!mixer_iface->get_item_info) {
318 async_answer_0(callid, ENOTSUP);
319 return;
320 }
321
322 const unsigned item = DEV_IPC_GET_ARG1(*call);
323 const char *name = NULL;
324 unsigned channels = 0;
325 const int ret = mixer_iface->get_item_info(fun, item, &name, &channels);
326 const size_t name_size = name ? str_size(name) + 1 : 0;
327 async_answer_2(callid, ret, name_size, channels);
328 /* Send the name. */
329 if (ret == EOK && name_size > 0) {
330 size_t size;
331 ipc_callid_t name_id;
332 if (!async_data_read_receive(&name_id, &size)) {
333 async_answer_0(name_id, EPARTY);
334 return;
335 }
336 if (size != name_size) {
337 async_answer_0(name_id, ELIMIT);
338 return;
339 }
340 async_data_read_finalize(name_id, name, name_size);
341 }
342}
343/*----------------------------------------------------------------------------*/
344void remote_audio_mixer_get_channel_info(
345 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
346{
347 audio_mixer_iface_t *mixer_iface = iface;
348
349 if (!mixer_iface->get_channel_info) {
350 async_answer_0(callid, ENOTSUP);
351 return;
352 }
353
354 const unsigned item = DEV_IPC_GET_ARG1(*call);
355 const unsigned channel = DEV_IPC_GET_ARG2(*call);
356 const char *name = NULL;
357 unsigned levels = 0;
358 const int ret =
359 mixer_iface->get_channel_info(fun, item, channel, &name, &levels);
360 const size_t name_size = name ? str_size(name) + 1 : 0;
361 async_answer_2(callid, ret, name_size, levels);
362 /* Send the name. */
363 if (ret == EOK && name_size > 0) {
364 size_t size;
365 ipc_callid_t name_id;
366 if (!async_data_read_receive(&name_id, &size)) {
367 async_answer_0(name_id, EPARTY);
368 return;
369 }
370 if (size != name_size) {
371 async_answer_0(name_id, ELIMIT);
372 return;
373 }
374 async_data_read_finalize(name_id, name, name_size);
375 }
376}
377/*----------------------------------------------------------------------------*/
378void remote_audio_mixer_channel_mute_set(
379 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
380{
381 audio_mixer_iface_t *mixer_iface = iface;
382
383 if (!mixer_iface->channel_mute_set) {
384 async_answer_0(callid, ENOTSUP);
385 return;
386 }
387 const unsigned item = DEV_IPC_GET_ARG1(*call);
388 const unsigned channel = DEV_IPC_GET_ARG2(*call);
389 const bool mute = DEV_IPC_GET_ARG3(*call);
390 const int ret = mixer_iface->channel_mute_set(fun, item, channel, mute);
391 async_answer_0(callid, ret);
392}
393/*----------------------------------------------------------------------------*/
394void remote_audio_mixer_channel_mute_get(
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->channel_mute_get) {
400 async_answer_0(callid, ENOTSUP);
401 return;
402 }
403 const unsigned item = DEV_IPC_GET_ARG1(*call);
404 const unsigned channel = DEV_IPC_GET_ARG2(*call);
405 bool mute = false;
406 const int ret =
407 mixer_iface->channel_mute_get(fun, item, channel, &mute);
408 async_answer_1(callid, ret, mute);
409}
410/*----------------------------------------------------------------------------*/
411void remote_audio_mixer_channel_volume_set(
412 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
413{
414 audio_mixer_iface_t *mixer_iface = iface;
415
416 if (!mixer_iface->channel_volume_set) {
417 async_answer_0(callid, ENOTSUP);
418 return;
419 }
420 const unsigned item = DEV_IPC_GET_ARG1(*call);
421 const unsigned channel = DEV_IPC_GET_ARG2(*call);
422 const unsigned level = DEV_IPC_GET_ARG3(*call);
423 const int ret =
424 mixer_iface->channel_volume_set(fun, item, channel, level);
425 async_answer_0(callid, ret);
426}
427/*----------------------------------------------------------------------------*/
428void remote_audio_mixer_channel_volume_get(
429 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
430{
431 audio_mixer_iface_t *mixer_iface = iface;
432
433 if (!mixer_iface->channel_volume_get) {
434 async_answer_0(callid, ENOTSUP);
435 return;
436 }
437 const unsigned item = DEV_IPC_GET_ARG1(*call);
438 const unsigned channel = DEV_IPC_GET_ARG2(*call);
439 unsigned current = 0, max = 0;
440 const int ret =
441 mixer_iface->channel_volume_get(fun, item, channel, &current, &max);
442 async_answer_2(callid, ret, current, max);
443}
444
445/**
446 * @}
447 */
Note: See TracBrowser for help on using the repository browser.