VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvAudio.c@ 50680

Last change on this file since 50680 was 50680, checked in by vboxsync, 11 years ago

VBox/Devices/Audio: New files added as a part of audio restructuring exercise . DrvAudio.c and DrvAudioUtil.c are intermediate driver files and DrvHost* are the host backend drivers (each specific to different platform).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 79.1 KB
Line 
1/* $Id: DrvAudio.c 50680 2014-03-04 16:26:34Z vboxsync $ */
2/** @file
3 * Intermedia audio driver..
4 *
5 * @remarks Intermediate audio driver having audio device as one of the sink and
6 * host backend as other..
7 */
8
9/*
10 * Copyright (C) 2006-2014 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be1 useful, but WITHOUT ANY WARRANTY of any kind.
19 * --------------------------------------------------------------------
20 *
21 * This code is based on: audio.c from QEMU AUDIO subsystem.
22 *
23 * QEMU Audio subsystem
24 *
25 * Copyright (c) 2003-2005 Vassili Karpov (malc)
26 *
27 * Permission is hereby granted, free of charge, to any person obtaining a copy
28 * of this software and associated documentation files (the "Software"), to deal
29 * in the Software without restriction, including without limitation the rights
30 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31 * copies of the Software, and to permit persons to whom the Software is
32 * furnished to do so, subject to the following conditions:
33 *
34 * The above copyright notice and this permission notice shall be included in
35 * all copies or substantial portions of the Software.
36 *
37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
40 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
43 * THE SOFTWARE.
44 */
45
46
47#define LOG_GROUP LOG_GROUP_DEV_AUDIO
48#include <VBox/vmm/pdm.h>
49#include <VBox/err.h>
50#include <VBox/vmm/mm.h>
51#include <VBox/vmm/pdmaudioifs.h>
52
53#include <VBox/log.h>
54#include <iprt/asm-math.h>
55#include <iprt/assert.h>
56#include <iprt/uuid.h>
57#include <iprt/string.h>
58#include <iprt/alloc.h>
59
60#include "VBoxDD.h"
61#include "vl_vbox.h"
62
63#include <ctype.h>
64#include <stdlib.h>
65
66#define AUDIO_CAP "audio"
67#include "DrvAudio.h"
68
69#ifdef RT_OS_WINDOWS
70#define strcasecmp stricmp
71#endif
72
73static struct audio_driver *drvtab[] = {
74#if defined (RT_OS_LINUX) || defined (RT_OS_FREEBSD) || defined(VBOX_WITH_SOLARIS_OSS)
75 &oss_audio_driver,
76#endif
77#ifdef RT_OS_LINUX
78# ifdef VBOX_WITH_PULSE
79 &pulse_audio_driver,
80# endif
81# ifdef VBOX_WITH_ALSA
82 &alsa_audio_driver,
83# endif
84#endif /* RT_OS_LINUX */
85#ifdef RT_OS_FREEBSD
86# ifdef VBOX_WITH_PULSE
87 &pulse_audio_driver,
88# endif
89#endif
90#ifdef RT_OS_DARWIN
91 &coreaudio_audio_driver,
92#endif
93#ifdef RT_OS_WINDOWS
94 &dsound_audio_driver,
95#endif
96#ifdef RT_OS_L4
97 &oss_audio_driver,
98#endif
99#ifdef RT_OS_SOLARIS
100 &solaudio_audio_driver,
101#endif
102 &no_audio_driver
103};
104
105extern t_sample *convAudio;
106extern f_sample *clipAudio;
107
108extern t_sample *convAudioIn;
109extern f_sample *clipAudioIn;
110static char *audio_streamname;
111
112const char *audio_get_stream_name(void)
113{
114 return audio_streamname;
115}
116
117volume_t nominal_volume = {
118 0,
119#ifdef FLOAT_MIXENG
120 1.0,
121 1.0
122#else
123#ifndef VBOX
124 UINT_MAX,
125 UINT_MAX
126#else
127 INT_MAX,
128 INT_MAX
129#endif
130#endif
131};
132
133volume_t sum_out_volume =
134{
135 0,
136 INT_MAX,
137 INT_MAX
138};
139volume_t master_out_volume =
140{
141 0,
142 INT_MAX,
143 INT_MAX
144};
145volume_t pcm_out_volume =
146{
147 0,
148 INT_MAX,
149 INT_MAX
150};
151volume_t pcm_in_volume =
152{
153 0,
154 INT_MAX,
155 INT_MAX
156};
157
158
159/***************** ring buffer Hanlding section **************/
160static void IORingBufferCreate(PIORINGBUFFER *ppBuffer, uint32_t cSize)
161{
162 PIORINGBUFFER pTmpBuffer;
163
164 AssertPtr(ppBuffer);
165
166 *ppBuffer = NULL;
167 pTmpBuffer = RTMemAllocZ(sizeof(IORINGBUFFER));
168 if (pTmpBuffer)
169 {
170 pTmpBuffer->pBuffer = RTMemAlloc(cSize);
171 if(pTmpBuffer->pBuffer)
172 {
173 pTmpBuffer->cBufSize = cSize;
174 *ppBuffer = pTmpBuffer;
175 }
176 else
177 RTMemFree(pTmpBuffer);
178 }
179}
180
181static void IORingBufferDestroy(PIORINGBUFFER pBuffer)
182{
183 if (pBuffer)
184 {
185 if (pBuffer->pBuffer)
186 RTMemFree(pBuffer->pBuffer);
187 RTMemFree(pBuffer);
188 }
189}
190
191DECL_FORCE_INLINE(void) IORingBufferReset(PIORINGBUFFER pBuffer)
192{
193 AssertPtr(pBuffer);
194
195 pBuffer->uReadPos = 0;
196 pBuffer->uWritePos = 0;
197 pBuffer->cBufferUsed = 0;
198}
199
200DECL_FORCE_INLINE(uint32_t) IORingBufferFree(PIORINGBUFFER pBuffer)
201{
202 AssertPtr(pBuffer);
203 return pBuffer->cBufSize - ASMAtomicReadU32(&pBuffer->cBufferUsed);
204}
205
206DECL_FORCE_INLINE(uint32_t) IORingBufferUsed(PIORINGBUFFER pBuffer)
207{
208 AssertPtr(pBuffer);
209 return ASMAtomicReadU32(&pBuffer->cBufferUsed);
210}
211
212DECL_FORCE_INLINE(uint32_t) IORingBufferSize(PIORINGBUFFER pBuffer)
213{
214 AssertPtr(pBuffer);
215 return pBuffer->cBufSize;
216}
217
218static void IORingBufferAquireReadBlock(PIORINGBUFFER pBuffer, uint32_t cReqSize, char **ppStart, uint32_t *pcSize)
219{
220 uint32_t uUsed = 0;
221 uint32_t uSize = 0;
222
223 AssertPtr(pBuffer);
224
225 *ppStart = 0;
226 *pcSize = 0;
227
228 /* How much is in use? */
229 uUsed = ASMAtomicReadU32(&pBuffer->cBufferUsed);
230 if (uUsed > 0)
231 {
232 /* Get the size out of the requested size, the read block till the end
233 * of the buffer & the currently used size. */
234 uSize = RT_MIN(cReqSize, RT_MIN(pBuffer->cBufSize - pBuffer->uReadPos, uUsed));
235 if (uSize > 0)
236 {
237 /* Return the pointer address which point to the current read
238 * position. */
239 *ppStart = pBuffer->pBuffer + pBuffer->uReadPos;
240 *pcSize = uSize;
241 }
242 }
243}
244
245DECL_FORCE_INLINE(void) IORingBufferReleaseReadBlock(PIORINGBUFFER pBuffer, uint32_t cSize)
246{
247 AssertPtr(pBuffer);
248
249 /* Split at the end of the buffer. */
250 pBuffer->uReadPos = (pBuffer->uReadPos + cSize) % pBuffer->cBufSize;
251 ASMAtomicSubU32(&pBuffer->cBufferUsed, cSize);
252}
253
254static void IORingBufferAquireWriteBlock(PIORINGBUFFER pBuffer, uint32_t cReqSize, char **ppStart, uint32_t *pcSize)
255{
256 uint32_t uFree;
257 uint32_t uSize;
258
259 AssertPtr(pBuffer);
260
261 *ppStart = 0;
262 *pcSize = 0;
263
264 /* How much is free? */
265 uFree = pBuffer->cBufSize - ASMAtomicReadU32(&pBuffer->cBufferUsed);
266 if (uFree > 0)
267 {
268 /* Get the size out of the requested size, the write block till the end
269 * of the buffer & the currently free size. */
270 uSize = RT_MIN(cReqSize, RT_MIN(pBuffer->cBufSize - pBuffer->uWritePos, uFree));
271 if (uSize > 0)
272 {
273 /* Return the pointer address which point to the current write
274 * position. */
275 *ppStart = pBuffer->pBuffer + pBuffer->uWritePos;
276 *pcSize = uSize;
277 }
278 }
279}
280
281DECL_FORCE_INLINE(void) IORingBufferReleaseWriteBlock(PIORINGBUFFER pBuffer, uint32_t cSize)
282{
283 AssertPtr(pBuffer);
284
285 /* Split at the end of the buffer. */
286 pBuffer->uWritePos = (pBuffer->uWritePos + cSize) % pBuffer->cBufSize;
287
288 ASMAtomicAddU32(&pBuffer->cBufferUsed, cSize);
289}
290
291/****************** Ring Buffer Function Ends *****************/
292
293/* http://www.df.lth.se/~john_e/gems/gem002d.html */
294/* http://www.multi-platforms.com/Tips/PopCount.htm */
295uint32_t popcount (uint32_t u)
296{
297 u = ((u&0x55555555) + ((u>>1)&0x55555555));
298 u = ((u&0x33333333) + ((u>>2)&0x33333333));
299 u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
300 u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
301 u = ( u&0x0000ffff) + (u>>16);
302 return u;
303}
304uint32_t lsbindex (uint32_t u)
305{
306 return popcount ((u&-u)-1);
307}
308uint64_t audio_get_clock (void)
309{
310 return PDMDrvHlpTMGetVirtualTime (gpDrvIns);
311}
312uint64_t audio_get_ticks_per_sec (void)
313{
314 return PDMDrvHlpTMGetVirtualFreq (gpDrvIns);
315}
316
317inline int audio_bits_to_index (int bits)
318{
319 switch (bits) {
320 case 8:
321 return 0;
322
323 case 16:
324 return 1;
325
326 case 32:
327 return 2;
328
329 default:
330 LogFlow(("invalid bits %d\n", bits));
331 return 0;
332 }
333}
334
335static const char *audio_audfmt_to_string (audfmt_e fmt)
336{
337 switch (fmt) {
338 case AUD_FMT_U8:
339 return "U8";
340
341 case AUD_FMT_U16:
342 return "U16";
343
344 case AUD_FMT_U32:
345 return "U32";
346
347 case AUD_FMT_S8:
348 return "S8";
349
350 case AUD_FMT_S16:
351 return "S16";
352
353 case AUD_FMT_S32:
354 return "S32";
355 }
356
357 LogFlow(("Bogus audfmt %d returning S16\n", fmt));
358 return "S16";
359}
360
361static audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp)
362{
363 if (!strcasecmp (s, "u8")) {
364 *defaultp = 0;
365 return AUD_FMT_U8;
366 }
367 else if (!strcasecmp (s, "u16")) {
368 *defaultp = 0;
369 return AUD_FMT_U16;
370 }
371 else if (!strcasecmp (s, "u32")) {
372 *defaultp = 0;
373 return AUD_FMT_U32;
374 }
375 else if (!strcasecmp (s, "s8")) {
376 *defaultp = 0;
377 return AUD_FMT_S8;
378 }
379 else if (!strcasecmp (s, "s16")) {
380 *defaultp = 0;
381 return AUD_FMT_S16;
382 }
383 else if (!strcasecmp (s, "s32")) {
384 *defaultp = 0;
385 return AUD_FMT_S32;
386 }
387 else {
388 LogFlow(("Bogus audio format `%s' using %s\n",
389 s, audio_audfmt_to_string (defval)));
390 *defaultp = 1;
391 return defval;
392 }
393}
394
395static audfmt_e drvAudioGetConfFormat(PCFGMNODE pCfgHandle, const char *envname, audfmt_e defval, int *defaultp)
396{
397 char *var = NULL;
398 int rc;
399
400 if(pCfgHandle == NULL || envname == NULL) {
401 *defaultp = 1;
402 return defval;
403 }
404
405 rc = CFGMR3QueryStringAlloc(pCfgHandle, envname, &var);
406 if (RT_FAILURE (rc)) {
407 *defaultp = 1;
408 return defval;
409 }
410 return audio_string_to_audfmt (var, defval, defaultp);
411}
412
413static int drvAudioGetConfInt(PCFGMNODE pCfgHandle, const char *key, int defval, int *defaultp)
414{
415 int rc;
416 uint64_t u64Data = 0;
417 if(pCfgHandle == NULL || key == NULL) {
418 *defaultp = 1;
419 return defval;
420 }
421
422 *defaultp = 0;
423 rc = CFGMR3QueryInteger(pCfgHandle, key, &u64Data);
424 if (RT_FAILURE (rc))
425 {
426 *defaultp = 1;
427 return defval;
428
429 }
430 else
431 {
432 LogFlow(("%s, Value = %d\n", key, u64Data));
433 *defaultp = 0;
434 return u64Data;
435 }
436}
437
438static const char *drvAudioGetConfStr(PCFGMNODE pCfgHandle, const char *key, const char *defval, int *defaultp)
439{
440 char *val = NULL;
441 int rc;
442 if(pCfgHandle == NULL || key == NULL) {
443 *defaultp = 1;
444 return defval;
445 }
446
447 rc = CFGMR3QueryStringAlloc(pCfgHandle, key, &val);
448 if (RT_FAILURE (rc)) {
449 *defaultp = 1;
450 return defval;
451 }
452 else {
453 *defaultp = 0;
454 return val;
455 }
456}
457
458static void drvAudioProcessOptions(PCFGMNODE pCfgHandle, const char *prefix, struct audio_option *opt)
459{
460 int def;
461 PCFGMNODE pCfgChildHandle = NULL;
462 PCFGMNODE pCfgChildChildHandle = NULL;
463
464 if (!prefix || !opt)
465 {
466 LogFlow(("prefix = NULL OR opt = NULL\n"));
467 return;
468 }
469
470 /* if pCfgHandle is NULL, let NULL be passed to get int and get string functions..
471 * The getter function will return default values.
472 */
473 if(pCfgHandle != NULL)
474 {
475 /* If its audio general setting, need to traverse to one child node.
476 * /Devices/ichac97/0/LUN#0/Config/Audio
477 */
478 if(!strncmp(prefix, "AUDIO", 5)) {
479 pCfgChildHandle = CFGMR3GetFirstChild(pCfgHandle);
480 if(pCfgChildHandle) {
481 pCfgHandle = pCfgChildHandle;
482 }
483 }
484 else
485 {
486 /* If its driver specific configuration , then need to traverse two level deep child
487 * child nodes. for eg. in case of DirectSoundConfiguration item
488 * /Devices/ichac97/0/LUN#0/Config/Audio/DirectSoundConfig
489 */
490 pCfgChildHandle = CFGMR3GetFirstChild(pCfgHandle);
491 if (pCfgChildHandle) {
492 pCfgChildChildHandle = CFGMR3GetFirstChild(pCfgChildHandle);
493 if(pCfgChildChildHandle) {
494 pCfgHandle = pCfgChildChildHandle;
495 }
496 }
497 }
498 }
499
500
501 for (; opt->name; opt++) {
502 LogFlow(("Option value pointer for `%s' is not set\n",
503 opt->name));
504 if (!opt->valp) {
505 LogFlow(("Option value pointer for `%s' is not set\n",
506 opt->name));
507 continue;
508 }
509 def = 1;
510 switch (opt->tag) {
511 case AUD_OPT_BOOL:
512 case AUD_OPT_INT:
513 {
514 int *intp = opt->valp;
515 *intp = drvAudioGetConfInt(pCfgHandle, opt->name, *intp, &def);
516 }
517 break;
518
519 case AUD_OPT_FMT:
520 {
521 audfmt_e *fmtp = opt->valp;
522 *fmtp = drvAudioGetConfFormat(pCfgHandle, opt->name, *fmtp, &def);
523 }
524 break;
525
526 case AUD_OPT_STR:
527 {
528 const char **strp = opt->valp;
529 *strp = drvAudioGetConfStr(pCfgHandle, opt->name, *strp, &def);
530 }
531 break;
532
533 default:
534 LogFlow(("Bad value tag for option `%s' - %d\n",
535 opt->name, opt->tag));
536 break;
537 }
538
539 if (!opt->overridenp) {
540 opt->overridenp = &opt->overriden;
541 }
542 *opt->overridenp = !def;
543 }
544}
545
546static void drvAudioPrintSettings(audsettings_t *as)
547{
548 LogFlow(("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels));
549
550 switch (as->fmt) {
551 case AUD_FMT_S8:
552 LogFlow(("S8\n"));
553 break;
554 case AUD_FMT_U8:
555 LogFlow(("U8\n"));
556 break;
557 case AUD_FMT_S16:
558 LogFlow(("S16\n"));
559 break;
560 case AUD_FMT_U16:
561 LogFlow(("U16\n"));
562 break;
563 case AUD_FMT_S32:
564 LogFlow(("S32\n"));
565 break;
566 case AUD_FMT_U32:
567 LogFlow(("U32\n"));
568 break;
569 default:
570 LogFlow(("invalid(%d)\n", as->fmt));
571 break;
572 }
573
574 LogFlow(("endianness=\n"));
575 switch (as->endianness)
576 {
577 case 0:
578 LogFlow(("little\n"));
579 break;
580 case 1:
581 LogFlow(("big\n"));
582 break;
583 default:
584 LogFlow(("invalid\n"));
585 break;
586 }
587}
588
589static int drvAudioValidateSettings(audsettings_t *as)
590{
591 int invalid;
592
593 invalid = as->nchannels != 1 && as->nchannels != 2;
594 invalid |= as->endianness != 0 && as->endianness != 1;
595
596 switch (as->fmt) {
597 case AUD_FMT_S8:
598 case AUD_FMT_U8:
599 case AUD_FMT_S16:
600 case AUD_FMT_U16:
601 case AUD_FMT_S32:
602 case AUD_FMT_U32:
603 break;
604 default:
605 invalid = 1;
606 break;
607 }
608
609 invalid |= as->freq <= 0;
610 return invalid ? -1 : 0;
611}
612
613int drvAudioPcmInfoEq(PDMPCMPROPERTIES * pProps, audsettings_t *as)
614{
615 int bits = 8, sign = 0;
616
617 switch (as->fmt) {
618 case AUD_FMT_S8:
619 sign = 1;
620 case AUD_FMT_U8:
621 break;
622
623 case AUD_FMT_S16:
624 sign = 1;
625 case AUD_FMT_U16:
626 bits = 16;
627 break;
628
629 case AUD_FMT_S32:
630 sign = 1;
631 case AUD_FMT_U32:
632 bits = 32;
633 break;
634 }
635 return pProps->uFrequency == as->freq
636 && pProps->cChannels == as->nchannels
637 && pProps->fSigned == sign
638 && pProps->cBits == bits
639 && pProps->fSwapEndian == (as->endianness != AUDIO_HOST_ENDIANNESS);
640}
641
642void drvAudioPcmInitInfo(PDMPCMPROPERTIES * pProps, audsettings_t *as)
643{
644 int bits = 8, sign = 0, shift = 0;
645
646 switch (as->fmt) {
647 case AUD_FMT_S8:
648 sign = 1;
649 case AUD_FMT_U8:
650 break;
651
652 case AUD_FMT_S16:
653 sign = 1;
654 case AUD_FMT_U16:
655 bits = 16;
656 shift = 1;
657 break;
658
659 case AUD_FMT_S32:
660 sign = 1;
661 case AUD_FMT_U32:
662 bits = 32;
663 shift = 2;
664 break;
665 }
666
667 pProps->uFrequency = as->freq;
668 pProps->cBits = bits;
669 pProps->fSigned = sign;
670 pProps->cChannels = as->nchannels;
671 pProps->cShift = (as->nchannels == 2) + shift;
672 pProps->fAlign = (1 << pProps->cShift) - 1;
673 pProps->cbPerSec = pProps->uFrequency << pProps->cShift;
674 pProps->fSwapEndian = (as->endianness != AUDIO_HOST_ENDIANNESS);
675}
676
677void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
678{
679 if (!len) {
680 return;
681 }
682
683 if (info->sign) {
684 memset (buf, 0x00, len << info->shift);
685 }
686 else {
687 switch (info->bits) {
688 case 8:
689 memset (buf, 0x80, len << info->shift);
690 break;
691
692 case 16:
693 {
694 int i;
695 uint16_t *p = buf;
696 int shift = info->nchannels - 1;
697 short s = INT16_MAX;
698
699 if (info->swap_endianness) {
700 s = bswap16 (s);
701 }
702
703 for (i = 0; i < len << shift; i++) {
704 p[i] = s;
705 }
706 }
707 break;
708
709 case 32:
710 {
711 int i;
712 uint32_t *p = buf;
713 int shift = info->nchannels - 1;
714 int32_t s = INT32_MAX;
715
716 if (info->swap_endianness) {
717 s = bswap32 (s);
718 }
719
720 for (i = 0; i < len << shift; i++) {
721 p[i] = s;
722 }
723 }
724 break;
725
726 default:
727 LogFlow(("audio_pcm_info_clear_buf: invalid bits %d\n", info->bits));
728 break;
729 }
730 }
731}
732
733/*
734 * Capture
735 */
736static void noop_conv (st_sample_t *dst, const void *src, int samples, volume_t *vol)
737{
738 (void) src;
739 (void) dst;
740 (void) samples;
741 (void) vol;
742}
743
744static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled)
745{
746 if (cap->hw.fEnabled != enabled)
747 {
748 audcnotification_e cmd;
749 cap->hw.fEnabled = enabled;
750 cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE;
751 }
752}
753
754static void drvAudioRecalcAndNotifyCapture(CaptureVoiceOut *cap)
755{
756 PPDMHOSTVOICEOUT hw = &cap->hw;
757 PPDMGSTVOICEOUT sw;
758 PPDMGSTVOICEOUT pIter;
759 int enabled = 0;
760 LogFlow(("drvAudioRecalcAndNotifyCaptuer \n"));
761
762 RTListForEach(&hw->HeadGstVoiceOut, pIter, PDMGSTVOICEOUT, ListGstVoiceOut)
763 {
764 sw = pIter;
765 LogFlow(("1\n"));
766 if (sw->State.fActive) {
767 enabled = 1;
768 break;
769 }
770 }
771 audio_capture_maybe_changed (cap, enabled);
772}
773
774void drvAudioDetachCapture(PPDMHOSTVOICEOUT pHostVoiceOut)
775{
776 SWVoiceCap * sc;
777 SWVoiceCap *pIter;
778 LogFlow(("drvAudioDetachCapture \n"));
779 RTListForEach(&pHostVoiceOut->HeadCapturedVoice, pIter, SWVoiceCap, ListCapturedVoice)
780 {
781 sc = pIter;
782 PPDMGSTVOICEOUT sw = &sc->sw;
783 CaptureVoiceOut *cap = sc->cap;
784 int was_active = sw->State.fActive;
785
786 if (sw->State.rate) {
787 st_rate_stop (sw->State.rate);
788 sw->State.rate = NULL;
789 }
790
791 while (!RTListIsEmpty(&sw->ListGstVoiceOut))
792 {
793 PPDMGSTVOICEOUT pIterTmp = RTListGetFirst(&sw->ListGstVoiceOut, PDMGSTVOICEOUT, ListGstVoiceOut);
794 RTListNodeRemove(&pIterTmp->ListGstVoiceOut);
795 }
796
797 while (!RTListIsEmpty(&sc->ListCapturedVoice))
798 {
799 SWVoiceCap * pIterTmp = RTListGetFirst(&sc->ListCapturedVoice, SWVoiceCap, ListCapturedVoice);
800 RTListNodeRemove(&pIterTmp->ListCapturedVoice);
801 }
802
803 if (was_active) {
804 /* We have removed soft voice from the capture:
805 this might have changed the overall status of the capture
806 since this might have been the only active voice */
807 drvAudioRecalcAndNotifyCapture(cap);
808 }
809 }
810}
811
812int drvAudioAttachCapture(PDRVAUDIO pDrvAudio, PPDMHOSTVOICEOUT pHostVoiceOut)
813{
814 CaptureVoiceOut *cap;
815 CaptureVoiceOut *pIter;
816
817 drvAudioDetachCapture(pHostVoiceOut);
818 RTListForEach(&pDrvAudio->HeadCapturedVoice, pIter, CaptureVoiceOut, ListCapturedVoice)
819 {
820 SWVoiceCap *sc;
821 PPDMGSTVOICEOUT pGstVoiceOut;
822 cap = pIter;
823 PPDMHOSTVOICEOUT hw_cap = &cap->hw;
824 sc = (SWVoiceCap*) RTMemAllocZ(1 * sizeof (SWVoiceCap));
825 if (!sc)
826 {
827 LogFlow(("Could not allocate soft capture voice (%u bytes)\n",
828 sizeof (*sc)));
829 return -1;
830 }
831
832 sc->cap = cap;
833 pGstVoiceOut = &sc->sw;
834 pGstVoiceOut->pHostVoiceOut = hw_cap;
835 pGstVoiceOut->Props = pHostVoiceOut->Props;
836 pGstVoiceOut->State.fEmpty = 1;
837 pGstVoiceOut->State.fActive = pHostVoiceOut->fEnabled;
838 LogFlow(("DrvAudio: setting gstvoiceout ratio. Freq=%d and Frew=%d",
839 hw_cap->Props.uFrequency, pGstVoiceOut->Props.uFrequency ));
840 pGstVoiceOut->State.ratio = ((int64_t) hw_cap->Props.uFrequency << 32) / pGstVoiceOut->Props.uFrequency;
841 pGstVoiceOut->State.rate = st_rate_start (pGstVoiceOut->Props.uFrequency, hw_cap->Props.uFrequency);
842 if (!pGstVoiceOut->State.rate)
843 {
844 LogFlow(("Error Could not start rate conversion \n"));
845 RTMemFree(pGstVoiceOut);
846 return -1;
847 }
848 RTListPrepend(&hw_cap->HeadGstVoiceOut, &pGstVoiceOut->ListGstVoiceOut);
849 RTListPrepend(&pHostVoiceOut->HeadCapturedVoice, &sc->ListCapturedVoice);
850 if (pGstVoiceOut->State.fActive)
851 {
852 audio_capture_maybe_changed (cap, 1);
853 }
854 }
855 return 0;
856}
857
858/*
859 * Hard voice (capture)
860 */
861static int audio_pcm_hw_find_min_in (PPDMHOSTVOICEIN hw)
862{
863 PPDMGSTVOICEIN pIter = NULL;
864 PPDMGSTVOICEIN pGstVoiceIn = NULL;
865 int m = hw->cSamplesCaptured;
866
867 RTListForEach(&hw->HeadGstVoiceIn, pIter, PDMGSTVOICEIN, ListGstVoiceIn)
868 {
869 pGstVoiceIn = pIter;
870 LogFlow(("DrvAudio: pGstVioceIn = %p\n", pGstVoiceIn));
871 if (pGstVoiceIn->State.fActive)
872 {
873 m = audio_MIN (m, pGstVoiceIn->cHostSamplesAcquired);
874 }
875 }
876 return m;
877}
878
879int audio_pcm_hw_get_live_in (PPDMHOSTVOICEIN hw)
880{
881 int live = hw->cSamplesCaptured - audio_pcm_hw_find_min_in (hw);
882 if (live < 0 || live > hw->cSamples)
883 {
884 LogFlow(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
885 return 0;
886 }
887 return live;
888}
889
890/*
891 * Soft voice (capture)
892 */
893static int audio_pcm_sw_get_rpos_in (PPDMGSTVOICEIN sw)
894{
895 PPDMHOSTVOICEIN hw = sw->hw;
896 int live = hw->cSamplesCaptured - sw->cHostSamplesAcquired;
897 int rpos;
898
899 if (live < 0 || live > hw->cSamples)
900 {
901 LogFlow(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
902 return 0;
903 }
904
905 rpos = hw->offWrite - live;
906 if (rpos >= 0) {
907 return rpos;
908 }
909 else {
910 return hw->cSamples + rpos;
911 }
912}
913
914int audio_pcm_sw_read (PDRVAUDIO pThis, PPDMGSTVOICEIN sw, PPDMHOSTSTEREOSAMPLE buf, int size)
915{
916 PPDMHOSTVOICEIN hw = sw->hw;
917 int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
918 PPDMHOSTSTEREOSAMPLE src, dst = sw->buf;
919 PPDMHOSTSTEREOSAMPLE tmp = sw->buf;
920 PPDMHOSTSTEREOSAMPLE pSampleBuf;
921 char *pcDst = NULL;
922 char *pcSrc = NULL;
923 uint32_t cbToWrite;
924 uint32_t csAvail = 0;
925 uint32_t cSamplesRead = 0;
926 uint32_t cbToRead = 0;
927 uint32_t csWritten = 0;
928 uint32_t cSamplesInRingBuffer = 0;
929 uint32_t csToWrite;
930 uint32_t csLimit;
931
932 /* Max capacity to hold 1000 PDMHOSTSTERESAMPLE type samples. */
933 pSampleBuf = (PPDMHOSTSTEREOSAMPLE) RTMemAlloc(1000 * sizeof(PDMHOSTSTEREOSAMPLE));
934 rpos = audio_pcm_sw_get_rpos_in (sw) % hw->cSamples;
935
936 /* difference between how many samples have be captured/read by the host and how
937 * many have been transferred to guest (guest physical memory) to be utilized by the guest
938 * eg skype on guest or saving samples in file in guest.
939 */
940 live = hw->cSamplesCaptured - sw->cHostSamplesAcquired;
941 if (live < 0 || live > hw->cSamples)
942 {
943 LogFlow(("Error: live_in=%d hw->samples=%d\n", live, hw->cSamples));
944 return 0;
945 }
946
947 samples = size >> sw->Props.cShift;
948 if (!live)
949 {
950 LogFlow(("DrvAudio: Error: No Live data \n"));
951 return 0;
952 }
953
954 swlim = (live * sw->State.ratio) >> 32;
955 csLimit = swlim;
956 swlim = audio_MIN (swlim, samples);
957 while (swlim)
958 {
959 src = hw->pConversionBuf + rpos;
960 isamp = hw->offWrite - rpos;
961 /* XXX: <= ? */
962 if (isamp <= 0)
963 isamp = hw->cSamples - rpos;
964
965 if (!isamp)
966 break;
967
968 osamp = swlim;
969 if (osamp < 0)
970 {
971 LogFlow(("Error: osamp=%d\n", osamp));
972 return 0;
973 }
974
975 if (ret + osamp > sw->buf_samples)
976 Log(("audio_pcm_sw_read: buffer overflow!! ret = %d, osamp = %d, buf_samples = %d\n",
977 ret, osamp, sw->buf_samples));
978 st_rate_flow (sw->State.rate, src, dst, &isamp, &osamp);
979 swlim -= osamp;
980 rpos = (rpos + isamp) % hw->cSamples;
981 dst += osamp;
982 ret += osamp;
983 total += isamp;
984 }
985 sw->cHostSamplesAcquired = sw->cHostSamplesAcquired + total;
986 if (csLimit >= samples)
987 {
988 /* read audio that is there in the ring buffer */
989 cSamplesInRingBuffer = IORingBufferUsed(pThis->pAudioReadBuf) / sizeof(PDMHOSTSTEREOSAMPLE);
990 if (cSamplesInRingBuffer >= 45000) /* 750 K Buffer / sizeof(PDMHOSTSTEREOSAMPLE)*/
991 {
992 IORingBufferReset(pThis->pAudioReadBuf);
993 cSamplesInRingBuffer = 0;
994 }
995 if (cSamplesInRingBuffer > samples)
996 cSamplesInRingBuffer = samples;
997 cSamplesRead = 0, cbToRead = 0;
998 while (cSamplesRead < cSamplesInRingBuffer)
999 {
1000 cbToRead = cSamplesInRingBuffer * sizeof(PDMHOSTSTEREOSAMPLE);
1001 IORingBufferAquireReadBlock(pThis->pAudioReadBuf, cbToRead,
1002 &pcSrc, &cbToRead);
1003 if (!cbToRead)
1004 LogFlow(("DrvAudio: There are no audio in queue to be written. \n"));
1005 memcpy((uint8_t *)pSampleBuf, pcSrc, cbToRead);
1006 cSamplesRead = cSamplesRead + (cbToRead / sizeof(PDMHOSTSTEREOSAMPLE));
1007 /* Release the read buffer, so it could be used for new data. */
1008 IORingBufferReleaseReadBlock(pThis->pAudioReadBuf, cbToRead);
1009 }
1010 memcpy((uint8_t *)pSampleBuf + cbToRead, (uint8_t *)sw->buf,
1011 (samples - cSamplesRead) * sizeof(PDMHOSTSTEREOSAMPLE));
1012
1013 memcpy((uint8_t *)buf, (uint8_t *)pSampleBuf, samples * sizeof(PDMHOSTSTEREOSAMPLE));
1014
1015 csToWrite = ret - (samples - cSamplesRead);
1016 csAvail = IORingBufferFree(pThis->pAudioReadBuf) / sizeof(PDMHOSTSTEREOSAMPLE);
1017 csWritten = 0;
1018 while (csWritten < csToWrite)
1019 {
1020 cbToWrite = csToWrite * sizeof(PDMHOSTSTEREOSAMPLE);
1021 IORingBufferAquireWriteBlock(pThis->pAudioReadBuf, cbToWrite, &pcDst, &cbToWrite);
1022
1023 csToWrite = cbToWrite / sizeof(PDMHOSTSTEREOSAMPLE);
1024 if (RT_UNLIKELY(csToWrite == 0))
1025 {
1026 IORingBufferReleaseWriteBlock(pThis->pAudioReadBuf, cbToWrite);
1027 IORingBufferReset(pThis->pAudioReadBuf);
1028 LogFlow(("DrvAudio: NO space in Ring buffer. Not doing anything, just discarding samples.\n"));
1029 }
1030
1031 /* copy the audio data not accepted by the backend to the ring buffer */
1032 memcpy(pcDst, (uint8_t*)sw->buf + ((samples - cSamplesRead) * sizeof(PDMHOSTSTEREOSAMPLE)) +
1033 (csWritten * sizeof(PDMHOSTSTEREOSAMPLE)), cbToWrite);
1034 IORingBufferReleaseWriteBlock(pThis->pAudioReadBuf, cbToWrite);
1035 csWritten += csToWrite;
1036 }
1037 return samples << sw->Props.cShift;
1038 }
1039 else if (csLimit < samples && csLimit != 0)
1040 {
1041 csAvail = IORingBufferFree(pThis->pAudioReadBuf) / sizeof(PDMHOSTSTEREOSAMPLE);
1042 csWritten = 0;
1043 while (csWritten < ret)
1044 {
1045 csToWrite = ret - csWritten;
1046 cbToWrite = csToWrite * sizeof(PDMHOSTSTEREOSAMPLE);
1047 IORingBufferAquireWriteBlock(pThis->pAudioReadBuf, cbToWrite, &pcDst, &cbToWrite);
1048
1049 csToWrite = cbToWrite / sizeof(PDMHOSTSTEREOSAMPLE);
1050 if (RT_UNLIKELY(csToWrite == 0))
1051 LogFlow(("DrvAudio: NO space in Ring buffer. Not doing anything, just discarding samples.\n"));
1052
1053 /* copy the audio data not accepted by the backend to the ring buffer */
1054 memcpy(pcDst, (uint8_t*)sw->buf + (csWritten * sizeof(PDMHOSTSTEREOSAMPLE)), cbToWrite);
1055 IORingBufferReleaseWriteBlock(pThis->pAudioReadBuf, cbToWrite);
1056 csWritten += csToWrite;
1057 }
1058 memcpy(buf, pSampleBuf, 0);
1059 return 0;
1060 }
1061 return 0;
1062}
1063
1064/*
1065 * Hard voice (playback)
1066 */
1067static int audio_pcm_hw_find_min_out (PPDMHOSTVOICEOUT hw, int *nb_livep)
1068{
1069 PPDMGSTVOICEOUT sw;
1070 PPDMGSTVOICEOUT pIter;
1071 int m = INT_MAX;
1072 int nb_live = 0;
1073 LogFlow(("Hard Voice Playback \n"));
1074
1075 RTListForEach(&hw->HeadGstVoiceOut, pIter, PDMGSTVOICEOUT, ListGstVoiceOut)
1076 {
1077 sw = pIter;
1078 if (sw->State.fActive || !sw->State.fEmpty)
1079 {
1080 m = audio_MIN (m, sw->cSamplesMixed);
1081 nb_live += 1;
1082 }
1083 }
1084
1085 *nb_livep = nb_live;
1086 return m;
1087}
1088
1089int audio_pcm_hw_get_live_out2 (PPDMHOSTVOICEOUT hw, int *nb_live)
1090{
1091 int smin;
1092
1093 smin = audio_pcm_hw_find_min_out (hw, nb_live);
1094
1095 if (!*nb_live) {
1096 return 0;
1097 }
1098 else
1099 {
1100 int live = smin;
1101
1102 if (live < 0 || live > hw->cSamples)
1103 {
1104 LogFlow(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
1105 return 0;
1106 }
1107 return live;
1108 }
1109}
1110
1111int audio_pcm_hw_get_live_out (PPDMHOSTVOICEOUT hw)
1112{
1113 int nb_live;
1114 int live;
1115
1116 live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
1117 if (live < 0 || live > hw->cSamples)
1118 {
1119 LogFlow(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
1120 return 0;
1121 }
1122 return live;
1123}
1124
1125#if 0
1126/*
1127 * Soft voice (playback)
1128 */
1129int audio_pcm_sw_write (PDRVAUDIO pThis,PPDMGSTVOICEOUT pGstVoiceOut, void *buf, int size)
1130{
1131 int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
1132 int ret = 0, pos = 0, total = 0;
1133
1134 if (!pGstVoiceOut) {
1135 return size;
1136 }
1137
1138 hwsamples = pGstVoiceOut->pHostVoiceOut->cSamples;
1139 LogFlow(("DrvAudio: hwSamples = %d\n", hwsamples));
1140
1141 live = pGstVoiceOut->cSamplesMixed;
1142 if (live < 0 || live > hwsamples)
1143 {
1144 LogFlow(("Error: live=%d hw->samples=%d\n", live, hwsamples));
1145 return size;
1146 }
1147
1148 if (live == hwsamples) {
1149 LogFlow(("DrvAudio: full %d\n", live));
1150 return size;
1151 }
1152
1153 wpos = (pGstVoiceOut->pHostVoiceOut->offRead + live) % hwsamples;
1154 samples = size >> pGstVoiceOut->Props.cShift;
1155
1156 dead = hwsamples - live;
1157 swlim = ((int64_t) dead << 32) / pGstVoiceOut->State.ratio;
1158 swlim = audio_MIN (swlim, samples);
1159 if (swlim > pGstVoiceOut->cSamples)
1160 Log(("audio_pcm_sw_write: buffer overflow!! swlim = %d, buf_samples = %d\n",
1161 swlim, pos, pGstVoiceOut->cSamples));
1162 //swlim = samples;
1163 if (swlim) {
1164 convAudio (pGstVoiceOut->buf, buf, swlim, &sum_out_volume);
1165 }
1166
1167 while (swlim)
1168 {
1169 dead = hwsamples - live;
1170 left = hwsamples - wpos;
1171 blck = audio_MIN (dead, left);
1172 if (!blck) {
1173 break;
1174 }
1175 isamp = swlim;
1176 osamp = blck;
1177 //osamp = left;
1178 if (pos + isamp > pGstVoiceOut->cSamples)
1179 Log(("audio_pcm_sw_write: buffer overflow!! isamp = %d, pos = %d, buf_samples = %d\n",
1180 isamp, pos, pGstVoiceOut->cSamples));
1181 st_rate_flow_mix (
1182 pGstVoiceOut->State.rate,
1183 pGstVoiceOut->buf + pos,
1184 pGstVoiceOut->pHostVoiceOut->pHostSterioSampleBuf + wpos,
1185 &isamp,
1186 &osamp
1187 );
1188 ret += isamp;
1189 swlim -= isamp;
1190 pos += isamp;
1191 live += osamp;
1192 wpos = (wpos + osamp) % hwsamples;
1193 total += osamp;
1194 }
1195
1196 pGstVoiceOut->cSamplesMixed += total;
1197 pGstVoiceOut->State.fEmpty = pGstVoiceOut->cSamplesMixed == 0;
1198
1199 LogFlow((
1200 "write size %d ret %d total sw %d\n",
1201 size >> pGstVoiceOut->Props.cShift,
1202 ret,
1203 pGstVoiceOut->cSamplesMixed
1204 ));
1205
1206 //return ret << pGstVoiceOut->Props.cShift;
1207 return size;
1208}
1209#endif
1210
1211/*
1212 * Soft voice (playback)
1213 */
1214int audio_pcm_sw_write(PDRVAUDIO pThis, PPDMGSTVOICEOUT pGstVoiceOut, void *buf, int size)
1215{
1216 int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
1217 int ret = 0, pos = 0, total = 0;
1218 uint8_t *pcDst = NULL;
1219 uint8_t *pcSrc = NULL;
1220 uint32_t cbToWrite;
1221 uint32_t cSamplesInQueue = 0;
1222 uint32_t cbSamplesInQueue = 0;
1223 uint32_t cbTotalSamples = 0;
1224 uint32_t cTotalSamples = 0;
1225 uint32_t cSamplesAccepted = 0;
1226 /* sample buf to hold the samples that have been passed from Device and to hold samples from the queue
1227 * 500 KB.
1228 */
1229 uint8_t SampleBuf[512000];
1230 PDMHOSTSTEREOSAMPLE pdmSampleBuf[5120];
1231 uint32_t cSamplesLeft;
1232
1233 if (!pGstVoiceOut)
1234 {
1235 LogFlow(("DrvAudio: GstVoiceOut NULL \n"));
1236 return size;
1237 }
1238 LogFlow(("DrvAudio: size to write = %d\n", size));
1239
1240 hwsamples = pGstVoiceOut->pHostVoiceOut->cSamples;
1241
1242 live = pGstVoiceOut->cSamplesMixed;
1243 if (live < 0 || live > hwsamples)
1244 {
1245 /* save all the samples in the ring buffer, and return as if all the samples have been accepted.
1246 * Saving in ring buffer as host buffer is full and can't take any more samples.
1247 */
1248 cbToWrite = size;
1249 LogFlow(("DrvAudio: Error: live=%d hw->samples=%d\n", live, hwsamples));
1250 //return 0
1251 IORingBufferAquireWriteBlock(pThis->pAudioWriteBuf, cbToWrite, &pcDst, &cbToWrite);
1252 if (RT_UNLIKELY(cbToWrite == 0))
1253 LogFlow(("DrvAudio: NO space in Ring buffer. Not doing anything, just discarding samples.\n"));
1254
1255 /* copy the audio data not accepted by the backend to the ring buffer */
1256 memcpy(pcDst, (uint8_t*)buf , cbToWrite);
1257
1258 /* Rlease the ring buffer */
1259 IORingBufferReleaseWriteBlock(pThis->pAudioWriteBuf, cbToWrite);
1260 return size;
1261 }
1262
1263 if (live == hwsamples)
1264 {
1265 /* save all the samples in the ring buffer, and return as if all the samples have been accepted.
1266 * Saving in ring buffer as host buffer is full and can't take any more samples.
1267 */
1268 LogFlow(("DrvAudio: full %d\n", live));
1269 //return 0;
1270 cbToWrite = size;
1271 IORingBufferAquireWriteBlock(pThis->pAudioWriteBuf, cbToWrite, &pcDst, &cbToWrite);
1272 if (RT_UNLIKELY(cbToWrite == 0))
1273 LogFlow(("DrvAudio: NO space in Ring buffer. Not doing anything, just discarding samples.\n"));
1274
1275 /* copy the audio data not accepted by the backend to the ring buffer */
1276 memcpy(pcDst, (uint8_t*)buf, cbToWrite);
1277
1278 /* Rlease the ring buffer */
1279 IORingBufferReleaseWriteBlock(pThis->pAudioWriteBuf, cbToWrite);
1280 return size;
1281 }
1282
1283 wpos = (pGstVoiceOut->pHostVoiceOut->offRead + live) % hwsamples;
1284 /* @todo check it. to convert size to num of samples */
1285 //samples = cbTotalSamples >> pGstVoiceOut->Props.cShift;
1286 samples = size >> pGstVoiceOut->Props.cShift;
1287
1288 dead = hwsamples - live;
1289 /* swlim is upper limit of max no. of samples that can be transferred in this cycle to backend */
1290 swlim = ((int64_t) dead << 32) / pGstVoiceOut->State.ratio;
1291 swlim = audio_MIN (swlim, samples);
1292
1293 LogFlow(("DrvAudio: swlim = %d\n", swlim));
1294
1295 if (swlim > pGstVoiceOut->cSamples)
1296 Log(("audio_pcm_sw_write: buffer overflow!! swlim = %d, buf_samples = %d\n",
1297 swlim, pos, pGstVoiceOut->cSamples));
1298 cSamplesAccepted = swlim;
1299 /* find out how much of the queue is full. */
1300 cbSamplesInQueue = IORingBufferUsed(pThis->pAudioWriteBuf);
1301 /* if ring buffer hold samples > 100 KB, discard samples */
1302 if (cbSamplesInQueue > 102400)
1303 {
1304 LogFlow(("DrvAudio: Samples in ring buffer > 300 KB. Discarding \n"));
1305 cbSamplesInQueue = 0;
1306 IORingBufferReset(pThis->pAudioWriteBuf);
1307 }
1308 /* read only that much samples as requried to be processed */
1309 if (cbSamplesInQueue > (cSamplesAccepted << pGstVoiceOut->Props.cShift))
1310 cbSamplesInQueue = (cSamplesAccepted << pGstVoiceOut->Props.cShift);
1311
1312 LogFlow(("DrvAudio: Samples in queue =%d and its size=%d\n",
1313 cbSamplesInQueue >> pGstVoiceOut->Props.cShift, cbSamplesInQueue));
1314
1315 /* read all the samples that are there in the queue and copy them to SampleBuf .
1316 * Reading all samples from the ring buffer as we need to send these samples first
1317 * and then add the samples received in this iteration to the ring buffer.
1318 */
1319 IORingBufferAquireReadBlock(pThis->pAudioWriteBuf, cbSamplesInQueue, &pcSrc, &cbSamplesInQueue);
1320 if (!cbSamplesInQueue)
1321 LogFlow(("DrvAudio: There are no audio in queue to be written. \n"));
1322
1323
1324 memcpy(SampleBuf, pcSrc, cbSamplesInQueue);
1325 /* Append the buf to samples that were there in the queue. SampBuf holds all the data to transfer */
1326 memcpy(SampleBuf + cbSamplesInQueue, buf, size);
1327 /* Release the read buffer, so it could be used for new data. */
1328 IORingBufferReleaseReadBlock(pThis->pAudioWriteBuf, cbSamplesInQueue);
1329
1330 /* reset the ring buffer to accept new data. */
1331
1332 /* cbTotalSamples = size of samples passed from the device + size of samples in the queue */
1333 cbTotalSamples = size + cbSamplesInQueue;
1334 LogFlow(("DrvAudio: size of samples read = %d and sz of samples recd = %d\n",
1335 cbSamplesInQueue, size));
1336 LogFlow(("DrvAudio: TotalSamples = %d\n", cbTotalSamples >> pGstVoiceOut->Props.cShift));
1337 if (swlim) {
1338 /* conversion engine: dest, source, num of samples, volume */
1339 convAudio (pGstVoiceOut->buf, SampleBuf, swlim, &sum_out_volume);
1340 }
1341
1342 while (swlim)
1343 {
1344 dead = hwsamples - live;
1345 left = hwsamples - wpos;
1346 blck = audio_MIN (dead, left);
1347 if (!blck) {
1348 break;
1349 }
1350 isamp = swlim;
1351 osamp = blck;
1352 if (pos + isamp > pGstVoiceOut->cSamples)
1353 Log(("audio_pcm_sw_write: buffer overflow!! isamp = %d, pos = %d, buf_samples = %d\n",
1354 isamp, pos, pGstVoiceOut->cSamples));
1355 /* mix and write to the host buffer to be read by the host during playout */
1356 st_rate_flow_mix (
1357 pGstVoiceOut->State.rate,
1358 pGstVoiceOut->buf + pos,
1359 pGstVoiceOut->pHostVoiceOut->pHostSterioSampleBuf + wpos,
1360 &isamp,
1361 &osamp
1362 );
1363 ret += isamp;
1364 swlim -= isamp;
1365 pos += isamp;
1366 live += osamp;
1367 wpos = (wpos + osamp) % hwsamples;
1368 total += osamp;
1369 }
1370
1371 pGstVoiceOut->cSamplesMixed += total;
1372 pGstVoiceOut->State.fEmpty = pGstVoiceOut->cSamplesMixed == 0;
1373
1374 cSamplesLeft = (cbTotalSamples >> pGstVoiceOut->Props.cShift) - cSamplesAccepted ;
1375 LogFlow(("DrvAudio: cSamplesLeft = %d\n", cSamplesLeft));
1376 if (cSamplesLeft > 0)
1377 {
1378 cbToWrite = cSamplesLeft << pGstVoiceOut->Props.cShift;
1379 /* max capacity of ring buffer is 516196 */
1380 //cbToWrite = audio_MIN(cbToWrite, 516196);
1381 IORingBufferAquireWriteBlock(pThis->pAudioWriteBuf, cbToWrite, &pcDst, &cbToWrite);
1382 if (RT_UNLIKELY(cbToWrite == 0))
1383 LogFlow(("DrvAudio: NO space in Ring buffer. Not doing anything, just discarding samples.\n"));
1384
1385 /* copy the audio data not accepted by the backend to the ring buffer */
1386 memcpy(pcDst, (uint8_t*)SampleBuf + (cSamplesAccepted << pGstVoiceOut->Props.cShift), cbToWrite);
1387
1388 /* Rlease the ring buffer */
1389 IORingBufferReleaseWriteBlock(pThis->pAudioWriteBuf, cbToWrite);
1390 }
1391 /* convert no of samples to bytes */
1392 return size;
1393}
1394
1395#ifdef DEBUG_AUDIO
1396static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
1397{
1398 LogFlow(("%s: bits %d, sign %d, freq %d, nchan %d\n",
1399 cap, info->bits, info->sign, info->freq, info->nchannels));
1400}
1401#endif
1402
1403int AUD_get_buffer_size_out (PPDMGSTVOICEOUT sw)
1404{
1405 return sw->pHostVoiceOut->cSamples << sw->pHostVoiceOut->Props.cShift;
1406}
1407
1408static int audio_get_avail (PPDMGSTVOICEIN sw)
1409{
1410 int live;
1411
1412 if (!sw)
1413 {
1414 LogFlow(("Error Voice Input Stream NUL \n"));
1415 return 0;
1416 }
1417
1418 live = sw->hw->cSamplesCaptured - sw->cHostSamplesAcquired;
1419 if (live < 0 || live > sw->hw->cSamples)
1420 {
1421 LogFlow(("DrvAudio: Error, live=%d sw->hw->samples=%d\n", live, sw->hw->cSamples));
1422 return 0;
1423 }
1424 return (((int64_t) live << 32) / sw->State.ratio) << sw->Props.cShift;
1425}
1426
1427static int audio_get_free(PPDMGSTVOICEOUT sw)
1428{
1429 int live, dead;
1430
1431 if (!sw)
1432 {
1433 LogFlow(("DrvAudio: Error, guest voice output stream null \n"));
1434 return 0;
1435 }
1436
1437 live = sw->cSamplesMixed;
1438
1439 if (live < 0 || live > sw->pHostVoiceOut->cSamples)
1440 {
1441 LogFlow(("DrvAudio: Error, live=%d sw->hw->samples=%d\n", live, sw->pHostVoiceOut->cSamples));
1442 return 0;
1443 }
1444 dead = sw->pHostVoiceOut->cSamples - live;
1445 return (((int64_t) dead << 32) / sw->State.ratio) << sw->Props.cShift;
1446}
1447
1448static void audio_capture_mix_and_clear (PDRVAUDIO pThis, PPDMHOSTVOICEOUT hw, int rpos, int samples)
1449{
1450 int n;
1451 LogFlow(("audio_capture_mix_and_clear \n"));
1452 if (hw->fEnabled)
1453 {
1454 SWVoiceCap *sc;
1455 SWVoiceCap *pIter;
1456
1457 RTListForEach(&hw->HeadCapturedVoice, pIter, SWVoiceCap, ListCapturedVoice)
1458 {
1459 sc = pIter;
1460 PPDMGSTVOICEOUT sw = &sc->sw;
1461 int rpos2 = rpos;
1462
1463 n = samples;
1464 while (n)
1465 {
1466 int till_end_of_hw = hw->cSamples - rpos2;
1467 int to_write = audio_MIN (till_end_of_hw, n);
1468 int bytes = to_write << hw->Props.cShift;
1469 int written;
1470
1471 sw->buf = hw->pHostSterioSampleBuf + rpos2;
1472 written = audio_pcm_sw_write (pThis, sw, NULL, bytes);
1473 if (written - bytes) {
1474 LogFlow(("Could not mix %d bytes into a capture "
1475 "buffer, mixed %d\n",
1476 bytes, written));
1477 break;
1478 }
1479 n -= to_write;
1480 rpos2 = (rpos2 + to_write) % hw->cSamples;
1481 }
1482 }
1483 }
1484
1485 n = audio_MIN (samples, hw->cSamples - rpos);
1486 mixeng_sniff_and_clear (hw, hw->pHostSterioSampleBuf + rpos, n);
1487 mixeng_sniff_and_clear (hw, hw->pHostSterioSampleBuf, samples - n);
1488}
1489
1490static void drvAudioPlayOut(PDRVAUDIO pThis)
1491{
1492 PPDMHOSTVOICEOUT hw = NULL;
1493 PPDMGSTVOICEOUT sw;
1494 PPDMGSTVOICEOUT pIter;
1495 PPDMGSTVOICEOUT pIter1;
1496
1497 while ((hw = drvAudioHlpPcmHwFindAnyEnabledOut(pThis, hw)))
1498 {
1499 int played;
1500 int live, myfree, nb_live, cleanup_required, prev_rpos;
1501
1502 live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
1503 if (!nb_live)
1504 {
1505 LogFlow(("DrvAudio: Live samples 0\n"));
1506 live = 0;
1507 }
1508
1509 if (live < 0 || live > hw->cSamples)
1510 {
1511 LogFlow(("DrvAudio: live=%d hw->samples=%d\n", live, hw->cSamples));
1512 continue;
1513 }
1514
1515 if (hw->pending_disable && !nb_live)
1516 {
1517 SWVoiceCap *sc;
1518 SWVoiceCap *pIter;
1519 hw->fEnabled = 0;
1520 hw->pending_disable = 0;
1521 pThis->pHostDrvAudio->pfnDisableEnableOut(pThis->pHostDrvAudio, hw, VOICE_DISABLE);
1522 RTListForEach(&hw->HeadCapturedVoice, pIter, SWVoiceCap , ListCapturedVoice)
1523 {
1524 sc = pIter;
1525 sc->sw.State.fActive = 0;
1526 drvAudioRecalcAndNotifyCapture(sc->cap);
1527 }
1528 continue;
1529 }
1530
1531 if (!live)
1532 {
1533 RTListForEach(&hw->HeadGstVoiceOut, pIter, PDMGSTVOICEOUT, ListGstVoiceOut)
1534 {
1535 sw = pIter;
1536 if (sw->State.fActive)
1537 {
1538 myfree = audio_get_free (sw);
1539 if (myfree > 0)
1540 sw->callback.fn (sw->callback.opaque, myfree);
1541 }
1542 }
1543 continue;
1544 }
1545
1546 prev_rpos = hw->offRead;
1547 played = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, hw);
1548 if (hw->offRead >= hw->cSamples)
1549 {
1550 LogFlow(("DrvAudio: hw->rpos=%d hw->samples=%d played=%d\n",
1551 hw->offRead, hw->cSamples, played));
1552 hw->offRead = 0;
1553 }
1554 /* I think this code relates to the point to accomodate no of audio samples
1555 * that have got accumulated during the above call of pfnplayout. So , it basically
1556 * tries to mix the old samples that have already been played, new samples that have
1557 * been gathered in due time of playing. Mix them up and send it to audiosniffer for
1558 * to be sent to VRDP server to be played on the client.
1559 */
1560 if (played) {
1561 audio_capture_mix_and_clear (pThis, hw, prev_rpos, played);
1562 }
1563
1564 cleanup_required = 0;
1565 RTListForEach(&hw->HeadGstVoiceOut, pIter1, PDMGSTVOICEOUT, ListGstVoiceOut)
1566 {
1567 sw = pIter1;
1568 if (!sw->State.fActive && sw->State.fEmpty)
1569 continue;
1570
1571 if (played > sw->cSamplesMixed)
1572 {
1573 LogFlow(("DrvAudio: played=%d sw->total_hw_samples_mixed=%d\n",
1574 played, sw->cSamplesMixed));
1575 played = sw->cSamplesMixed;
1576 }
1577
1578 sw->cSamplesMixed -= played;
1579
1580 if (!sw->cSamplesMixed)
1581 {
1582 sw->State.fEmpty = 1;
1583 cleanup_required |= !sw->State.fActive && !sw->callback.fn;
1584 }
1585
1586 if (sw->State.fActive)
1587 {
1588 myfree = audio_get_free (sw);
1589 if (myfree > 0)
1590 sw->callback.fn (sw->callback.opaque, myfree);
1591 }
1592 }
1593
1594 if (cleanup_required)
1595 {
1596 PPDMGSTVOICEOUT sw1;
1597 RTListForEach(&hw->HeadGstVoiceOut, pIter, PDMGSTVOICEOUT, ListGstVoiceOut)
1598 {
1599 sw = pIter;
1600 if (!sw->State.fActive && !sw->callback.fn)
1601 drvAudioHlpCloseOut(pThis, &pThis->qemuSoundCard, sw);
1602 }
1603 }
1604 }
1605}
1606
1607static void drvAudioPlayIn(PDRVAUDIO pThis)
1608{
1609 PPDMHOSTVOICEIN hw = NULL;
1610
1611 while ((hw = drvAudioHlpPcmHwFindAnyEnabledIn(pThis, hw)))
1612 {
1613 PPDMGSTVOICEIN pIter;
1614 int captured, min;
1615 captured = pThis->pHostDrvAudio->pfnPlayIn(pThis->pHostDrvAudio, hw);
1616
1617 min = audio_pcm_hw_find_min_in (hw);
1618 hw->cSamplesCaptured += captured - min;
1619 hw->ts_helper += captured;
1620
1621 RTListForEach(&hw->HeadGstVoiceIn, pIter, PDMGSTVOICEIN, ListGstVoiceIn)
1622 {
1623 pIter->cHostSamplesAcquired -= min;
1624
1625 if (pIter->State.fActive)
1626 {
1627 int avail;
1628 avail = audio_get_avail (pIter);
1629 if (avail > 0)
1630 {
1631 pIter->callback.fn(pIter->callback.opaque, avail);
1632 }
1633 }
1634 }
1635 }
1636}
1637
1638static void drvAudioCapture(PDRVAUDIO pThis)
1639{
1640 CaptureVoiceOut *cap;
1641 CaptureVoiceOut *pIter;
1642
1643 RTListForEach(&pThis->HeadCapturedVoice, pIter, CaptureVoiceOut, ListCapturedVoice)
1644 {
1645 cap = pIter;
1646 int live, rpos, captured;
1647 PPDMHOSTVOICEOUT hw = &cap->hw;
1648 PPDMGSTVOICEOUT sw;
1649 PPDMGSTVOICEOUT pIter;
1650
1651 captured = live = audio_pcm_hw_get_live_out (hw);
1652 rpos = hw->offRead;
1653 while (live)
1654 {
1655 int left = hw->cSamples - rpos;
1656 int to_capture = audio_MIN (live, left);
1657 st_sample_t *src;
1658 struct capture_callback *cb;
1659
1660 src = hw->pHostSterioSampleBuf + rpos;
1661 clipAudio (cap->buf, src, to_capture);
1662 mixeng_sniff_and_clear (hw, src, to_capture);
1663
1664 rpos = (rpos + to_capture) % hw->cSamples;
1665 live -= to_capture;
1666 }
1667 hw->offRead = rpos;
1668
1669 RTListForEach(&hw->HeadGstVoiceOut, pIter, PDMGSTVOICEOUT, ListGstVoiceOut)
1670 {
1671 sw = pIter;
1672 LogFlow(("6\n"));
1673 if (!sw->State.fActive && sw->State.fEmpty) {
1674 continue;
1675 }
1676
1677 if (captured > sw->cSamplesMixed)
1678 {
1679 LogFlow(("DrvAudio: captured=%d sw->total_hw_samples_mixed=%d\n",
1680 captured, sw->cSamplesMixed));
1681 captured = sw->cSamplesMixed;
1682 }
1683
1684 sw->cSamplesMixed -= captured;
1685 sw->State.fEmpty = sw->cSamplesMixed == 0;
1686 }
1687 }
1688}
1689static void drvAudioTimer(PDRVAUDIO pThis)
1690{
1691 drvAudioPlayOut(pThis);
1692 drvAudioPlayIn(pThis);
1693 drvAudioCapture(pThis);
1694 TMTimerSet (pThis->pTimer, TMTimerGet (pThis->pTimer) + pThis->ticks);
1695}
1696
1697static int audio_driver_init (PCFGMNODE pCfgHandle, PDRVAUDIO pThis, struct audio_driver *drv)
1698{
1699 int max_voices;
1700 int voice_size;
1701 if (drv->options)
1702 {
1703 drvAudioProcessOptions(pCfgHandle, drv->name, drv->options);
1704 }
1705 if (!pThis->pHostDrvAudio->pfnInit(pThis->pHostDrvAudio))
1706 {
1707 LogFlow(("DrvAudio: Could not init audio driver %p\n", pThis));
1708 return VERR_GENERAL_FAILURE;
1709 }
1710
1711 max_voices = pThis->AudioConf.MaxHostVoicesOut;
1712 voice_size = pThis->AudioConf.szHostVoiceOut;
1713 pThis->cHostOutVoices = 1;
1714 if (pThis->cHostOutVoices > max_voices)
1715 {
1716 if (!max_voices)
1717 LogFlow(("Driver `%s' does not support \n", drv->name));
1718 else
1719 LogFlow(("Driver `%s' does not support %d voices, max %d\n",
1720 drv->name,
1721 pThis->cHostOutVoices,
1722 max_voices));
1723 pThis->cHostOutVoices = 1;//max_voices;
1724 }
1725
1726 if (!voice_size && max_voices)
1727 {
1728 LogFlow(("drv=`%s' voice_size=0 max_voices=%d\n",
1729 drv->name, max_voices));
1730 pThis->cHostOutVoices = 0;
1731 }
1732
1733 if (voice_size && !max_voices)
1734 {
1735 LogFlow(("drv=`%s' voice_size=%d max_voices=0\n",
1736 drv->name, voice_size));
1737 }
1738
1739
1740 max_voices = pThis->AudioConf.MaxHostVoicesIn;
1741 voice_size = pThis->AudioConf.szHostVoiceIn;
1742
1743 LogFlow(("DrvAudio: voice_size =%d max_voices=%d cHostInVoices=%d\n", voice_size, max_voices, pThis->cHostInVoices));
1744 //pThis->cHostInVoices = 1; //@todo handle this
1745 if (pThis->cHostInVoices > max_voices)
1746 {
1747 if (!max_voices)
1748 LogFlow(("Driver `%s' does not support \n", drv->name));
1749 else
1750 LogFlow(("Driver `%s' does not support %d voices, max %d\n",
1751 drv->name,
1752 pThis->cHostOutVoices,
1753 max_voices));
1754 pThis->cHostInVoices = max_voices;
1755 }
1756
1757 if (!voice_size && max_voices)
1758 {
1759 LogFlow(("drv=`%s' voice_size=0 max_voices=%d\n",
1760 drv->name, max_voices));
1761 //@todo in original code its 0, but I have made it 1 to avoid crash
1762 pThis->cHostInVoices = 0;
1763 }
1764
1765 if (voice_size && !max_voices)
1766 {
1767 LogFlow(("drv=`%s' voice_size=%d max_voices=0\n",
1768 drv->name, voice_size));
1769 }
1770 return VINF_SUCCESS;
1771}
1772
1773static void audio_vm_change_state_handler (PPDMDRVINS pDrvIns,/* void *opaque,*/ int running)
1774{
1775 PPDMHOSTVOICEOUT hwo = NULL;
1776 PPDMHOSTVOICEIN hwi = NULL;
1777 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
1778 int op = running ? VOICE_ENABLE : VOICE_DISABLE;
1779
1780 while ((hwo = drvAudioHlpPcmHwFindAnyEnabledOut(pThis, hwo))) {
1781 pThis->pHostDrvAudio->pfnDisableEnableOut(pThis->pHostDrvAudio, hwo, op);
1782 }
1783
1784 while ((hwi = drvAudioHlpPcmHwFindAnyEnabledIn(pThis, hwi))) {
1785 pThis->pHostDrvAudio->pfnDisableEnableIn(pThis->pHostDrvAudio, hwi, op);
1786 }
1787}
1788
1789static void drvAudioExit(PPDMDRVINS pDrvIns)
1790{
1791 PPDMHOSTVOICEOUT hwo = NULL;
1792 PPDMHOSTVOICEIN hwi = NULL;
1793 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
1794 /* VBox change: audio_pcm_hw_find_any_enabled_out => audio_pcm_hw_find_any_out */
1795 while ((hwo = drvAudioHlpPcmHwFindAnyOut(pThis, hwo)))
1796 {
1797 SWVoiceCap *sc;
1798 SWVoiceCap *pIter;
1799
1800 pThis->pHostDrvAudio->pfnDisableEnableOut(pThis->pHostDrvAudio, hwo, VOICE_DISABLE);
1801 pThis->pHostDrvAudio->pfnFiniOut(pThis->pHostDrvAudio, hwo);
1802
1803 RTListForEach(&hwo->HeadCapturedVoice, pIter, SWVoiceCap, ListCapturedVoice)
1804 {
1805 sc = pIter;
1806 CaptureVoiceOut *cap = sc->cap;
1807 struct capture_callback *cb;
1808 }
1809 }
1810
1811 /* VBox change: audio_pcm_hw_find_any_enabled_in => audio_pcm_hw_find_any_in */
1812 while ((hwi = drvAudioHlpPcmHwFindAnyIn(pThis, hwi)))
1813 {
1814 pThis->pHostDrvAudio->pfnDisableEnableIn(pThis->pHostDrvAudio, hwi, VOICE_DISABLE);
1815 pThis->pHostDrvAudio->pfnFiniIn(pThis->pHostDrvAudio, hwi);
1816 }
1817}
1818
1819static DECLCALLBACK(void) audio_timer_helper (PPDMDRVINS pDrvIns, PTMTIMER pTimer, void *pvUser)
1820{
1821 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
1822 drvAudioTimer(pThis);
1823}
1824
1825static struct audio_option audio_options[] =
1826{
1827 /* DAC */
1828 {"DACFixedSettings", AUD_OPT_BOOL, &conf.fixed_out.enabled,
1829 "Use fixed settings for host DAC", NULL, 0},
1830
1831 {"DACFixedFreq", AUD_OPT_INT, &conf.fixed_out.settings.freq,
1832 "Frequency for fixed host DAC", NULL, 0},
1833
1834 {"DACFixedFmt", AUD_OPT_FMT, &conf.fixed_out.settings.fmt,
1835 "Format for fixed host DAC", NULL, 0},
1836
1837 {"DACFixedChannels", AUD_OPT_INT, &conf.fixed_out.settings.nchannels,
1838 "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},
1839
1840 {"DACVoices", AUD_OPT_INT, &conf.fixed_out.nb_voices,
1841 "Number of voices for DAC", NULL, 0},
1842
1843 /* ADC */
1844 {"ADCFixedSettings", AUD_OPT_BOOL, &conf.fixed_in.enabled,
1845 "Use fixed settings for host ADC", NULL, 0},
1846
1847 {"ADCFixedFreq", AUD_OPT_INT, &conf.fixed_in.settings.freq,
1848 "Frequency for fixed host ADC", NULL, 0},
1849
1850 {"ADCFixedFmt", AUD_OPT_FMT, &conf.fixed_in.settings.fmt,
1851 "Format for fixed host ADC", NULL, 0},
1852
1853 {"ADCFixedChannels", AUD_OPT_INT, &conf.fixed_in.settings.nchannels,
1854 "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},
1855
1856 {"ADCVoices", AUD_OPT_INT, &conf.fixed_in.nb_voices,
1857 "Number of voices for ADC", NULL, 0},
1858
1859 /* Misc */
1860 {"TimerFreq", AUD_OPT_INT, &conf.period.hz,
1861 "Timer frequency in Hz (0 - use lowest possible)", NULL, 0},
1862
1863 {"PLIVE", AUD_OPT_BOOL, &conf.plive,
1864 "(undocumented)", NULL, 0},
1865
1866 {NULL, 0, NULL, NULL, NULL, 0}
1867};
1868
1869static DECLCALLBACK (void) drvAudioRegisterCard(PPDMIAUDIOCONNECTOR pInterface, const char *name)
1870{
1871 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
1872 LogFlow(("DrvAudio: drvAudioRegisterCard \n"));
1873 pThis->qemuSoundCard.name = RTStrDup(name);
1874}
1875
1876static DECLCALLBACK(int) drvAudioInit(PCFGMNODE pCfgHandle, PPDMDRVINS pDrvIns, const char *drvname, PDRVAUDIO pDrvAudio)
1877{
1878 size_t i;
1879 int done = 0;
1880 int rc;
1881 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
1882 LogFlow(("DrvAudio: drvAudioInit pDrvAudio=%p and pDrvIns=%p\n", pDrvAudio, pDrvIns));
1883
1884 RTListInit(&pDrvAudio->HeadHostVoiceOut);
1885 RTListInit(&pDrvAudio->HeadHostVoiceIn);
1886 RTListInit(&pDrvAudio->HeadHostVoiceIn);
1887 RTListInit(&pDrvAudio->HeadCapturedVoice);
1888
1889 /* get the configuration data from the backend */
1890 pDrvAudio->pHostDrvAudio->pfnGetConf(pDrvAudio->pHostDrvAudio, &pDrvAudio->AudioConf);
1891
1892 rc = PDMDrvHlpTMTimerCreate (pDrvIns, TMCLOCK_VIRTUAL, audio_timer_helper,
1893 pThis, 0, "Audio timer", &pDrvAudio->pTimer);
1894 if (RT_FAILURE (rc))
1895 {
1896 LogRel(("DrvAudio: Failed to create timer \n"));
1897 return rc;
1898 }
1899
1900 drvAudioProcessOptions(pCfgHandle, "AUDIO", audio_options);
1901
1902 pDrvAudio->cHostOutVoices = conf.fixed_out.nb_voices;
1903 pDrvAudio->cHostInVoices = conf.fixed_in.nb_voices;
1904
1905 pDrvAudio->ticks = 200; /* initialization of ticks */
1906
1907 /* initialization of audio buffer. Create ring buffer of around 200 KB each . */
1908 IORingBufferCreate(&pDrvAudio->pAudioWriteBuf, 512000); /* 500 KB */
1909
1910 /* allocating space for about 500 msec of audio data 48KHz, 128 bit sample
1911 * (guest format - PDMHOSTSTEREOSAMPLE) and dual channel
1912 */
1913 IORingBufferCreate(&pDrvAudio->pAudioReadBuf, 768000); /* 750 KB */
1914
1915
1916 if (pDrvAudio->cHostOutVoices <= 0)
1917 {
1918 LogFlow(("Bogus number of playback voices %d, setting to 1\n", pDrvAudio->cHostOutVoices));
1919 pDrvAudio->cHostOutVoices = 1;
1920 }
1921
1922 if (pDrvAudio->cHostInVoices <= 0)
1923 {
1924 LogFlow(("Bogus number of capture voices %d, setting to 0\n", pDrvAudio->cHostInVoices));
1925 //@todo in original code its set to 0 currently being set to 1 to ensure atleas 1 voice IN
1926 pDrvAudio->cHostInVoices = 1;
1927 }
1928 LogFlow(("Audio: Trying driver '%s'.\n", drvname));
1929
1930 if (drvname)
1931 {
1932 int found = 0;
1933 for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++)
1934 {
1935 /* @todo: audioVRDE name wont be visible here. So hardcoding */
1936 if (!strcmp (drvname, drvtab[i]->name) || !strcmp(drvname, "AudioVRDE"))
1937 {
1938 if (!strcmp(drvname, "AudioVRDE"))
1939 {
1940 struct audio_driver vrde_audio_driver =
1941 {
1942 INIT_FIELD (name = ) "AudioVRDE",
1943 INIT_FIELD (descr = ) "AudioVRDE http://www.pulseaudio.org",
1944 INIT_FIELD (options = ) NULL,
1945 };
1946 struct audio_driver *drvtabAudioVRDE = &vrde_audio_driver;
1947 done = !audio_driver_init (pCfgHandle, pDrvAudio, drvtabAudioVRDE);
1948 }
1949 else
1950 {
1951 done = !audio_driver_init (pCfgHandle, pDrvAudio, drvtab[i]);
1952 }
1953 found = 1;
1954 break;
1955 }
1956 }
1957
1958 if (!found)
1959 {
1960 LogFlow(("Audio: Unknown audio driver `%s'\n", drvname));
1961 }
1962 }
1963
1964 if (!done)
1965 {
1966 for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
1967 if (drvtab[i]->can_be_default) {
1968 LogRel(("Audio: Initialization of driver '%s' failed, trying '%s'.\n",drvname, drvtab[i]->name));
1969 drvname = drvtab[i]->name;
1970 done = !audio_driver_init (pCfgHandle, pDrvAudio, drvtab[i]);
1971 }
1972 }
1973 }
1974
1975 if (!done) {
1976 done = !audio_driver_init (pCfgHandle, pThis, &no_audio_driver);
1977 if (!done) {
1978 LogFlow(("Could not initialize audio subsystem\n"));
1979 }
1980 else {
1981 LogRel(("Audio: Initialization of driver '%s' failed, using NULL driver.\n", drvname));
1982 LogFlow(("warning: Using timer based audio emulation\n"));
1983 }
1984 }
1985 if (done)
1986 {
1987 if (conf.period.hz <= 0)
1988 {
1989 if (conf.period.hz < 0)
1990 {
1991 LogFlow(("warning: Timer period is negative - %d "
1992 "treating as zero\n",
1993 conf.period.hz));
1994 }
1995 pDrvAudio->ticks = 1;
1996 }
1997 else
1998 {
1999 pDrvAudio->ticks = PDMDrvHlpTMGetVirtualFreq(pDrvIns) / conf.period.hz;
2000 }
2001 }
2002 else {
2003 /* XXX */
2004 rc = TMR3TimerDestroy (pDrvAudio->pTimer);
2005 return rc;
2006 }
2007 TMTimerSet (pDrvAudio->pTimer, TMTimerGet (pDrvAudio->pTimer) + pDrvAudio->ticks);
2008 return VINF_SUCCESS;
2009}
2010static DECLCALLBACK(int) drvAudioInitNull(PPDMIAUDIOCONNECTOR pInterface)
2011{
2012 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
2013 return audio_driver_init(NULL, pThis, &no_audio_driver);
2014}
2015
2016static DECLCALLBACK(int) drvAudioWrite(PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEOUT sw, void *buf, int size)
2017{
2018 int bytes;
2019 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
2020 if (!sw || size < 0)
2021 {
2022 LogFlow(("DrvAudio: GstVoiceOut is NULL \n"));
2023 /* XXX: Consider options */
2024 return size;
2025 }
2026
2027 if (!sw->pHostVoiceOut->fEnabled) {
2028 return 0;
2029 }
2030 bytes = audio_pcm_sw_write(pThis, sw, buf, size);
2031 return bytes;
2032}
2033
2034static DECLCALLBACK(int) drvAudioRead(PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEIN sw, void *buf, int size)
2035{
2036 int bytes;
2037 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
2038 if (!sw) {
2039 /* XXX: Consider options */
2040 return size;
2041 }
2042
2043 if (!sw->hw->enabled) {
2044 LogFlow(("DrvAudio: Reading from disabled voice \n"));
2045 return 0;
2046 }
2047 bytes = audio_pcm_sw_read(pThis, sw, (PPDMHOSTSTEREOSAMPLE)buf, size);
2048 return bytes;
2049}
2050
2051static DECLCALLBACK(void) drvAudioIsSetOutVolume (PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEOUT sw, int mute, uint8_t lvol, uint8_t rvol)
2052{
2053 if (sw)
2054 {
2055 sw->State.uVolumeMute = mute;
2056 sw->State.uVolumeLeft = (uint32_t)lvol * 0x808080; /* maximum is INT_MAX = 0x7fffffff */
2057 sw->State.uVolumeRight = (uint32_t)rvol * 0x808080; /* maximum is INT_MAX = 0x7fffffff */
2058 }
2059}
2060
2061
2062static DECLCALLBACK(void) drvAudioSetVolume (PPDMIAUDIOCONNECTOR pInterface, int *mute, uint8_t *lvol, uint8_t *rvol)
2063{
2064 volume_t vol;
2065 const char *name;
2066
2067 uint32_t u32VolumeLeft = (uint32_t)*lvol;
2068 uint32_t u32VolumeRight = (uint32_t)*rvol;
2069 /* 0x00..0xff => 0x01..0x100 */
2070 if (u32VolumeLeft)
2071 u32VolumeLeft++;
2072 if (u32VolumeRight)
2073 u32VolumeRight++;
2074 vol.mute = *mute;
2075 vol.l = u32VolumeLeft * 0x800000; /* maximum is 0x80000000 */
2076 vol.r = u32VolumeRight * 0x800000; /* maximum is 0x80000000 */
2077 sum_out_volume.mute = 0;
2078 sum_out_volume.l = ASMMultU64ByU32DivByU32(INT_MAX, INT_MAX, 0x80000000U);
2079 sum_out_volume.r = ASMMultU64ByU32DivByU32(INT_MAX, INT_MAX, 0x80000000U);
2080}
2081
2082static DECLCALLBACK(void) drvAudioEnableOut (PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEOUT sw, int on)
2083{
2084 PPDMHOSTVOICEOUT hw;
2085 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
2086
2087 if (!sw)
2088 return;
2089
2090 hw = sw->pHostVoiceOut;
2091 if (sw->State.fActive != on)
2092 {
2093 PPDMGSTVOICEOUT pIter;
2094 SWVoiceCap *sc;
2095 SWVoiceCap *pIterCap;
2096
2097 if (on)
2098 {
2099 hw->pending_disable = 0;
2100 if (!hw->fEnabled)
2101 {
2102 hw->fEnabled = 1;
2103 pThis->pHostDrvAudio->pfnDisableEnableOut(pThis->pHostDrvAudio, hw, VOICE_ENABLE);
2104 }
2105 }
2106 else
2107 {
2108 if (hw->fEnabled)
2109 {
2110 int nb_active = 0;
2111
2112 RTListForEach(&hw->HeadGstVoiceOut, pIter, PDMGSTVOICEOUT, ListGstVoiceOut)
2113 {
2114 nb_active += pIter->State.fActive != 0;
2115 }
2116
2117 hw->pending_disable = nb_active == 1;
2118 }
2119 }
2120
2121 RTListForEach(&hw->HeadCapturedVoice, pIterCap, SWVoiceCap, ListCapturedVoice)
2122 {
2123 sc = pIterCap;
2124 sc->sw.State.fActive = hw->fEnabled;
2125 if (hw->fEnabled) {
2126 audio_capture_maybe_changed (sc->cap, 1);
2127 }
2128 }
2129 sw->State.fActive = on;
2130 }
2131}
2132
2133static DECLCALLBACK(void) drvAudioEnableIn(PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEIN sw , int on)
2134{
2135 PPDMHOSTVOICEIN hw;
2136 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
2137 if (!sw) {
2138 LogFlow(("DrvAudio: NO GuestVoiceIn. Returning 0\n"));
2139 return;
2140 }
2141
2142 hw = sw->hw;
2143 if (sw->State.fActive != on)
2144 {
2145 PPDMGSTVOICEIN pIter;
2146
2147 if (on)
2148 {
2149 if (!hw->enabled)
2150 {
2151 hw->enabled = 1;
2152 pThis->pHostDrvAudio->pfnDisableEnableIn(pThis->pHostDrvAudio, hw, VOICE_ENABLE);
2153 }
2154 sw->cHostSamplesAcquired = hw->cSamplesCaptured;
2155 }
2156 else
2157 {
2158 if (hw->enabled)
2159 {
2160 int nb_active = 0;
2161
2162 RTListForEach(&hw->HeadGstVoiceIn, pIter, PDMGSTVOICEIN, ListGstVoiceIn)
2163 {
2164 nb_active += pIter->State.fActive != 0;
2165 }
2166
2167 if (nb_active == 1) {
2168 hw->enabled = 0;
2169 pThis->pHostDrvAudio->pfnDisableEnableIn(pThis->pHostDrvAudio, hw, VOICE_DISABLE);
2170 }
2171 }
2172 }
2173 sw->State.fActive = on;
2174 }
2175}
2176
2177static DECLCALLBACK(int) drvAudioIsHostVoiceInOK(PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEIN sw)
2178{
2179 if (sw == NULL) {
2180 return 0;
2181 }
2182 return 1;
2183}
2184
2185static DECLCALLBACK(int) drvAudioIsHostVoiceOutOK(PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEOUT sw)
2186{
2187 if (sw == NULL) {
2188 return 0;
2189 }
2190 return 1;
2191}
2192
2193static DECLCALLBACK(int) drvAudioOpenIn(PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEIN *ppGstVoiceIn,
2194 const char *name, void *callback_opaque , audio_callback_fn_t callback_fn,
2195 uint32_t uFrequency, uint32_t cChannels, audfmt_e Format, uint32_t Endian)
2196{
2197 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
2198 audsettings_t AudioSettings;
2199 AudioSettings.freq = uFrequency;
2200 AudioSettings.nchannels = cChannels;
2201 AudioSettings.fmt = Format;
2202 AudioSettings.endianness = Endian;
2203 LogFlow(("DrvAudio: open IN %s, freq %d, nchannels %d, fmt %d\n",
2204 name, AudioSettings.freq, AudioSettings.nchannels, AudioSettings.fmt));
2205
2206 if (drvAudioValidateSettings(&AudioSettings))
2207 {
2208 LogRel(("Audio: Audio Settings Validation failed \n"));
2209 drvAudioPrintSettings(&AudioSettings);
2210 drvAudioHlpCloseIn(pThis, &pThis->qemuSoundCard, *ppGstVoiceIn);
2211 *ppGstVoiceIn = (PPDMGSTVOICEIN)NULL;
2212 return VERR_GENERAL_FAILURE;
2213 }
2214
2215 if (*ppGstVoiceIn && drvAudioPcmInfoEq(&(*ppGstVoiceIn)->Props, &AudioSettings))
2216 return VINF_SUCCESS;
2217
2218 if (!conf.fixed_in.enabled && *ppGstVoiceIn)
2219 {
2220 drvAudioHlpCloseIn(pThis, &pThis->qemuSoundCard, *ppGstVoiceIn);
2221 *ppGstVoiceIn = (PPDMGSTVOICEIN )NULL;
2222 }
2223
2224 if (*ppGstVoiceIn)
2225 {
2226 PPDMHOSTVOICEIN pHostVoiceIn = (*ppGstVoiceIn)->hw;
2227
2228 if (!pHostVoiceIn)
2229 {
2230 LogFlow(("Internal logic error voice has no hardware store\n"));
2231 drvAudioHlpCloseIn(pThis, &pThis->qemuSoundCard, *ppGstVoiceIn);
2232 *ppGstVoiceIn = (PPDMGSTVOICEIN)NULL;
2233 return VERR_GENERAL_FAILURE;
2234 }
2235
2236 drvAudioHlpPcmSwFinishedIn(*ppGstVoiceIn);
2237 if (drvAudioHlpPcmSwInitIn(*ppGstVoiceIn, pHostVoiceIn, name, &AudioSettings))
2238 {
2239 drvAudioHlpCloseIn(pThis, &pThis->qemuSoundCard, *ppGstVoiceIn);
2240 *ppGstVoiceIn = (PPDMGSTVOICEIN)NULL;
2241 return VERR_GENERAL_FAILURE;
2242 }
2243 }
2244 else
2245 {
2246 *ppGstVoiceIn = drvAudioHlpPcmCreateVoicePairIn(pThis, name, &AudioSettings);
2247 if (!(*ppGstVoiceIn))
2248 {
2249 LogFlow(("Failed to create voice `%s'\n", name));
2250 *ppGstVoiceIn = (PPDMGSTVOICEIN)NULL;
2251 return VERR_GENERAL_FAILURE;
2252 }
2253 }
2254
2255 if (*ppGstVoiceIn)
2256 {
2257 (*ppGstVoiceIn)->State.uVolumeLeft = nominal_volume.l;
2258 (*ppGstVoiceIn)->State.uVolumeRight = nominal_volume.r;
2259 (*ppGstVoiceIn)->State.uVolumeMute = nominal_volume.mute;
2260 (*ppGstVoiceIn)->callback.fn = callback_fn;
2261 (*ppGstVoiceIn)->callback.opaque = callback_opaque;
2262 }
2263 return VINF_SUCCESS;
2264}
2265
2266
2267static DECLCALLBACK(int) drvAudioOpenOut(PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEOUT *ppGstVoiceOut, const char *name,
2268 void *callback_opaque, audio_callback_fn_t callback_fn,
2269 uint32_t uFrequency, uint32_t cChannels, audfmt_e Format, uint32_t Endian)
2270{
2271 int cLiveSamples = 0;
2272 AudioState *s;
2273 int rc;
2274 PPDMGSTVOICEOUT pOldGstVoiceOut;
2275 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
2276 audsettings_t AudioSettings;
2277 AudioSettings.freq = uFrequency;
2278 AudioSettings.nchannels = cChannels;
2279 AudioSettings.fmt = Format;
2280 AudioSettings.endianness = Endian;
2281
2282 LogFlow(("DrvAudio: open OUT %s, freq %d, nchannels %d, fmt %d\n",
2283 name, AudioSettings.freq, AudioSettings.nchannels, AudioSettings.fmt));
2284
2285 if (drvAudioValidateSettings(&AudioSettings))
2286 {
2287 LogRel(("DrvAudio: Audio Settings Validation failed \n"));
2288 drvAudioPrintSettings(&AudioSettings);
2289 drvAudioHlpCloseOut(pThis, &pThis->qemuSoundCard, *ppGstVoiceOut);
2290 *ppGstVoiceOut = (PPDMGSTVOICEOUT)NULL;
2291 return VERR_GENERAL_FAILURE;
2292 }
2293
2294 if (*ppGstVoiceOut && drvAudioPcmInfoEq(&(*ppGstVoiceOut)->Props, &AudioSettings))
2295 return VINF_SUCCESS;
2296
2297 if ( conf.plive && *ppGstVoiceOut
2298 && (!(*ppGstVoiceOut)->State.fActive
2299 && !(*ppGstVoiceOut)->State.fEmpty)
2300 )
2301 {
2302 cLiveSamples = (*ppGstVoiceOut)->cSamplesMixed;
2303 if(cLiveSamples)
2304 {
2305 pOldGstVoiceOut = *ppGstVoiceOut;
2306 *ppGstVoiceOut = NULL;
2307 }
2308 }
2309
2310 if (!conf.fixed_out.enabled && *ppGstVoiceOut)
2311 {
2312 drvAudioHlpCloseOut(pThis, &pThis->qemuSoundCard, *ppGstVoiceOut);
2313 *ppGstVoiceOut = (PPDMGSTVOICEOUT *)NULL;
2314 }
2315
2316 if (*ppGstVoiceOut)
2317 {
2318 PPDMHOSTVOICEOUT pHostVoiceOut = (*ppGstVoiceOut)->pHostVoiceOut;
2319 if (!pHostVoiceOut)
2320 {
2321 LogFlow(("Guest Voice Stream has no Host voice stream in store\n"));
2322 return VERR_GENERAL_FAILURE;
2323 }
2324
2325 drvAudioHlpPcmSwFinishedOut(*ppGstVoiceOut);
2326 rc = drvAudioHlpPcmSwInitOut(*ppGstVoiceOut, pHostVoiceOut, name, &AudioSettings);
2327 if (RT_FAILURE(rc))
2328 return rc;
2329 }
2330 else
2331 {
2332 (*ppGstVoiceOut) = drvAudioHlpPcmCreateVoicePairOut(pThis, s, name, &AudioSettings);
2333 if (!(*ppGstVoiceOut))
2334 {
2335 LogFlow(("Failed to create voice `%s'\n", name));
2336 *ppGstVoiceOut = (PPDMGSTVOICEOUT)NULL;
2337 return VERR_GENERAL_FAILURE;
2338 }
2339 }
2340
2341 if (*ppGstVoiceOut)
2342 {
2343 (*ppGstVoiceOut)->State.uVolumeLeft = nominal_volume.l;
2344 (*ppGstVoiceOut)->State.uVolumeRight = nominal_volume.r;
2345 (*ppGstVoiceOut)->State.uVolumeMute = nominal_volume.mute;
2346 (*ppGstVoiceOut)->callback.fn = callback_fn;
2347 (*ppGstVoiceOut)->callback.opaque = callback_opaque;
2348 if (cLiveSamples)
2349 {
2350 int mixed =
2351 (cLiveSamples << pOldGstVoiceOut->Props.cShift)
2352 * pOldGstVoiceOut->Props.cbPerSec
2353 / (*ppGstVoiceOut)->Props.cbPerSec;
2354
2355 (*ppGstVoiceOut)->cSamplesMixed += mixed;
2356 }
2357 }
2358
2359 return VINF_SUCCESS;
2360}
2361
2362static DECLCALLBACK(int) drvAudioIsActiveIn(PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEIN pGstVoiceIn)
2363{
2364 return pGstVoiceIn ? pGstVoiceIn->State.fActive : 0;
2365}
2366
2367static DECLCALLBACK(int) drvAudioIsActiveOut(PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEOUT pGstVoiceOut)
2368{
2369 return pGstVoiceOut ? pGstVoiceOut->State.fActive : 0;
2370}
2371
2372static DECLCALLBACK(t_sample *)drvAudioConvDevFmtToStSample(PPDMIAUDIOCONNECTOR pInterface, uint32_t cChannels,
2373 uint32_t fSign, uint32_t uEndian, uint32_t ubitIdx)
2374{
2375 LogFlow(("DrvAudio: drvAudioConvStSamplToFmt \n"));
2376 return mixeng_conv[cChannels] /* stereo */
2377 [fSign] /* sign */
2378 [uEndian] /* big endian */
2379 [ubitIdx]; /* bits */
2380
2381}
2382
2383static DECLCALLBACK(f_sample *)drvAudioConvStSampleToDevFmt(PPDMIAUDIOCONNECTOR pInterface, void *buf,
2384 PPDMHOSTSTEREOSAMPLE pSampleBuf, uint32_t samples)
2385{
2386 /*@todo handle ths properly*/
2387 clipAudioIn (buf, pSampleBuf, samples);
2388}
2389
2390
2391static DECLCALLBACK(void *)drvAudioPrepareAudioConversion(PPDMIAUDIOCONNECTOR pInterface, uint32_t uSampleFreq, uint32_t uTgtFreq)
2392{
2393 return st_rate_start (uSampleFreq, uTgtFreq);
2394}
2395
2396static DECLCALLBACK(void)drvAudioEndAudioConversion(PPDMIAUDIOCONNECTOR pInterface, void * pRate)
2397{
2398 AssertPtr(pRate);
2399 st_rate_stop (pRate);
2400}
2401
2402static DECLCALLBACK(void)drvAudioDoRateConversion(PPDMIAUDIOCONNECTOR pInterface, void * pRate,
2403 PPDMHOSTSTEREOSAMPLE pHostStereoSampleBuf,
2404 PPDMHOSTSTEREOSAMPLE pConvertedSampleBuf,
2405 uint32_t * pcSampleSrc, uint32_t *pcConvertedSamples)
2406{
2407 AssertPtr(pRate);
2408 st_rate_flow(pRate, pHostStereoSampleBuf, pConvertedSampleBuf, pcSampleSrc, pcConvertedSamples);
2409
2410}
2411
2412static DECLCALLBACK(void)drvAudioDoRateConvAndMix(PPDMIAUDIOCONNECTOR pInterface, void * pRate,
2413 PPDMHOSTSTEREOSAMPLE pSourceSampleBuf,
2414 PPDMHOSTSTEREOSAMPLE pTargetMixedSampleBuf,
2415 uint32_t * pcSampleSrc, uint32_t *pcMixedSamples)
2416{
2417 st_rate_flow_mix(pRate, pSourceSampleBuf, pTargetMixedSampleBuf, pcSampleSrc, pcMixedSamples);
2418
2419}
2420
2421/****************************************************************/
2422
2423static DECLCALLBACK(void) drvAudioCloseIn(PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEIN pGstVoiceIn)
2424{
2425 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
2426 if (pGstVoiceIn)
2427 {
2428 if (!&pThis->qemuSoundCard || !pThis->qemuSoundCard.audio)
2429 {
2430 LogFlow(("DrvAudio: Error, card=%p card->audio=%p\n",
2431 (void *) &pThis->qemuSoundCard, &pThis->qemuSoundCard ? (void *) pThis->qemuSoundCard.audio : NULL));
2432 return;
2433 }
2434 drvAudioHlpCloseIn(pThis, pThis->qemuSoundCard.audio, pGstVoiceIn);
2435 }
2436}
2437
2438DECLCALLBACK(void) drvAudioCloseOut(PPDMIAUDIOCONNECTOR pInterface, PPDMGSTVOICEOUT pGstVoiceOut)
2439{
2440 PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
2441 if (pGstVoiceOut) {
2442 if (!&pThis->qemuSoundCard || !pThis->qemuSoundCard.audio)
2443 {
2444 LogFlow(("DrvAudio: Error, card=%p card->audio=%p\n",
2445 (void *) &pThis->qemuSoundCard, &pThis->qemuSoundCard ? (void *) pThis->qemuSoundCard.audio : NULL));
2446 return;
2447 }
2448
2449 drvAudioHlpCloseOut(pThis, pThis->qemuSoundCard.audio, pGstVoiceOut);
2450 }
2451}
2452
2453
2454/********************************************************************/
2455
2456
2457
2458/**
2459 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2460 */
2461static DECLCALLBACK(void *) drvAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2462{
2463 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
2464 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
2465 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
2466 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIOCONNECTOR, &pThis->IAudioConnector);
2467 return NULL;
2468}
2469
2470/**
2471 * Power Off notification.
2472 *
2473 * @param pDrvIns The driver instance data.
2474 */
2475static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns)
2476{
2477 audio_vm_change_state_handler (pDrvIns, 0);
2478}
2479
2480/**
2481 * Destruct a driver instance.
2482 *
2483 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
2484 * resources can be freed correctly.
2485 *
2486 * @param pDrvIns The driver instance data.
2487 */
2488static DECLCALLBACK(void) drvAudioDestruct(PPDMDRVINS pDrvIns)
2489{
2490 LogFlow(("drvAUDIODestruct:\n"));
2491 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
2492
2493 if (audio_streamname)
2494 {
2495 MMR3HeapFree(audio_streamname);
2496 audio_streamname = NULL;
2497 }
2498 drvAudioExit(pDrvIns);
2499}
2500
2501
2502/**
2503 * Construct an AUDIO driver instance.
2504 *
2505 * @copydoc FNPDMDRVCONSTRUCT
2506 */
2507static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
2508{
2509 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
2510 char *drvname;
2511 int rc = 0;
2512 PPDMIBASE pBase;
2513
2514 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
2515
2516 /*
2517 * Init the static parts.
2518 */
2519 pThis->pDrvIns = pDrvIns;
2520 /* IBase */
2521 pDrvIns->IBase.pfnQueryInterface = drvAudioQueryInterface;
2522 /* IAudio */
2523 pThis->IAudioConnector.pfnRead = drvAudioRead;
2524 pThis->IAudioConnector.pfnWrite = drvAudioWrite;
2525 pThis->IAudioConnector.pfnRegisterCard = drvAudioRegisterCard;
2526 pThis->IAudioConnector.pfnIsHostVoiceInOK = drvAudioIsHostVoiceInOK;
2527 pThis->IAudioConnector.pfnIsHostVoiceOutOK = drvAudioIsHostVoiceOutOK;
2528 pThis->IAudioConnector.pfnInitNull = drvAudioInitNull;
2529 pThis->IAudioConnector.pfnIsSetOutVolume = drvAudioIsSetOutVolume;
2530 pThis->IAudioConnector.pfnSetVolume = drvAudioSetVolume;
2531 pThis->IAudioConnector.pfnEnableOut = drvAudioEnableOut;
2532 pThis->IAudioConnector.pfnEnableIn = drvAudioEnableIn;
2533 pThis->IAudioConnector.pfnCloseIn = drvAudioCloseIn;
2534 pThis->IAudioConnector.pfnCloseOut = drvAudioCloseOut;
2535 pThis->IAudioConnector.pfnOpenIn = drvAudioOpenIn;
2536 pThis->IAudioConnector.pfnOpenOut = drvAudioOpenOut;
2537 pThis->IAudioConnector.pfnIsActiveIn = drvAudioIsActiveIn;
2538 pThis->IAudioConnector.pfnIsActiveOut = drvAudioIsActiveOut;
2539 /* Mixer/Conversion */
2540 pThis->IAudioConnector.pfnConvDevFmtToStSample = drvAudioConvDevFmtToStSample;
2541 pThis->IAudioConnector.pfnConvStSampleToDevFmt = drvAudioConvStSampleToDevFmt;
2542 pThis->IAudioConnector.pfnPrepareAudioConversion = drvAudioPrepareAudioConversion;
2543 pThis->IAudioConnector.pfnEndAudioConversion = drvAudioEndAudioConversion;
2544 pThis->IAudioConnector.pfnDoRateConversion = drvAudioDoRateConversion;
2545 pThis->IAudioConnector.pfnDoRateConvAndMix = drvAudioDoRateConvAndMix;
2546
2547 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
2548 if (RT_FAILURE(rc))
2549 {
2550 LogRel(("Failed to attach the audio device rc = %d \n", rc));
2551 return rc;
2552 }
2553 pThis->pHostDrvAudio = PDMIBASE_QUERY_INTERFACE(pBase, PDMIHOSTAUDIO);
2554 if (!pThis->pHostDrvAudio)
2555 {
2556 LogRel(("Audio: Failed to attach to underlying host driver \n"));
2557 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
2558 N_("No media or async media interface below"));
2559 }
2560
2561 pThis->pDrvIns = pDrvIns;
2562 gpDrvIns = pThis->pDrvIns;
2563 rc = CFGMR3QueryStringAlloc (pCfgHandle, "AudioDriver", &drvname);
2564 if (RT_FAILURE (rc))
2565 {
2566 LogFlow(("Failed to get AudioDriver from CFGM\n"));
2567 return rc;
2568 }
2569
2570 rc = CFGMR3QueryStringAlloc (pCfgHandle, "StreamName", &audio_streamname);
2571 if (RT_FAILURE (rc))
2572 {
2573 LogFlow(("Failed to get SteamName from CFGM \n"));
2574 audio_streamname = NULL;
2575 }
2576 rc = drvAudioInit(pCfgHandle, pDrvIns, drvname, pThis);
2577 if (RT_FAILURE (rc))
2578 return rc;
2579
2580 MMR3HeapFree (drvname);
2581
2582 return VINF_SUCCESS;
2583}
2584
2585/**
2586 * Suspend notification.
2587 *
2588 * @returns VBox status.
2589 * @param pDrvIns The driver instance data.
2590 */
2591static DECLCALLBACK(void) drvAudioSuspend(PPDMDRVINS pDrvIns)
2592{
2593 audio_vm_change_state_handler(pDrvIns, 0);
2594}
2595
2596/**
2597 * Resume notification.
2598 *
2599 * @returns VBox status.
2600 * @param pDrvIns The driver instance data.
2601 */
2602static DECLCALLBACK(void) audioResume(PPDMDRVINS pDrvIns)
2603{
2604 audio_vm_change_state_handler(pDrvIns, 1);
2605}
2606
2607/**
2608 * Audio driver registration record.
2609 */
2610const PDMDRVREG g_DrvAUDIO =
2611{
2612 /* u32Version */
2613 PDM_DRVREG_VERSION,
2614 /* szName */
2615 "AUDIO",
2616 /* szRCMod */
2617 "",
2618 /* szR0Mod */
2619 "",
2620 /* pszDescription */
2621 "AUDIO Driver",
2622 /* fFlags */
2623 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
2624 /* fClass. */
2625 PDM_DRVREG_CLASS_AUDIO,
2626 /* cMaxInstances */
2627 2,
2628 /* cbInstance */
2629 sizeof(DRVAUDIO),
2630 /* pfnConstruct */
2631 drvAudioConstruct,
2632 /* pfnDestruct */
2633 drvAudioDestruct,
2634 /* pfnRelocate */
2635 NULL,
2636 /* pfnIOCtl */
2637 NULL,
2638 /* pfnPowerOn */
2639 NULL,
2640 /* pfnReset */
2641 NULL,
2642 /* pfnSuspend */
2643 drvAudioSuspend,
2644 /* pfnResume */
2645 audioResume,
2646 /* pfnAttach */
2647 NULL,
2648 /* pfnDetach */
2649 NULL,
2650 /* pfnPowerOff */
2651 drvAudioPowerOff,
2652 /* pfnSoftReset */
2653 NULL,
2654 /* u32EndVersion */
2655 PDM_DRVREG_VERSION
2656};
2657
2658
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