source: mainline/uspace/lib/drv/generic/remote_audio_pcm_buffer.c@ 2f7042e

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

audio: Allow client to specify buffer size.

  • Property mode set to 100644
File size: 15.8 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/** @addtogroup libdrv
29 * @{
30 */
31/** @file
32 */
33
34#include <async.h>
35#include <errno.h>
36#include <str.h>
37#include <as.h>
38#include <sys/mman.h>
39
40#include "audio_pcm_buffer_iface.h"
41#include "ddf/driver.h"
42
43typedef enum {
44 IPC_M_AUDIO_PCM_GET_INFO_STR,
45 IPC_M_AUDIO_PCM_GET_BUFFER,
46 IPC_M_AUDIO_PCM_RELEASE_BUFFER,
47 IPC_M_AUDIO_PCM_START_PLAYBACK,
48 IPC_M_AUDIO_PCM_STOP_PLAYBACK,
49 IPC_M_AUDIO_PCM_START_RECORD,
50 IPC_M_AUDIO_PCM_STOP_RECORD,
51} audio_pcm_iface_funcs_t;
52
53/*
54 * CLIENT SIDE
55 */
56int audio_pcm_buffer_get_info_str(async_exch_t *exch, const char **name)
57{
58 if (!exch)
59 return EINVAL;
60 sysarg_t name_size;
61 const int ret = async_req_1_1(exch,
62 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
63 IPC_M_AUDIO_PCM_GET_INFO_STR, &name_size);
64 if (ret == EOK && name) {
65 char *name_place = calloc(1, name_size);
66 if (!name_place) {
67 /* Make the other side fail
68 * as it waits for read request */
69 async_data_read_start(exch, (void*)-1, 0);
70 return ENOMEM;
71 }
72 const int ret =
73 async_data_read_start(exch, name_place, name_size);
74 if (ret != EOK) {
75 free(name_place);
76 return ret;
77 }
78 *name = name_place;
79 }
80 return ret;
81}
82/*----------------------------------------------------------------------------*/
83int audio_pcm_buffer_get_buffer(async_exch_t *exch, void **buffer, size_t *size,
84 unsigned *id)
85{
86 if (!exch || !buffer || !size || !id)
87 return EINVAL;
88
89 sysarg_t buffer_size = *size, buffer_id = 0;
90 const int ret = async_req_2_2(exch,
91 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE), IPC_M_AUDIO_PCM_GET_BUFFER,
92 (sysarg_t)buffer_size, &buffer_size, &buffer_id);
93 if (ret == EOK) {
94 void *dst = NULL;
95 // FIXME Do we need to know the flags?
96 const int ret = async_share_in_start_0_0(exch, buffer_size, &dst);
97 if (ret != EOK) {
98 return ret;
99 }
100 *buffer = dst;
101 *size = buffer_size;
102 *id = buffer_id;
103 }
104 return ret;
105}
106/*----------------------------------------------------------------------------*/
107int audio_pcm_buffer_release_buffer(async_exch_t *exch, unsigned id)
108{
109 if (!exch)
110 return EINVAL;
111 return async_req_2_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
112 IPC_M_AUDIO_PCM_RELEASE_BUFFER, id);
113}
114/*----------------------------------------------------------------------------*/
115int audio_pcm_buffer_start_playback(async_exch_t *exch, unsigned id,
116 unsigned sample_rate, uint16_t sample_size, uint8_t channels, bool sign)
117{
118 if (!exch)
119 return EINVAL;
120 sysarg_t packed =
121 (sample_size << 16) | (channels << 8) | (sign ? 1 : 0);
122 return async_req_4_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
123 IPC_M_AUDIO_PCM_START_PLAYBACK, id, sample_rate, packed);
124}
125/*----------------------------------------------------------------------------*/
126int audio_pcm_buffer_stop_playback(async_exch_t *exch, unsigned id)
127{
128 if (!exch)
129 return EINVAL;
130 return async_req_2_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
131 IPC_M_AUDIO_PCM_STOP_PLAYBACK, id);
132}
133/*----------------------------------------------------------------------------*/
134int audio_pcm_buffer_start_record(async_exch_t *exch, unsigned id,
135 unsigned sample_rate, unsigned sample_size, unsigned channels, bool sign)
136{
137 if (!exch || sample_size > UINT16_MAX || channels > (UINT16_MAX >> 1))
138 return EINVAL;
139 sysarg_t packed = sample_size << 16 | channels << 1 | sign ? 1 : 0;
140 return async_req_4_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
141 IPC_M_AUDIO_PCM_START_RECORD, id, sample_rate, packed);
142}
143/*----------------------------------------------------------------------------*/
144int audio_pcm_buffer_stop_record(async_exch_t *exch, unsigned id)
145{
146 if (!exch)
147 return EINVAL;
148 return async_req_2_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
149 IPC_M_AUDIO_PCM_STOP_RECORD, id);
150}
151
152/*
153 * SERVER SIDE
154 */
155static void remote_audio_pcm_get_info_str(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
156static void remote_audio_pcm_get_buffer(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
157static void remote_audio_pcm_release_buffer(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
158static void remote_audio_pcm_start_playback(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
159static void remote_audio_pcm_stop_playback(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
160static void remote_audio_pcm_start_record(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
161static void remote_audio_pcm_stop_record(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
162
163/** Remote audio pcm buffer interface operations. */
164static remote_iface_func_ptr_t remote_audio_pcm_iface_ops[] = {
165 [IPC_M_AUDIO_PCM_GET_INFO_STR] = remote_audio_pcm_get_info_str,
166 [IPC_M_AUDIO_PCM_GET_BUFFER] = remote_audio_pcm_get_buffer,
167 [IPC_M_AUDIO_PCM_RELEASE_BUFFER] = remote_audio_pcm_release_buffer,
168 [IPC_M_AUDIO_PCM_START_PLAYBACK] = remote_audio_pcm_start_playback,
169 [IPC_M_AUDIO_PCM_STOP_PLAYBACK] = remote_audio_pcm_stop_playback,
170 [IPC_M_AUDIO_PCM_START_RECORD] = remote_audio_pcm_start_record,
171 [IPC_M_AUDIO_PCM_STOP_RECORD] = remote_audio_pcm_stop_record,
172};
173
174/** Remote audio mixer interface structure. */
175remote_iface_t remote_audio_pcm_buffer_iface = {
176 .method_count = sizeof(remote_audio_pcm_iface_ops) /
177 sizeof(remote_audio_pcm_iface_ops[0]),
178 .methods = remote_audio_pcm_iface_ops
179};
180/*----------------------------------------------------------------------------*/
181void remote_audio_pcm_get_info_str(ddf_fun_t *fun, void *iface,
182 ipc_callid_t callid, ipc_call_t *call)
183{
184 const audio_pcm_buffer_iface_t *pcm_iface = iface;
185
186 if (!pcm_iface->get_info_str) {
187 async_answer_0(callid, ENOTSUP);
188 return;
189 }
190 const char *name = NULL;
191 const int ret = pcm_iface->get_info_str(fun, &name);
192 const size_t name_size = name ? str_size(name) + 1 : 0;
193 async_answer_1(callid, ret, name_size);
194 /* Send the string. */
195 if (ret == EOK && name_size > 0) {
196 size_t size;
197 ipc_callid_t name_id;
198 if (!async_data_read_receive(&name_id, &size)) {
199 async_answer_0(name_id, EPARTY);
200 return;
201 }
202 if (size != name_size) {
203 async_answer_0(name_id, ELIMIT);
204 return;
205 }
206 async_data_read_finalize(name_id, name, name_size);
207 }
208}
209/*----------------------------------------------------------------------------*/
210void remote_audio_pcm_get_buffer(ddf_fun_t *fun, void *iface,
211 ipc_callid_t callid, ipc_call_t *call)
212{
213 const audio_pcm_buffer_iface_t *pcm_iface = iface;
214
215 if (!pcm_iface->get_buffer) {
216 async_answer_0(callid, ENOTSUP);
217 return;
218 }
219 void *buffer = NULL;
220 size_t size = DEV_IPC_GET_ARG1(*call);
221 unsigned id = 0;
222 const int ret = pcm_iface->get_buffer(fun, &buffer, &size, &id);
223 async_answer_2(callid, ret, size, id);
224 /* Share the buffer. */
225 if (ret == EOK && size > 0) {
226 size_t share_size;
227 ipc_callid_t name_id;
228 if (!async_share_in_receive(&name_id, &share_size)) {
229 async_answer_0(name_id, EPARTY);
230 return;
231 }
232 if (share_size != size) {
233 async_answer_0(name_id, ELIMIT);
234 return;
235 }
236 async_share_in_finalize(name_id, buffer, PROTO_READ | PROTO_WRITE);
237 }
238}
239/*----------------------------------------------------------------------------*/
240void remote_audio_pcm_release_buffer(ddf_fun_t *fun, void *iface,
241 ipc_callid_t callid, ipc_call_t *call)
242{
243 const audio_pcm_buffer_iface_t *pcm_iface = iface;
244
245 const unsigned id = DEV_IPC_GET_ARG1(*call);
246 const int ret = pcm_iface->release_buffer ?
247 pcm_iface->release_buffer(fun, id) : ENOTSUP;
248 async_answer_0(callid, ret);
249}
250/*----------------------------------------------------------------------------*/
251void remote_audio_pcm_start_playback(ddf_fun_t *fun, void *iface,
252 ipc_callid_t callid, ipc_call_t *call)
253{
254 const audio_pcm_buffer_iface_t *pcm_iface = iface;
255
256 const unsigned id = DEV_IPC_GET_ARG1(*call);
257 const unsigned rate = DEV_IPC_GET_ARG2(*call);
258 const unsigned size = DEV_IPC_GET_ARG3(*call) >> 16;
259 const unsigned channels = (DEV_IPC_GET_ARG3(*call) >> 8) && UINT8_MAX;
260 const bool sign = (bool)(DEV_IPC_GET_ARG3(*call) & 1);
261
262 const int ret = pcm_iface->start_playback
263 ? pcm_iface->start_playback(fun, id, rate, size, channels, sign)
264 : ENOTSUP;
265 async_answer_0(callid, ret);
266}
267/*----------------------------------------------------------------------------*/
268void remote_audio_pcm_stop_playback(ddf_fun_t *fun, void *iface,
269 ipc_callid_t callid, ipc_call_t *call)
270{
271 const audio_pcm_buffer_iface_t *pcm_iface = iface;
272
273 const unsigned id = DEV_IPC_GET_ARG1(*call);
274 const int ret = pcm_iface->stop_playback ?
275 pcm_iface->stop_playback(fun, id) : ENOTSUP;
276 async_answer_0(callid, ret);
277}
278/*----------------------------------------------------------------------------*/
279void remote_audio_pcm_start_record(ddf_fun_t *fun, void *iface,
280 ipc_callid_t callid, ipc_call_t *call)
281{
282 const audio_pcm_buffer_iface_t *pcm_iface = iface;
283
284 const unsigned id = DEV_IPC_GET_ARG1(*call);
285 const unsigned rate = DEV_IPC_GET_ARG2(*call);
286 const unsigned size = DEV_IPC_GET_ARG3(*call) >> 16;
287 const unsigned channels = (DEV_IPC_GET_ARG3(*call) & UINT16_MAX) >> 1;
288 const bool sign = (bool)(DEV_IPC_GET_ARG3(*call) & 1);
289
290 const int ret = pcm_iface->start_record
291 ? pcm_iface->start_record(fun, id, rate, size, channels, sign)
292 : ENOTSUP;
293 async_answer_0(callid, ret);
294}
295/*----------------------------------------------------------------------------*/
296void remote_audio_pcm_stop_record(ddf_fun_t *fun, void *iface,
297 ipc_callid_t callid, ipc_call_t *call)
298{
299 const audio_pcm_buffer_iface_t *pcm_iface = iface;
300
301 const unsigned id = DEV_IPC_GET_ARG1(*call);
302 const int ret = pcm_iface->stop_record ?
303 pcm_iface->stop_record(fun, id) : ENOTSUP;
304 async_answer_0(callid, ret);
305}
306
307#if 0
308/*----------------------------------------------------------------------------*/
309void remote_audio_mixer_get_info(
310 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
311{
312 audio_mixer_iface_t *mixer_iface = iface;
313
314 if (!mixer_iface->get_info) {
315 async_answer_0(callid, ENOTSUP);
316 return;
317 }
318 const char *name = NULL;
319 unsigned items = 0;
320 const int ret = mixer_iface->get_info(fun, &name, &items);
321 const size_t name_size = name ? str_size(name) + 1 : 0;
322 async_answer_2(callid, ret, name_size, items);
323 /* Send the name. */
324 if (ret == EOK && name_size > 0) {
325 size_t size;
326 ipc_callid_t name_id;
327 if (!async_data_read_receive(&name_id, &size)) {
328 async_answer_0(name_id, EPARTY);
329 return;
330 }
331 if (size != name_size) {
332 async_answer_0(name_id, ELIMIT);
333 return;
334 }
335 async_data_read_finalize(name_id, name, name_size);
336 }
337}
338/*----------------------------------------------------------------------------*/
339void remote_audio_mixer_get_item_info(
340 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
341{
342 audio_mixer_iface_t *mixer_iface = iface;
343
344 if (!mixer_iface->get_item_info) {
345 async_answer_0(callid, ENOTSUP);
346 return;
347 }
348
349 const unsigned item = DEV_IPC_GET_ARG1(*call);
350 const char *name = NULL;
351 unsigned channels = 0;
352 const int ret = mixer_iface->get_item_info(fun, item, &name, &channels);
353 const size_t name_size = name ? str_size(name) + 1 : 0;
354 async_answer_2(callid, ret, name_size, channels);
355 /* Send the name. */
356 if (ret == EOK && name_size > 0) {
357 size_t size;
358 ipc_callid_t name_id;
359 if (!async_data_read_receive(&name_id, &size)) {
360 async_answer_0(name_id, EPARTY);
361 return;
362 }
363 if (size != name_size) {
364 async_answer_0(name_id, ELIMIT);
365 return;
366 }
367 async_data_read_finalize(name_id, name, name_size);
368 }
369}
370/*----------------------------------------------------------------------------*/
371void remote_audio_mixer_get_channel_info(
372 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
373{
374 audio_mixer_iface_t *mixer_iface = iface;
375
376 if (!mixer_iface->get_channel_info) {
377 async_answer_0(callid, ENOTSUP);
378 return;
379 }
380
381 const unsigned item = DEV_IPC_GET_ARG1(*call);
382 const unsigned channel = DEV_IPC_GET_ARG2(*call);
383 const char *name = NULL;
384 unsigned levels = 0;
385 const int ret =
386 mixer_iface->get_channel_info(fun, item, channel, &name, &levels);
387 const size_t name_size = name ? str_size(name) + 1 : 0;
388 async_answer_2(callid, ret, name_size, levels);
389 /* Send the name. */
390 if (ret == EOK && name_size > 0) {
391 size_t size;
392 ipc_callid_t name_id;
393 if (!async_data_read_receive(&name_id, &size)) {
394 async_answer_0(name_id, EPARTY);
395 return;
396 }
397 if (size != name_size) {
398 async_answer_0(name_id, ELIMIT);
399 return;
400 }
401 async_data_read_finalize(name_id, name, name_size);
402 }
403}
404/*----------------------------------------------------------------------------*/
405void remote_audio_mixer_channel_mute_set(
406 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
407{
408 audio_mixer_iface_t *mixer_iface = iface;
409
410 if (!mixer_iface->channel_mute_set) {
411 async_answer_0(callid, ENOTSUP);
412 return;
413 }
414 const unsigned item = DEV_IPC_GET_ARG1(*call);
415 const unsigned channel = DEV_IPC_GET_ARG2(*call);
416 const bool mute = DEV_IPC_GET_ARG3(*call);
417 const int ret = mixer_iface->channel_mute_set(fun, item, channel, mute);
418 async_answer_0(callid, ret);
419}
420/*----------------------------------------------------------------------------*/
421void remote_audio_mixer_channel_mute_get(
422 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
423{
424 audio_mixer_iface_t *mixer_iface = iface;
425
426 if (!mixer_iface->channel_mute_get) {
427 async_answer_0(callid, ENOTSUP);
428 return;
429 }
430 const unsigned item = DEV_IPC_GET_ARG1(*call);
431 const unsigned channel = DEV_IPC_GET_ARG2(*call);
432 bool mute = false;
433 const int ret =
434 mixer_iface->channel_mute_get(fun, item, channel, &mute);
435 async_answer_1(callid, ret, mute);
436}
437/*----------------------------------------------------------------------------*/
438void remote_audio_mixer_channel_volume_set(
439 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
440{
441 audio_mixer_iface_t *mixer_iface = iface;
442
443 if (!mixer_iface->channel_volume_set) {
444 async_answer_0(callid, ENOTSUP);
445 return;
446 }
447 const unsigned item = DEV_IPC_GET_ARG1(*call);
448 const unsigned channel = DEV_IPC_GET_ARG2(*call);
449 const unsigned level = DEV_IPC_GET_ARG3(*call);
450 const int ret =
451 mixer_iface->channel_volume_set(fun, item, channel, level);
452 async_answer_0(callid, ret);
453}
454/*----------------------------------------------------------------------------*/
455void remote_audio_mixer_channel_volume_get(
456 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
457{
458 audio_mixer_iface_t *mixer_iface = iface;
459
460 if (!mixer_iface->channel_volume_get) {
461 async_answer_0(callid, ENOTSUP);
462 return;
463 }
464 const unsigned item = DEV_IPC_GET_ARG1(*call);
465 const unsigned channel = DEV_IPC_GET_ARG2(*call);
466 unsigned current = 0, max = 0;
467 const int ret =
468 mixer_iface->channel_volume_get(fun, item, channel, &current, &max);
469 async_answer_2(callid, ret, current, max);
470}
471#endif
472
473/**
474 * @}
475 */
476
Note: See TracBrowser for help on using the repository browser.