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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 24.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 <macros.h>
39#include <str.h>
40#include <as.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_REGISTER_EVENTS,
49 IPC_M_AUDIO_PCM_UNREGISTER_EVENTS,
50 IPC_M_AUDIO_PCM_TEST_FORMAT,
51 IPC_M_AUDIO_PCM_GET_BUFFER,
52 IPC_M_AUDIO_PCM_RELEASE_BUFFER,
53 IPC_M_AUDIO_PCM_GET_BUFFER_POS,
54 IPC_M_AUDIO_PCM_START_PLAYBACK,
55 IPC_M_AUDIO_PCM_STOP_PLAYBACK,
56 IPC_M_AUDIO_PCM_START_CAPTURE,
57 IPC_M_AUDIO_PCM_STOP_CAPTURE,
58} audio_pcm_iface_funcs_t;
59
60/**
61 * Get human readable capability name.
62 * @param cap audio capability.
63 * @return Valid string
64 */
65const char *audio_pcm_cap_str(audio_cap_t cap)
66{
67 static const char *caps[] = {
68 [AUDIO_CAP_CAPTURE] = "CAPTURE",
69 [AUDIO_CAP_PLAYBACK] = "PLAYBACK",
70 [AUDIO_CAP_MAX_BUFFER] = "MAXIMUM BUFFER SIZE",
71 [AUDIO_CAP_BUFFER_POS] = "KNOWS BUFFER POSITION",
72 [AUDIO_CAP_INTERRUPT] = "FRAGMENT INTERRUPTS",
73 [AUDIO_CAP_INTERRUPT_MIN_FRAMES] = "MINIMUM FRAGMENT SIZE",
74 [AUDIO_CAP_INTERRUPT_MAX_FRAMES] = "MAXIMUM FRAGMENT SIZE",
75 };
76 if (cap >= ARRAY_SIZE(caps))
77 return "UNKNOWN CAP";
78 return caps[cap];
79
80}
81
82/**
83 * Get human readable event name.
84 * @param event Audio device event
85 * @return Valid string
86 */
87const char *audio_pcm_event_str(pcm_event_t event)
88{
89 static const char *events[] = {
90 [PCM_EVENT_PLAYBACK_STARTED] = "PLAYBACK STARTED",
91 [PCM_EVENT_CAPTURE_STARTED] = "CAPTURE STARTED",
92 [PCM_EVENT_FRAMES_PLAYED] = "FRAGMENT PLAYED",
93 [PCM_EVENT_FRAMES_CAPTURED] = "FRAGMENT CAPTURED",
94 [PCM_EVENT_PLAYBACK_TERMINATED] = "PLAYBACK TERMINATED",
95 [PCM_EVENT_CAPTURE_TERMINATED] = "CAPTURE TERMINATED",
96 };
97 if (event >= ARRAY_SIZE(events))
98 return "UNKNOWN EVENT";
99 return events[event];
100}
101
102/*
103 * CLIENT SIDE
104 */
105
106/**
107 * Open audio session with the first registered device.
108 *
109 * @return Pointer to a new audio device session, NULL on failure.
110 */
111audio_pcm_sess_t *audio_pcm_open_default(void)
112{
113 static bool resolved = false;
114 static category_id_t pcm_id = 0;
115 if (!resolved) {
116 const errno_t ret = loc_category_get_id("audio-pcm", &pcm_id,
117 IPC_FLAG_BLOCKING);
118 if (ret != EOK)
119 return NULL;
120 resolved = true;
121 }
122
123 service_id_t *svcs = NULL;
124 size_t count = 0;
125 const errno_t ret = loc_category_get_svcs(pcm_id, &svcs, &count);
126 if (ret != EOK)
127 return NULL;
128
129 audio_pcm_sess_t *session = NULL;
130 if (count)
131 session = audio_pcm_open_service(svcs[0]);
132 free(svcs);
133 return session;
134}
135
136/**
137 * Open audio session with device identified by location service string.
138 *
139 * @param name Location service string.
140 * @return Pointer to a new audio device session, NULL on failure.
141 */
142audio_pcm_sess_t *audio_pcm_open(const char *name)
143{
144 devman_handle_t device_handle = 0;
145 const errno_t ret = devman_fun_get_handle(name, &device_handle, 0);
146 if (ret != EOK)
147 return NULL;
148 return devman_device_connect(device_handle, IPC_FLAG_BLOCKING);
149}
150
151/**
152 * Open audio session with device identified by location service id
153 *
154 * @param name Location service id.
155 * @return Pointer to a new audio device session, NULL on failure.
156 */
157audio_pcm_sess_t *audio_pcm_open_service(service_id_t id)
158{
159 return loc_service_connect(id, INTERFACE_DDF, IPC_FLAG_BLOCKING);
160}
161
162/**
163 * Close open audio device session.
164 *
165 * @param name Open audio device session.
166 *
167 * @note Calling this function on already closed or invalid session results
168 * in undefined behavior.
169 */
170void audio_pcm_close(audio_pcm_sess_t *sess)
171{
172 if (sess)
173 async_hangup(sess);
174}
175
176/**
177 * Get a short description string.
178 *
179 * @param sess Audio device session.
180 * @param name Place to store newly allocated string.
181 *
182 * @return Error code.
183 *
184 * @note Caller is responsible for freeing newly allocated memory.
185 */
186errno_t audio_pcm_get_info_str(audio_pcm_sess_t *sess, char **name)
187{
188 if (!name)
189 return EINVAL;
190 async_exch_t *exch = async_exchange_begin(sess);
191 sysarg_t name_size;
192 const errno_t ret = async_req_1_1(exch,
193 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
194 IPC_M_AUDIO_PCM_GET_INFO_STR, &name_size);
195 if (ret == EOK) {
196 char *name_place = calloc(1, name_size);
197 if (!name_place) {
198 /* Make the other side fail
199 * as it waits for read request */
200 async_data_read_start(exch, (void*)-1, 0);
201 async_exchange_end(exch);
202 return ENOMEM;
203 }
204 const errno_t ret =
205 async_data_read_start(exch, name_place, name_size);
206 if (ret != EOK) {
207 free(name_place);
208 async_exchange_end(exch);
209 return ret;
210 }
211 *name = name_place;
212 }
213 async_exchange_end(exch);
214 return ret;
215}
216
217
218/**
219 * Query value of specified capability.
220 *
221 * @param sess Audio device session.
222 * @param cap Audio device capability.
223 * @param[out] val Place to store queried value.
224 *
225 * @return Error code.
226 */
227errno_t audio_pcm_query_cap(audio_pcm_sess_t *sess, audio_cap_t cap, sysarg_t *value)
228{
229 async_exch_t *exch = async_exchange_begin(sess);
230 const errno_t ret = async_req_2_1(exch,
231 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE), IPC_M_AUDIO_PCM_QUERY_CAPS,
232 cap, value);
233 async_exchange_end(exch);
234 return ret;
235}
236
237/**
238 * Query current position in device buffer.
239 *
240 * @param sess Audio device session.
241 * @param pos Place to store the result.
242 *
243 * @return Error code.
244 *
245 * Works for both playback and capture.
246 */
247errno_t audio_pcm_get_buffer_pos(audio_pcm_sess_t *sess, size_t *pos)
248{
249 if (!pos)
250 return EINVAL;
251 async_exch_t *exch = async_exchange_begin(sess);
252 sysarg_t value = 0;
253 const errno_t ret = async_req_1_1(exch,
254 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
255 IPC_M_AUDIO_PCM_GET_BUFFER_POS, &value);
256 if (ret == EOK)
257 *pos = value;
258 async_exchange_end(exch);
259 return ret;
260}
261
262/**
263 * Test format parameters for device support.
264 *
265 * @param sess Audio device session.
266 * @param channels Number of channels
267 * @param rate Sampling rate.
268 * @format Sample format.
269 *
270 * @return Error code.
271 *
272 * Works for both playback and capture. This function modifies provided
273 * parameters to the nearest values supported by the device.
274 */
275errno_t audio_pcm_test_format(audio_pcm_sess_t *sess, unsigned *channels,
276 unsigned *rate, pcm_sample_format_t *format)
277{
278 async_exch_t *exch = async_exchange_begin(sess);
279 sysarg_t channels_arg = channels ? *channels : 0;
280 sysarg_t rate_arg = rate ? *rate : 0;
281 sysarg_t format_arg = format ? *format : 0;
282 const errno_t ret = async_req_4_3(exch,
283 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
284 IPC_M_AUDIO_PCM_TEST_FORMAT, channels_arg, rate_arg, format_arg,
285 &channels_arg, &rate_arg, &format_arg);
286 async_exchange_end(exch);
287
288 /* All OK or something has changed. Verify that it was not one of the
289 * params we care about */
290 if ((ret == EOK || ret == ELIMIT)
291 && (!channels || *channels == channels_arg)
292 && (!rate || *rate == rate_arg)
293 && (!format || *format == format_arg))
294 return EOK;
295 if (channels)
296 *channels = channels_arg;
297 if (rate)
298 *rate = rate_arg;
299 if (format)
300 *format = format_arg;
301 return ret;
302}
303
304/**
305 * Register callback for device generated events.
306 *
307 * @param sess Audio device session.
308 * @param event_rec Event callback function.
309 * @param arg Event callback custom parameter.
310 *
311 * @return Error code.
312 */
313errno_t audio_pcm_register_event_callback(audio_pcm_sess_t *sess,
314 async_port_handler_t event_callback, void *arg)
315{
316 if (!event_callback)
317 return EINVAL;
318
319 async_exch_t *exch = async_exchange_begin(sess);
320
321 errno_t ret = async_req_1_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
322 IPC_M_AUDIO_PCM_REGISTER_EVENTS);
323 if (ret == EOK) {
324 port_id_t port;
325 ret = async_create_callback_port(exch, INTERFACE_AUDIO_PCM_CB, 0, 0,
326 event_callback, arg, &port);
327 }
328
329 async_exchange_end(exch);
330 return ret;
331}
332
333/**
334 * Unregister callback for device generated events.
335 *
336 * @param sess Audio device session.
337 *
338 * @return Error code.
339 */
340errno_t audio_pcm_unregister_event_callback(audio_pcm_sess_t *sess)
341{
342 async_exch_t *exch = async_exchange_begin(sess);
343 const errno_t ret = async_req_1_0(exch,
344 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
345 IPC_M_AUDIO_PCM_UNREGISTER_EVENTS);
346 async_exchange_end(exch);
347 return ret;
348}
349
350/**
351 * Get device accessible playback/capture buffer.
352 *
353 * @param sess Audio device session.
354 * @param buffer Place to store pointer to the buffer.
355 * @param size Place to store buffer size (bytes).
356 *
357 * @return Error code.
358 */
359errno_t audio_pcm_get_buffer(audio_pcm_sess_t *sess, void **buffer, size_t *size)
360{
361 if (!buffer || !size)
362 return EINVAL;
363
364 async_exch_t *exch = async_exchange_begin(sess);
365
366 sysarg_t buffer_size = *size;
367 errno_t ret = async_req_2_1(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
368 IPC_M_AUDIO_PCM_GET_BUFFER, (sysarg_t)buffer_size, &buffer_size);
369 if (ret == EOK) {
370 void *dst = NULL;
371 ret = async_share_in_start_0_0(exch, buffer_size, &dst);
372 if (ret != EOK) {
373 async_exchange_end(exch);
374 return ret;
375 }
376 *buffer = dst;
377 *size = buffer_size;
378 }
379 async_exchange_end(exch);
380 return ret;
381}
382
383/**
384 * Release device accessible playback/capture buffer.
385 *
386 * @param sess Audio device session.
387 *
388 * @return Error code.
389 */
390errno_t audio_pcm_release_buffer(audio_pcm_sess_t *sess)
391{
392 async_exch_t *exch = async_exchange_begin(sess);
393 const errno_t ret = async_req_1_0(exch,
394 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
395 IPC_M_AUDIO_PCM_RELEASE_BUFFER);
396 async_exchange_end(exch);
397 return ret;
398}
399
400/**
401 * Start playback on buffer from position 0.
402 *
403 * @param sess Audio device session.
404 * @param frames Size of fragment (in frames).
405 * @param channels Number of channels.
406 * @param sample_rate Sampling rate (for one channel).
407 * @param format Sample format.
408 *
409 * @return Error code.
410 *
411 * Event will be generated after every fragment. Set fragment size to
412 * 0 to turn off event generation.
413 */
414errno_t audio_pcm_start_playback_fragment(audio_pcm_sess_t *sess, unsigned frames,
415 unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
416{
417 if (channels > UINT16_MAX)
418 return EINVAL;
419 assert((format & UINT16_MAX) == format);
420 const sysarg_t packed = (channels << 16) | (format & UINT16_MAX);
421 async_exch_t *exch = async_exchange_begin(sess);
422 const errno_t ret = async_req_4_0(exch,
423 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
424 IPC_M_AUDIO_PCM_START_PLAYBACK,
425 frames, sample_rate, packed);
426 async_exchange_end(exch);
427 return ret;
428}
429/**
430 * Stops playback after current fragment.
431 *
432 * @param sess Audio device session.
433 *
434 * @return Error code.
435 */
436errno_t audio_pcm_last_playback_fragment(audio_pcm_sess_t *sess)
437{
438 async_exch_t *exch = async_exchange_begin(sess);
439 const errno_t ret = async_req_2_0(exch,
440 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
441 IPC_M_AUDIO_PCM_STOP_PLAYBACK, false);
442 async_exchange_end(exch);
443 return ret;
444}
445
446/**
447 * Start playback on buffer from the current position.
448 *
449 * @param sess Audio device session.
450 * @param channels Number of channels.
451 * @param sample_rate Sampling rate (for one channel).
452 * @param format Sample format.
453 *
454 * @return Error code.
455 */
456errno_t audio_pcm_start_playback(audio_pcm_sess_t *sess,
457 unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
458{
459 return audio_pcm_start_playback_fragment(
460 sess, 0, channels, sample_rate, format);
461}
462
463/**
464 * Immediately stops current playback.
465 *
466 * @param sess Audio device session.
467 *
468 * @return Error code.
469 */
470errno_t audio_pcm_stop_playback_immediate(audio_pcm_sess_t *sess)
471{
472 async_exch_t *exch = async_exchange_begin(sess);
473 const errno_t ret = async_req_2_0(exch,
474 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
475 IPC_M_AUDIO_PCM_STOP_PLAYBACK, true);
476 async_exchange_end(exch);
477 return ret;
478}
479
480/**
481 * Stops playback at the end of the current fragment.
482 *
483 * @param sess Audio device session.
484 *
485 * @return Error code.
486 */
487errno_t audio_pcm_stop_playback(audio_pcm_sess_t *sess)
488{
489 async_exch_t *exch = async_exchange_begin(sess);
490 const errno_t ret = async_req_2_0(exch,
491 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
492 IPC_M_AUDIO_PCM_STOP_PLAYBACK, false);
493 async_exchange_end(exch);
494 return ret;
495}
496
497/**
498 * Start capture on buffer from the current position.
499 *
500 * @param sess Audio device session.
501 * @param frames Size of fragment (in frames).
502 * @param channels Number of channels.
503 * @param sample_rate Sampling rate (for one channel).
504 * @param format Sample format.
505 *
506 * @return Error code.
507 *
508 * Event will be generated after every fragment. Set fragment size to
509 * 0 to turn off event generation.
510 */
511errno_t audio_pcm_start_capture_fragment(audio_pcm_sess_t *sess, unsigned frames,
512 unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
513{
514 if (channels > UINT16_MAX)
515 return EINVAL;
516 assert((format & UINT16_MAX) == format);
517 const sysarg_t packed = (channels << 16) | (format & UINT16_MAX);
518 async_exch_t *exch = async_exchange_begin(sess);
519 const errno_t ret = async_req_4_0(exch,
520 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE), IPC_M_AUDIO_PCM_START_CAPTURE,
521 frames, sample_rate, packed);
522 async_exchange_end(exch);
523 return ret;
524}
525
526/**
527 * Start capture on buffer from the current position.
528 *
529 * @param sess Audio device session.
530 * @param channels Number of channels.
531 * @param sample_rate Sampling rate (for one channel).
532 * @param format Sample format.
533 *
534 * @return Error code.
535 */
536errno_t audio_pcm_start_capture(audio_pcm_sess_t *sess,
537 unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
538{
539 return audio_pcm_start_capture_fragment(
540 sess, 0, channels, sample_rate, format);
541}
542
543/**
544 * Stops capture at the end of current fragment.
545 *
546 * Won't work if capture was started with fragment size 0.
547 * @param sess Audio device session.
548 *
549 * @return Error code.
550 */
551errno_t audio_pcm_last_capture_fragment(audio_pcm_sess_t *sess)
552{
553 async_exch_t *exch = async_exchange_begin(sess);
554 const errno_t ret = async_req_2_0(exch,
555 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
556 IPC_M_AUDIO_PCM_STOP_CAPTURE, false);
557 async_exchange_end(exch);
558 return ret;
559}
560
561/**
562 * Immediately stops current capture.
563 *
564 * @param sess Audio device session.
565 *
566 * @return Error code.
567 */
568errno_t audio_pcm_stop_capture_immediate(audio_pcm_sess_t *sess)
569{
570 async_exch_t *exch = async_exchange_begin(sess);
571 const errno_t ret = async_req_2_0(exch,
572 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
573 IPC_M_AUDIO_PCM_STOP_CAPTURE, true);
574 async_exchange_end(exch);
575 return ret;
576}
577
578/**
579 * Stops capture at the end of the current fragment.
580 *
581 * @param sess Audio device session.
582 *
583 * @return Error code.
584 */
585errno_t audio_pcm_stop_capture(audio_pcm_sess_t *sess)
586{
587 async_exch_t *exch = async_exchange_begin(sess);
588 const errno_t ret = async_req_2_0(exch,
589 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
590 IPC_M_AUDIO_PCM_STOP_CAPTURE, false);
591 async_exchange_end(exch);
592 return ret;
593}
594
595/*
596 * SERVER SIDE
597 */
598static void remote_audio_pcm_get_info_str(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
599static void remote_audio_pcm_query_caps(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
600static void remote_audio_pcm_events_register(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
601static void remote_audio_pcm_events_unregister(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
602static void remote_audio_pcm_get_buffer_pos(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
603static void remote_audio_pcm_test_format(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
604static void remote_audio_pcm_get_buffer(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
605static void remote_audio_pcm_release_buffer(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
606static void remote_audio_pcm_start_playback(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
607static void remote_audio_pcm_stop_playback(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
608static void remote_audio_pcm_start_capture(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
609static void remote_audio_pcm_stop_capture(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
610
611/** Remote audio pcm buffer interface operations. */
612static const remote_iface_func_ptr_t remote_audio_pcm_iface_ops[] = {
613 [IPC_M_AUDIO_PCM_GET_INFO_STR] = remote_audio_pcm_get_info_str,
614 [IPC_M_AUDIO_PCM_QUERY_CAPS] = remote_audio_pcm_query_caps,
615 [IPC_M_AUDIO_PCM_REGISTER_EVENTS] = remote_audio_pcm_events_register,
616 [IPC_M_AUDIO_PCM_UNREGISTER_EVENTS] = remote_audio_pcm_events_unregister,
617 [IPC_M_AUDIO_PCM_GET_BUFFER_POS] = remote_audio_pcm_get_buffer_pos,
618 [IPC_M_AUDIO_PCM_TEST_FORMAT] = remote_audio_pcm_test_format,
619 [IPC_M_AUDIO_PCM_GET_BUFFER] = remote_audio_pcm_get_buffer,
620 [IPC_M_AUDIO_PCM_RELEASE_BUFFER] = remote_audio_pcm_release_buffer,
621 [IPC_M_AUDIO_PCM_START_PLAYBACK] = remote_audio_pcm_start_playback,
622 [IPC_M_AUDIO_PCM_STOP_PLAYBACK] = remote_audio_pcm_stop_playback,
623 [IPC_M_AUDIO_PCM_START_CAPTURE] = remote_audio_pcm_start_capture,
624 [IPC_M_AUDIO_PCM_STOP_CAPTURE] = remote_audio_pcm_stop_capture,
625};
626
627/** Remote audio mixer interface structure. */
628const remote_iface_t remote_audio_pcm_iface = {
629 .method_count = ARRAY_SIZE(remote_audio_pcm_iface_ops),
630 .methods = remote_audio_pcm_iface_ops
631};
632
633void remote_audio_pcm_get_info_str(ddf_fun_t *fun, void *iface,
634 ipc_callid_t callid, ipc_call_t *call)
635{
636 const audio_pcm_iface_t *pcm_iface = iface;
637
638 if (!pcm_iface->get_info_str) {
639 async_answer_0(callid, ENOTSUP);
640 return;
641 }
642 const char *name = NULL;
643 const errno_t ret = pcm_iface->get_info_str(fun, &name);
644 const size_t name_size = name ? str_size(name) + 1 : 0;
645 async_answer_1(callid, ret, name_size);
646 /* Send the string. */
647 if (ret == EOK && name_size > 0) {
648 size_t size;
649 ipc_callid_t name_id;
650 if (!async_data_read_receive(&name_id, &size)) {
651 async_answer_0(name_id, EPARTY);
652 return;
653 }
654 if (size != name_size) {
655 async_answer_0(name_id, ELIMIT);
656 return;
657 }
658 async_data_read_finalize(name_id, name, name_size);
659 }
660}
661
662void remote_audio_pcm_query_caps(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
663{
664 const audio_pcm_iface_t *pcm_iface = iface;
665 const audio_cap_t cap = DEV_IPC_GET_ARG1(*call);
666 if (pcm_iface->query_cap) {
667 const unsigned value = pcm_iface->query_cap(fun, cap);
668 async_answer_1(callid, EOK, value);
669 } else {
670 async_answer_0(callid, ENOTSUP);
671 }
672}
673
674static void remote_audio_pcm_events_register(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
675{
676 const audio_pcm_iface_t *pcm_iface = iface;
677 if (!pcm_iface->get_event_session ||
678 !pcm_iface->set_event_session) {
679 async_answer_0(callid, ENOTSUP);
680 return;
681 }
682
683 async_answer_0(callid, EOK);
684
685 ipc_call_t callback_call;
686 ipc_callid_t callback_id = async_get_call(&callback_call);
687 async_sess_t *sess =
688 async_callback_receive_start(EXCHANGE_ATOMIC, &callback_call);
689 if (sess == NULL) {
690 ddf_msg(LVL_DEBUG, "Failed to create event callback");
691 async_answer_0(callback_id, EAGAIN);
692 return;
693 }
694 const errno_t ret = pcm_iface->set_event_session(fun, sess);
695 if (ret != EOK) {
696 ddf_msg(LVL_DEBUG, "Failed to set event callback.");
697 async_hangup(sess);
698 async_answer_0(callback_id, ret);
699 return;
700 }
701 async_answer_0(callback_id, EOK);
702}
703
704static void remote_audio_pcm_events_unregister(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
705{
706 const audio_pcm_iface_t *pcm_iface = iface;
707 if (!pcm_iface->get_event_session ||
708 !pcm_iface->set_event_session) {
709 async_answer_0(callid, ENOTSUP);
710 return;
711 }
712 async_sess_t *sess = pcm_iface->get_event_session(fun);
713 if (sess) {
714 async_hangup(sess);
715 pcm_iface->set_event_session(fun, NULL);
716 }
717 async_answer_0(callid, EOK);
718}
719
720void remote_audio_pcm_get_buffer_pos(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
721{
722 const audio_pcm_iface_t *pcm_iface = iface;
723 size_t pos = 0;
724 const errno_t ret = pcm_iface->get_buffer_pos ?
725 pcm_iface->get_buffer_pos(fun, &pos) : ENOTSUP;
726 async_answer_1(callid, ret, pos);
727}
728
729void remote_audio_pcm_test_format(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
730{
731 const audio_pcm_iface_t *pcm_iface = iface;
732 unsigned channels = DEV_IPC_GET_ARG1(*call);
733 unsigned rate = DEV_IPC_GET_ARG2(*call);
734 pcm_sample_format_t format = DEV_IPC_GET_ARG3(*call);
735 const errno_t ret = pcm_iface->test_format ?
736 pcm_iface->test_format(fun, &channels, &rate, &format) : ENOTSUP;
737 async_answer_3(callid, ret, channels, rate, format);
738}
739
740void remote_audio_pcm_get_buffer(ddf_fun_t *fun, void *iface,
741 ipc_callid_t callid, ipc_call_t *call)
742{
743 const audio_pcm_iface_t *pcm_iface = iface;
744
745 if (!pcm_iface->get_buffer ||
746 !pcm_iface->release_buffer) {
747 async_answer_0(callid, ENOTSUP);
748 return;
749 }
750 void *buffer = NULL;
751 size_t size = DEV_IPC_GET_ARG1(*call);
752 errno_t ret = pcm_iface->get_buffer(fun, &buffer, &size);
753 async_answer_1(callid, ret, size);
754 if (ret != EOK || size == 0)
755 return;
756
757 /* Share the buffer. */
758 size_t share_size = 0;
759 ipc_callid_t share_id = 0;
760
761 ddf_msg(LVL_DEBUG2, "Receiving share request.");
762 if (!async_share_in_receive(&share_id, &share_size)) {
763 ddf_msg(LVL_DEBUG, "Failed to share pcm buffer.");
764 pcm_iface->release_buffer(fun);
765 async_answer_0(share_id, EPARTY);
766 return;
767 }
768
769 ddf_msg(LVL_DEBUG2, "Checking requested share size.");
770 if (share_size != size) {
771 ddf_msg(LVL_DEBUG, "Incorrect pcm buffer size requested.");
772 pcm_iface->release_buffer(fun);
773 async_answer_0(share_id, ELIMIT);
774 return;
775 }
776
777 ddf_msg(LVL_DEBUG2, "Calling share finalize.");
778 ret = async_share_in_finalize(share_id, buffer, AS_AREA_WRITE
779 | AS_AREA_READ);
780 if (ret != EOK) {
781 ddf_msg(LVL_DEBUG, "Failed to share buffer.");
782 pcm_iface->release_buffer(fun);
783 return;
784 }
785
786 ddf_msg(LVL_DEBUG2, "Buffer shared with size %zu.", share_size);
787}
788
789void remote_audio_pcm_release_buffer(ddf_fun_t *fun, void *iface,
790 ipc_callid_t callid, ipc_call_t *call)
791{
792 const audio_pcm_iface_t *pcm_iface = iface;
793
794 const errno_t ret = pcm_iface->release_buffer ?
795 pcm_iface->release_buffer(fun) : ENOTSUP;
796 async_answer_0(callid, ret);
797}
798
799void remote_audio_pcm_start_playback(ddf_fun_t *fun, void *iface,
800 ipc_callid_t callid, ipc_call_t *call)
801{
802 const audio_pcm_iface_t *pcm_iface = iface;
803
804 const unsigned frames = DEV_IPC_GET_ARG1(*call);
805 const unsigned rate = DEV_IPC_GET_ARG2(*call);
806 const unsigned channels = (DEV_IPC_GET_ARG3(*call) >> 16) & UINT8_MAX;
807 const pcm_sample_format_t format = DEV_IPC_GET_ARG3(*call) & UINT16_MAX;
808
809 const errno_t ret = pcm_iface->start_playback
810 ? pcm_iface->start_playback(fun, frames, channels, rate, format)
811 : ENOTSUP;
812 async_answer_0(callid, ret);
813}
814
815void remote_audio_pcm_stop_playback(ddf_fun_t *fun, void *iface,
816 ipc_callid_t callid, ipc_call_t *call)
817{
818 const audio_pcm_iface_t *pcm_iface = iface;
819 const bool immediate = DEV_IPC_GET_ARG1(*call);
820
821 const errno_t ret = pcm_iface->stop_playback ?
822 pcm_iface->stop_playback(fun, immediate) : ENOTSUP;
823 async_answer_0(callid, ret);
824}
825
826void remote_audio_pcm_start_capture(ddf_fun_t *fun, void *iface,
827 ipc_callid_t callid, ipc_call_t *call)
828{
829 const audio_pcm_iface_t *pcm_iface = iface;
830
831 const unsigned frames = DEV_IPC_GET_ARG1(*call);
832 const unsigned rate = DEV_IPC_GET_ARG2(*call);
833 const unsigned channels = (DEV_IPC_GET_ARG3(*call) >> 16) & UINT16_MAX;
834 const pcm_sample_format_t format = DEV_IPC_GET_ARG3(*call) & UINT16_MAX;
835
836 const errno_t ret = pcm_iface->start_capture
837 ? pcm_iface->start_capture(fun, frames, channels, rate, format)
838 : ENOTSUP;
839 async_answer_0(callid, ret);
840}
841
842void remote_audio_pcm_stop_capture(ddf_fun_t *fun, void *iface,
843 ipc_callid_t callid, ipc_call_t *call)
844{
845 const audio_pcm_iface_t *pcm_iface = iface;
846 const bool immediate = DEV_IPC_GET_ARG1(*call);
847
848 const errno_t ret = pcm_iface->stop_capture ?
849 pcm_iface->stop_capture(fun, immediate) : ENOTSUP;
850 async_answer_0(callid, ret);
851}
852
853/**
854 * @}
855 */
856
Note: See TracBrowser for help on using the repository browser.