VirtualBox

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

Last change on this file since 54774 was 54491, checked in by vboxsync, 10 years ago

PDM/Audio: Fixed crashes on termination.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.1 KB
Line 
1/* $Id: DrvHostALSAAudio.cpp 54491 2015-02-25 13:23:21Z 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, PDMAUDIOENDIANESS *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 = PDMAUDIOENDIANESS_LITTLE;
232 break;
233
234 case SND_PCM_FORMAT_U8:
235 *pFmt = AUD_FMT_U8;
236 if (pEndianness)
237 *pEndianness = PDMAUDIOENDIANESS_LITTLE;
238 break;
239
240 case SND_PCM_FORMAT_S16_LE:
241 *pFmt = AUD_FMT_S16;
242 if (pEndianness)
243 *pEndianness = PDMAUDIOENDIANESS_LITTLE;
244 break;
245
246 case SND_PCM_FORMAT_U16_LE:
247 *pFmt = AUD_FMT_U16;
248 if (pEndianness)
249 *pEndianness = PDMAUDIOENDIANESS_LITTLE;
250 break;
251
252 case SND_PCM_FORMAT_S16_BE:
253 *pFmt = AUD_FMT_S16;
254 if (pEndianness)
255 *pEndianness = PDMAUDIOENDIANESS_BIG;
256 break;
257
258 case SND_PCM_FORMAT_U16_BE:
259 *pFmt = AUD_FMT_U16;
260 if (pEndianness)
261 *pEndianness = PDMAUDIOENDIANESS_BIG;
262 break;
263
264 case SND_PCM_FORMAT_S32_LE:
265 *pFmt = AUD_FMT_S32;
266 if (pEndianness)
267 *pEndianness = PDMAUDIOENDIANESS_LITTLE;
268 break;
269
270 case SND_PCM_FORMAT_U32_LE:
271 *pFmt = AUD_FMT_U32;
272 if (pEndianness)
273 *pEndianness = PDMAUDIOENDIANESS_LITTLE;
274 break;
275
276 case SND_PCM_FORMAT_S32_BE:
277 *pFmt = AUD_FMT_S32;
278 if (pEndianness)
279 *pEndianness = PDMAUDIOENDIANESS_BIG;
280 break;
281
282 case SND_PCM_FORMAT_U32_BE:
283 *pFmt = AUD_FMT_U32;
284 if (pEndianness)
285 *pEndianness = PDMAUDIOENDIANESS_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 {
840 cToRead = RT_MIN(AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cbToRead),
841 AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, pThisStrmIn->cbBuf));
842 AssertBreakStmt(cToRead, rc = VERR_NO_DATA);
843 cRead = snd_pcm_readi(pThisStrmIn->phPCM, pThisStrmIn->pvBuf, cToRead);
844 if (cRead <= 0)
845 {
846 switch (cRead)
847 {
848 case 0:
849 {
850 LogFunc(("Failed to read %RI32 frames\n", cRead));
851 rc = VERR_ACCESS_DENIED;
852 break;
853 }
854
855 case -EAGAIN:
856 break;
857
858 case -EPIPE:
859 {
860 rc = drvHostALSAAudioRecover(pThisStrmIn->phPCM);
861 if (RT_FAILURE(rc))
862 break;
863
864 LogFlowFunc(("Recovered from capturing\n"));
865 continue;
866 }
867
868 default:
869 LogFlowFunc(("Failed to read %RI32 input frames, rc=%Rrc\n",
870 cRead, rc));
871 rc = VERR_GENERAL_FAILURE; /** @todo */
872 break;
873 }
874 }
875 else
876 {
877 uint32_t cWritten;
878 rc = audioMixBufWriteCirc(&pHstStrmIn->MixBuf,
879 pThisStrmIn->pvBuf, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cRead),
880 &cWritten);
881 if (RT_FAILURE(rc))
882 break;
883
884 uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
885
886 Assert(cbToRead >= cbWritten);
887 cbToRead -= cbWritten;
888 cWrittenTotal += cWritten;
889 }
890 }
891
892 if (RT_SUCCESS(rc))
893 {
894 uint32_t cProcessed = 0;
895 if (cWrittenTotal)
896 rc = audioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
897 &cProcessed);
898
899 if (pcSamplesCaptured)
900 *pcSamplesCaptured = cWrittenTotal;
901
902 LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
903 cWrittenTotal, cProcessed, rc));
904 }
905
906 LogFlowFuncLeaveRC(rc);
907 return rc;
908}
909
910static DECLCALLBACK(int) drvHostALSAAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
911 uint32_t *pcSamplesPlayed)
912{
913 NOREF(pInterface);
914 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
915
916 PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
917
918 int rc = VINF_SUCCESS;
919 uint32_t cbReadTotal = 0;
920
921 do
922 {
923 snd_pcm_sframes_t cAvail;
924 rc = drvHostALSAAudioGetAvail(pThisStrmOut->phPCM, &cAvail);
925 if (RT_FAILURE(rc))
926 {
927 LogFunc(("Error getting number of playback frames, rc=%Rrc\n", rc));
928 break;
929 }
930
931 size_t cbToRead = RT_MIN(AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf,
932 cAvail),
933 AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf,
934 drvAudioHstOutSamplesLive(pHstStrmOut, NULL /* pcStreamsLive */)));
935 LogFlowFunc(("cbToRead=%zu, cbAvail=%zu\n",
936 cbToRead, AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cAvail)));
937
938 uint32_t cRead, cbRead;
939 snd_pcm_sframes_t cWritten;
940 while (cbToRead)
941 {
942 rc = audioMixBufReadCirc(&pHstStrmOut->MixBuf, pThisStrmOut->pvBuf, cbToRead, &cRead);
943 if (RT_FAILURE(rc))
944 break;
945
946 cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
947 AssertBreak(cbRead);
948
949 cWritten = snd_pcm_writei(pThisStrmOut->phPCM, pThisStrmOut->pvBuf, cRead);
950 if (cWritten <= 0)
951 {
952 switch (cWritten)
953 {
954 case 0:
955 {
956 LogFunc(("Failed to write %RI32 frames\n", cRead));
957 rc = VERR_ACCESS_DENIED;
958 break;
959 }
960
961 case -EPIPE:
962 {
963 rc = drvHostALSAAudioRecover(pThisStrmOut->phPCM);
964 if (RT_FAILURE(rc))
965 break;
966
967 LogFlowFunc(("Recovered from playback\n"));
968 continue;
969 }
970
971 case -ESTRPIPE:
972 {
973 /* Stream was suspended and waiting for a recovery. */
974 rc = drvHostALSAAudioResume(pThisStrmOut->phPCM);
975 if (RT_FAILURE(rc))
976 {
977 LogRel(("ALSA: Failed to resume output stream\n"));
978 break;
979 }
980
981 LogFlowFunc(("Resumed suspended output stream\n"));
982 continue;
983 }
984
985 default:
986 LogFlowFunc(("Failed to write %RI32 output frames, rc=%Rrc\n",
987 cRead, rc));
988 rc = VERR_GENERAL_FAILURE; /** @todo */
989 break;
990 }
991 }
992
993 if (RT_FAILURE(rc))
994 break;
995
996 Assert(cbToRead >= cRead);
997 cbToRead -= cbRead;
998 cbReadTotal += cbRead;
999 }
1000 }
1001 while (0);
1002
1003 if (RT_SUCCESS(rc))
1004 {
1005 uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
1006 if (cReadTotal)
1007 audioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
1008
1009 if (pcSamplesPlayed)
1010 *pcSamplesPlayed = cReadTotal;
1011
1012 LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n",
1013 cReadTotal, cbReadTotal, rc));
1014 }
1015
1016 LogFlowFuncLeaveRC(rc);
1017 return rc;
1018}
1019
1020static DECLCALLBACK(int) drvHostALSAAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
1021{
1022 NOREF(pInterface);
1023 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
1024
1025 PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
1026
1027 drvHostALSAAudioClose(&pThisStrmIn->phPCM);
1028
1029 if (pThisStrmIn->pvBuf)
1030 {
1031 RTMemFree(pThisStrmIn->pvBuf);
1032 pThisStrmIn->pvBuf = NULL;
1033 }
1034
1035 return VINF_SUCCESS;
1036}
1037
1038static DECLCALLBACK(int) drvHostALSAAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
1039{
1040 NOREF(pInterface);
1041 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
1042
1043 PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
1044
1045 drvHostALSAAudioClose(&pThisStrmOut->phPCM);
1046
1047 if (pThisStrmOut->pvBuf)
1048 {
1049 RTMemFree(pThisStrmOut->pvBuf);
1050 pThisStrmOut->pvBuf = NULL;
1051 }
1052
1053 return VINF_SUCCESS;
1054}
1055
1056static DECLCALLBACK(int) drvHostALSAAudioInitOut(PPDMIHOSTAUDIO pInterface,
1057 PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfg,
1058 uint32_t *pcSamples)
1059{
1060 NOREF(pInterface);
1061 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
1062 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1063
1064 PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
1065 snd_pcm_t *phPCM = NULL;
1066
1067 int rc;
1068
1069 do
1070 {
1071 ALSAAUDIOSTREAMCFG req;
1072 req.fmt = drvHostALSAAudioFmtToALSA(pCfg->enmFormat);
1073 req.freq = pCfg->uHz;
1074 req.nchannels = pCfg->cChannels;
1075 req.period_size = s_ALSAConf.period_size_out;
1076 req.buffer_size = s_ALSAConf.buffer_size_out;
1077
1078 ALSAAUDIOSTREAMCFG obt;
1079 rc = drvHostALSAAudioOpen(false /* false */, &req, &obt, &phPCM);
1080 if (RT_FAILURE(rc))
1081 break;
1082
1083 PDMAUDIOFMT enmFormat;
1084 PDMAUDIOENDIANESS enmEnd;
1085 rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
1086 if (RT_FAILURE(rc))
1087 break;
1088
1089 PDMAUDIOSTREAMCFG streamCfg;
1090 streamCfg.uHz = obt.freq;
1091 streamCfg.cChannels = obt.nchannels;
1092 streamCfg.enmFormat = enmFormat;
1093 streamCfg.enmEndianness = enmEnd;
1094
1095 rc = drvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
1096 if (RT_FAILURE(rc))
1097 break;
1098
1099 AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
1100 size_t cbBuf = obt.samples * (1 << pHstStrmOut->Props.cShift);
1101 AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
1102 pThisStrmOut->pvBuf = RTMemAlloc(cbBuf);
1103 if (!pThisStrmOut->pvBuf)
1104 {
1105 LogRel(("ALSA: Not enough memory for output DAC buffer (%RU32 samples, each %d bytes)\n",
1106 obt.samples, 1 << pHstStrmOut->Props.cShift));
1107 rc = VERR_NO_MEMORY;
1108 break;
1109 }
1110
1111 pThisStrmOut->cbBuf = cbBuf;
1112 pThisStrmOut->phPCM = phPCM;
1113
1114 if (pcSamples)
1115 *pcSamples = obt.samples;
1116 }
1117 while (0);
1118
1119 if (RT_FAILURE(rc))
1120 drvHostALSAAudioClose(&phPCM);
1121
1122 LogFlowFuncLeaveRC(rc);
1123 return rc;
1124}
1125
1126static DECLCALLBACK(int) drvHostALSAAudioInitIn(PPDMIHOSTAUDIO pInterface,
1127 PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfg,
1128 PDMAUDIORECSOURCE enmRecSource,
1129 uint32_t *pcSamples)
1130{
1131 NOREF(pInterface);
1132 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
1133 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1134
1135 int rc;
1136
1137 PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
1138 snd_pcm_t *phPCM = NULL;
1139
1140 do
1141 {
1142 ALSAAUDIOSTREAMCFG req;
1143 req.fmt = drvHostALSAAudioFmtToALSA(pCfg->enmFormat);
1144 req.freq = pCfg->uHz;
1145 req.nchannels = pCfg->cChannels;
1146 req.period_size = s_ALSAConf.period_size_in;
1147 req.buffer_size = s_ALSAConf.buffer_size_in;
1148
1149 ALSAAUDIOSTREAMCFG obt;
1150 rc = drvHostALSAAudioOpen(true /* fIn */, &req, &obt, &phPCM);
1151 if (RT_FAILURE(rc))
1152 break;
1153
1154 PDMAUDIOFMT enmFormat;
1155 PDMAUDIOENDIANESS enmEnd;
1156 rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
1157 if (RT_FAILURE(rc))
1158 break;
1159
1160 PDMAUDIOSTREAMCFG streamCfg;
1161 streamCfg.uHz = obt.freq;
1162 streamCfg.cChannels = obt.nchannels;
1163 streamCfg.enmFormat = enmFormat;
1164 streamCfg.enmEndianness = enmEnd;
1165
1166 rc = drvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
1167 if (RT_FAILURE(rc))
1168 break;
1169
1170 AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
1171 size_t cbBuf = obt.samples * (1 << pHstStrmIn->Props.cShift);
1172 AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
1173 pThisStrmIn->pvBuf = RTMemAlloc(cbBuf);
1174 if (!pThisStrmIn->pvBuf)
1175 {
1176 LogRel(("ALSA: Not enough memory for input ADC buffer (%RU32 samples, each %d bytes)\n",
1177 obt.samples, 1 << pHstStrmIn->Props.cShift));
1178 rc = VERR_NO_MEMORY;
1179 break;
1180 }
1181
1182 pThisStrmIn->cbBuf = cbBuf;
1183 pThisStrmIn->phPCM = phPCM;
1184
1185 if (pcSamples)
1186 *pcSamples = obt.samples;
1187 }
1188 while (0);
1189
1190 if (RT_FAILURE(rc))
1191 drvHostALSAAudioClose(&phPCM);
1192
1193 LogFlowFuncLeaveRC(rc);
1194 return rc;
1195}
1196
1197static DECLCALLBACK(bool) drvHostALSAAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
1198{
1199 NOREF(pInterface);
1200 NOREF(enmDir);
1201 return true; /* Always all enabled. */
1202}
1203
1204static DECLCALLBACK(int) drvHostALSAAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
1205 PDMAUDIOSTREAMCMD enmStreamCmd)
1206{
1207 NOREF(pInterface);
1208 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
1209 PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
1210
1211 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
1212
1213 int rc;
1214 switch (enmStreamCmd)
1215 {
1216 case PDMAUDIOSTREAMCMD_ENABLE:
1217 rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, false /* fStop */);
1218 break;
1219
1220 case PDMAUDIOSTREAMCMD_DISABLE:
1221 rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, true /* fStop */);
1222 break;
1223
1224 default:
1225 AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
1226 rc = VERR_INVALID_PARAMETER;
1227 break;
1228 }
1229
1230 return rc;
1231}
1232
1233static DECLCALLBACK(int) drvHostALSAAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
1234 PDMAUDIOSTREAMCMD enmStreamCmd)
1235{
1236 NOREF(pInterface);
1237 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
1238 PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
1239
1240 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
1241
1242 int rc;
1243 switch (enmStreamCmd)
1244 {
1245 case PDMAUDIOSTREAMCMD_ENABLE:
1246 rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, false /* fStop */);
1247 break;
1248
1249 case PDMAUDIOSTREAMCMD_DISABLE:
1250 rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, true /* fStop */);
1251 break;
1252
1253 default:
1254 AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
1255 rc = VERR_INVALID_PARAMETER;
1256 break;
1257 }
1258
1259 return rc;
1260}
1261
1262static DECLCALLBACK(int) drvHostALSAAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
1263{
1264 NOREF(pInterface);
1265 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1266
1267 pCfg->cbStreamOut = sizeof(ALSAAUDIOSTREAMOUT);
1268 pCfg->cbStreamIn = sizeof(ALSAAUDIOSTREAMIN);
1269 pCfg->cMaxHstStrmsOut = INT_MAX;
1270 pCfg->cMaxHstStrmsIn = INT_MAX;
1271
1272 return VINF_SUCCESS;
1273}
1274
1275static DECLCALLBACK(void) drvHostALSAAudioShutdown(PPDMIHOSTAUDIO pInterface)
1276{
1277 NOREF(pInterface);
1278}
1279
1280/**
1281 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1282 */
1283static DECLCALLBACK(void *) drvHostALSAAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1284{
1285 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1286 PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
1287 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1288 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
1289
1290 return NULL;
1291}
1292
1293/**
1294 * Construct a DirectSound Audio driver instance.
1295 *
1296 * @copydoc FNPDMDRVCONSTRUCT
1297 */
1298static DECLCALLBACK(int) drvHostAlsaAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1299{
1300 PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
1301 LogRel(("Audio: Initializing ALSA driver\n"));
1302
1303 /*
1304 * Init the static parts.
1305 */
1306 pThis->pDrvIns = pDrvIns;
1307 /* IBase */
1308 pDrvIns->IBase.pfnQueryInterface = drvHostALSAAudioQueryInterface;
1309 /* IHostAudio */
1310 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostALSAAudio);
1311
1312 return VINF_SUCCESS;
1313}
1314
1315/**
1316 * Char driver registration record.
1317 */
1318const PDMDRVREG g_DrvHostALSAAudio =
1319{
1320 /* u32Version */
1321 PDM_DRVREG_VERSION,
1322 /* szName */
1323 "ALSAAudio",
1324 /* szRCMod */
1325 "",
1326 /* szR0Mod */
1327 "",
1328 /* pszDescription */
1329 "ALSA host audio driver",
1330 /* fFlags */
1331 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1332 /* fClass. */
1333 PDM_DRVREG_CLASS_AUDIO,
1334 /* cMaxInstances */
1335 ~0U,
1336 /* cbInstance */
1337 sizeof(DRVHOSTALSAAUDIO),
1338 /* pfnConstruct */
1339 drvHostAlsaAudioConstruct,
1340 /* pfnDestruct */
1341 NULL,
1342 /* pfnRelocate */
1343 NULL,
1344 /* pfnIOCtl */
1345 NULL,
1346 /* pfnPowerOn */
1347 NULL,
1348 /* pfnReset */
1349 NULL,
1350 /* pfnSuspend */
1351 NULL,
1352 /* pfnResume */
1353 NULL,
1354 /* pfnAttach */
1355 NULL,
1356 /* pfnDetach */
1357 NULL,
1358 /* pfnPowerOff */
1359 NULL,
1360 /* pfnSoftReset */
1361 NULL,
1362 /* u32EndVersion */
1363 PDM_DRVREG_VERSION
1364};
1365
1366static struct audio_option alsa_options[] =
1367{
1368 {"DACSizeInUsec", AUD_OPT_BOOL, &s_ALSAConf.size_in_usec_out,
1369 "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
1370 {"DACPeriodSize", AUD_OPT_INT, &s_ALSAConf.period_size_out,
1371 "DAC period size", &s_ALSAConf.period_size_out_overriden, 0},
1372 {"DACBufferSize", AUD_OPT_INT, &s_ALSAConf.buffer_size_out,
1373 "DAC buffer size", &s_ALSAConf.buffer_size_out_overriden, 0},
1374
1375 {"ADCSizeInUsec", AUD_OPT_BOOL, &s_ALSAConf.size_in_usec_in,
1376 "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
1377 {"ADCPeriodSize", AUD_OPT_INT, &s_ALSAConf.period_size_in,
1378 "ADC period size", &s_ALSAConf.period_size_in_overriden, 0},
1379 {"ADCBufferSize", AUD_OPT_INT, &s_ALSAConf.buffer_size_in,
1380 "ADC buffer size", &s_ALSAConf.buffer_size_in_overriden, 0},
1381
1382 {"Threshold", AUD_OPT_INT, &s_ALSAConf.threshold,
1383 "(undocumented)", NULL, 0},
1384
1385 {"DACDev", AUD_OPT_STR, &s_ALSAConf.pcm_name_out,
1386 "DAC device name (for instance dmix)", NULL, 0},
1387
1388 {"ADCDev", AUD_OPT_STR, &s_ALSAConf.pcm_name_in,
1389 "ADC device name", NULL, 0},
1390
1391 NULL
1392};
1393
Note: See TracBrowser for help on using the repository browser.

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