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

Last change on this file since 08e103d4 was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

  • Property mode set to 100644
File size: 24.1 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 service_id_t sid;
145 const errno_t ret = loc_service_get_id(name, &sid, 0);
146 if (ret != EOK)
147 return NULL;
148 return loc_service_connect(sid, INTERFACE_DDF, 0);
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 /*
199 * Make the other side fail
200 * as it waits for read request
201 */
202 async_data_read_start(exch, (void *)-1, 0);
203 async_exchange_end(exch);
204 return ENOMEM;
205 }
206 const errno_t ret =
207 async_data_read_start(exch, name_place, name_size);
208 if (ret != EOK) {
209 free(name_place);
210 async_exchange_end(exch);
211 return ret;
212 }
213 *name = name_place;
214 }
215 async_exchange_end(exch);
216 return ret;
217}
218
219/**
220 * Query value of specified capability.
221 *
222 * @param sess Audio device session.
223 * @param cap Audio device capability.
224 * @param[out] val Place to store queried value.
225 *
226 * @return Error code.
227 */
228errno_t audio_pcm_query_cap(audio_pcm_sess_t *sess, audio_cap_t cap, sysarg_t *value)
229{
230 async_exch_t *exch = async_exchange_begin(sess);
231 const errno_t ret = async_req_2_1(exch,
232 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE), IPC_M_AUDIO_PCM_QUERY_CAPS,
233 cap, value);
234 async_exchange_end(exch);
235 return ret;
236}
237
238/**
239 * Query current position in device buffer.
240 *
241 * @param sess Audio device session.
242 * @param pos Place to store the result.
243 *
244 * @return Error code.
245 *
246 * Works for both playback and capture.
247 */
248errno_t audio_pcm_get_buffer_pos(audio_pcm_sess_t *sess, size_t *pos)
249{
250 if (!pos)
251 return EINVAL;
252 async_exch_t *exch = async_exchange_begin(sess);
253 sysarg_t value = 0;
254 const errno_t ret = async_req_1_1(exch,
255 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
256 IPC_M_AUDIO_PCM_GET_BUFFER_POS, &value);
257 if (ret == EOK)
258 *pos = value;
259 async_exchange_end(exch);
260 return ret;
261}
262
263/**
264 * Test format parameters for device support.
265 *
266 * @param sess Audio device session.
267 * @param channels Number of channels
268 * @param rate Sampling rate.
269 * @format Sample format.
270 *
271 * @return Error code.
272 *
273 * Works for both playback and capture. This function modifies provided
274 * parameters to the nearest values supported by the device.
275 */
276errno_t audio_pcm_test_format(audio_pcm_sess_t *sess, unsigned *channels,
277 unsigned *rate, pcm_sample_format_t *format)
278{
279 async_exch_t *exch = async_exchange_begin(sess);
280 sysarg_t channels_arg = channels ? *channels : 0;
281 sysarg_t rate_arg = rate ? *rate : 0;
282 sysarg_t format_arg = format ? *format : 0;
283 const errno_t ret = async_req_4_3(exch,
284 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
285 IPC_M_AUDIO_PCM_TEST_FORMAT, channels_arg, rate_arg, format_arg,
286 &channels_arg, &rate_arg, &format_arg);
287 async_exchange_end(exch);
288
289 /*
290 * All OK or something has changed. Verify that it was not one of the
291 * params we care about
292 */
293 if ((ret == EOK || ret == ELIMIT) &&
294 (!channels || *channels == channels_arg) &&
295 (!rate || *rate == rate_arg) &&
296 (!format || *format == format_arg))
297 return EOK;
298 if (channels)
299 *channels = channels_arg;
300 if (rate)
301 *rate = rate_arg;
302 if (format)
303 *format = format_arg;
304 return ret;
305}
306
307/**
308 * Register callback for device generated events.
309 *
310 * @param sess Audio device session.
311 * @param event_rec Event callback function.
312 * @param arg Event callback custom parameter.
313 *
314 * @return Error code.
315 */
316errno_t audio_pcm_register_event_callback(audio_pcm_sess_t *sess,
317 async_port_handler_t event_callback, void *arg)
318{
319 if (!event_callback)
320 return EINVAL;
321
322 async_exch_t *exch = async_exchange_begin(sess);
323
324 errno_t ret = async_req_1_0(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
325 IPC_M_AUDIO_PCM_REGISTER_EVENTS);
326 if (ret == EOK) {
327 port_id_t port;
328 ret = async_create_callback_port(exch, INTERFACE_AUDIO_PCM_CB, 0, 0,
329 event_callback, arg, &port);
330 }
331
332 async_exchange_end(exch);
333 return ret;
334}
335
336/**
337 * Unregister callback for device generated events.
338 *
339 * @param sess Audio device session.
340 *
341 * @return Error code.
342 */
343errno_t audio_pcm_unregister_event_callback(audio_pcm_sess_t *sess)
344{
345 async_exch_t *exch = async_exchange_begin(sess);
346 const errno_t ret = async_req_1_0(exch,
347 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
348 IPC_M_AUDIO_PCM_UNREGISTER_EVENTS);
349 async_exchange_end(exch);
350 return ret;
351}
352
353/**
354 * Get device accessible playback/capture buffer.
355 *
356 * @param sess Audio device session.
357 * @param buffer Place to store pointer to the buffer.
358 * @param size Place to store buffer size (bytes).
359 *
360 * @return Error code.
361 */
362errno_t audio_pcm_get_buffer(audio_pcm_sess_t *sess, void **buffer, size_t *size)
363{
364 if (!buffer || !size)
365 return EINVAL;
366
367 async_exch_t *exch = async_exchange_begin(sess);
368
369 sysarg_t buffer_size = *size;
370 errno_t ret = async_req_2_1(exch, DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
371 IPC_M_AUDIO_PCM_GET_BUFFER, (sysarg_t)buffer_size, &buffer_size);
372 if (ret == EOK) {
373 void *dst = NULL;
374 ret = async_share_in_start_0_0(exch, buffer_size, &dst);
375 if (ret != EOK) {
376 async_exchange_end(exch);
377 return ret;
378 }
379 *buffer = dst;
380 *size = buffer_size;
381 }
382 async_exchange_end(exch);
383 return ret;
384}
385
386/**
387 * Release device accessible playback/capture buffer.
388 *
389 * @param sess Audio device session.
390 *
391 * @return Error code.
392 */
393errno_t audio_pcm_release_buffer(audio_pcm_sess_t *sess)
394{
395 async_exch_t *exch = async_exchange_begin(sess);
396 const errno_t ret = async_req_1_0(exch,
397 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
398 IPC_M_AUDIO_PCM_RELEASE_BUFFER);
399 async_exchange_end(exch);
400 return ret;
401}
402
403/**
404 * Start playback on buffer from position 0.
405 *
406 * @param sess Audio device session.
407 * @param frames Size of fragment (in frames).
408 * @param channels Number of channels.
409 * @param sample_rate Sampling rate (for one channel).
410 * @param format Sample format.
411 *
412 * @return Error code.
413 *
414 * Event will be generated after every fragment. Set fragment size to
415 * 0 to turn off event generation.
416 */
417errno_t audio_pcm_start_playback_fragment(audio_pcm_sess_t *sess, unsigned frames,
418 unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
419{
420 if (channels > UINT16_MAX)
421 return EINVAL;
422 assert((format & UINT16_MAX) == format);
423 const sysarg_t packed = (channels << 16) | (format & UINT16_MAX);
424 async_exch_t *exch = async_exchange_begin(sess);
425 const errno_t ret = async_req_4_0(exch,
426 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
427 IPC_M_AUDIO_PCM_START_PLAYBACK,
428 frames, sample_rate, packed);
429 async_exchange_end(exch);
430 return ret;
431}
432/**
433 * Stops playback after current fragment.
434 *
435 * @param sess Audio device session.
436 *
437 * @return Error code.
438 */
439errno_t audio_pcm_last_playback_fragment(audio_pcm_sess_t *sess)
440{
441 async_exch_t *exch = async_exchange_begin(sess);
442 const errno_t ret = async_req_2_0(exch,
443 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
444 IPC_M_AUDIO_PCM_STOP_PLAYBACK, false);
445 async_exchange_end(exch);
446 return ret;
447}
448
449/**
450 * Start playback on buffer from the current position.
451 *
452 * @param sess Audio device session.
453 * @param channels Number of channels.
454 * @param sample_rate Sampling rate (for one channel).
455 * @param format Sample format.
456 *
457 * @return Error code.
458 */
459errno_t audio_pcm_start_playback(audio_pcm_sess_t *sess,
460 unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
461{
462 return audio_pcm_start_playback_fragment(
463 sess, 0, channels, sample_rate, format);
464}
465
466/**
467 * Immediately stops current playback.
468 *
469 * @param sess Audio device session.
470 *
471 * @return Error code.
472 */
473errno_t audio_pcm_stop_playback_immediate(audio_pcm_sess_t *sess)
474{
475 async_exch_t *exch = async_exchange_begin(sess);
476 const errno_t ret = async_req_2_0(exch,
477 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
478 IPC_M_AUDIO_PCM_STOP_PLAYBACK, true);
479 async_exchange_end(exch);
480 return ret;
481}
482
483/**
484 * Stops playback at the end of the current fragment.
485 *
486 * @param sess Audio device session.
487 *
488 * @return Error code.
489 */
490errno_t audio_pcm_stop_playback(audio_pcm_sess_t *sess)
491{
492 async_exch_t *exch = async_exchange_begin(sess);
493 const errno_t ret = async_req_2_0(exch,
494 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
495 IPC_M_AUDIO_PCM_STOP_PLAYBACK, false);
496 async_exchange_end(exch);
497 return ret;
498}
499
500/**
501 * Start capture on buffer from the current position.
502 *
503 * @param sess Audio device session.
504 * @param frames Size of fragment (in frames).
505 * @param channels Number of channels.
506 * @param sample_rate Sampling rate (for one channel).
507 * @param format Sample format.
508 *
509 * @return Error code.
510 *
511 * Event will be generated after every fragment. Set fragment size to
512 * 0 to turn off event generation.
513 */
514errno_t audio_pcm_start_capture_fragment(audio_pcm_sess_t *sess, unsigned frames,
515 unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
516{
517 if (channels > UINT16_MAX)
518 return EINVAL;
519 assert((format & UINT16_MAX) == format);
520 const sysarg_t packed = (channels << 16) | (format & UINT16_MAX);
521 async_exch_t *exch = async_exchange_begin(sess);
522 const errno_t ret = async_req_4_0(exch,
523 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE), IPC_M_AUDIO_PCM_START_CAPTURE,
524 frames, sample_rate, packed);
525 async_exchange_end(exch);
526 return ret;
527}
528
529/**
530 * Start capture on buffer from the current position.
531 *
532 * @param sess Audio device session.
533 * @param channels Number of channels.
534 * @param sample_rate Sampling rate (for one channel).
535 * @param format Sample format.
536 *
537 * @return Error code.
538 */
539errno_t audio_pcm_start_capture(audio_pcm_sess_t *sess,
540 unsigned channels, unsigned sample_rate, pcm_sample_format_t format)
541{
542 return audio_pcm_start_capture_fragment(
543 sess, 0, channels, sample_rate, format);
544}
545
546/**
547 * Stops capture at the end of current fragment.
548 *
549 * Won't work if capture was started with fragment size 0.
550 * @param sess Audio device session.
551 *
552 * @return Error code.
553 */
554errno_t audio_pcm_last_capture_fragment(audio_pcm_sess_t *sess)
555{
556 async_exch_t *exch = async_exchange_begin(sess);
557 const errno_t ret = async_req_2_0(exch,
558 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
559 IPC_M_AUDIO_PCM_STOP_CAPTURE, false);
560 async_exchange_end(exch);
561 return ret;
562}
563
564/**
565 * Immediately stops current capture.
566 *
567 * @param sess Audio device session.
568 *
569 * @return Error code.
570 */
571errno_t audio_pcm_stop_capture_immediate(audio_pcm_sess_t *sess)
572{
573 async_exch_t *exch = async_exchange_begin(sess);
574 const errno_t ret = async_req_2_0(exch,
575 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
576 IPC_M_AUDIO_PCM_STOP_CAPTURE, true);
577 async_exchange_end(exch);
578 return ret;
579}
580
581/**
582 * Stops capture at the end of the current fragment.
583 *
584 * @param sess Audio device session.
585 *
586 * @return Error code.
587 */
588errno_t audio_pcm_stop_capture(audio_pcm_sess_t *sess)
589{
590 async_exch_t *exch = async_exchange_begin(sess);
591 const errno_t ret = async_req_2_0(exch,
592 DEV_IFACE_ID(AUDIO_PCM_BUFFER_IFACE),
593 IPC_M_AUDIO_PCM_STOP_CAPTURE, false);
594 async_exchange_end(exch);
595 return ret;
596}
597
598/*
599 * SERVER SIDE
600 */
601static void remote_audio_pcm_get_info_str(ddf_fun_t *, void *, ipc_call_t *);
602static void remote_audio_pcm_query_caps(ddf_fun_t *, void *, ipc_call_t *);
603static void remote_audio_pcm_events_register(ddf_fun_t *, void *, ipc_call_t *);
604static void remote_audio_pcm_events_unregister(ddf_fun_t *, void *, ipc_call_t *);
605static void remote_audio_pcm_get_buffer_pos(ddf_fun_t *, void *, ipc_call_t *);
606static void remote_audio_pcm_test_format(ddf_fun_t *, void *, ipc_call_t *);
607static void remote_audio_pcm_get_buffer(ddf_fun_t *, void *, ipc_call_t *);
608static void remote_audio_pcm_release_buffer(ddf_fun_t *, void *, ipc_call_t *);
609static void remote_audio_pcm_start_playback(ddf_fun_t *, void *, ipc_call_t *);
610static void remote_audio_pcm_stop_playback(ddf_fun_t *, void *, ipc_call_t *);
611static void remote_audio_pcm_start_capture(ddf_fun_t *, void *, ipc_call_t *);
612static void remote_audio_pcm_stop_capture(ddf_fun_t *, void *, ipc_call_t *);
613
614/** Remote audio pcm buffer interface operations. */
615static const remote_iface_func_ptr_t remote_audio_pcm_iface_ops[] = {
616 [IPC_M_AUDIO_PCM_GET_INFO_STR] = remote_audio_pcm_get_info_str,
617 [IPC_M_AUDIO_PCM_QUERY_CAPS] = remote_audio_pcm_query_caps,
618 [IPC_M_AUDIO_PCM_REGISTER_EVENTS] = remote_audio_pcm_events_register,
619 [IPC_M_AUDIO_PCM_UNREGISTER_EVENTS] = remote_audio_pcm_events_unregister,
620 [IPC_M_AUDIO_PCM_GET_BUFFER_POS] = remote_audio_pcm_get_buffer_pos,
621 [IPC_M_AUDIO_PCM_TEST_FORMAT] = remote_audio_pcm_test_format,
622 [IPC_M_AUDIO_PCM_GET_BUFFER] = remote_audio_pcm_get_buffer,
623 [IPC_M_AUDIO_PCM_RELEASE_BUFFER] = remote_audio_pcm_release_buffer,
624 [IPC_M_AUDIO_PCM_START_PLAYBACK] = remote_audio_pcm_start_playback,
625 [IPC_M_AUDIO_PCM_STOP_PLAYBACK] = remote_audio_pcm_stop_playback,
626 [IPC_M_AUDIO_PCM_START_CAPTURE] = remote_audio_pcm_start_capture,
627 [IPC_M_AUDIO_PCM_STOP_CAPTURE] = remote_audio_pcm_stop_capture,
628};
629
630/** Remote audio mixer interface structure. */
631const remote_iface_t remote_audio_pcm_iface = {
632 .method_count = ARRAY_SIZE(remote_audio_pcm_iface_ops),
633 .methods = remote_audio_pcm_iface_ops
634};
635
636void remote_audio_pcm_get_info_str(ddf_fun_t *fun, void *iface,
637 ipc_call_t *call)
638{
639 const audio_pcm_iface_t *pcm_iface = iface;
640
641 if (!pcm_iface->get_info_str) {
642 async_answer_0(call, ENOTSUP);
643 return;
644 }
645
646 const char *name = NULL;
647 const errno_t ret = pcm_iface->get_info_str(fun, &name);
648 const size_t name_size = name ? str_bytes(name) + 1 : 0;
649 async_answer_1(call, ret, name_size);
650
651 /* Send the string. */
652 if (ret == EOK && name_size > 0) {
653 ipc_call_t call;
654 size_t size;
655 if (!async_data_read_receive(&call, &size)) {
656 async_answer_0(&call, EPARTY);
657 return;
658 }
659
660 if (size != name_size) {
661 async_answer_0(&call, ELIMIT);
662 return;
663 }
664
665 async_data_read_finalize(&call, name, name_size);
666 }
667}
668
669void remote_audio_pcm_query_caps(ddf_fun_t *fun, void *iface,
670 ipc_call_t *call)
671{
672 const audio_pcm_iface_t *pcm_iface = iface;
673 const audio_cap_t cap = DEV_IPC_GET_ARG1(*call);
674 if (pcm_iface->query_cap) {
675 const unsigned value = pcm_iface->query_cap(fun, cap);
676 async_answer_1(call, EOK, value);
677 } else {
678 async_answer_0(call, ENOTSUP);
679 }
680}
681
682static void remote_audio_pcm_events_register(ddf_fun_t *fun, void *iface,
683 ipc_call_t *call)
684{
685 const audio_pcm_iface_t *pcm_iface = iface;
686 if (!pcm_iface->get_event_session ||
687 !pcm_iface->set_event_session) {
688 async_answer_0(call, ENOTSUP);
689 return;
690 }
691
692 async_answer_0(call, EOK);
693
694 ipc_call_t callback_call;
695 async_get_call(&callback_call);
696 async_sess_t *sess =
697 async_callback_receive_start(EXCHANGE_ATOMIC, &callback_call);
698 if (sess == NULL) {
699 ddf_msg(LVL_DEBUG, "Failed to create event callback");
700 async_answer_0(&callback_call, EAGAIN);
701 return;
702 }
703
704 const errno_t ret = pcm_iface->set_event_session(fun, sess);
705 if (ret != EOK) {
706 ddf_msg(LVL_DEBUG, "Failed to set event callback.");
707 async_hangup(sess);
708 async_answer_0(&callback_call, ret);
709 return;
710 }
711
712 async_answer_0(&callback_call, EOK);
713}
714
715static void remote_audio_pcm_events_unregister(ddf_fun_t *fun, void *iface,
716 ipc_call_t *call)
717{
718 const audio_pcm_iface_t *pcm_iface = iface;
719 if (!pcm_iface->get_event_session ||
720 !pcm_iface->set_event_session) {
721 async_answer_0(call, ENOTSUP);
722 return;
723 }
724
725 async_sess_t *sess = pcm_iface->get_event_session(fun);
726 if (sess) {
727 async_hangup(sess);
728 pcm_iface->set_event_session(fun, NULL);
729 }
730
731 async_answer_0(call, EOK);
732}
733
734void remote_audio_pcm_get_buffer_pos(ddf_fun_t *fun, void *iface,
735 ipc_call_t *call)
736{
737 const audio_pcm_iface_t *pcm_iface = iface;
738 size_t pos = 0;
739 const errno_t ret = pcm_iface->get_buffer_pos ?
740 pcm_iface->get_buffer_pos(fun, &pos) : ENOTSUP;
741 async_answer_1(call, ret, pos);
742}
743
744void remote_audio_pcm_test_format(ddf_fun_t *fun, void *iface,
745 ipc_call_t *call)
746{
747 const audio_pcm_iface_t *pcm_iface = iface;
748 unsigned channels = DEV_IPC_GET_ARG1(*call);
749 unsigned rate = DEV_IPC_GET_ARG2(*call);
750 pcm_sample_format_t format = DEV_IPC_GET_ARG3(*call);
751 const errno_t ret = pcm_iface->test_format ?
752 pcm_iface->test_format(fun, &channels, &rate, &format) : ENOTSUP;
753 async_answer_3(call, ret, channels, rate, format);
754}
755
756void remote_audio_pcm_get_buffer(ddf_fun_t *fun, void *iface,
757 ipc_call_t *call)
758{
759 const audio_pcm_iface_t *pcm_iface = iface;
760
761 if (!pcm_iface->get_buffer ||
762 !pcm_iface->release_buffer) {
763 async_answer_0(call, ENOTSUP);
764 return;
765 }
766 void *buffer = NULL;
767 size_t size = DEV_IPC_GET_ARG1(*call);
768 errno_t ret = pcm_iface->get_buffer(fun, &buffer, &size);
769 async_answer_1(call, ret, size);
770 if (ret != EOK || size == 0)
771 return;
772
773 /* Share the buffer. */
774 ipc_call_t share;
775 size_t share_size = 0;
776
777 ddf_msg(LVL_DEBUG2, "Receiving share request.");
778 if (!async_share_in_receive(&share, &share_size)) {
779 ddf_msg(LVL_DEBUG, "Failed to share pcm buffer.");
780 pcm_iface->release_buffer(fun);
781 async_answer_0(&share, EPARTY);
782 return;
783 }
784
785 ddf_msg(LVL_DEBUG2, "Checking requested share size.");
786 if (share_size != size) {
787 ddf_msg(LVL_DEBUG, "Incorrect pcm buffer size requested.");
788 pcm_iface->release_buffer(fun);
789 async_answer_0(&share, ELIMIT);
790 return;
791 }
792
793 ddf_msg(LVL_DEBUG2, "Calling share finalize.");
794 ret = async_share_in_finalize(&share, buffer, AS_AREA_WRITE |
795 AS_AREA_READ);
796 if (ret != EOK) {
797 ddf_msg(LVL_DEBUG, "Failed to share buffer.");
798 pcm_iface->release_buffer(fun);
799 return;
800 }
801
802 ddf_msg(LVL_DEBUG2, "Buffer shared with size %zu.", share_size);
803}
804
805void remote_audio_pcm_release_buffer(ddf_fun_t *fun, void *iface,
806 ipc_call_t *call)
807{
808 const audio_pcm_iface_t *pcm_iface = iface;
809
810 const errno_t ret = pcm_iface->release_buffer ?
811 pcm_iface->release_buffer(fun) : ENOTSUP;
812 async_answer_0(call, ret);
813}
814
815void remote_audio_pcm_start_playback(ddf_fun_t *fun, void *iface,
816 ipc_call_t *call)
817{
818 const audio_pcm_iface_t *pcm_iface = iface;
819
820 const unsigned frames = DEV_IPC_GET_ARG1(*call);
821 const unsigned rate = DEV_IPC_GET_ARG2(*call);
822 const unsigned channels = (DEV_IPC_GET_ARG3(*call) >> 16) & UINT8_MAX;
823 const pcm_sample_format_t format = DEV_IPC_GET_ARG3(*call) & UINT16_MAX;
824
825 const errno_t ret = pcm_iface->start_playback ?
826 pcm_iface->start_playback(fun, frames, channels, rate, format) :
827 ENOTSUP;
828 async_answer_0(call, ret);
829}
830
831void remote_audio_pcm_stop_playback(ddf_fun_t *fun, void *iface,
832 ipc_call_t *call)
833{
834 const audio_pcm_iface_t *pcm_iface = iface;
835 const bool immediate = DEV_IPC_GET_ARG1(*call);
836
837 const errno_t ret = pcm_iface->stop_playback ?
838 pcm_iface->stop_playback(fun, immediate) : ENOTSUP;
839 async_answer_0(call, ret);
840}
841
842void remote_audio_pcm_start_capture(ddf_fun_t *fun, void *iface,
843 ipc_call_t *call)
844{
845 const audio_pcm_iface_t *pcm_iface = iface;
846
847 const unsigned frames = DEV_IPC_GET_ARG1(*call);
848 const unsigned rate = DEV_IPC_GET_ARG2(*call);
849 const unsigned channels = (DEV_IPC_GET_ARG3(*call) >> 16) & UINT16_MAX;
850 const pcm_sample_format_t format = DEV_IPC_GET_ARG3(*call) & UINT16_MAX;
851
852 const errno_t ret = pcm_iface->start_capture ?
853 pcm_iface->start_capture(fun, frames, channels, rate, format) :
854 ENOTSUP;
855 async_answer_0(call, ret);
856}
857
858void remote_audio_pcm_stop_capture(ddf_fun_t *fun, void *iface,
859 ipc_call_t *call)
860{
861 const audio_pcm_iface_t *pcm_iface = iface;
862 const bool immediate = DEV_IPC_GET_ARG1(*call);
863
864 const errno_t ret = pcm_iface->stop_capture ?
865 pcm_iface->stop_capture(fun, immediate) : ENOTSUP;
866 async_answer_0(call, ret);
867}
868
869/**
870 * @}
871 */
Note: See TracBrowser for help on using the repository browser.