VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp@ 55998

Last change on this file since 55998 was 55920, checked in by vboxsync, 10 years ago

PDM/Audio: AudioMixBuffer documentation, renaming.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.5 KB
Line 
1/* $Id: DrvHostALSAAudio.cpp 55920 2015-05-18 19:11:51Z vboxsync $ */
2/** @file
3 * VBox audio devices: ALSA audio driver.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 * --------------------------------------------------------------------
17 *
18 * This code is based on: alsaaudio.c
19 *
20 * QEMU ALSA audio driver
21 *
22 * Copyright (c) 2005 Vassili Karpov (malc)
23 *
24 * Permission is hereby granted, free of charge, to any person obtaining a copy
25 * of this software and associated documentation files (the "Software"), to deal
26 * in the Software without restriction, including without limitation the rights
27 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28 * copies of the Software, and to permit persons to whom the Software is
29 * furnished to do so, subject to the following conditions:
30 *
31 * The above copyright notice and this permission notice shall be included in
32 * all copies or substantial portions of the Software.
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
37 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40 * THE SOFTWARE.
41 */
42
43/*******************************************************************************
44* Header Files *
45*******************************************************************************/
46
47#include <iprt/alloc.h>
48#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
49#include <VBox/vmm/pdmaudioifs.h>
50
51RT_C_DECLS_BEGIN
52 #include "alsa_stubs.h"
53 #include "alsa_mangling.h"
54RT_C_DECLS_END
55
56#include <alsa/asoundlib.h>
57
58#include "DrvAudio.h"
59#include "AudioMixBuffer.h"
60
61#include "VBoxDD.h"
62#include "vl_vbox.h"
63
64
65
66#ifdef LOG_GROUP
67# undef LOG_GROUP
68#endif
69#define LOG_GROUP LOG_GROUP_DEV_AUDIO
70#include <VBox/log.h>
71
72typedef struct ALSAAUDIOSTREAMIN
73{
74 PDMAUDIOHSTSTRMIN pStreamIn;
75 snd_pcm_t *phPCM;
76 void *pvBuf;
77 size_t cbBuf;
78} ALSAAUDIOSTREAMIN, *PALSAAUDIOSTREAMIN;
79
80typedef struct ALSAAUDIOSTREAMOUT
81{
82 PDMAUDIOHSTSTRMOUT pStreamOut;
83 snd_pcm_t *phPCM;
84 void *pvBuf;
85 size_t cbBuf;
86} ALSAAUDIOSTREAMOUT, *PALSAAUDIOSTREAMOUT;
87
88/* latency = period_size * periods / (rate * bytes_per_frame) */
89
90typedef struct ALSAAUDIOCFG
91{
92 int size_in_usec_in;
93 int size_in_usec_out;
94 const char *pcm_name_in;
95 const char *pcm_name_out;
96 unsigned int buffer_size_in;
97 unsigned int period_size_in;
98 unsigned int buffer_size_out;
99 unsigned int period_size_out;
100 unsigned int threshold;
101
102 int buffer_size_in_overriden;
103 int period_size_in_overriden;
104
105 int buffer_size_out_overriden;
106 int period_size_out_overriden;
107
108} ALSAAUDIOCFG, *PALSAAUDIOCFG;
109
110static int drvHostALSAAudioRecover(snd_pcm_t *phPCM);
111
112static ALSAAUDIOCFG s_ALSAConf =
113{
114#ifdef HIGH_LATENCY
115 1,
116 1,
117#else
118 0,
119 0,
120#endif
121 "default",
122 "default",
123#ifdef HIGH_LATENCY
124 400000,
125 400000 / 4,
126 400000,
127 400000 / 4,
128#else
129# define DEFAULT_BUFFER_SIZE 1024
130# define DEFAULT_PERIOD_SIZE 256
131 DEFAULT_BUFFER_SIZE * 4,
132 DEFAULT_PERIOD_SIZE * 4,
133 DEFAULT_BUFFER_SIZE,
134 DEFAULT_PERIOD_SIZE,
135#endif
136 0,
137 0,
138 0,
139 0,
140 0
141};
142
143/**
144 * Host Alsa audio driver instance data.
145 * @implements PDMIAUDIOCONNECTOR
146 */
147typedef struct DRVHOSTALSAAUDIO
148{
149 /** Pointer to the driver instance structure. */
150 PPDMDRVINS pDrvIns;
151 /** Pointer to host audio interface. */
152 PDMIHOSTAUDIO IHostAudio;
153 /** Error count for not flooding the release log.
154 * UINT32_MAX for unlimited logging. */
155 uint32_t cLogErrors;
156} DRVHOSTALSAAUDIO, *PDRVHOSTALSAAUDIO;
157
158typedef struct ALSAAUDIOSTREAMCFG
159{
160 unsigned int freq;
161 snd_pcm_format_t fmt;
162 int nchannels;
163 unsigned long buffer_size;
164 unsigned long period_size;
165 snd_pcm_uframes_t samples;
166} ALSAAUDIOSTREAMCFG, *PALSAAUDIOSTREAMCFG;
167
168static int drvHostALSAAudioClose(snd_pcm_t **pphPCM)
169{
170 if (!pphPCM || !*pphPCM)
171 return VINF_SUCCESS;
172
173 int rc;
174 int rc2 = snd_pcm_close(*pphPCM);
175 if (rc2)
176 {
177 LogRel(("ALSA: Closing PCM descriptor failed: %s\n",
178 snd_strerror(rc2)));
179 rc = VERR_GENERAL_FAILURE; /** @todo */
180 }
181 else
182 {
183 *pphPCM = NULL;
184 rc = VINF_SUCCESS;
185 }
186
187 return rc;
188}
189
190static snd_pcm_format_t drvHostALSAAudioFmtToALSA(PDMAUDIOFMT fmt)
191{
192 switch (fmt)
193 {
194 case AUD_FMT_S8:
195 return SND_PCM_FORMAT_S8;
196
197 case AUD_FMT_U8:
198 return SND_PCM_FORMAT_U8;
199
200 case AUD_FMT_S16:
201 return SND_PCM_FORMAT_S16_LE;
202
203 case AUD_FMT_U16:
204 return SND_PCM_FORMAT_U16_LE;
205
206 case AUD_FMT_S32:
207 return SND_PCM_FORMAT_S32_LE;
208
209 case AUD_FMT_U32:
210 return SND_PCM_FORMAT_U32_LE;
211
212 default:
213 break;
214 }
215
216 AssertMsgFailed(("Format %ld not supported\n", fmt));
217 return SND_PCM_FORMAT_U8;
218}
219
220static int drvHostALSAAudioALSAToFmt(snd_pcm_format_t fmt,
221 PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pEndianness)
222{
223 AssertPtrReturn(pFmt, VERR_INVALID_POINTER);
224 /* pEndianness is optional. */
225
226 switch (fmt)
227 {
228 case SND_PCM_FORMAT_S8:
229 *pFmt = AUD_FMT_S8;
230 if (pEndianness)
231 *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
232 break;
233
234 case SND_PCM_FORMAT_U8:
235 *pFmt = AUD_FMT_U8;
236 if (pEndianness)
237 *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
238 break;
239
240 case SND_PCM_FORMAT_S16_LE:
241 *pFmt = AUD_FMT_S16;
242 if (pEndianness)
243 *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
244 break;
245
246 case SND_PCM_FORMAT_U16_LE:
247 *pFmt = AUD_FMT_U16;
248 if (pEndianness)
249 *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
250 break;
251
252 case SND_PCM_FORMAT_S16_BE:
253 *pFmt = AUD_FMT_S16;
254 if (pEndianness)
255 *pEndianness = PDMAUDIOENDIANNESS_BIG;
256 break;
257
258 case SND_PCM_FORMAT_U16_BE:
259 *pFmt = AUD_FMT_U16;
260 if (pEndianness)
261 *pEndianness = PDMAUDIOENDIANNESS_BIG;
262 break;
263
264 case SND_PCM_FORMAT_S32_LE:
265 *pFmt = AUD_FMT_S32;
266 if (pEndianness)
267 *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
268 break;
269
270 case SND_PCM_FORMAT_U32_LE:
271 *pFmt = AUD_FMT_U32;
272 if (pEndianness)
273 *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
274 break;
275
276 case SND_PCM_FORMAT_S32_BE:
277 *pFmt = AUD_FMT_S32;
278 if (pEndianness)
279 *pEndianness = PDMAUDIOENDIANNESS_BIG;
280 break;
281
282 case SND_PCM_FORMAT_U32_BE:
283 *pFmt = AUD_FMT_U32;
284 if (pEndianness)
285 *pEndianness = PDMAUDIOENDIANNESS_BIG;
286 break;
287
288 default:
289 AssertMsgFailed(("Format %ld not supported\n", fmt));
290 return VERR_NOT_SUPPORTED;
291 }
292
293 return VINF_SUCCESS;
294}
295
296static int drvHostALSAAudioALSAGetShift(snd_pcm_format_t fmt, unsigned *puShift)
297{
298 AssertPtrReturn(puShift, VERR_INVALID_POINTER);
299
300 switch (fmt)
301 {
302 case SND_PCM_FORMAT_S8:
303 case SND_PCM_FORMAT_U8:
304 *puShift = 0;
305 break;
306
307 case SND_PCM_FORMAT_S16_LE:
308 case SND_PCM_FORMAT_U16_LE:
309 case SND_PCM_FORMAT_S16_BE:
310 case SND_PCM_FORMAT_U16_BE:
311 *puShift = 1;
312 break;
313
314 case SND_PCM_FORMAT_S32_LE:
315 case SND_PCM_FORMAT_U32_LE:
316 case SND_PCM_FORMAT_S32_BE:
317 case SND_PCM_FORMAT_U32_BE:
318 *puShift = 2;
319 break;
320
321 default:
322 AssertMsgFailed(("Format %ld not supported\n", fmt));
323 return VERR_NOT_SUPPORTED;
324 }
325
326 return VINF_SUCCESS;
327}
328
329static int drvHostALSAAudioSetThreshold(snd_pcm_t *phPCM,
330 snd_pcm_uframes_t threshold)
331{
332 snd_pcm_sw_params_t *pSWParms = NULL;
333 snd_pcm_sw_params_alloca(&pSWParms);
334 if (!pSWParms)
335 return VERR_NO_MEMORY;
336
337 int rc;
338 do
339 {
340 int err = snd_pcm_sw_params_current(phPCM, pSWParms);
341 if (err < 0)
342 {
343 LogRel(("ALSA: Failed to get current software parameters for threshold: %s\n",
344 snd_strerror(err)));
345 rc = VERR_ACCESS_DENIED;
346 break;
347 }
348
349 err = snd_pcm_sw_params_set_start_threshold(phPCM, pSWParms, threshold);
350 if (err < 0)
351 {
352 LogRel(("ALSA: Failed to set software threshold to %ld: %s\n",
353 threshold, snd_strerror(err)));
354 rc = VERR_ACCESS_DENIED;
355 break;
356 }
357
358 err = snd_pcm_sw_params(phPCM, pSWParms);
359 if (err < 0)
360 {
361 LogRel(("ALSA: Failed to set new software parameters for threshold: %s\n",
362 snd_strerror(err)));
363 rc = VERR_ACCESS_DENIED;
364 break;
365 }
366
367 LogFlowFunc(("Setting threshold to %RU32\n", threshold));
368 rc = VINF_SUCCESS;
369 }
370 while (0);
371
372 return rc;
373}
374
375static int drvHostALSAAudioOpen(bool fIn,
376 PALSAAUDIOSTREAMCFG pCfgReq,
377 PALSAAUDIOSTREAMCFG pCfgObt,
378 snd_pcm_t **pphPCM)
379{
380 snd_pcm_t *phPCM = NULL;
381 int rc;
382
383 unsigned int cChannels = pCfgReq->nchannels;
384 unsigned int uFreq = pCfgReq->freq;
385 snd_pcm_uframes_t obt_buffer_size;
386
387 do
388 {
389 const char *pszDev = fIn ? s_ALSAConf.pcm_name_in : s_ALSAConf.pcm_name_out;
390 if (!pszDev)
391 {
392 LogRel(("ALSA: Invalid or no %s device name set\n",
393 fIn ? "input" : "output"));
394 rc = VERR_INVALID_PARAMETER;
395 break;
396 }
397
398 int err = snd_pcm_open(&phPCM, pszDev,
399 fIn ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
400 SND_PCM_NONBLOCK);
401 if (err < 0)
402 {
403 LogRel(("ALSA: Failed to open \"%s\" as %s: %s\n", pszDev,
404 fIn ? "ADC" : "DAC", snd_strerror(err)));
405 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
406 break;
407 }
408
409 snd_pcm_hw_params_t *pHWParms;
410 snd_pcm_hw_params_alloca(&pHWParms); /** @todo Check for successful allocation? */
411 err = snd_pcm_hw_params_any(phPCM, pHWParms);
412 if (err < 0)
413 {
414 LogRel(("ALSA: Failed to initialize hardware parameters: %s\n",
415 snd_strerror(err)));
416 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
417 break;
418 }
419
420 err = snd_pcm_hw_params_set_access(phPCM, pHWParms,
421 SND_PCM_ACCESS_RW_INTERLEAVED);
422 if (err < 0)
423 {
424 LogRel(("ALSA: Failed to set access type: %s\n", snd_strerror(err)));
425 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
426 break;
427 }
428
429 err = snd_pcm_hw_params_set_format(phPCM, pHWParms, pCfgReq->fmt);
430 if (err < 0)
431 {
432 LogRel(("ALSA: Failed to set audio format to %d: %s\n",
433 pCfgReq->fmt, snd_strerror(err)));
434 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
435 break;
436 }
437
438 err = snd_pcm_hw_params_set_rate_near(phPCM, pHWParms, &uFreq, 0);
439 if (err < 0)
440 {
441 LogRel(("ALSA: Failed to set frequency to %dHz: %s\n",
442 pCfgReq->freq, snd_strerror(err)));
443 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
444 break;
445 }
446
447 err = snd_pcm_hw_params_set_channels_near(phPCM, pHWParms, &cChannels);
448 if (err < 0)
449 {
450 LogRel(("ALSA: Failed to set number of channels to %d\n", pCfgReq->nchannels));
451 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
452 break;
453 }
454
455 if ( cChannels != 1
456 && cChannels != 2)
457 {
458 LogRel(("ALSA: Number of audio channels (%u) not supported\n", cChannels));
459 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
460 break;
461 }
462
463 unsigned int period_size = pCfgReq->period_size;
464 unsigned int buffer_size = pCfgReq->buffer_size;
465
466 if ( !((fIn && s_ALSAConf.size_in_usec_in)
467 || (!fIn && s_ALSAConf.size_in_usec_out)))
468 {
469 if (!buffer_size)
470 {
471 buffer_size = DEFAULT_BUFFER_SIZE;
472 period_size = DEFAULT_PERIOD_SIZE;
473 }
474 }
475
476 if (buffer_size)
477 {
478 if ( ( fIn && s_ALSAConf.size_in_usec_in)
479 || (!fIn && s_ALSAConf.size_in_usec_out))
480 {
481 if (period_size)
482 {
483 err = snd_pcm_hw_params_set_period_time_near(phPCM, pHWParms,
484 &period_size, 0);
485 if (err < 0)
486 {
487 LogRel(("ALSA: Failed to set period time %d\n", pCfgReq->period_size));
488 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
489 break;
490 }
491 }
492
493 err = snd_pcm_hw_params_set_buffer_time_near(phPCM, pHWParms,
494 &buffer_size, 0);
495 if (err < 0)
496 {
497 LogRel(("ALSA: Failed to set buffer time %d\n", pCfgReq->buffer_size));
498 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
499 break;
500 }
501 }
502 else
503 {
504 snd_pcm_uframes_t period_size_f = (snd_pcm_uframes_t)period_size;
505 snd_pcm_uframes_t buffer_size_f = (snd_pcm_uframes_t)buffer_size;
506
507 snd_pcm_uframes_t minval;
508
509 if (period_size_f)
510 {
511 minval = period_size_f;
512
513 int dir = 0;
514 err = snd_pcm_hw_params_get_period_size_min(pHWParms,
515 &minval, &dir);
516 if (err < 0)
517 {
518 LogRel(("ALSA: Could not determine minimal period size\n"));
519 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
520 break;
521 }
522 else
523 {
524 LogFunc(("Minimal period size is: %ld\n", minval));
525 if (period_size_f < minval)
526 {
527 if ( ( fIn && s_ALSAConf.period_size_in_overriden)
528 || (!fIn && s_ALSAConf.period_size_out_overriden))
529 {
530 LogFunc(("Period size %RU32 is less than minimal period size %RU32\n",
531 period_size_f, minval));
532 }
533
534 period_size_f = minval;
535 }
536 }
537
538 err = snd_pcm_hw_params_set_period_size_near(phPCM, pHWParms,
539 &period_size_f, 0);
540 LogFunc(("Period size is: %RU32\n", period_size_f));
541 if (err < 0)
542 {
543 LogRel(("ALSA: Failed to set period size %d (%s)\n",
544 period_size_f, snd_strerror(err)));
545 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
546 break;
547 }
548 }
549
550 /* Calculate default buffer size here since it might have been changed
551 * in the _near functions */
552 buffer_size_f = 4 * period_size_f;
553
554 minval = buffer_size_f;
555 err = snd_pcm_hw_params_get_buffer_size_min(pHWParms, &minval);
556 if (err < 0)
557 {
558 LogRel(("ALSA: Could not retrieve minimal buffer size\n"));
559 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
560 break;
561 }
562 else
563 {
564 LogFunc(("Minimal buffer size is: %RU32\n", minval));
565 if (buffer_size_f < minval)
566 {
567 if ( ( fIn && s_ALSAConf.buffer_size_in_overriden)
568 || (!fIn && s_ALSAConf.buffer_size_out_overriden))
569 {
570 LogFunc(("Buffer size %RU32 is less than minimal buffer size %RU32\n",
571 buffer_size_f, minval));
572 }
573
574 buffer_size_f = minval;
575 }
576 }
577
578 err = snd_pcm_hw_params_set_buffer_size_near(phPCM,
579 pHWParms, &buffer_size_f);
580 LogFunc(("Buffer size is: %RU32\n", buffer_size_f));
581 if (err < 0)
582 {
583 LogRel(("ALSA: Failed to set buffer size %d: %s\n",
584 buffer_size_f, snd_strerror(err)));
585 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
586 break;
587 }
588 }
589 }
590 else
591 LogFunc(("Warning: Buffer size is not set\n"));
592
593 err = snd_pcm_hw_params(phPCM, pHWParms);
594 if (err < 0)
595 {
596 LogRel(("ALSA: Failed to apply audio parameters\n"));
597 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
598 break;
599 }
600
601 err = snd_pcm_hw_params_get_buffer_size(pHWParms, &obt_buffer_size);
602 if (err < 0)
603 {
604 LogRel(("ALSA: Failed to get buffer size\n"));
605 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
606 break;
607 }
608
609 snd_pcm_uframes_t obt_period_size;
610 int dir = 0;
611 err = snd_pcm_hw_params_get_period_size(pHWParms, &obt_period_size, &dir);
612 if (err < 0)
613 {
614 LogRel(("ALSA: Failed to get period size\n"));
615 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
616 break;
617 }
618
619 LogFunc(("Freq=%dHz, period size=%RU32, buffer size=%RU32\n",
620 pCfgReq->freq, obt_period_size, obt_buffer_size));
621
622 err = snd_pcm_prepare(phPCM);
623 if (err < 0)
624 {
625 LogRel(("ALSA: Could not prepare hPCM %p\n", (void *)phPCM));
626 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
627 break;
628 }
629
630 if ( !fIn
631 && s_ALSAConf.threshold)
632 {
633 unsigned uShift;
634 rc = drvHostALSAAudioALSAGetShift(pCfgReq->fmt, &uShift);
635 if (RT_SUCCESS(rc))
636 {
637 int bytes_per_sec = uFreq
638 << (cChannels == 2)
639 << uShift;
640
641 snd_pcm_uframes_t threshold
642 = (s_ALSAConf.threshold * bytes_per_sec) / 1000;
643
644 rc = drvHostALSAAudioSetThreshold(phPCM, threshold);
645 }
646 }
647 else
648 rc = VINF_SUCCESS;
649 }
650 while (0);
651
652 if (RT_SUCCESS(rc))
653 {
654 pCfgObt->fmt = pCfgReq->fmt;
655 pCfgObt->nchannels = cChannels;
656 pCfgObt->freq = uFreq;
657 pCfgObt->samples = obt_buffer_size;
658
659 *pphPCM = phPCM;
660 }
661 else
662 drvHostALSAAudioClose(&phPCM);
663
664 LogFlowFuncLeaveRC(rc);
665 return rc;
666}
667
668#ifdef DEBUG
669static void drvHostALSAAudioErrorHandler(const char *file, int line, const char *function,
670 int err, const char *fmt, ...)
671{
672 /** @todo Implement me! */
673}
674#endif
675
676static int drvHostALSAAudioGetAvail(snd_pcm_t *phPCM, snd_pcm_sframes_t *pFramesAvail)
677{
678 AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
679 AssertPtrReturn(pFramesAvail, VERR_INVALID_POINTER);
680
681 int rc;
682
683 snd_pcm_sframes_t framesAvail;
684 framesAvail = snd_pcm_avail_update(phPCM);
685 if (framesAvail < 0)
686 {
687 if (framesAvail == -EPIPE)
688 {
689 rc = drvHostALSAAudioRecover(phPCM);
690 if (RT_SUCCESS(rc))
691 framesAvail = snd_pcm_avail_update(phPCM);
692 }
693 else
694 rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */
695 }
696 else
697 rc = VINF_SUCCESS;
698
699 if (framesAvail >= 0)
700 *pFramesAvail = framesAvail;
701
702 return rc;
703}
704
705static int drvHostALSAAudioRecover(snd_pcm_t *phPCM)
706{
707 AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
708
709 int err = snd_pcm_prepare(phPCM);
710 if (err < 0)
711 {
712 LogFunc(("Failed to recover stream %p: %s\n",
713 phPCM, snd_strerror(err)));
714 return VERR_ACCESS_DENIED; /** @todo Find a better rc. */
715 }
716
717 return VINF_SUCCESS;
718}
719
720static int drvHostALSAAudioResume(snd_pcm_t *phPCM)
721{
722 AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
723
724 int err = snd_pcm_resume(phPCM);
725 if (err < 0)
726 {
727 LogFunc(("Failed to resume stream %p: %s\n",
728 phPCM, snd_strerror(err)));
729 return VERR_ACCESS_DENIED; /** @todo Find a better rc. */
730 }
731
732 return VINF_SUCCESS;
733}
734
735static int drvHostALSAAudioStreamCtl(snd_pcm_t *phPCM, bool fPause)
736{
737 int err;
738 if (fPause)
739 {
740 err = snd_pcm_drop(phPCM);
741 if (err < 0)
742 {
743 LogFlow(("Error stopping stream %p: %s\n",
744 phPCM, snd_strerror(err)));
745 return VERR_ACCESS_DENIED;
746 }
747 }
748 else
749 {
750 err = snd_pcm_prepare (phPCM);
751 if (err < 0)
752 {
753 LogFlow(("Error preparing stream %p: %s\n",
754 phPCM, snd_strerror(err)));
755 return VERR_ACCESS_DENIED;
756 }
757 }
758
759 return VINF_SUCCESS;
760}
761
762static DECLCALLBACK(int) drvHostALSAAudioInit(PPDMIHOSTAUDIO pInterface)
763{
764 NOREF(pInterface);
765
766 LogFlowFuncEnter();
767
768 int rc = audioLoadAlsaLib();
769 if (RT_FAILURE(rc))
770 LogRel(("ALSA: Failed to load the ALSA shared library, rc=%Rrc\n", rc));
771 else
772 {
773#ifdef DEBUG
774 snd_lib_error_set_handler(drvHostALSAAudioErrorHandler);
775#endif
776 }
777
778 return rc;
779}
780
781static DECLCALLBACK(int) drvHostALSAAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
782 uint32_t *pcSamplesCaptured)
783{
784 NOREF(pInterface);
785 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
786
787 PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
788
789 snd_pcm_sframes_t cAvail;
790 int rc = drvHostALSAAudioGetAvail(pThisStrmIn->phPCM, &cAvail);
791 if (RT_FAILURE(rc))
792 {
793 LogFunc(("Error getting number of captured frames, rc=%Rrc\n", rc));
794 return rc;
795 }
796
797 if (!cAvail) /* No data yet? */
798 {
799 snd_pcm_state_t state = snd_pcm_state(pThisStrmIn->phPCM);
800 switch (state)
801 {
802 case SND_PCM_STATE_PREPARED:
803 cAvail = AudioMixBufFree(&pHstStrmIn->MixBuf);
804 break;
805
806 case SND_PCM_STATE_SUSPENDED:
807 {
808 rc = drvHostALSAAudioResume(pThisStrmIn->phPCM);
809 if (RT_FAILURE(rc))
810 break;
811
812 LogFlow(("Resuming suspended input stream\n"));
813 break;
814 }
815
816 default:
817 LogFlow(("No frames available, state=%d\n", state));
818 break;
819 }
820
821 if (!cAvail)
822 {
823 if (pcSamplesCaptured)
824 *pcSamplesCaptured = 0;
825 return VINF_SUCCESS;
826 }
827 }
828
829 Assert(cAvail);
830 size_t cbToRead = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cAvail);
831
832 LogFlowFunc(("cbToRead=%zu, cAvail=%RI32\n", cbToRead, cAvail));
833
834 uint32_t cWrittenTotal = 0;
835 snd_pcm_uframes_t cToRead;
836 snd_pcm_sframes_t cRead;
837
838 while ( cbToRead
839 && RT_SUCCESS(rc))
840 {
841 cToRead = RT_MIN(AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cbToRead),
842 AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, pThisStrmIn->cbBuf));
843 AssertBreakStmt(cToRead, rc = VERR_NO_DATA);
844 cRead = snd_pcm_readi(pThisStrmIn->phPCM, pThisStrmIn->pvBuf, cToRead);
845 if (cRead <= 0)
846 {
847 switch (cRead)
848 {
849 case 0:
850 {
851 LogFunc(("No input frames available\n"));
852 rc = VERR_ACCESS_DENIED;
853 break;
854 }
855
856 case -EAGAIN:
857 /*
858 * Don't set error here because EAGAIN means there are no further frames
859 * available at the moment, try later. As we might have read some frames
860 * already these need to be processed instead.
861 */
862 cbToRead = 0;
863 break;
864
865 case -EPIPE:
866 {
867 rc = drvHostALSAAudioRecover(pThisStrmIn->phPCM);
868 if (RT_FAILURE(rc))
869 break;
870
871 LogFlowFunc(("Recovered from capturing\n"));
872 continue;
873 }
874
875 default:
876 LogFunc(("Failed to read input frames: %s\n", snd_strerror(cRead)));
877 rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
878 break;
879 }
880 }
881 else
882 {
883 uint32_t cWritten;
884 rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
885 pThisStrmIn->pvBuf, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cRead),
886 &cWritten);
887 if (RT_FAILURE(rc))
888 break;
889
890 uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
891
892 Assert(cbToRead >= cbWritten);
893 cbToRead -= cbWritten;
894 cWrittenTotal += cWritten;
895 }
896 }
897
898 if (RT_SUCCESS(rc))
899 {
900 uint32_t cProcessed = 0;
901 if (cWrittenTotal)
902 rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
903 &cProcessed);
904
905 if (pcSamplesCaptured)
906 *pcSamplesCaptured = cWrittenTotal;
907
908 LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
909 cWrittenTotal, cProcessed, rc));
910 }
911
912 LogFlowFuncLeaveRC(rc);
913 return rc;
914}
915
916static DECLCALLBACK(int) drvHostALSAAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
917 uint32_t *pcSamplesPlayed)
918{
919 NOREF(pInterface);
920 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
921
922 PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
923
924 int rc = VINF_SUCCESS;
925 uint32_t cbReadTotal = 0;
926
927 do
928 {
929 snd_pcm_sframes_t cAvail;
930 rc = drvHostALSAAudioGetAvail(pThisStrmOut->phPCM, &cAvail);
931 if (RT_FAILURE(rc))
932 {
933 LogFunc(("Error getting number of playback frames, rc=%Rrc\n", rc));
934 break;
935 }
936
937 size_t cbToRead = RT_MIN(AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf,
938 cAvail),
939 AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf,
940 drvAudioHstOutSamplesLive(pHstStrmOut, NULL /* pcStreamsLive */)));
941 LogFlowFunc(("cbToRead=%zu, cbAvail=%zu\n",
942 cbToRead, AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cAvail)));
943
944 uint32_t cRead, cbRead;
945 snd_pcm_sframes_t cWritten;
946 while (cbToRead)
947 {
948 rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pThisStrmOut->pvBuf, cbToRead, &cRead);
949 if (RT_FAILURE(rc))
950 break;
951
952 cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
953 AssertBreak(cbRead);
954
955 cWritten = snd_pcm_writei(pThisStrmOut->phPCM, pThisStrmOut->pvBuf, cRead);
956 if (cWritten <= 0)
957 {
958 switch (cWritten)
959 {
960 case 0:
961 {
962 LogFunc(("Failed to write %RI32 frames\n", cRead));
963 rc = VERR_ACCESS_DENIED;
964 break;
965 }
966
967 case -EPIPE:
968 {
969 rc = drvHostALSAAudioRecover(pThisStrmOut->phPCM);
970 if (RT_FAILURE(rc))
971 break;
972
973 LogFlowFunc(("Recovered from playback\n"));
974 continue;
975 }
976
977 case -ESTRPIPE:
978 {
979 /* Stream was suspended and waiting for a recovery. */
980 rc = drvHostALSAAudioResume(pThisStrmOut->phPCM);
981 if (RT_FAILURE(rc))
982 {
983 LogRel(("ALSA: Failed to resume output stream\n"));
984 break;
985 }
986
987 LogFlowFunc(("Resumed suspended output stream\n"));
988 continue;
989 }
990
991 default:
992 LogFlowFunc(("Failed to write %RI32 output frames, rc=%Rrc\n",
993 cRead, rc));
994 rc = VERR_GENERAL_FAILURE; /** @todo */
995 break;
996 }
997 }
998
999 if (RT_FAILURE(rc))
1000 break;
1001
1002 Assert(cbToRead >= cRead);
1003 cbToRead -= cbRead;
1004 cbReadTotal += cbRead;
1005 }
1006 }
1007 while (0);
1008
1009 if (RT_SUCCESS(rc))
1010 {
1011 uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
1012 if (cReadTotal)
1013 AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
1014
1015 if (pcSamplesPlayed)
1016 *pcSamplesPlayed = cReadTotal;
1017
1018 LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n",
1019 cReadTotal, cbReadTotal, rc));
1020 }
1021
1022 LogFlowFuncLeaveRC(rc);
1023 return rc;
1024}
1025
1026static DECLCALLBACK(int) drvHostALSAAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
1027{
1028 NOREF(pInterface);
1029 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
1030
1031 PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
1032
1033 drvHostALSAAudioClose(&pThisStrmIn->phPCM);
1034
1035 if (pThisStrmIn->pvBuf)
1036 {
1037 RTMemFree(pThisStrmIn->pvBuf);
1038 pThisStrmIn->pvBuf = NULL;
1039 }
1040
1041 return VINF_SUCCESS;
1042}
1043
1044static DECLCALLBACK(int) drvHostALSAAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
1045{
1046 NOREF(pInterface);
1047 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
1048
1049 PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
1050
1051 drvHostALSAAudioClose(&pThisStrmOut->phPCM);
1052
1053 if (pThisStrmOut->pvBuf)
1054 {
1055 RTMemFree(pThisStrmOut->pvBuf);
1056 pThisStrmOut->pvBuf = NULL;
1057 }
1058
1059 return VINF_SUCCESS;
1060}
1061
1062static DECLCALLBACK(int) drvHostALSAAudioInitOut(PPDMIHOSTAUDIO pInterface,
1063 PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfg,
1064 uint32_t *pcSamples)
1065{
1066 NOREF(pInterface);
1067 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
1068 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1069
1070 PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
1071 snd_pcm_t *phPCM = NULL;
1072
1073 int rc;
1074
1075 do
1076 {
1077 ALSAAUDIOSTREAMCFG req;
1078 req.fmt = drvHostALSAAudioFmtToALSA(pCfg->enmFormat);
1079 req.freq = pCfg->uHz;
1080 req.nchannels = pCfg->cChannels;
1081 req.period_size = s_ALSAConf.period_size_out;
1082 req.buffer_size = s_ALSAConf.buffer_size_out;
1083
1084 ALSAAUDIOSTREAMCFG obt;
1085 rc = drvHostALSAAudioOpen(false /* false */, &req, &obt, &phPCM);
1086 if (RT_FAILURE(rc))
1087 break;
1088
1089 PDMAUDIOFMT enmFormat;
1090 PDMAUDIOENDIANNESS enmEnd;
1091 rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
1092 if (RT_FAILURE(rc))
1093 break;
1094
1095 PDMAUDIOSTREAMCFG streamCfg;
1096 streamCfg.uHz = obt.freq;
1097 streamCfg.cChannels = obt.nchannels;
1098 streamCfg.enmFormat = enmFormat;
1099 streamCfg.enmEndianness = enmEnd;
1100
1101 rc = drvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
1102 if (RT_FAILURE(rc))
1103 break;
1104
1105 AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
1106 size_t cbBuf = obt.samples * (1 << pHstStrmOut->Props.cShift);
1107 AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
1108 pThisStrmOut->pvBuf = RTMemAlloc(cbBuf);
1109 if (!pThisStrmOut->pvBuf)
1110 {
1111 LogRel(("ALSA: Not enough memory for output DAC buffer (%RU32 samples, each %d bytes)\n",
1112 obt.samples, 1 << pHstStrmOut->Props.cShift));
1113 rc = VERR_NO_MEMORY;
1114 break;
1115 }
1116
1117 pThisStrmOut->cbBuf = cbBuf;
1118 pThisStrmOut->phPCM = phPCM;
1119
1120 if (pcSamples)
1121 *pcSamples = obt.samples;
1122 }
1123 while (0);
1124
1125 if (RT_FAILURE(rc))
1126 drvHostALSAAudioClose(&phPCM);
1127
1128 LogFlowFuncLeaveRC(rc);
1129 return rc;
1130}
1131
1132static DECLCALLBACK(int) drvHostALSAAudioInitIn(PPDMIHOSTAUDIO pInterface,
1133 PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfg,
1134 PDMAUDIORECSOURCE enmRecSource,
1135 uint32_t *pcSamples)
1136{
1137 NOREF(pInterface);
1138 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
1139 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1140
1141 int rc;
1142
1143 PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
1144 snd_pcm_t *phPCM = NULL;
1145
1146 do
1147 {
1148 ALSAAUDIOSTREAMCFG req;
1149 req.fmt = drvHostALSAAudioFmtToALSA(pCfg->enmFormat);
1150 req.freq = pCfg->uHz;
1151 req.nchannels = pCfg->cChannels;
1152 req.period_size = s_ALSAConf.period_size_in;
1153 req.buffer_size = s_ALSAConf.buffer_size_in;
1154
1155 ALSAAUDIOSTREAMCFG obt;
1156 rc = drvHostALSAAudioOpen(true /* fIn */, &req, &obt, &phPCM);
1157 if (RT_FAILURE(rc))
1158 break;
1159
1160 PDMAUDIOFMT enmFormat;
1161 PDMAUDIOENDIANNESS enmEnd;
1162 rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
1163 if (RT_FAILURE(rc))
1164 break;
1165
1166 PDMAUDIOSTREAMCFG streamCfg;
1167 streamCfg.uHz = obt.freq;
1168 streamCfg.cChannels = obt.nchannels;
1169 streamCfg.enmFormat = enmFormat;
1170 streamCfg.enmEndianness = enmEnd;
1171
1172 rc = drvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
1173 if (RT_FAILURE(rc))
1174 break;
1175
1176 AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
1177 size_t cbBuf = obt.samples * (1 << pHstStrmIn->Props.cShift);
1178 AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
1179 pThisStrmIn->pvBuf = RTMemAlloc(cbBuf);
1180 if (!pThisStrmIn->pvBuf)
1181 {
1182 LogRel(("ALSA: Not enough memory for input ADC buffer (%RU32 samples, each %d bytes)\n",
1183 obt.samples, 1 << pHstStrmIn->Props.cShift));
1184 rc = VERR_NO_MEMORY;
1185 break;
1186 }
1187
1188 pThisStrmIn->cbBuf = cbBuf;
1189 pThisStrmIn->phPCM = phPCM;
1190
1191 if (pcSamples)
1192 *pcSamples = obt.samples;
1193 }
1194 while (0);
1195
1196 if (RT_FAILURE(rc))
1197 drvHostALSAAudioClose(&phPCM);
1198
1199 LogFlowFuncLeaveRC(rc);
1200 return rc;
1201}
1202
1203static DECLCALLBACK(bool) drvHostALSAAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
1204{
1205 NOREF(pInterface);
1206 NOREF(enmDir);
1207 return true; /* Always all enabled. */
1208}
1209
1210static DECLCALLBACK(int) drvHostALSAAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
1211 PDMAUDIOSTREAMCMD enmStreamCmd)
1212{
1213 NOREF(pInterface);
1214 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
1215 PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
1216
1217 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
1218
1219 int rc;
1220 switch (enmStreamCmd)
1221 {
1222 case PDMAUDIOSTREAMCMD_ENABLE:
1223 rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, false /* fStop */);
1224 break;
1225
1226 case PDMAUDIOSTREAMCMD_DISABLE:
1227 rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, true /* fStop */);
1228 break;
1229
1230 default:
1231 AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
1232 rc = VERR_INVALID_PARAMETER;
1233 break;
1234 }
1235
1236 return rc;
1237}
1238
1239static DECLCALLBACK(int) drvHostALSAAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
1240 PDMAUDIOSTREAMCMD enmStreamCmd)
1241{
1242 NOREF(pInterface);
1243 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
1244 PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
1245
1246 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
1247
1248 int rc;
1249 switch (enmStreamCmd)
1250 {
1251 case PDMAUDIOSTREAMCMD_ENABLE:
1252 rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, false /* fStop */);
1253 break;
1254
1255 case PDMAUDIOSTREAMCMD_DISABLE:
1256 rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, true /* fStop */);
1257 break;
1258
1259 default:
1260 AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
1261 rc = VERR_INVALID_PARAMETER;
1262 break;
1263 }
1264
1265 return rc;
1266}
1267
1268static DECLCALLBACK(int) drvHostALSAAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
1269{
1270 NOREF(pInterface);
1271 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1272
1273 pCfg->cbStreamOut = sizeof(ALSAAUDIOSTREAMOUT);
1274 pCfg->cbStreamIn = sizeof(ALSAAUDIOSTREAMIN);
1275 pCfg->cMaxHstStrmsOut = INT_MAX;
1276 pCfg->cMaxHstStrmsIn = INT_MAX;
1277
1278 return VINF_SUCCESS;
1279}
1280
1281static DECLCALLBACK(void) drvHostALSAAudioShutdown(PPDMIHOSTAUDIO pInterface)
1282{
1283 NOREF(pInterface);
1284}
1285
1286/**
1287 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1288 */
1289static DECLCALLBACK(void *) drvHostALSAAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1290{
1291 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1292 PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
1293 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1294 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
1295
1296 return NULL;
1297}
1298
1299/**
1300 * Construct a DirectSound Audio driver instance.
1301 *
1302 * @copydoc FNPDMDRVCONSTRUCT
1303 */
1304static DECLCALLBACK(int) drvHostAlsaAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1305{
1306 PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
1307 LogRel(("Audio: Initializing ALSA driver\n"));
1308
1309 /*
1310 * Init the static parts.
1311 */
1312 pThis->pDrvIns = pDrvIns;
1313 /* IBase */
1314 pDrvIns->IBase.pfnQueryInterface = drvHostALSAAudioQueryInterface;
1315 /* IHostAudio */
1316 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostALSAAudio);
1317
1318 return VINF_SUCCESS;
1319}
1320
1321/**
1322 * Char driver registration record.
1323 */
1324const PDMDRVREG g_DrvHostALSAAudio =
1325{
1326 /* u32Version */
1327 PDM_DRVREG_VERSION,
1328 /* szName */
1329 "ALSAAudio",
1330 /* szRCMod */
1331 "",
1332 /* szR0Mod */
1333 "",
1334 /* pszDescription */
1335 "ALSA host audio driver",
1336 /* fFlags */
1337 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1338 /* fClass. */
1339 PDM_DRVREG_CLASS_AUDIO,
1340 /* cMaxInstances */
1341 ~0U,
1342 /* cbInstance */
1343 sizeof(DRVHOSTALSAAUDIO),
1344 /* pfnConstruct */
1345 drvHostAlsaAudioConstruct,
1346 /* pfnDestruct */
1347 NULL,
1348 /* pfnRelocate */
1349 NULL,
1350 /* pfnIOCtl */
1351 NULL,
1352 /* pfnPowerOn */
1353 NULL,
1354 /* pfnReset */
1355 NULL,
1356 /* pfnSuspend */
1357 NULL,
1358 /* pfnResume */
1359 NULL,
1360 /* pfnAttach */
1361 NULL,
1362 /* pfnDetach */
1363 NULL,
1364 /* pfnPowerOff */
1365 NULL,
1366 /* pfnSoftReset */
1367 NULL,
1368 /* u32EndVersion */
1369 PDM_DRVREG_VERSION
1370};
1371
1372static struct audio_option alsa_options[] =
1373{
1374 {"DACSizeInUsec", AUD_OPT_BOOL, &s_ALSAConf.size_in_usec_out,
1375 "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
1376 {"DACPeriodSize", AUD_OPT_INT, &s_ALSAConf.period_size_out,
1377 "DAC period size", &s_ALSAConf.period_size_out_overriden, 0},
1378 {"DACBufferSize", AUD_OPT_INT, &s_ALSAConf.buffer_size_out,
1379 "DAC buffer size", &s_ALSAConf.buffer_size_out_overriden, 0},
1380
1381 {"ADCSizeInUsec", AUD_OPT_BOOL, &s_ALSAConf.size_in_usec_in,
1382 "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
1383 {"ADCPeriodSize", AUD_OPT_INT, &s_ALSAConf.period_size_in,
1384 "ADC period size", &s_ALSAConf.period_size_in_overriden, 0},
1385 {"ADCBufferSize", AUD_OPT_INT, &s_ALSAConf.buffer_size_in,
1386 "ADC buffer size", &s_ALSAConf.buffer_size_in_overriden, 0},
1387
1388 {"Threshold", AUD_OPT_INT, &s_ALSAConf.threshold,
1389 "(undocumented)", NULL, 0},
1390
1391 {"DACDev", AUD_OPT_STR, &s_ALSAConf.pcm_name_out,
1392 "DAC device name (for instance dmix)", NULL, 0},
1393
1394 {"ADCDev", AUD_OPT_STR, &s_ALSAConf.pcm_name_in,
1395 "ADC device name", NULL, 0},
1396
1397 NULL
1398};
1399
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette